2 Commits

Author SHA1 Message Date
7633e8c9b1 ethernet: stmmac: dwmac-rk: generate the mac address from the system serial number
Added the feature of generating MAC addresses from serial numbers for dwmac-rk
and added the necessary fallback strategies.

Signed-off-by: meilimao <meilimao@meilimao.org>
2025-12-16 00:22:36 +08:00
4638dcb7ce ethernet: stmmac: dwmac-rk: Fixed the Makefile pointed to a non-existent file when DWMAC_ROCKCHIP was selected
The Makefile pointing to a non-existent path has been corrected now.

Signed-off-by: meilimao <meilimao@meilimao.org>
2025-12-15 21:58:26 +08:00
3 changed files with 192 additions and 39 deletions

View File

@@ -168,11 +168,21 @@ config DWMAC_ROCKCHIP
depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
select MFD_SYSCON
help
Support for Ethernet controller on Rockchip RK3288 SoC.
Support for Ethernet controller on Rockchip SoC.
This selects the Rockchip RK3288 SoC glue layer support for
This selects the Rockchip SoC glue layer support for
the stmmac device driver.
config DWMAC_ROCKCHIP_SERIAL_MAC
bool "Generate static ethernet mac address from system serial number"
depends on DWMAC_ROCKCHIP
default n
help
Generate consistent MAC address from system serial number.
This selects uses the system serial number to generate a
fixed Ethernet Mac address instead of a random one.
config DWMAC_ROCKCHIP_TOOL
bool "Rockchip dwmac tool support"
depends on DWMAC_ROCKCHIP

View File

