]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
net: mdio: Add workaround for Micrel PHYs which are not C45 compatible
authorAndrew Lunn <andrew@lunn.ch>
Wed, 18 Jan 2023 10:01:37 +0000 (11:01 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 19 Jan 2023 15:23:19 +0000 (16:23 +0100)
After scanning the bus for C22 devices, check if any Micrel PHYs have
been found.  They are known to do bad things if there are C45
transactions on the bus. Prevent the scanning of the bus using C45 if
such a PHY has been detected.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Michael Walle <michael@walle.cc>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/phy/mdio_bus.c
include/linux/micrel_phy.h

index 667247f661c568645559ee97a9314dde6fa78288..a664eeb1868d683cc12c251a8f6b6d5b932c7411 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/micrel_phy.h>
 #include <linux/mii.h>
 #include <linux/mm.h>
 #include <linux/module.h>
@@ -600,6 +601,32 @@ static int mdiobus_scan_bus_c45(struct mii_bus *bus)
        return 0;
 }
 
+/* There are some C22 PHYs which do bad things when where is a C45
+ * transaction on the bus, like accepting a read themselves, and
+ * stomping over the true devices reply, to performing a write to
+ * themselves which was intended for another device. Now that C22
+ * devices have been found, see if any of them are bad for C45, and if we
+ * should skip the C45 scan.
+ */
+static bool mdiobus_prevent_c45_scan(struct mii_bus *bus)
+{
+       int i;
+
+       for (i = 0; i < PHY_MAX_ADDR; i++) {
+               struct phy_device *phydev;
+               u32 oui;
+
+               phydev = mdiobus_get_phy(bus, i);
+               if (!phydev)
+                       continue;
+               oui = phydev->phy_id >> 10;
+
+               if (oui == MICREL_OUI)
+                       return true;
+       }
+       return false;
+}
+
 /**
  * __mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
  * @bus: target mii_bus
@@ -617,8 +644,9 @@ static int mdiobus_scan_bus_c45(struct mii_bus *bus)
 int __mdiobus_register(struct mii_bus *bus, struct module *owner)
 {
        struct mdio_device *mdiodev;
-       int i, err;
        struct gpio_desc *gpiod;
+       bool prevent_c45_scan;
+       int i, err;
 
        if (!bus || !bus->name)
                return -EINVAL;
@@ -691,8 +719,11 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
                        goto error;
        }
 
-       if (bus->probe_capabilities == MDIOBUS_C45 ||
-           bus->probe_capabilities == MDIOBUS_C22_C45) {
+       prevent_c45_scan = mdiobus_prevent_c45_scan(bus);
+
+       if (!prevent_c45_scan &&
+           (bus->probe_capabilities == MDIOBUS_C45 ||
+            bus->probe_capabilities == MDIOBUS_C22_C45)) {
                err = mdiobus_scan_bus_c45(bus);
                if (err)
                        goto error;
index 1f7c33b2f5a3f49370c7d1654fd4f33d8a34d21b..771e050883db74dcdfc1c5c6e71e844d2a7413c4 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _MICREL_PHY_H
 #define _MICREL_PHY_H
 
+#define MICREL_OUI             0x0885
+
 #define MICREL_PHY_ID_MASK     0x00fffff0
 
 #define PHY_ID_KSZ8873MLL      0x000e7237