net: phy: split devices_in_package
[linux-2.6-microblaze.git] / drivers / net / phy / phy_device.c
index 697c74d..c1f81c4 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
@@ -675,23 +697,18 @@ EXPORT_SYMBOL(phy_device_create);
 static int get_phy_c45_devs_in_pkg(struct mii_bus *bus, int addr, int dev_addr,
                                   u32 *devices_in_package)
 {
-       int phy_reg, reg_addr;
+       int phy_reg;
 
-       reg_addr = MII_ADDR_C45 | dev_addr << 16 | MDIO_DEVS2;
-       phy_reg = mdiobus_read(bus, addr, reg_addr);
+       phy_reg = mdiobus_c45_read(bus, addr, dev_addr, MDIO_DEVS2);
        if (phy_reg < 0)
                return -EIO;
        *devices_in_package = phy_reg << 16;
 
-       reg_addr = MII_ADDR_C45 | dev_addr << 16 | MDIO_DEVS1;
-       phy_reg = mdiobus_read(bus, addr, reg_addr);
+       phy_reg = mdiobus_c45_read(bus, addr, dev_addr, MDIO_DEVS1);
        if (phy_reg < 0)
                return -EIO;
        *devices_in_package |= phy_reg;
 
-       /* Bit 0 doesn't represent a device, it indicates c22 regs presence */
-       *devices_in_package &= ~BIT(0);
-
        return 0;
 }
 
@@ -699,94 +716,97 @@ static int get_phy_c45_devs_in_pkg(struct mii_bus *bus, int addr, int dev_addr,
  * 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.
+ * Read the PHY "devices in package". If this appears to be valid, read
+ * the PHY identifiers for each device. Return the "devices in package"
+ * and identifiers in @c45_ids.
  *
+ * Returns zero on success, %-EIO on bus access error, or %-ENODEV if
+ * the "devices in package" is invalid.
  */
-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;
+static int get_phy_c45_ids(struct mii_bus *bus, int addr,
+                          struct phy_c45_device_ids *c45_ids)
+{
        const int num_ids = ARRAY_SIZE(c45_ids->device_ids);
-       u32 *devs = &c45_ids->devices_in_package;
+       u32 devs_in_pkg = 0;
+       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++) {
-               phy_reg = get_phy_c45_devs_in_pkg(bus, addr, i, devs);
-               if (phy_reg < 0)
-                       return -EIO;
-
-               if ((*devs & 0x1fffffff) == 0x1fffffff) {
-                       /*  If mostly Fs, there is no device there,
-                        *  then let's continue to probe more, as some
-                        *  10G PHYs have zero Devices In package,
-                        *  e.g. Cortina CS4315/CS4340 PHY.
+       for (i = 1; i < MDIO_MMD_NUM && devs_in_pkg == 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.
                         */
-                       phy_reg = get_phy_c45_devs_in_pkg(bus, addr, 0, devs);
-                       if (phy_reg < 0)
+                       ret = phy_c45_probe_present(bus, addr, i);
+                       if (ret < 0)
                                return -EIO;
-                       /* no device there, let's get out of here */
-                       if ((*devs & 0x1fffffff) == 0x1fffffff) {
-                               *phy_id = 0xffffffff;
-                               return 0;
-                       } else {
-                               break;
-                       }
+
+                       if (!ret)
+                               continue;
                }
+               phy_reg = get_phy_c45_devs_in_pkg(bus, addr, i, &devs_in_pkg);
+               if (phy_reg < 0)
+                       return -EIO;
+       }
+
+       if ((devs_in_pkg & 0x1fffffff) == 0x1fffffff) {
+               /* If mostly Fs, there is no device there, then let's probe
+                * MMD 0, as some 10G PHYs have zero Devices In package,
+                * e.g. Cortina CS4315/CS4340 PHY.
+                */
+               phy_reg = get_phy_c45_devs_in_pkg(bus, addr, 0, &devs_in_pkg);
+               if (phy_reg < 0)
+                       return -EIO;
+
+               /* no device there, let's get out of here */
+               if ((devs_in_pkg & 0x1fffffff) == 0x1fffffff)
+                       return -ENODEV;
        }
 
        /* Now probe Device Identifiers for each device present. */
        for (i = 1; i < num_ids; i++) {
-               if (!(c45_ids->devices_in_package & (1 << i)))
+               if (!(devs_in_pkg & (1 << i)))
                        continue;
 
-               reg_addr = MII_ADDR_C45 | i << 16 | MII_PHYSID1;
-               phy_reg = mdiobus_read(bus, addr, reg_addr);
+               phy_reg = mdiobus_c45_read(bus, addr, i, MII_PHYSID1);
                if (phy_reg < 0)
                        return -EIO;
                c45_ids->device_ids[i] = phy_reg << 16;
 
-               reg_addr = MII_ADDR_C45 | i << 16 | MII_PHYSID2;
-               phy_reg = mdiobus_read(bus, addr, reg_addr);
+               phy_reg = mdiobus_c45_read(bus, addr, i, MII_PHYSID2);
                if (phy_reg < 0)
                        return -EIO;
                c45_ids->device_ids[i] |= phy_reg;
        }
-       *phy_id = 0;
+
+       c45_ids->devices_in_package = devs_in_pkg;
+       /* Bit 0 doesn't represent a device, it indicates c22 regs presence */
+       c45_ids->mmds_present = devs_in_pkg & ~BIT(0);
+
        return 0;
 }
 
 /**
- * get_phy_id - reads the specified addr for its ID.
+ * get_phy_c22_id - reads the specified addr for its clause 22 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.
  *
+ * Read the 802.3 clause 22 PHY ID from the PHY at @addr on the @bus,
+ * placing it in @phy_id. Return zero on successful read and the ID is
+ * valid, %-EIO on bus access error, or %-ENODEV if no device responds
+ * or invalid 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)
+static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id)
 {
        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);
        if (phy_reg < 0) {
@@ -803,6 +823,10 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,
 
        *phy_id |= phy_reg;
 
+       /* If the phy_id is mostly Fs, there is no device there */
+       if ((*phy_id & 0x1fffffff) == 0x1fffffff)
+               return -ENODEV;
+
        return 0;
 }
 