@@ -27,9 +27,8 @@ obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas.o
obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rockchip.o
dwmac-rockchip-objs := dwmac-rk.o
dwmac-rockchip-$(CONFIG_DWMAC_ROCKCHIP_TOOL) += dwmac-rk-tool.o
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
obj-$(CONFIG_DWMAC_ROCKCHIP_TOOL) += dwmac-rk-tool.o
obj-$(CONFIG_STMMAC_UIO) += stmmac_uio.o
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
@@ -48,3 +47,5 @@ obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
obj-$(CONFIG_DWMAC_INTEL) += dwmac-intel.o
obj-$(CONFIG_DWMAC_LOONGSON) += dwmac-loongson.o
stmmac-pci-objs:= stmmac_pci.o
ccflags-$(CONFIG_DWMAC_ROCKCHIP_SERIAL_MAC) += -DDWMAC_ROCKCHIP_SERIAL_MAC

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/**
* DOC: dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
* DOC: dwmac-rk.c - Rockchip DWMAC specific glue layer
*
* Copyright (C) 2014 Chen-Zhi (Roger Chen)
*
@@ -28,6 +28,9 @@
#include <soc/rockchip/rockchip_csu.h>
#include "stmmac_platform.h"
#include "dwmac-rk-tool.h"
#ifdef DWMAC_ROCKCHIP_SERIAL_MAC
#include <asm/system_info.h>
#endif
#define MAX_ETH 2
@@ -3254,45 +3257,184 @@ int dwmac_rk_get_phy_interface(struct stmmac_priv *priv)
}
EXPORT_SYMBOL(dwmac_rk_get_phy_interface);
/**
* rk_generate_fallback_mac - Generate a fallback MAC address
* @addr: Buffer to store the MAC address (6 bytes)
* @iface_id: Interface identifier
*
* Generate a random MAC address with a local-admin OUI as fallback.
* Always returns a valid MAC address.
*/
static void rk_generate_fallback_mac(u8 *addr, int iface_id)
{
/* Generate a random MAC address */
eth_random_addr(addr);
/* Ensure the address is valid */
if (!is_valid_ether_addr(addr)) {
eth_zero_addr(addr);
/* Set a fallback locally administered address */
addr[0] = 0x02; /* Locally administered bit is set */
addr[1] = 0x00;
addr[2] = 0xa4;
addr[3] = 0xff;
addr[4] = iface_id & 0xff;
addr[5] = 0xfe;
}
}
#ifdef DWMAC_ROCKCHIP_SERIAL_MAC
/*
* rk_get_mac_from_serial - Generate MAC address from system serial number
* @addr: Buffer to store the MAC address (6 bytes)
* @iface_id: Interface identifier
*
* Return: 0 on success, negative error code on failure
*/
static int rk_get_mac_from_serial(u8 *addr, int iface_id)
{
unsigned long long serial;
/* Check the validity of the serial number */
if (system_serial_low == 0 && system_serial_high == 0)
return -ENODEV;
/* Combine the 64-bit serial number */
serial = ((unsigned long long)system_serial_high << 32) | system_serial_low;
/* Validate the serial number (optional but recommended) */
if (serial == 0 || serial == 0xFFFFFFFFFFFFFFFFULL)
return -EINVAL;
/* Generate OUI: 02:00:a4 (locally administered address) */
addr[0] = 0x02; /* Locally administered bit is set */
addr[1] = 0x00;
addr[2] = 0xa4;
/* Use parts of the serial number */
addr[3] = 0x10 + ((serial >> 40) & 0xff);
addr[4] = (serial >> 32) & 0xff;
addr[5] = ((serial >> 24) & 0xff) + iface_id;
return 0;
}
#endif /* DWMAC_ROCKCHIP_SERIAL_MAC */
/*
* rk_set_mac_address - Set up MAC address for an interface
* @addr: Buffer to store the MAC address (6 bytes)
* @iface_id: Interface identifier
*
* This function attempts to generate a deterministic MAC address from the
* system serial number if DWMAC_ROCKCHIP_SERIAL_MAC is enabled. If that fails
* or the feature is disabled, it falls back to a random MAC address.
*
* Return: Always returns 0 (success), as we guarantee a valid address.
*/
static int rk_set_mac_address(u8 *addr, int iface_id)
{
#ifdef DWMAC_ROCKCHIP_SERIAL_MAC
int ret;
/* Attempt to generate MAC from serial number */
ret = rk_get_mac_from_serial(addr, iface_id);
if (ret == 0 && is_valid_ether_addr(addr)) {
return 0; /* Success, return immediately */
}
/* Fall back to a random address on failure */
printk_once(KERN_WARNING "dwc-rockchip: Serial MAC generation failed, using random for interface %d\n",
iface_id);
#endif
/* Generate fallback MAC address */
rk_generate_fallback_mac(addr, iface_id);
return 0;
}
static void rk_get_eth_addr(void *priv, unsigned char *addr)
{
struct rk_priv_data *bsp_priv = priv;
struct device *dev = &bsp_priv->pdev->dev;
unsigned char ethaddr[ETH_ALEN * MAX_ETH] = {0};
int ret, id = bsp_priv->id;
struct rk_priv_data *bsp_priv = priv;
struct device *dev = &bsp_priv->pdev->dev;
unsigned char ethaddr[ETH_ALEN * MAX_ETH] = {0};
int ret, id = bsp_priv->id;
if (is_valid_ether_addr(addr))
goto out;
/* Check if the address is already valid */
if (is_valid_ether_addr(addr)) {
dev_info(dev, "%s: MAC address already set: %pM\n", __func__, addr);
return;
}
if (id < 0 || id >= MAX_ETH) {
dev_err(dev, "%s: Invalid ethernet bus id %d\n", __func__, id);
return;
}
if (id < 0 || id >= MAX_ETH) {
dev_err(dev, "%s: Invalid ethernet bus id %d\n", __func__, id);
/* Still try to set a MAC address even with invalid ID */
id = 0;
}
ret = rk_vendor_read(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
if (ret <= 0 ||
!is_valid_ether_addr(&ethaddr[id * ETH_ALEN])) {
dev_err(dev, "%s: rk_vendor_read eth mac address failed (%d)\n",
__func__, ret);
eth_random_addr(&ethaddr[id * ETH_ALEN]);
memcpy(addr, &ethaddr[id * ETH_ALEN], ETH_ALEN);
dev_err(dev, "%s: generate random eth mac address: %pM\n", __func__, addr);
#ifdef DWMAC_ROCKCHIP_SERIAL_MAC
/* Try to generate MAC from system serial number first */
dev_info(dev, "%s: Attempting to generate MAC from system serial number for interface %d\n",
__func__, id);
if (rk_set_mac_address(addr, id) == 0 && is_valid_ether_addr(addr)) {
dev_info(dev, "%s: Generated MAC from serial: %pM\n", __func__, addr);
/* Store the generated MAC address to vendor storage for persistence */
ret = rk_vendor_read(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
if (ret < 0) {
/* Initialize the buffer if read failed */
memset(ethaddr, 0, ETH_ALEN * MAX_ETH);
}
/* Copy our generated MAC to the appropriate position */
memcpy(&ethaddr[id * ETH_ALEN], addr, ETH_ALEN);
/* Write back to vendor storage */
ret = rk_vendor_write(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
if (ret != 0) {
dev_warn(dev, "%s: Failed to store MAC to vendor storage (%d)\n",
__func__, ret);
} else {
dev_info(dev, "%s: Stored generated MAC to vendor storage\n", __func__);
}
return;
}
dev_warn(dev, "%s: Serial-based MAC generation failed for interface %d, falling back to vendor storage\n",
__func__, id);
#endif /* DWMAC_ROCKCHIP_SERIAL_MAC */
ret = rk_vendor_write(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
if (ret != 0)
dev_err(dev, "%s: rk_vendor_write eth mac address failed (%d)\n",
__func__, ret);
/* Fallback: try to read from vendor storage */
ret = rk_vendor_read(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
if (ret > 0 && is_valid_ether_addr(&ethaddr[id * ETH_ALEN])) {
memcpy(addr, &ethaddr[id * ETH_ALEN], ETH_ALEN);
dev_info(dev, "%s: Retrieved MAC from vendor storage: %pM\n",
__func__, addr);
return;
}
ret = rk_vendor_read(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
if (ret != ETH_ALEN * MAX_ETH)
dev_err(dev, "%s: id: %d rk_vendor_read eth mac address failed (%d)\n",
__func__, id, ret);
} else {
memcpy(addr, &ethaddr[id * ETH_ALEN], ETH_ALEN);
}
out:
dev_err(dev, "%s: mac address: %pM\n", __func__, addr);
/* Last resort: generate fallback MAC */
dev_warn(dev, "%s: No valid MAC found, generating fallback for interface %d\n",
__func__, id);
rk_generate_fallback_mac(addr, id);
/* Store the fallback MAC to vendor storage */
if (ret < 0) {
/* Initialize the buffer if read failed */
memset(ethaddr, 0, ETH_ALEN * MAX_ETH);
}
memcpy(&ethaddr[id * ETH_ALEN], addr, ETH_ALEN);
ret = rk_vendor_write(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
if (ret != 0) {
dev_err(dev, "%s: Failed to store fallback MAC to vendor storage (%d)\n",
__func__, ret);
} else {
dev_info(dev, "%s: Stored fallback MAC to vendor storage: %pM\n",
__func__, addr);
}
}
static int rk_gmac_probe(struct platform_device *pdev)
@@ -3483,5 +3625,5 @@ static struct platform_driver rk_gmac_dwmac_driver = {
module_platform_driver(rk_gmac_dwmac_driver);
MODULE_AUTHOR("Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer");
MODULE_DESCRIPTION("Rockchip DWMAC specific glue layer");
MODULE_LICENSE("GPL");