From fca91be2db2cb15190b5006fff06932a18609517 Mon Sep 17 00:00:00 2001 From: Mihai Ordean Date: Fri, 31 Jul 2026 12:00:00 +0000 Subject: [PATCH 1/2] net: phy: as21xxx: don't write to a nonexistent PHY after C45 reads aeon_cl45_read() ends with aeon_mdio_patch(), which issues __mdiobus_c45_write(bus, 30, 0x1, 0x1, 0x1); a write to PHY address 30 on whatever bus the phydev happens to live on. Nothing is at address 30. phylib calls match_phy_device() for every registered driver entry against every phydev, so aeon_gen1_read_pid() runs against PHYs that are not Aeonsemi parts - including the four internal GPY cores of an MxL86252C DSA switch, whose bus is the switch firmware's MDIO relay. There the write becomes an INT_GPHY_WRITE mailbox command for PHY 30, which the firmware rejects: mxl862xx mdio-bus:10: CMD 1802 returned error -19 On a BPI-R4 Pro that is 4 GPY cores x 12 match entries x 2 PID reads = 96 rejected commands on every boot. A read needs no flush: __mdiobus_c45_read() has already completed and dropped the bus lock when the patch write is issued. The mainline as21xxx driver performs the same identification and firmware load with no such write at all. Drop it from the read path. aeon_mdio_patch() is kept in aeon_cl45_write(), where the original workaround was reported to matter. After this change every remaining caller is reached only once a device has been confirmed to be an AS21xxx, so no foreign bus is touched. Signed-off-by: Mihai Ordean --- drivers/net/phy/as21xx_1.9.2/as21xxx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/phy/as21xx_1.9.2/as21xxx.c b/drivers/net/phy/as21xx_1.9.2/as21xxx.c index b5cf7a9c1b1a8..26f11cf71d0cd 100644 --- a/drivers/net/phy/as21xx_1.9.2/as21xxx.c +++ b/drivers/net/phy/as21xx_1.9.2/as21xxx.c @@ -493,7 +493,6 @@ int aeon_cl45_read(struct phy_device *phydev, int dev_addr, mutex_lock(&bus->mdio_lock); ret = __mdiobus_c45_read(bus, phy_addr, dev_addr, phy_reg); mutex_unlock(&bus->mdio_lock); - aeon_mdio_patch(phydev); return ret; } From a433dbf4c7c757ae352428dbd961d1034aa6856d Mon Sep 17 00:00:00 2001 From: Mihai Ordean Date: Fri, 31 Jul 2026 12:05:00 +0000 Subject: [PATCH 2/2] net: phy: as21xxx: only probe Aeonsemi PHYs when matching aeon_gen1_match_phy_device() and aeon_gen2_match_phy_device() read the PHY ID out of every phydev phylib offers them, with no check that the device is an Aeonsemi part at all. phylib calls match_phy_device() for every registered driver entry against every phydev on every bus, so the driver issues C45 vendor register accesses to foreign PHYs. On a BPI-R4 Pro the four internal GPY cores of the MxL86252C sit on the switch firmware's MDIO relay, where each of those reads is a full mailbox transaction: write LEN_RET, write CTRL, poll for BUSY to clear, read CTRL and LEN_RET back. With 12 match entries (11 gen1, 1 gen2) and two PID reads each, that is 96 pointless mailbox commands - several thousand SMDIO frames - during PHY probing, delaying the switch setup that follows. The mainline as21xxx driver guards its match function with a vendor comparison and returns genphy_match_phy_device() for everything else. Do the same here. PHY_VENDOR_AEONSEMI is already defined and was previously unused. Signed-off-by: Mihai Ordean --- drivers/net/phy/as21xx_1.9.2/as21xxx.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/as21xx_1.9.2/as21xxx.c b/drivers/net/phy/as21xx_1.9.2/as21xxx.c index 26f11cf71d0cd..ed001d3a834e3 100644 --- a/drivers/net/phy/as21xx_1.9.2/as21xxx.c +++ b/drivers/net/phy/as21xx_1.9.2/as21xxx.c @@ -1480,7 +1480,17 @@ static int aeon_config_led(struct phy_device *phydev) static int aeon_gen1_match_phy_device(struct phy_device *phydev, const struct phy_driver *phydrv) { - u32 phy_id = aeon_gen1_read_pid(phydev); + u32 phy_id; + + /* Skip PHYs that are not Aeonsemi. Probing every PHY on every bus + * sends vendor register accesses to foreign devices, which on a + * DSA switch relay bus become failing firmware mailbox commands. + */ + if (!phy_id_compare_vendor(phydev->c45_ids.device_ids[MDIO_MMD_PCS], + PHY_VENDOR_AEONSEMI)) + return genphy_match_phy_device(phydev, phydrv); + + phy_id = aeon_gen1_read_pid(phydev); if (phy_id != PHY_ID_AS21XXX) return 0; @@ -1494,6 +1504,11 @@ static int aeon_gen1_match_phy_device(struct phy_device *phydev, static int aeon_gen2_match_phy_device(struct phy_device *phydev, const struct phy_driver *phydrv) { + /* Skip PHYs that are not Aeonsemi - see aeon_gen1_match_phy_device(). */ + if (!phy_id_compare_vendor(phydev->c45_ids.device_ids[MDIO_MMD_PCS], + PHY_VENDOR_AEONSEMI)) + return genphy_match_phy_device(phydev, phydrv); + /* AEONSEMI get pid. */ phydev->phy_id = aeon_gen2_read_pid(phydev);