* C22/C45 decision in phy_restart_aneg()
@ 2025-08-31 7:45 markus.stockhausen
2025-08-31 10:08 ` Russell King (Oracle)
0 siblings, 1 reply; 3+ messages in thread
From: markus.stockhausen @ 2025-08-31 7:45 UTC (permalink / raw)
To: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni, netdev
Cc: jan, 'Chris Packham'
Hi,
@Russell: Sorry for the inconvenience of my first mail. After a lengthy
analysis session, I focused too much on the initial C45 enhancement
of the below function that you wrote. I sent it off too hastily.
So, once again, here is some interesting finding regarding the
limitations of the Realtek MDIO driver. Remember that it can only run
in either C22 or C45. This time it is about autonegotiation restart.
int phy_restart_aneg(struct phy_device *phydev) {
int ret;
if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))
ret = genphy_c45_restart_aneg(phydev);
else
ret = genphy_restart_aneg(phydev);
return ret;
}
I assume that BIT(0) means MDIO_DEVS_C22_PRESENT. As I understand it,
this basically uses C22 commands for C45 PHYs if C22 support is detected.
Currently, I have no reasonable explanation for this additional check.
In our case, this function fails for C45 PHYs because the bus and PHY are
locked down to this single mode. It's stupid, of course, but that's how
it is. I see two options for fixing the issue:
1) Mask the C22 presence in the bus for all PHYs when running in C45.
2) Drop the C22 condition check in the above function.
Any advice?
Thanks in advance.
Markus
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: C22/C45 decision in phy_restart_aneg() 2025-08-31 7:45 C22/C45 decision in phy_restart_aneg() markus.stockhausen @ 2025-08-31 10:08 ` Russell King (Oracle) 2025-08-31 15:35 ` Andrew Lunn 0 siblings, 1 reply; 3+ messages in thread From: Russell King (Oracle) @ 2025-08-31 10:08 UTC (permalink / raw) To: markus.stockhausen Cc: andrew, hkallweit1, davem, edumazet, kuba, pabeni, netdev, jan, 'Chris Packham' On Sun, Aug 31, 2025 at 09:45:46AM +0200, markus.stockhausen@gmx.de wrote: > @Russell: Sorry for the inconvenience of my first mail. After a lengthy > analysis session, I focused too much on the initial C45 enhancement > of the below function that you wrote. I sent it off too hastily. It's important to send messages to the right people for a proper discussion. Andrew may have some input on this - maybe as a result of my ideas below. > So, once again, here is some interesting finding regarding the > limitations of the Realtek MDIO driver. Remember that it can only run > in either C22 or C45. This time it is about autonegotiation restart. > > int phy_restart_aneg(struct phy_device *phydev) { > int ret; > > if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)) > ret = genphy_c45_restart_aneg(phydev); > else > ret = genphy_restart_aneg(phydev); > > return ret; > } > > I assume that BIT(0) means MDIO_DEVS_C22_PRESENT. As I understand it, > this basically uses C22 commands for C45 PHYs if C22 support is detected. > Currently, I have no reasonable explanation for this additional check. There was discussion and delving into the spec when this was added. See https://lore.kernel.org/all/20170601102327.GF27796@n2100.armlinux.org.uk/ (side note: google is now useless for finding that, searching for "hook up clause 45 autonegotiation restart" returns very few results, none of them with the full history. I've had to search my mailboxes for it, find the message ID, and then look it up on lore. We now have various web high-bandwidth crawlers that do not respect robots.txt to thank for this as sites have ended up blocking all crawlers using stuff like Anubis proof of work.) It's been a long time, and so I've forgotten the details now, so all there is to go on are the above emails. You may notice that the initial version I submitted just used phydev->is_c45. > In our case, this function fails for C45 PHYs because the bus and PHY are > locked down to this single mode. It's stupid, of course, but that's how > it is. I see two options for fixing the issue: > > 1) Mask the C22 presence in the bus for all PHYs when running in C45. > 2) Drop the C22 condition check in the above function. I guess we also need to make these kinds of tests conditional on whether the bus supports C45 or not. static bool mdiobus_supports_c22(struct mii_bus *bus) { return bus->read && bus->write; } static bool mdiobus_supports_c45(struct mii_bus *bus) { return bus->read_c45 && bus->write_c45; } This should be fine, because we already require MII bus drivers to only populate these methods only when they're supported (see commit fbfe97597c77 ("net: phy: Decide on C45 capabilities based on presence of method"). if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)) can then become: if (phydev->is_c45 && !(mdiobus_supports_c22(phydev->mdio.bus) && phydev->c45_ids.devices_in_package & MDIO_DEVS_C22PRESENT)) -- RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last! ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: C22/C45 decision in phy_restart_aneg() 2025-08-31 10:08 ` Russell King (Oracle) @ 2025-08-31 15:35 ` Andrew Lunn 0 siblings, 0 replies; 3+ messages in thread From: Andrew Lunn @ 2025-08-31 15:35 UTC (permalink / raw) To: Russell King (Oracle) Cc: markus.stockhausen, hkallweit1, davem, edumazet, kuba, pabeni, netdev, jan, 'Chris Packham' > > In our case, this function fails for C45 PHYs because the bus and PHY are > > locked down to this single mode. It's stupid, of course, but that's how > > it is. I see two options for fixing the issue: > > > > 1) Mask the C22 presence in the bus for all PHYs when running in C45. > > 2) Drop the C22 condition check in the above function. > > I guess we also need to make these kinds of tests conditional on > whether the bus supports C45 or not. > > static bool mdiobus_supports_c22(struct mii_bus *bus) > { > return bus->read && bus->write; > } > > static bool mdiobus_supports_c45(struct mii_bus *bus) > { > return bus->read_c45 && bus->write_c45; > } Something i've said in the past is that we have a mess regarding what does phydev->is_c45 mean? And really, this is an extension of that mess. There are two separate C45 concepts which get mixed up in is_c45. One concept is, does the PHY have the C45 register address space? The second concept is, how do you access the C45 address space? Via C45 bus transactions, or C45 over C22 bus transactions. The extension here is, does the PHY have the C22 address space, and what sort of bus transactions do you use to access the C22 address space. It is however simplified, there is no C22 over C45 as far as i know. So it is actually, can you do C22 bus transactions or not? I've tried in the past to get developers to sort out this mess, but it never got very far. Maybe we can use this as an opportunity to address a little bit of the problem? > This should be fine, because we already require MII bus drivers to only > populate these methods only when they're supported (see commit > fbfe97597c77 ("net: phy: Decide on C45 capabilities based on presence > of method"). > > if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)) > > can then become: > > if (phydev->is_c45 && > !(mdiobus_supports_c22(phydev->mdio.bus) && > phydev->c45_ids.devices_in_package & MDIO_DEVS_C22PRESENT)) So what we are asking here is, can we do C22 bus transfers, and does the PHY have the C22 address space? And looking in the code, there are at least three places this is needed: int phy_restart_aneg(struct phy_device *phydev) { int ret; if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) ret = genphy_c45_restart_aneg(phydev); else ret = genphy_restart_aneg(phydev); return ret; } int phy_aneg_done(struct phy_device *phydev) { if (phydev->drv && phydev->drv->aneg_done) return phydev->drv->aneg_done(phydev); else if (phydev->is_c45) return genphy_c45_aneg_done(phydev); else return genphy_aneg_done(phydev); } This i _think_ is currently broken, i would expect the same condition to apply. int phy_config_aneg(struct phy_device *phydev) { if (phydev->drv->config_aneg) return phydev->drv->config_aneg(phydev); /* Clause 45 PHYs that don't implement Clause 22 registers are not * allowed to call genphy_config_aneg() */ if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) return genphy_c45_config_aneg(phydev); return genphy_config_aneg(phydev); } So maybe we should add new members to phydev? @bus_has_c22: The bus can perform C22 transactions @phy_has_c22_regs: The PHY has the C22 register address space. During probe, we set bus_has_c22 based on Russells mdiobus_supports_c22() above. phy_has_c22_regs should be set if we discover the PHY by C22 ID registers, or phydev->c45_ids.devices_in_package indicates the PHY has C22 registers. We also need to handle the PHY is instantiated via ID values in DT. After the PHY has probed, we can read C22 registers 2 and 3, and see if the ID look valid, i.e. mostly not F, same as we do in get_phy_c22_id(). The condition then becomes: if (phydev->is_c45 && !(phydev->bus_has_c22 && phydev->phy_has_c22_regs)) Then maybe some time in the future, the is_c45 will get replaced with something similar? Andrew ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-08-31 15:36 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-08-31 7:45 C22/C45 decision in phy_restart_aneg() markus.stockhausen 2025-08-31 10:08 ` Russell King (Oracle) 2025-08-31 15:35 ` Andrew Lunn
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox