net: phy: add support for probing MMDs >= 8 for devices-in-package
authorRussell King <rmk+kernel@armlinux.org.uk>
Thu, 18 Jun 2020 13:45:58 +0000 (14:45 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sat, 20 Jun 2020 03:17:15 +0000 (20:17 -0700)
Add support for probing MMDs above 7 for a valid devices-in-package
specifier, but only probe the vendor MMDs for this if they also report
that there the device is present in status register 2.  This avoids
issues where the MMD is implemented, but does not provide IEEE 802.3
compliant registers (such as the MV88X3310 PHY.)

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/phy_device.c
include/linux/phy.h

index 09096c3..8d9af27 100644 (file)
@@ -661,6 +661,28 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
 }
 EXPORT_SYMBOL(phy_device_create);
 
+/* phy_c45_probe_present - checks to see if a MMD is present in the package
+ * @bus: the target MII bus
+ * @prtad: PHY package address on the MII bus
+ * @devad: PHY device (MMD) address
+ *
+ * Read the MDIO_STAT2 register, and check whether a device is responding
+ * at this address.
+ *
+ * Returns: negative error number on bus access error, zero if no device
+ * is responding, or positive if a device is present.
+ */
+static int phy_c45_probe_present(struct mii_bus *bus, int prtad, int devad)
+{
+       int stat2;
+
+       stat2 = mdiobus_c45_read(bus, prtad, devad, MDIO_STAT2);
+       if (stat2 < 0)
+               return stat2;
+
+       return (stat2 & MDIO_STAT2_DEVPRST) == MDIO_STAT2_DEVPRST_VAL;
+}
+
 /* get_phy_c45_devs_in_pkg - reads a MMD's devices in package registers.
  * @bus: the target MII bus
  * @addr: PHY address on the MII bus
@@ -711,12 +733,26 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr,
 {
        const int num_ids = ARRAY_SIZE(c45_ids->device_ids);
        u32 *devs = &c45_ids->devices_in_package;
-       int i, phy_reg;
+       int i, ret, phy_reg;
 
        /* Find first non-zero Devices In package. Device zero is reserved
         * for 802.3 c45 complied PHYs, so don't probe it at first.
         */
-       for (i = 1; i < num_ids && *devs == 0; i++) {
+       for (i = 1; i < MDIO_MMD_NUM && *devs == 0; i++) {
+               if (i == MDIO_MMD_VEND1 || i == MDIO_MMD_VEND2) {
+                       /* Check that there is a device present at this
+                        * address before reading the devices-in-package
+                        * register to avoid reading garbage from the PHY.
+                        * Some PHYs (88x3310) vendor space is not IEEE802.3
+                        * compliant.
+                        */
+                       ret = phy_c45_probe_present(bus, addr, i);
+                       if (ret < 0)
+                               return -EIO;
+
+                       if (!ret)
+                               continue;
+               }
                phy_reg = get_phy_c45_devs_in_pkg(bus, addr, i, devs);
                if (phy_reg < 0)
                        return -EIO;
index 8c05d0f..abe3183 100644 (file)
@@ -388,6 +388,8 @@ enum phy_state {
        PHY_CABLETEST,
 };
 
+#define MDIO_MMD_NUM 32
+
 /**
  * struct phy_c45_device_ids - 802.3-c45 Device Identifiers
  * @devices_in_package: Bit vector of devices present.