summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/phy/phy_device.c40
-rw-r--r--include/linux/phy.h2
2 files changed, 40 insertions, 2 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 09096c3ceb86..8d9af2772853 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -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;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 8c05d0fb5c00..abe318387331 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -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.