[devel] [PATCH 24/35] net: fwnode_get_phy_id: consider all compatible strings

asheplyakov на yandex.ru asheplyakov на yandex.ru
Пт Май 20 19:28:38 MSK 2022


From: Alexey Sheplyakov <asheplyakov на altlinux.org>

Commit cf99686072a1b7037a1d782b66037b2b722bf2c9 ("of: mdio:
Refactor of_get_phy_id()") has broken Ethernet on TF307 board
(and possibly other boards based on Baikal-M/T1 SoCs).

That commit replaces `of_get_phy_id` with `fwnode_get_phy_id`.
And `fwnode_get_phy_id` considers only the 1st compatible string
to find out phy_id. This works well for all schema compliant device
trees, since the `compatible` property of PHY nodes is supposed
to be "ethernet-phy-idNNNN.MMMM".

However DTB embedded in TF307 firmware describes PHY like this:

gmac0_phy: ethernet-phy на 3 {
  compatible = "micrel,ksz9031", "ethernet-phy-id0022.1620", "ethernet-phy-ieee802.3-c22";
  reg = <0x3>;
};

That is, the 1st compatible string is "micrel,ksz9031". Thus
`fwnode_get_phy_id` is unable to parse phy_id, and
`stmmac_mdio_register` fails. As a result Ethernet driver is
unable to attach to PHY, and can't send/receive anything.

To avoid the problem this patch adjusts `fwnode_get_phy_id`
to consider *all* compatible strings.

X-DONTUPSTREAM
X-feature-Baikal-M
---
 drivers/net/phy/phy_device.c | 41 ++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 11 deletions(-)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ce0bb5951b81..27cf041fafb1 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -840,18 +840,37 @@ static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id)
 int fwnode_get_phy_id(struct fwnode_handle *fwnode, u32 *phy_id)
 {
 	unsigned int upper, lower;
-	const char *cp;
-	int ret;
-
-	ret = fwnode_property_read_string(fwnode, "compatible", &cp);
-	if (ret)
-		return ret;
-
-	if (sscanf(cp, "ethernet-phy-id%4x.%4x", &upper, &lower) != 2)
-		return -EINVAL;
+	const char **compat;
+	int ret, count, i;
+
+	/* FIXME: where is fwnode_property_for_each_string? */
+	count = fwnode_property_read_string_array(fwnode, "compatible", NULL, 0);
+	if (count < 0)
+		return count;
+	else if (count == 0)
+		return -ENODATA;
+
+	compat = kcalloc(count, sizeof(*compat), GFP_KERNEL);
+	if (!compat)
+		return -ENOMEM;
+	ret = fwnode_property_read_string_array(fwnode, "compatible", compat, count);
+	if (ret < 0)
+		goto out;
 
-	*phy_id = ((upper & GENMASK(15, 0)) << 16) | (lower & GENMASK(15, 0));
-	return 0;
+	ret = -EINVAL;
+	for (i = 0; i < count; i++) {
+		pr_info("%s: considering '%s'\n", __func__, compat[i]);
+		if (sscanf(compat[i], "ethernet-phy-id%4x.%4x", &upper, &lower) != 2)
+			continue;
+		else {
+			*phy_id = ((upper & GENMASK(15, 0)) << 16) | (lower & GENMASK(15, 0));
+			ret = 0;
+			break;
+		}
+	}
+out:
+	kfree(compat);
+	return ret;
 }
 EXPORT_SYMBOL(fwnode_get_phy_id);
 
-- 
2.32.0



Подробная информация о списке рассылки Devel