realtek: mdio: enhance reading phy id

Reading the PHY ID to assign a PHY config is currently simple. For C45
two MDIO reads of a hardcoded MMD are done to get the standard PHY ID
registers. MMD 31 (MMD_VEND2) is used for that purpose, assuming there
will be a valid PHY ID stored in this MMD in all cases. However, with
Aquantia AQR813 there's at least one example for which this isn't true.
This PHY returns 0 for the PHY ID in MMD_VEND2, instead MMD_VEND1 would
have the correct ID.

Enhance reading the PHY by accessing a common set of MMDs of which most
PHY at least implement one and have a valid PHY ID in. To keep overhead
low, do not scan all MMDs. As soon as a valid PHY ID is found, exit and
use that. This is similar to the kernel logic, jsut reduced to fewer
MMDs.

Also handle possible errors coming from MDIO reads to avoid reading garbage.

While at it, move reading the PHY ID to a separate function to not
pollute the poll fixup retrievel function.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/21515
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
This commit is contained in:
Jonas Jelonek 2026-01-11 10:12:00 +00:00 committed by Robert Marko
parent 12fd85eb79
commit 322041ffeb
No known key found for this signature in database
GPG key ID: 66D805C09F36AFA5

View file

@ -532,6 +532,52 @@ static int rtmdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
return 0;
}
static int rtmdio_read_phy_id(struct mii_bus *bus, u8 addr, unsigned int *phy_id)
{
static const int common_mmds[] = {
MDIO_MMD_PMAPMD, MDIO_MMD_PCS, MDIO_MMD_AN,
MDIO_MMD_VEND1, MDIO_MMD_VEND2
};
struct rtmdio_bus_priv *priv = bus->priv;
int devid1 = 0, devid2 = 0;
unsigned int id = 0;
/* Clause 22 */
if (!priv->smi_bus_isc45[priv->smi_bus[addr]]) {
devid1 = rtmdio_read(bus, addr, MDIO_DEVID1);
devid2 = rtmdio_read(bus, addr, MDIO_DEVID2);
if (devid1 < 0 || devid2 < 0)
return -EIO;
id = (devid1 << 16) | devid2;
if (!id || (id & 0x1fffffff) == 0x1fffffff)
return -ENODEV;
*phy_id = id;
return 0;
}
/* Clause 45
* only scan some MMDs which can be considered as common i.e.
* implemented by most PHYs.
*/
for (int i = 0; i < ARRAY_SIZE(common_mmds); i++) {
devid1 = rtmdio_read_c45(bus, addr, common_mmds[i], MDIO_DEVID1);
devid2 = rtmdio_read_c45(bus, addr, common_mmds[i], MDIO_DEVID2);
if (devid1 < 0 || devid2 < 0)
continue;
id = (devid1 << 16) | devid2;
if (id && id != 0xffffffff) {
*phy_id = id;
return 0;
}
}
return -ENODEV;
}
static void rtmdio_get_phy_info(struct mii_bus *bus, int addr, struct rtmdio_phy_info *phyinfo)
{
struct rtmdio_bus_priv *priv = bus->priv;
@ -547,12 +593,10 @@ static void rtmdio_get_phy_info(struct mii_bus *bus, int addr, struct rtmdio_phy
return;
}
if (priv->smi_bus_isc45[priv->smi_bus[addr]])
phyinfo->phy_id = (rtmdio_read_c45(bus, addr, 31, 2) << 16) +
rtmdio_read_c45(bus, addr, 31, 3);
else
phyinfo->phy_id = (rtmdio_read(bus, addr, 2) << 16) +
rtmdio_read(bus, addr, 3);
if (rtmdio_read_phy_id(bus, addr, &phyinfo->phy_id) < 0) {
phyinfo->phy_unknown = true;
return;
}
switch(phyinfo->phy_id) {
case RTMDIO_PHY_AQR113C: