|
@@ -152,8 +152,8 @@ int phy_scan_fixups(struct phy_device *phydev)
|
|
|
}
|
|
|
EXPORT_SYMBOL(phy_scan_fixups);
|
|
|
|
|
|
-static struct phy_device* phy_device_create(struct mii_bus *bus,
|
|
|
- int addr, int phy_id)
|
|
|
+struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
|
|
|
+ bool is_c45, struct phy_c45_device_ids *c45_ids)
|
|
|
{
|
|
|
struct phy_device *dev;
|
|
|
|
|
@@ -174,8 +174,11 @@ static struct phy_device* phy_device_create(struct mii_bus *bus,
|
|
|
|
|
|
dev->autoneg = AUTONEG_ENABLE;
|
|
|
|
|
|
+ dev->is_c45 = is_c45;
|
|
|
dev->addr = addr;
|
|
|
dev->phy_id = phy_id;
|
|
|
+ if (c45_ids)
|
|
|
+ dev->c45_ids = *c45_ids;
|
|
|
dev->bus = bus;
|
|
|
dev->dev.parent = bus->parent;
|
|
|
dev->dev.bus = &mdio_bus_type;
|
|
@@ -200,20 +203,99 @@ static struct phy_device* phy_device_create(struct mii_bus *bus,
|
|
|
|
|
|
return dev;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(phy_device_create);
|
|
|
+
|
|
|
+/**
|
|
|
+ * get_phy_c45_ids - reads the specified addr for its 802.3-c45 IDs.
|
|
|
+ * @bus: the target MII bus
|
|
|
+ * @addr: PHY address on the MII bus
|
|
|
+ * @phy_id: where to store the ID retrieved.
|
|
|
+ * @c45_ids: where to store the c45 ID information.
|
|
|
+ *
|
|
|
+ * If the PHY devices-in-package appears to be valid, it and the
|
|
|
+ * corresponding identifiers are stored in @c45_ids, zero is stored
|
|
|
+ * in @phy_id. Otherwise 0xffffffff is stored in @phy_id. Returns
|
|
|
+ * zero on success.
|
|
|
+ *
|
|
|
+ */
|
|
|
+static int get_phy_c45_ids(struct mii_bus *bus, int addr, u32 *phy_id,
|
|
|
+ struct phy_c45_device_ids *c45_ids) {
|
|
|
+ int phy_reg;
|
|
|
+ int i, reg_addr;
|
|
|
+ const int num_ids = ARRAY_SIZE(c45_ids->device_ids);
|
|
|
+
|
|
|
+ /* Find first non-zero Devices In package. Device
|
|
|
+ * zero is reserved, so don't probe it.
|
|
|
+ */
|
|
|
+ for (i = 1;
|
|
|
+ i < num_ids && c45_ids->devices_in_package == 0;
|
|
|
+ i++) {
|
|
|
+ reg_addr = MII_ADDR_C45 | i << 16 | 6;
|
|
|
+ phy_reg = mdiobus_read(bus, addr, reg_addr);
|
|
|
+ if (phy_reg < 0)
|
|
|
+ return -EIO;
|
|
|
+ c45_ids->devices_in_package = (phy_reg & 0xffff) << 16;
|
|
|
+
|
|
|
+ reg_addr = MII_ADDR_C45 | i << 16 | 5;
|
|
|
+ phy_reg = mdiobus_read(bus, addr, reg_addr);
|
|
|
+ if (phy_reg < 0)
|
|
|
+ return -EIO;
|
|
|
+ c45_ids->devices_in_package |= (phy_reg & 0xffff);
|
|
|
+
|
|
|
+ /* If mostly Fs, there is no device there,
|
|
|
+ * let's get out of here.
|
|
|
+ */
|
|
|
+ if ((c45_ids->devices_in_package & 0x1fffffff) == 0x1fffffff) {
|
|
|
+ *phy_id = 0xffffffff;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Now probe Device Identifiers for each device present. */
|
|
|
+ for (i = 1; i < num_ids; i++) {
|
|
|
+ if (!(c45_ids->devices_in_package & (1 << i)))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ reg_addr = MII_ADDR_C45 | i << 16 | MII_PHYSID1;
|
|
|
+ phy_reg = mdiobus_read(bus, addr, reg_addr);
|
|
|
+ if (phy_reg < 0)
|
|
|
+ return -EIO;
|
|
|
+ c45_ids->device_ids[i] = (phy_reg & 0xffff) << 16;
|
|
|
+
|
|
|
+ reg_addr = MII_ADDR_C45 | i << 16 | MII_PHYSID2;
|
|
|
+ phy_reg = mdiobus_read(bus, addr, reg_addr);
|
|
|
+ if (phy_reg < 0)
|
|
|
+ return -EIO;
|
|
|
+ c45_ids->device_ids[i] |= (phy_reg & 0xffff);
|
|
|
+ }
|
|
|
+ *phy_id = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* get_phy_id - reads the specified addr for its ID.
|
|
|
* @bus: the target MII bus
|
|
|
* @addr: PHY address on the MII bus
|
|
|
* @phy_id: where to store the ID retrieved.
|
|
|
+ * @is_c45: If true the PHY uses the 802.3 clause 45 protocol
|
|
|
+ * @c45_ids: where to store the c45 ID information.
|
|
|
+ *
|
|
|
+ * Description: In the case of a 802.3-c22 PHY, reads the ID registers
|
|
|
+ * of the PHY at @addr on the @bus, stores it in @phy_id and returns
|
|
|
+ * zero on success.
|
|
|
+ *
|
|
|
+ * In the case of a 802.3-c45 PHY, get_phy_c45_ids() is invoked, and
|
|
|
+ * its return value is in turn returned.
|
|
|
*
|
|
|
- * Description: Reads the ID registers of the PHY at @addr on the
|
|
|
- * @bus, stores it in @phy_id and returns zero on success.
|
|
|
*/
|
|
|
-static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
|
|
|
+static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,
|
|
|
+ bool is_c45, struct phy_c45_device_ids *c45_ids)
|
|
|
{
|
|
|
int phy_reg;
|
|
|
|
|
|
+ if (is_c45)
|
|
|
+ return get_phy_c45_ids(bus, addr, phy_id, c45_ids);
|
|
|
+
|
|
|
/* Grab the bits from PHYIR1, and put them
|
|
|
* in the upper half */
|
|
|
phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
|
|
@@ -238,17 +320,19 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
|
|
|
* get_phy_device - reads the specified PHY device and returns its @phy_device struct
|
|
|
* @bus: the target MII bus
|
|
|
* @addr: PHY address on the MII bus
|
|
|
+ * @is_c45: If true the PHY uses the 802.3 clause 45 protocol
|
|
|
*
|
|
|
* Description: Reads the ID registers of the PHY at @addr on the
|
|
|
* @bus, then allocates and returns the phy_device to represent it.
|
|
|
*/
|
|
|
-struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
|
|
|
+struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
|
|
|
{
|
|
|
struct phy_device *dev = NULL;
|
|
|
u32 phy_id;
|
|
|
+ struct phy_c45_device_ids c45_ids = {0};
|
|
|
int r;
|
|
|
|
|
|
- r = get_phy_id(bus, addr, &phy_id);
|
|
|
+ r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
|
|
|
if (r)
|
|
|
return ERR_PTR(r);
|
|
|
|
|
@@ -256,7 +340,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
|
|
|
if ((phy_id & 0x1fffffff) == 0x1fffffff)
|
|
|
return NULL;
|
|
|
|
|
|
- dev = phy_device_create(bus, addr, phy_id);
|
|
|
+ dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
|
|
|
|
|
|
return dev;
|
|
|
}
|
|
@@ -449,6 +533,11 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
|
|
|
/* Assume that if there is no driver, that it doesn't
|
|
|
* exist, and we should use the genphy driver. */
|
|
|
if (NULL == d->driver) {
|
|
|
+ if (phydev->is_c45) {
|
|
|
+ pr_err("No driver for phy %x\n", phydev->phy_id);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
d->driver = &genphy_driver.driver;
|
|
|
|
|
|
err = d->driver->probe(d);
|