realtek: 6.12: allow fiber media status to be read without lock
authorMarkus Stockhausen <[email protected]>
Tue, 3 Jun 2025 18:21:48 +0000 (14:21 -0400)
committerRobert Marko <[email protected]>
Wed, 11 Jun 2025 20:27:22 +0000 (22:27 +0200)
rtl8214fc_media_is_fibre() will need to be run when bus lock is held.
Split the function into two versions.

Signed-off-by: Markus Stockhausen <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/18935
Signed-off-by: Robert Marko <[email protected]>
target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c

index ab8126f82ad2d9ee54bf648a3292428d42ff4fc0..8d30348082543a6400b75b802d0e21f6027d2bcb 100644 (file)
@@ -981,21 +981,40 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
        return 0;
 }
 
-static bool rtl8214fc_media_is_fibre(struct phy_device *phydev)
+static bool __rtl8214fc_media_is_fibre(struct phy_device *phydev)
 {
-       int mac = phydev->mdio.addr;
+       struct mii_bus *bus = phydev->mdio.bus;
+       static int regs[] = {16, 19, 20, 21};
+       int addr = phydev->mdio.addr & ~3;
+       int reg = regs[phydev->mdio.addr & 3];
+       int oldpage, val;
 
-       static int reg[] = {16, 19, 20, 21};
-       u32 val;
+       /*
+        * The fiber status cannot be read directly from the phy. It is a package "global"
+        * attribute and therefore located in the first phy. To avoid state handling assume
+        * an aligment to addresses divisible by 4.
+        */
 
-       phy_package_write_paged(phydev, RTL838X_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
-       val = phy_package_read_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4]);
-       phy_package_write_paged(phydev, RTL838X_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
+       oldpage = __mdiobus_read(bus, addr, RTL8XXX_PAGE_SELECT);
+       __mdiobus_write(bus, addr, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
+       __mdiobus_write(bus, addr, RTL8XXX_PAGE_SELECT, RTL821X_PAGE_PORT);
+       val = __mdiobus_read(bus, addr, reg);
+       __mdiobus_write(bus, addr, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
+       __mdiobus_write(bus, addr, RTL8XXX_PAGE_SELECT, oldpage);
 
-       if (val & BMCR_PDOWN)
-               return false;
+       return !(val & BMCR_PDOWN);
+}
+
+static bool rtl8214fc_media_is_fibre(struct phy_device *phydev)
+{
+       struct mii_bus *bus = phydev->mdio.bus;
+       int ret;
 
-       return true;
+       mutex_lock(&bus->mdio_lock);
+       ret = __rtl8214fc_media_is_fibre(phydev);
+       mutex_unlock(&bus->mdio_lock);
+
+       return ret;
 }
 
 static void rtl8214fc_power_set(struct phy_device *phydev, int port, bool on)