diff --git a/arch/arm64/boot/dts/rockchip/rk3528-radxa-e24c.dts b/arch/arm64/boot/dts/rockchip/rk3528-radxa-e24c.dts index aed681893afe3..7f130a728e20e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3528-radxa-e24c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3528-radxa-e24c.dts @@ -379,28 +379,28 @@ port@0 { reg = <0>; label = "wan"; - local-mac-address = [00 48 54 20 00 00]; + mac-at-eeprom = <&eeprom 0x9E 0x06>; phy-handle = <&phy0>; }; port@1 { reg = <1>; label = "lan1"; - local-mac-address = [00 48 54 20 00 01]; + mac-at-eeprom = <&eeprom 0xA4 0x06>; phy-handle = <&phy1>; }; port@2 { reg = <2>; label = "lan2"; - local-mac-address = [00 48 54 20 00 02]; + mac-at-eeprom = <&eeprom 0xAA 0x06>; phy-handle = <&phy2>; }; port@3 { reg = <3>; label = "lan3"; - local-mac-address = [00 48 54 20 00 03]; + mac-at-eeprom = <&eeprom 0xB0 0x06>; phy-handle = <&phy3>; }; @@ -408,7 +408,6 @@ reg = <6>; label = "cpu"; ethernet = <&gmac1>; - local-mac-address = [00 48 54 20 00 33]; phy-mode = "rgmii"; tx-internal-delay-ps = <2000>; rx-internal-delay-ps = <2000>; diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 5417f7b1187cb..c7309fee3f06b 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "dsa_priv.h" @@ -527,6 +528,112 @@ static void dsa_port_devlink_teardown(struct dsa_port *dp) devlink_port_fini(dlp); } +int dsa_port_read_mac_from_eeprom(struct dsa_port *dp) +{ + struct device_node *np = dp->dn; + struct device_node *eeprom_np; + struct i2c_client *client; + struct i2c_adapter *adapter; + struct i2c_msg msg[2]; + u32 offset, len; + u8 offbuf[1]; + int ret; + + if (!np) + return -EINVAL; + + /* Format: mac-at-eeprom = <&eeprom offset len>; */ + eeprom_np = of_parse_phandle(np, "mac-at-eeprom", 0); + if (!eeprom_np) + return -ENOENT; + + ret = of_property_read_u32_index(np, "mac-at-eeprom", 1, &offset); + if (ret) { + dev_err(dp->ds->dev, + "failed to read mac-at-eeprom offset\n"); + goto out_put_np; + } + + ret = of_property_read_u32_index(np, "mac-at-eeprom", 2, &len); + if (ret) { + dev_err(dp->ds->dev, + "failed to read mac-at-eeprom length\n"); + goto out_put_np; + } + + if (len != ETH_ALEN) { + ret = -EINVAL; + goto out_put_np; + } + + /* 24c16 uses 1-byte address */ + if (offset > 0xff || offset > 0x100 - len) { + dev_err(dp->ds->dev, + "mac-at-eeprom offset %u + len %u out of range\n", + offset, len); + ret = -EINVAL; + goto out_put_np; + } + + client = of_find_i2c_device_by_node(eeprom_np); + if (!client) { + ret = -ENODEV; + goto out_put_np; + } + + of_node_put(eeprom_np); + + if (!get_device(&client->dev)) + return -ENODEV; + + adapter = client->adapter; + + offbuf[0] = offset & 0xff; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = offbuf; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = ETH_ALEN; + msg[1].buf = dp->mac; + + ret = i2c_transfer(adapter, msg, 2); + put_device(&client->dev); + + if (ret != 2) + return -EIO; + + return is_valid_ether_addr(dp->mac) ? 0 : -EINVAL; + +out_put_np: + of_node_put(eeprom_np); + return ret; +} +EXPORT_SYMBOL_GPL(dsa_port_read_mac_from_eeprom); + +static bool dsa_port_get_mac(struct dsa_port *dp, u8 *mac) +{ + /* 1. try DTS */ + if (!of_get_mac_address(dp->dn, mac) && + is_valid_ether_addr(mac)) { + return true; + } + + /* 2. try EEPROM */ + if (dsa_port_read_mac_from_eeprom(dp) == 0 && + is_valid_ether_addr(dp->mac)) { + ether_addr_copy(mac, dp->mac); + return true; + } + + /* 3. fallback */ + eth_random_addr(mac); + return true; +} + static int dsa_port_setup(struct dsa_port *dp) { struct devlink_port *dlp = &dp->devlink_port; @@ -583,7 +690,8 @@ static int dsa_port_setup(struct dsa_port *dp) break; case DSA_PORT_TYPE_USER: - of_get_mac_address(dp->dn, dp->mac); + dsa_port_get_mac(dp, dp->mac); + pr_info("dsa port %s mac = %pM\n", dp->name, dp->mac); err = dsa_slave_create(dp); if (err) break;