@@ -813,8 +837,17 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,
  * @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.
+ * Probe for a PHY at @addr on @bus.
+ *
+ * When probing for a clause 22 PHY, then read the ID registers. If we find
+ * a valid ID, allocate and return a &struct phy_device.
+ *
+ * When probing for a clause 45 PHY, read the "devices in package" registers.
+ * If the "devices in package" appears valid, read the ID registers for each
+ * MMD, allocate and return a &struct phy_device.
+ *
+ * Returns an allocated &struct phy_device on success, %-ENODEV if there is
+ * no PHY present, or %-EIO on bus access error.
  */
 struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
 {
@@ -823,16 +856,17 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
        int r;
 
        c45_ids.devices_in_package = 0;
+       c45_ids.mmds_present = 0;
        memset(c45_ids.device_ids, 0xff, sizeof(c45_ids.device_ids));
 
-       r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
+       if (is_c45)
+               r = get_phy_c45_ids(bus, addr, &c45_ids);
+       else
+               r = get_phy_c22_id(bus, addr, &phy_id);
+
        if (r)
                return ERR_PTR(r);
 
-       /* If the phy_id is mostly Fs, there is no device there */
-       if ((phy_id & 0x1fffffff) == 0x1fffffff)
-               return ERR_PTR(-ENODEV);
-
        return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
 }
 EXPORT_SYMBOL(get_phy_device);
@@ -916,16 +950,14 @@ struct phy_device *phy_find_first(struct mii_bus *bus)
 }
 EXPORT_SYMBOL(phy_find_first);
 
-static void phy_link_change(struct phy_device *phydev, bool up, bool do_carrier)
+static void phy_link_change(struct phy_device *phydev, bool up)
 {
        struct net_device *netdev = phydev->attached_dev;
 
-       if (do_carrier) {
-               if (up)
-                       netif_carrier_on(netdev);
-               else
-                       netif_carrier_off(netdev);
-       }
+       if (up)
+               netif_carrier_on(netdev);
+       else
+               netif_carrier_off(netdev);
        phydev->adjust_link(netdev);
        if (phydev->mii_ts && phydev->mii_ts->link_state)
                phydev->mii_ts->link_state(phydev->mii_ts, phydev);
@@ -1082,8 +1114,12 @@ int phy_init_hw(struct phy_device *phydev)
        if (!phydev->drv)
                return 0;
 
-       if (phydev->drv->soft_reset)
+       if (phydev->drv->soft_reset) {
                ret = phydev->drv->soft_reset(phydev);
+               /* see comment in genphy_soft_reset for an explanation */
+               if (!ret)
+                       phydev->suspended = 0;
+       }
 
        if (ret < 0)
                return ret;
@@ -1457,6 +1493,144 @@ bool phy_driver_is_genphy_10g(struct phy_device *phydev)
 }
 EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
 
