Compare commits
2 Commits
1d6cba4093
...
7633e8c9b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
7633e8c9b1
|
|||
|
4638dcb7ce
|
@@ -168,11 +168,21 @@ config DWMAC_ROCKCHIP
|
|||||||
depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
|
depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
|
||||||
select MFD_SYSCON
|
select MFD_SYSCON
|
||||||
help
|
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.
|
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
|
config DWMAC_ROCKCHIP_TOOL
|
||||||
bool "Rockchip dwmac tool support"
|
bool "Rockchip dwmac tool support"
|
||||||
depends on DWMAC_ROCKCHIP
|
depends on DWMAC_ROCKCHIP
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
|
|||||||
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
|
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
|
||||||
obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas.o
|
obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas.o
|
||||||
obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o
|
obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o
|
||||||
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rockchip.o
|
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
|
||||||
dwmac-rockchip-objs := dwmac-rk.o
|
obj-$(CONFIG_DWMAC_ROCKCHIP_TOOL) += dwmac-rk-tool.o
|
||||||
dwmac-rockchip-$(CONFIG_DWMAC_ROCKCHIP_TOOL) += dwmac-rk-tool.o
|
|
||||||
obj-$(CONFIG_STMMAC_UIO) += stmmac_uio.o
|
obj-$(CONFIG_STMMAC_UIO) += stmmac_uio.o
|
||||||
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
|
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
|
||||||
obj-$(CONFIG_DWMAC_STI) += dwmac-sti.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_INTEL) += dwmac-intel.o
|
||||||
obj-$(CONFIG_DWMAC_LOONGSON) += dwmac-loongson.o
|
obj-$(CONFIG_DWMAC_LOONGSON) += dwmac-loongson.o
|
||||||
stmmac-pci-objs:= stmmac_pci.o
|
stmmac-pci-objs:= stmmac_pci.o
|
||||||
|
|
||||||
|
ccflags-$(CONFIG_DWMAC_ROCKCHIP_SERIAL_MAC) += -DDWMAC_ROCKCHIP_SERIAL_MAC
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// 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)
|
* Copyright (C) 2014 Chen-Zhi (Roger Chen)
|
||||||
*
|
*
|
||||||
@@ -28,6 +28,9 @@
|
|||||||
#include <soc/rockchip/rockchip_csu.h>
|
#include <soc/rockchip/rockchip_csu.h>
|
||||||
#include "stmmac_platform.h"
|
#include "stmmac_platform.h"
|
||||||
#include "dwmac-rk-tool.h"
|
#include "dwmac-rk-tool.h"
|
||||||
|
#ifdef DWMAC_ROCKCHIP_SERIAL_MAC
|
||||||
|
#include <asm/system_info.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MAX_ETH 2
|
#define MAX_ETH 2
|
||||||
|
|
||||||
@@ -3254,6 +3257,102 @@ int dwmac_rk_get_phy_interface(struct stmmac_priv *priv)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dwmac_rk_get_phy_interface);
|
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)
|
static void rk_get_eth_addr(void *priv, unsigned char *addr)
|
||||||
{
|
{
|
||||||
struct rk_priv_data *bsp_priv = priv;
|
struct rk_priv_data *bsp_priv = priv;
|
||||||
@@ -3261,38 +3360,81 @@ static void rk_get_eth_addr(void *priv, unsigned char *addr)
|
|||||||
unsigned char ethaddr[ETH_ALEN * MAX_ETH] = {0};
|
unsigned char ethaddr[ETH_ALEN * MAX_ETH] = {0};
|
||||||
int ret, id = bsp_priv->id;
|
int ret, id = bsp_priv->id;
|
||||||
|
|
||||||
if (is_valid_ether_addr(addr))
|
/* Check if the address is already valid */
|
||||||
goto out;
|
if (is_valid_ether_addr(addr)) {
|
||||||
|
dev_info(dev, "%s: MAC address already set: %pM\n", __func__, addr);
|
||||||
if (id < 0 || id >= MAX_ETH) {
|
|
||||||
dev_err(dev, "%s: Invalid ethernet bus id %d\n", __func__, id);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = rk_vendor_read(LAN_MAC_ID, ethaddr, ETH_ALEN * MAX_ETH);
|
if (id < 0 || id >= MAX_ETH) {
|
||||||
if (ret <= 0 ||
|
dev_err(dev, "%s: Invalid ethernet bus id %d\n", __func__, id);
|
||||||
!is_valid_ether_addr(ðaddr[id * ETH_ALEN])) {
|
/* Still try to set a MAC address even with invalid ID */
|
||||||
dev_err(dev, "%s: rk_vendor_read eth mac address failed (%d)\n",
|
id = 0;
|
||||||
__func__, ret);
|
|
||||||
eth_random_addr(ðaddr[id * ETH_ALEN]);
|
|
||||||
memcpy(addr, ðaddr[id * ETH_ALEN], ETH_ALEN);
|
|
||||||
dev_err(dev, "%s: generate random eth mac address: %pM\n", __func__, addr);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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, ðaddr[id * ETH_ALEN], ETH_ALEN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
#ifdef DWMAC_ROCKCHIP_SERIAL_MAC
|
||||||
dev_err(dev, "%s: mac address: %pM\n", __func__, addr);
|
/* 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(ðaddr[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 */
|
||||||
|
|
||||||
|
/* 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(ðaddr[id * ETH_ALEN])) {
|
||||||
|
memcpy(addr, ðaddr[id * ETH_ALEN], ETH_ALEN);
|
||||||
|
dev_info(dev, "%s: Retrieved MAC from vendor storage: %pM\n",
|
||||||
|
__func__, addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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(ðaddr[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)
|
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_platform_driver(rk_gmac_dwmac_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>");
|
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");
|
MODULE_LICENSE("GPL");
|
||||||
|
|||||||
Reference in New Issue
Block a user