+/**
+ * phy_package_join - join a common PHY group
+ * @phydev: target phy_device struct
+ * @addr: cookie and PHY address for global register access
+ * @priv_size: if non-zero allocate this amount of bytes for private data
+ *
+ * This joins a PHY group and provides a shared storage for all phydevs in
+ * this group. This is intended to be used for packages which contain
+ * more than one PHY, for example a quad PHY transceiver.
+ *
+ * The addr parameter serves as a cookie which has to have the same value
+ * for all members of one group and as a PHY address to access generic
+ * registers of a PHY package. Usually, one of the PHY addresses of the
+ * different PHYs in the package provides access to these global registers.
+ * The address which is given here, will be used in the phy_package_read()
+ * and phy_package_write() convenience functions. If your PHY doesn't have
+ * global registers you can just pick any of the PHY addresses.
+ *
+ * This will set the shared pointer of the phydev to the shared storage.
+ * If this is the first call for a this cookie the shared storage will be
+ * allocated. If priv_size is non-zero, the given amount of bytes are
+ * allocated for the priv member.
+ *
+ * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
+ * with the same cookie but a different priv_size is an error.
+ */
+int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
+{
+       struct mii_bus *bus = phydev->mdio.bus;
+       struct phy_package_shared *shared;
+       int ret;
+
+       if (addr < 0 || addr >= PHY_MAX_ADDR)
+               return -EINVAL;
+
+       mutex_lock(&bus->shared_lock);
+       shared = bus->shared[addr];
+       if (!shared) {
+               ret = -ENOMEM;
+               shared = kzalloc(sizeof(*shared), GFP_KERNEL);
+               if (!shared)
+                       goto err_unlock;
+               if (priv_size) {
+                       shared->priv = kzalloc(priv_size, GFP_KERNEL);
+                       if (!shared->priv)
+                               goto err_free;
+                       shared->priv_size = priv_size;
+               }
+               shared->addr = addr;
+               refcount_set(&shared->refcnt, 1);
+               bus->shared[addr] = shared;
+       } else {
+               ret = -EINVAL;
+               if (priv_size && priv_size != shared->priv_size)
+                       goto err_unlock;
+               refcount_inc(&shared->refcnt);
+       }
+       mutex_unlock(&bus->shared_lock);
+
+       phydev->shared = shared;
+
+       return 0;
+
+err_free:
+       kfree(shared);
+err_unlock:
+       mutex_unlock(&bus->shared_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(phy_package_join);
+
+/**
+ * phy_package_leave - leave a common PHY group
+ * @phydev: target phy_device struct
+ *
+ * This leaves a PHY group created by phy_package_join(). If this phydev
+ * was the last user of the shared data between the group, this data is
+ * freed. Resets the phydev->shared pointer to NULL.
+ */
+void phy_package_leave(struct phy_device *phydev)
+{
+       struct phy_package_shared *shared = phydev->shared;
+       struct mii_bus *bus = phydev->mdio.bus;
+
+       if (!shared)
+               return;
+
+       if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
+               bus->shared[shared->addr] = NULL;
+               mutex_unlock(&bus->shared_lock);
+               kfree(shared->priv);
+               kfree(shared);
+       }
+
+       phydev->shared = NULL;
+}
+EXPORT_SYMBOL_GPL(phy_package_leave);
+
+static void devm_phy_package_leave(struct device *dev, void *res)
+{
+       phy_package_leave(*(struct phy_device **)res);
+}
+
+/**
+ * devm_phy_package_join - resource managed phy_package_join()
+ * @dev: device that is registering this PHY package
+ * @phydev: target phy_device struct
+ * @addr: cookie and PHY address for global register access
+ * @priv_size: if non-zero allocate this amount of bytes for private data
+ *
+ * Managed phy_package_join(). Shared storage fetched by this function,
+ * phy_package_leave() is automatically called on driver detach. See
+ * phy_package_join() for more information.
+ */
+int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
+                         int addr, size_t priv_size)
+{
+       struct phy_device **ptr;
+       int ret;
+
+       ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
+                          GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       ret = phy_package_join(phydev, addr, priv_size);
+
+       if (!ret) {
+               *ptr = phydev;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(devm_phy_package_join);
+
 /**
  * phy_detach - detach a PHY device from its network device
  * @phydev: target phy_device struct
@@ -1524,6 +1698,9 @@ int phy_suspend(struct phy_device *phydev)
        struct phy_driver *phydrv = phydev->drv;
        int ret;
 
+       if (phydev->suspended)
+               return 0;
+
        /* If the device has WOL enabled, we cannot suspend the PHY */
        phy_ethtool_get_wol(phydev, &wol);
        if (wol.wolopts || (netdev && netdev->wol_enabled))
@@ -1768,6 +1945,90 @@ int genphy_setup_forced(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_setup_forced);
 
+static int genphy_setup_master_slave(struct phy_device *phydev)
+{
+       u16 ctl = 0;
+
+       if (!phydev->is_gigabit_capable)
+               return 0;
+
+       switch (phydev->master_slave_set) {
+       case MASTER_SLAVE_CFG_MASTER_PREFERRED:
+               ctl |= CTL1000_PREFER_MASTER;
+               break;
+       case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
+               break;
+       case MASTER_SLAVE_CFG_MASTER_FORCE:
+               ctl |= CTL1000_AS_MASTER;
+               /* fallthrough */
+       case MASTER_SLAVE_CFG_SLAVE_FORCE:
+               ctl |= CTL1000_ENABLE_MASTER;
+               break;
+       case MASTER_SLAVE_CFG_UNKNOWN:
+       case MASTER_SLAVE_CFG_UNSUPPORTED:
+               return 0;
+       default:
+               phydev_warn(phydev, "Unsupported Master/Slave mode\n");
+               return -EOPNOTSUPP;
+       }
+
+       return phy_modify_changed(phydev, MII_CTRL1000,
+                                 (CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER |
+                                  CTL1000_PREFER_MASTER), ctl);
+}
+
+static int genphy_read_master_slave(struct phy_device *phydev)
+{
+       int cfg, state;
+       int val;
+
+       if (!phydev->is_gigabit_capable) {
+               phydev->master_slave_get = MASTER_SLAVE_CFG_UNSUPPORTED;
+               phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
+               return 0;
+       }
+
+       phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
+       phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
+
+       val = phy_read(phydev, MII_CTRL1000);
+       if (val < 0)
+               return val;
+
+       if (val & CTL1000_ENABLE_MASTER) {
+               if (val & CTL1000_AS_MASTER)
+                       cfg = MASTER_SLAVE_CFG_MASTER_FORCE;
+               else
+                       cfg = MASTER_SLAVE_CFG_SLAVE_FORCE;
+       } else {
+               if (val & CTL1000_PREFER_MASTER)
+                       cfg = MASTER_SLAVE_CFG_MASTER_PREFERRED;
+               else
+                       cfg = MASTER_SLAVE_CFG_SLAVE_PREFERRED;
+       }
+
+       val = phy_read(phydev, MII_STAT1000);
+       if (val < 0)
+               return val;
+
+       if (val & LPA_1000MSFAIL) {
+               state = MASTER_SLAVE_STATE_ERR;
+       } else if (phydev->link) {
+               /* this bits are valid only for active link */
+               if (val & LPA_1000MSRES)
+                       state = MASTER_SLAVE_STATE_MASTER;
+               else
+                       state = MASTER_SLAVE_STATE_SLAVE;
+       } else {
+               state = MASTER_SLAVE_STATE_UNKNOWN;
+       }
+
+       phydev->master_slave_get = cfg;
+       phydev->master_slave_state = state;
+
+       return 0;
+}
+
 /**
  * genphy_restart_aneg - Enable and Restart Autonegotiation
  * @phydev: target phy_device struct
@@ -1826,6 +2087,12 @@ int __genphy_config_aneg(struct phy_device *phydev, bool changed)
        if (genphy_config_eee_advert(phydev))
                changed = true;
 
+       err = genphy_setup_master_slave(phydev);
+       if (err < 0)
+               return err;
+       else if (err)
+               changed = true;
+
        if (AUTONEG_ENABLE != phydev->autoneg)
                return genphy_setup_forced(phydev);
 
@@ -2060,6 +2327,10 @@ int genphy_read_status(struct phy_device *phydev)
        phydev->pause = 0;
        phydev->asym_pause = 0;
 
+       err = genphy_read_master_slave(phydev);
+       if (err < 0)
+               return err;
+
        err = genphy_read_lpa(phydev);
        if (err < 0)
                return err;
@@ -2154,6 +2425,12 @@ int genphy_soft_reset(struct phy_device *phydev)
        if (ret < 0)
                return ret;
 
+       /* Clause 22 states that setting bit BMCR_RESET sets control registers
+        * to their default value. Therefore the POWER DOWN bit is supposed to
+        * be cleared after soft reset.
+        */
+       phydev->suspended = 0;
+
        ret = phy_poll_reset(phydev);
        if (ret)
                return ret;
@@ -2627,7 +2904,6 @@ static struct phy_driver genphy_driver = {
        .phy_id         = 0xffffffff,
        .phy_id_mask    = 0xffffffff,
        .name           = "Generic PHY",
-       .soft_reset     = genphy_no_soft_reset,
        .get_features   = genphy_read_abilities,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,