diff options
Diffstat (limited to 'drivers/net/phy/phy_device.c')
| -rw-r--r-- | drivers/net/phy/phy_device.c | 578 | 
1 files changed, 407 insertions, 171 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 74630e94fa3..22c57be4dfa 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1,7 +1,4 @@ -/* - * drivers/net/phy/phy_device.c - * - * Framework for finding and configuring PHYs. +/* Framework for finding and configuring PHYs.   * Also contains generic PHY driver   *   * Author: Andy Fleming @@ -33,10 +30,12 @@  #include <linux/mii.h>  #include <linux/ethtool.h>  #include <linux/phy.h> +#include <linux/mdio.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/of.h> -#include <asm/io.h>  #include <asm/irq.h> -#include <asm/uaccess.h>  MODULE_DESCRIPTION("PHY library");  MODULE_AUTHOR("Andy Fleming"); @@ -53,31 +52,31 @@ static void phy_device_release(struct device *dev)  	kfree(to_phy_device(dev));  } -static struct phy_driver genphy_driver; -extern int mdio_bus_init(void); -extern void mdio_bus_exit(void); +enum genphy_driver { +	GENPHY_DRV_1G, +	GENPHY_DRV_10G, +	GENPHY_DRV_MAX +}; + +static struct phy_driver genphy_driver[GENPHY_DRV_MAX];  static LIST_HEAD(phy_fixup_list);  static DEFINE_MUTEX(phy_fixup_lock); -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, -			     u32 flags, phy_interface_t interface); - -/* - * Creates a new phy_fixup and adds it to the list +/** + * phy_register_fixup - creates a new phy_fixup and adds it to the list   * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)   * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY) - * 	It can also be PHY_ANY_UID + *	It can also be PHY_ANY_UID   * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before - * 	comparison + *	comparison   * @run: The actual code to be run when a matching PHY is found   */  int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, -		int (*run)(struct phy_device *)) +		       int (*run)(struct phy_device *))  { -	struct phy_fixup *fixup; +	struct phy_fixup *fixup = kzalloc(sizeof(*fixup), GFP_KERNEL); -	fixup = kzalloc(sizeof(struct phy_fixup), GFP_KERNEL);  	if (!fixup)  		return -ENOMEM; @@ -96,7 +95,7 @@ EXPORT_SYMBOL(phy_register_fixup);  /* Registers a fixup to be run on any PHY with the UID in phy_uid */  int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask, -		int (*run)(struct phy_device *)) +			       int (*run)(struct phy_device *))  {  	return phy_register_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask, run);  } @@ -104,14 +103,13 @@ EXPORT_SYMBOL(phy_register_fixup_for_uid);  /* Registers a fixup to be run on the PHY with id string bus_id */  int phy_register_fixup_for_id(const char *bus_id, -		int (*run)(struct phy_device *)) +			      int (*run)(struct phy_device *))  {  	return phy_register_fixup(bus_id, PHY_ANY_UID, 0xffffffff, run);  }  EXPORT_SYMBOL(phy_register_fixup_for_id); -/* - * Returns 1 if fixup matches phydev in bus_id and phy_uid. +/* Returns 1 if fixup matches phydev in bus_id and phy_uid.   * Fixups can be set to match any in one or more fields.   */  static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) @@ -121,7 +119,7 @@ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)  			return 0;  	if ((fixup->phy_uid & fixup->phy_uid_mask) != -			(phydev->phy_id & fixup->phy_uid_mask)) +	    (phydev->phy_id & fixup->phy_uid_mask))  		if (fixup->phy_uid != PHY_ANY_UID)  			return 0; @@ -129,46 +127,44 @@ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)  }  /* Runs any matching fixups for this phydev */ -int phy_scan_fixups(struct phy_device *phydev) +static int phy_scan_fixups(struct phy_device *phydev)  {  	struct phy_fixup *fixup;  	mutex_lock(&phy_fixup_lock);  	list_for_each_entry(fixup, &phy_fixup_list, list) {  		if (phy_needs_fixup(phydev, fixup)) { -			int err; - -			err = fixup->run(phydev); +			int err = fixup->run(phydev);  			if (err < 0) {  				mutex_unlock(&phy_fixup_lock);  				return err;  			} +			phydev->has_fixups = true;  		}  	}  	mutex_unlock(&phy_fixup_lock);  	return 0;  } -EXPORT_SYMBOL(phy_scan_fixups);  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) +				     bool is_c45, +				     struct phy_c45_device_ids *c45_ids)  {  	struct phy_device *dev; -	/* We allocate the device, and initialize the -	 * default values */ +	/* We allocate the device, and initialize the default values */  	dev = kzalloc(sizeof(*dev), GFP_KERNEL); -  	if (NULL == dev) -		return (struct phy_device*) PTR_ERR((void*)-ENOMEM); +		return (struct phy_device *)PTR_ERR((void *)-ENOMEM);  	dev->dev.release = phy_device_release;  	dev->speed = 0;  	dev->duplex = -1; -	dev->pause = dev->asym_pause = 0; +	dev->pause = 0; +	dev->asym_pause = 0;  	dev->link = 1;  	dev->interface = PHY_INTERFACE_MODE_GMII; @@ -192,14 +188,15 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,  	INIT_WORK(&dev->phy_queue, phy_change);  	/* Request the appropriate module unconditionally; don't -	   bother trying to do so only if it isn't already loaded, -	   because that gets complicated. A hotplug event would have -	   done an unconditional modprobe anyway. -	   We don't do normal hotplug because it won't work for MDIO -	   -- because it relies on the device staying around for long -	   enough for the driver to get loaded. With MDIO, the NIC -	   driver will get bored and give up as soon as it finds that -	   there's no driver _already_ loaded. */ +	 * bother trying to do so only if it isn't already loaded, +	 * because that gets complicated. A hotplug event would have +	 * done an unconditional modprobe anyway. +	 * We don't do normal hotplug because it won't work for MDIO +	 * -- because it relies on the device staying around for long +	 * enough for the driver to get loaded. With MDIO, the NIC +	 * driver will get bored and give up as soon as it finds that +	 * there's no driver _already_ loaded. +	 */  	request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));  	device_initialize(&dev->dev); @@ -299,10 +296,8 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,  	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 */ +	/* Grab the bits from PHYIR1, and put them in the upper half */  	phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); -  	if (phy_reg < 0)  		return -EIO; @@ -310,7 +305,6 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,  	/* Grab the bits from PHYIR2, and put them in the lower half */  	phy_reg = mdiobus_read(bus, addr, MII_PHYSID2); -  	if (phy_reg < 0)  		return -EIO; @@ -320,7 +314,8 @@ 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 + * 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 @@ -331,7 +326,6 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,  struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)  {  	struct phy_c45_device_ids c45_ids = {0}; -	struct phy_device *dev = NULL;  	u32 phy_id = 0;  	int r; @@ -343,9 +337,7 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)  	if ((phy_id & 0x1fffffff) == 0x1fffffff)  		return NULL; -	dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); - -	return dev; +	return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);  }  EXPORT_SYMBOL(get_phy_device); @@ -357,14 +349,17 @@ int phy_device_register(struct phy_device *phydev)  {  	int err; -	/* Don't register a phy if one is already registered at this -	 * address */ +	/* Don't register a phy if one is already registered at this address */  	if (phydev->bus->phy_map[phydev->addr])  		return -EINVAL;  	phydev->bus->phy_map[phydev->addr] = phydev;  	/* Run all of the fixups for this PHY */ -	phy_scan_fixups(phydev); +	err = phy_scan_fixups(phydev); +	if (err) { +		pr_err("PHY %d failed to initialize\n", phydev->addr); +		goto out; +	}  	err = device_add(&phydev->dev);  	if (err) { @@ -409,7 +404,7 @@ EXPORT_SYMBOL(phy_find_first);   *   this function.   */  static void phy_prepare_link(struct phy_device *phydev, -		void (*handler)(struct net_device *)) +			     void (*handler)(struct net_device *))  {  	phydev->adjust_link = handler;  } @@ -432,7 +427,7 @@ int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,  		return rc;  	phy_prepare_link(phydev, handler); -	phy_start_machine(phydev, NULL); +	phy_start_machine(phydev);  	if (phydev->irq > 0)  		phy_start_interrupts(phydev); @@ -455,16 +450,17 @@ EXPORT_SYMBOL(phy_connect_direct);   *   choose to call only the subset of functions which provide   *   the desired functionality.   */ -struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, -		void (*handler)(struct net_device *), -		phy_interface_t interface) +struct phy_device *phy_connect(struct net_device *dev, const char *bus_id, +			       void (*handler)(struct net_device *), +			       phy_interface_t interface)  {  	struct phy_device *phydev;  	struct device *d;  	int rc;  	/* Search the list of PHY devices on the mdio bus for the -	 * PHY with the requested name */ +	 * PHY with the requested name +	 */  	d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id);  	if (!d) {  		pr_err("PHY %s not found\n", bus_id); @@ -481,7 +477,8 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,  EXPORT_SYMBOL(phy_connect);  /** - * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device + * phy_disconnect - disable interrupts, stop state machine, and detach a PHY + *		    device   * @phydev: target phy_device struct   */  void phy_disconnect(struct phy_device *phydev) @@ -490,26 +487,75 @@ void phy_disconnect(struct phy_device *phydev)  		phy_stop_interrupts(phydev);  	phy_stop_machine(phydev); -	 +  	phydev->adjust_link = NULL;  	phy_detach(phydev);  }  EXPORT_SYMBOL(phy_disconnect); -int phy_init_hw(struct phy_device *phydev) +/** + * phy_poll_reset - Safely wait until a PHY reset has properly completed + * @phydev: The PHY device to poll + * + * Description: According to IEEE 802.3, Section 2, Subsection 22.2.4.1.1, as + *   published in 2008, a PHY reset may take up to 0.5 seconds.  The MII BMCR + *   register must be polled until the BMCR_RESET bit clears. + * + *   Furthermore, any attempts to write to PHY registers may have no effect + *   or even generate MDIO bus errors until this is complete. + * + *   Some PHYs (such as the Marvell 88E1111) don't entirely conform to the + *   standard and do not fully reset after the BMCR_RESET bit is set, and may + *   even *REQUIRE* a soft-reset to properly restart autonegotiation.  In an + *   effort to support such broken PHYs, this function is separate from the + *   standard phy_init_hw() which will zero all the other bits in the BMCR + *   and reapply all driver-specific and board-specific fixups. + */ +static int phy_poll_reset(struct phy_device *phydev)  { +	/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ +	unsigned int retries = 12;  	int ret; +	do { +		msleep(50); +		ret = phy_read(phydev, MII_BMCR); +		if (ret < 0) +			return ret; +	} while (ret & BMCR_RESET && --retries); +	if (ret & BMCR_RESET) +		return -ETIMEDOUT; + +	/* Some chips (smsc911x) may still need up to another 1ms after the +	 * BMCR_RESET bit is cleared before they are usable. +	 */ +	msleep(1); +	return 0; +} + +int phy_init_hw(struct phy_device *phydev) +{ +	int ret = 0; +  	if (!phydev->drv || !phydev->drv->config_init)  		return 0; +	if (phydev->drv->soft_reset) +		ret = phydev->drv->soft_reset(phydev); +	else +		ret = genphy_soft_reset(phydev); + +	if (ret < 0) +		return ret; +  	ret = phy_scan_fixups(phydev);  	if (ret < 0)  		return ret;  	return phydev->drv->config_init(phydev);  } +EXPORT_SYMBOL(phy_init_hw);  /**   * phy_attach_direct - attach a network device to a given PHY device pointer @@ -520,26 +566,26 @@ int phy_init_hw(struct phy_device *phydev)   *   * Description: Called by drivers to attach to a particular PHY   *     device. The phy_device is found, and properly hooked up - *     to the phy_driver.  If no driver is attached, then the - *     genphy_driver is used.  The phy_device is given a ptr to + *     to the phy_driver.  If no driver is attached, then a + *     generic driver is used.  The phy_device is given a ptr to   *     the attaching device, and given a callback for link status   *     change.  The phy_device is returned to the attaching driver.   */ -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, -			     u32 flags, phy_interface_t interface) +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, +		      u32 flags, phy_interface_t interface)  {  	struct device *d = &phydev->dev; +	struct module *bus_module;  	int err;  	/* Assume that if there is no driver, that it doesn't -	 * exist, and we should use the genphy driver. */ +	 * 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; +		if (phydev->is_c45) +			d->driver = &genphy_driver[GENPHY_DRV_10G].driver; +		else +			d->driver = &genphy_driver[GENPHY_DRV_1G].driver;  		err = d->driver->probe(d);  		if (err >= 0) @@ -554,6 +600,14 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,  		return -EBUSY;  	} +	/* Increment the bus module reference count */ +	bus_module = phydev->bus->dev.driver ? +		     phydev->bus->dev.driver->owner : NULL; +	if (!try_module_get(bus_module)) { +		dev_err(&dev->dev, "failed to get the bus module\n"); +		return -EIO; +	} +  	phydev->attached_dev = dev;  	dev->phydev = phydev; @@ -565,13 +619,17 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,  	/* Do initial configuration here, now that  	 * we have certain key parameters -	 * (dev_flags and interface) */ +	 * (dev_flags and interface) +	 */  	err = phy_init_hw(phydev);  	if (err)  		phy_detach(phydev); +	else +		phy_resume(phydev);  	return err;  } +EXPORT_SYMBOL(phy_attach_direct);  /**   * phy_attach - attach a network device to a particular PHY device @@ -582,8 +640,8 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,   * Description: Same as phy_attach_direct() except that a PHY bus_id   *     string is passed instead of a pointer to a struct phy_device.   */ -struct phy_device *phy_attach(struct net_device *dev, -		const char *bus_id, phy_interface_t interface) +struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, +			      phy_interface_t interface)  {  	struct bus_type *bus = &mdio_bus_type;  	struct phy_device *phydev; @@ -591,7 +649,8 @@ struct phy_device *phy_attach(struct net_device *dev,  	int rc;  	/* Search the list of PHY devices on the mdio bus for the -	 * PHY with the requested name */ +	 * PHY with the requested name +	 */  	d = bus_find_device_by_name(bus, NULL, bus_id);  	if (!d) {  		pr_err("PHY %s not found\n", bus_id); @@ -613,18 +672,52 @@ EXPORT_SYMBOL(phy_attach);   */  void phy_detach(struct phy_device *phydev)  { +	int i; + +	if (phydev->bus->dev.driver) +		module_put(phydev->bus->dev.driver->owner); +  	phydev->attached_dev->phydev = NULL;  	phydev->attached_dev = NULL; +	phy_suspend(phydev);  	/* If the device had no specific driver before (i.e. - it  	 * was using the generic driver), we unbind the device  	 * from the generic driver so that there's a chance a -	 * real driver could be loaded */ -	if (phydev->dev.driver == &genphy_driver.driver) -		device_release_driver(&phydev->dev); +	 * real driver could be loaded +	 */ +	for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) { +		if (phydev->dev.driver == &genphy_driver[i].driver) { +			device_release_driver(&phydev->dev); +			break; +		} +	}  }  EXPORT_SYMBOL(phy_detach); +int phy_suspend(struct phy_device *phydev) +{ +	struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); +	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; + +	/* If the device has WOL enabled, we cannot suspend the PHY */ +	phy_ethtool_get_wol(phydev, &wol); +	if (wol.wolopts) +		return -EBUSY; + +	if (phydrv->suspend) +		return phydrv->suspend(phydev); +	return 0; +} + +int phy_resume(struct phy_device *phydev) +{ +	struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); + +	if (phydrv->resume) +		return phydrv->resume(phydev); +	return 0; +}  /* Generic PHY support and helper functions */ @@ -640,20 +733,19 @@ EXPORT_SYMBOL(phy_detach);  static int genphy_config_advert(struct phy_device *phydev)  {  	u32 advertise; -	int oldadv, adv; +	int oldadv, adv, bmsr;  	int err, changed = 0; -	/* Only allow advertising what -	 * this PHY supports */ +	/* Only allow advertising what this PHY supports */  	phydev->advertising &= phydev->supported;  	advertise = phydev->advertising;  	/* Setup standard advertisement */ -	oldadv = adv = phy_read(phydev, MII_ADVERTISE); - +	adv = phy_read(phydev, MII_ADVERTISE);  	if (adv < 0)  		return adv; +	oldadv = adv;  	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |  		 ADVERTISE_PAUSE_ASYM);  	adv |= ethtool_adv_to_mii_adv_t(advertise); @@ -666,26 +758,36 @@ static int genphy_config_advert(struct phy_device *phydev)  		changed = 1;  	} -	/* Configure gigabit if it's supported */ -	if (phydev->supported & (SUPPORTED_1000baseT_Half | -				SUPPORTED_1000baseT_Full)) { -		oldadv = adv = phy_read(phydev, MII_CTRL1000); +	bmsr = phy_read(phydev, MII_BMSR); +	if (bmsr < 0) +		return bmsr; -		if (adv < 0) -			return adv; +	/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all +	 * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a +	 * logical 1. +	 */ +	if (!(bmsr & BMSR_ESTATEN)) +		return changed; -		adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); -		adv |= ethtool_adv_to_mii_ctrl1000_t(advertise); +	/* Configure gigabit if it's supported */ +	adv = phy_read(phydev, MII_CTRL1000); +	if (adv < 0) +		return adv; -		if (adv != oldadv) { -			err = phy_write(phydev, MII_CTRL1000, adv); +	oldadv = adv; +	adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); -			if (err < 0) -				return err; +	if (phydev->supported & (SUPPORTED_1000baseT_Half | +				 SUPPORTED_1000baseT_Full)) { +		adv |= ethtool_adv_to_mii_ctrl1000_t(advertise); +		if (adv != oldadv)  			changed = 1; -		}  	} +	err = phy_write(phydev, MII_CTRL1000, adv); +	if (err < 0) +		return err; +  	return changed;  } @@ -697,12 +799,12 @@ static int genphy_config_advert(struct phy_device *phydev)   *   to the values in phydev. Assumes that the values are valid.   *   Please see phy_sanitize_settings().   */ -static int genphy_setup_forced(struct phy_device *phydev) +int genphy_setup_forced(struct phy_device *phydev)  { -	int err;  	int ctl = 0; -	phydev->pause = phydev->asym_pause = 0; +	phydev->pause = 0; +	phydev->asym_pause = 0;  	if (SPEED_1000 == phydev->speed)  		ctl |= BMCR_SPEED1000; @@ -711,12 +813,10 @@ static int genphy_setup_forced(struct phy_device *phydev)  	if (DUPLEX_FULL == phydev->duplex)  		ctl |= BMCR_FULLDPLX; -	 -	err = phy_write(phydev, MII_BMCR, ctl); -	return err; +	return phy_write(phydev, MII_BMCR, ctl);  } - +EXPORT_SYMBOL(genphy_setup_forced);  /**   * genphy_restart_aneg - Enable and Restart Autonegotiation @@ -724,25 +824,20 @@ static int genphy_setup_forced(struct phy_device *phydev)   */  int genphy_restart_aneg(struct phy_device *phydev)  { -	int ctl; - -	ctl = phy_read(phydev, MII_BMCR); +	int ctl = phy_read(phydev, MII_BMCR);  	if (ctl < 0)  		return ctl; -	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); +	ctl |= BMCR_ANENABLE | BMCR_ANRESTART;  	/* Don't isolate the PHY if we're negotiating */ -	ctl &= ~(BMCR_ISOLATE); +	ctl &= ~BMCR_ISOLATE; -	ctl = phy_write(phydev, MII_BMCR, ctl); - -	return ctl; +	return phy_write(phydev, MII_BMCR, ctl);  }  EXPORT_SYMBOL(genphy_restart_aneg); -  /**   * genphy_config_aneg - restart auto-negotiation or write BMCR   * @phydev: target phy_device struct @@ -759,13 +854,12 @@ int genphy_config_aneg(struct phy_device *phydev)  		return genphy_setup_forced(phydev);  	result = genphy_config_advert(phydev); -  	if (result < 0) /* error */  		return result; -  	if (result == 0) {  		/* Advertisement hasn't changed, but maybe aneg was never on to -		 * begin with?  Or maybe phy was isolated? */ +		 * begin with?  Or maybe phy was isolated? +		 */  		int ctl = phy_read(phydev, MII_BMCR);  		if (ctl < 0) @@ -776,7 +870,8 @@ int genphy_config_aneg(struct phy_device *phydev)  	}  	/* Only restart aneg if we are advertising something different -	 * than we were before.	 */ +	 * than we were before. +	 */  	if (result > 0)  		result = genphy_restart_aneg(phydev); @@ -785,6 +880,27 @@ int genphy_config_aneg(struct phy_device *phydev)  EXPORT_SYMBOL(genphy_config_aneg);  /** + * genphy_aneg_done - return auto-negotiation status + * @phydev: target phy_device struct + * + * Description: Reads the status register and returns 0 either if + *   auto-negotiation is incomplete, or if there was an error. + *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. + */ +int genphy_aneg_done(struct phy_device *phydev) +{ +	int retval = phy_read(phydev, MII_BMSR); + +	return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); +} +EXPORT_SYMBOL(genphy_aneg_done); + +static int gen10g_config_aneg(struct phy_device *phydev) +{ +	return 0; +} + +/**   * genphy_update_link - update link status in @phydev   * @phydev: target phy_device struct   * @@ -798,13 +914,11 @@ int genphy_update_link(struct phy_device *phydev)  	/* Do a fake read */  	status = phy_read(phydev, MII_BMSR); -  	if (status < 0)  		return status;  	/* Read link and autonegotiation status */  	status = phy_read(phydev, MII_BMSR); -  	if (status < 0)  		return status; @@ -832,65 +946,70 @@ int genphy_read_status(struct phy_device *phydev)  	int err;  	int lpa;  	int lpagb = 0; +	int common_adv; +	int common_adv_gb = 0; -	/* Update the link, but return if there -	 * was an error */ +	/* Update the link, but return if there was an error */  	err = genphy_update_link(phydev);  	if (err)  		return err; +	phydev->lp_advertising = 0; +  	if (AUTONEG_ENABLE == phydev->autoneg) {  		if (phydev->supported & (SUPPORTED_1000baseT_Half  					| SUPPORTED_1000baseT_Full)) {  			lpagb = phy_read(phydev, MII_STAT1000); -  			if (lpagb < 0)  				return lpagb;  			adv = phy_read(phydev, MII_CTRL1000); -  			if (adv < 0)  				return adv; -			lpagb &= adv << 2; +			phydev->lp_advertising = +				mii_stat1000_to_ethtool_lpa_t(lpagb); +			common_adv_gb = lpagb & adv << 2;  		}  		lpa = phy_read(phydev, MII_LPA); -  		if (lpa < 0)  			return lpa; -		adv = phy_read(phydev, MII_ADVERTISE); +		phydev->lp_advertising |= mii_lpa_to_ethtool_lpa_t(lpa); +		adv = phy_read(phydev, MII_ADVERTISE);  		if (adv < 0)  			return adv; -		lpa &= adv; +		common_adv = lpa & adv;  		phydev->speed = SPEED_10;  		phydev->duplex = DUPLEX_HALF; -		phydev->pause = phydev->asym_pause = 0; +		phydev->pause = 0; +		phydev->asym_pause = 0; -		if (lpagb & (LPA_1000FULL | LPA_1000HALF)) { +		if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {  			phydev->speed = SPEED_1000; -			if (lpagb & LPA_1000FULL) +			if (common_adv_gb & LPA_1000FULL)  				phydev->duplex = DUPLEX_FULL; -		} else if (lpa & (LPA_100FULL | LPA_100HALF)) { +		} else if (common_adv & (LPA_100FULL | LPA_100HALF)) {  			phydev->speed = SPEED_100; -			 -			if (lpa & LPA_100FULL) + +			if (common_adv & LPA_100FULL)  				phydev->duplex = DUPLEX_FULL;  		} else -			if (lpa & LPA_10FULL) +			if (common_adv & LPA_10FULL)  				phydev->duplex = DUPLEX_FULL; -		if (phydev->duplex == DUPLEX_FULL){ +		if (phydev->duplex == DUPLEX_FULL) {  			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;  			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;  		}  	} else {  		int bmcr = phy_read(phydev, MII_BMCR); +  		if (bmcr < 0)  			return bmcr; @@ -906,27 +1025,73 @@ int genphy_read_status(struct phy_device *phydev)  		else  			phydev->speed = SPEED_10; -		phydev->pause = phydev->asym_pause = 0; +		phydev->pause = 0; +		phydev->asym_pause = 0;  	}  	return 0;  }  EXPORT_SYMBOL(genphy_read_status); -static int genphy_config_init(struct phy_device *phydev) +static int gen10g_read_status(struct phy_device *phydev) +{ +	int devad, reg; +	u32 mmd_mask = phydev->c45_ids.devices_in_package; + +	phydev->link = 1; + +	/* For now just lie and say it's 10G all the time */ +	phydev->speed = SPEED_10000; +	phydev->duplex = DUPLEX_FULL; + +	for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { +		if (!(mmd_mask & 1)) +			continue; + +		/* Read twice because link state is latched and a +		 * read moves the current state into the register +		 */ +		phy_read_mmd(phydev, devad, MDIO_STAT1); +		reg = phy_read_mmd(phydev, devad, MDIO_STAT1); +		if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) +			phydev->link = 0; +	} + +	return 0; +} + +/** + * genphy_soft_reset - software reset the PHY via BMCR_RESET bit + * @phydev: target phy_device struct + * + * Description: Perform a software PHY reset using the standard + * BMCR_RESET bit and poll for the reset bit to be cleared. + * + * Returns: 0 on success, < 0 on failure + */ +int genphy_soft_reset(struct phy_device *phydev) +{ +	int ret; + +	ret = phy_write(phydev, MII_BMCR, BMCR_RESET); +	if (ret < 0) +		return ret; + +	return phy_poll_reset(phydev); +} +EXPORT_SYMBOL(genphy_soft_reset); + +int genphy_config_init(struct phy_device *phydev)  {  	int val;  	u32 features; -	/* For now, I'll claim that the generic driver supports -	 * all possible port types */  	features = (SUPPORTED_TP | SUPPORTED_MII  			| SUPPORTED_AUI | SUPPORTED_FIBRE |  			SUPPORTED_BNC);  	/* Do we support autonegotiation? */  	val = phy_read(phydev, MII_BMSR); -  	if (val < 0)  		return val; @@ -944,7 +1109,6 @@ static int genphy_config_init(struct phy_device *phydev)  	if (val & BMSR_ESTATEN) {  		val = phy_read(phydev, MII_ESTATUS); -  		if (val < 0)  			return val; @@ -954,11 +1118,28 @@ static int genphy_config_init(struct phy_device *phydev)  			features |= SUPPORTED_1000baseT_Half;  	} -	phydev->supported = features; -	phydev->advertising = features; +	phydev->supported &= features; +	phydev->advertising &= features; + +	return 0; +} + +static int gen10g_soft_reset(struct phy_device *phydev) +{ +	/* Do nothing for now */ +	return 0; +} +EXPORT_SYMBOL(genphy_config_init); + +static int gen10g_config_init(struct phy_device *phydev) +{ +	/* Temporarily just say we support everything */ +	phydev->supported = SUPPORTED_10000baseT_Full; +	phydev->advertising = SUPPORTED_10000baseT_Full;  	return 0;  } +  int genphy_suspend(struct phy_device *phydev)  {  	int value; @@ -966,7 +1147,7 @@ int genphy_suspend(struct phy_device *phydev)  	mutex_lock(&phydev->lock);  	value = phy_read(phydev, MII_BMCR); -	phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN)); +	phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);  	mutex_unlock(&phydev->lock); @@ -974,6 +1155,11 @@ int genphy_suspend(struct phy_device *phydev)  }  EXPORT_SYMBOL(genphy_suspend); +static int gen10g_suspend(struct phy_device *phydev) +{ +	return 0; +} +  int genphy_resume(struct phy_device *phydev)  {  	int value; @@ -981,7 +1167,7 @@ int genphy_resume(struct phy_device *phydev)  	mutex_lock(&phydev->lock);  	value = phy_read(phydev, MII_BMCR); -	phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN)); +	phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);  	mutex_unlock(&phydev->lock); @@ -989,6 +1175,43 @@ int genphy_resume(struct phy_device *phydev)  }  EXPORT_SYMBOL(genphy_resume); +static int gen10g_resume(struct phy_device *phydev) +{ +	return 0; +} + +static void of_set_phy_supported(struct phy_device *phydev) +{ +	struct device_node *node = phydev->dev.of_node; +	u32 max_speed; + +	if (!IS_ENABLED(CONFIG_OF_MDIO)) +		return; + +	if (!node) +		return; + +	if (!of_property_read_u32(node, "max-speed", &max_speed)) { +		/* The default values for phydev->supported are provided by the PHY +		 * driver "features" member, we want to reset to sane defaults fist +		 * before supporting higher speeds. +		 */ +		phydev->supported &= PHY_DEFAULT_FEATURES; + +		switch (max_speed) { +		default: +			return; + +		case SPEED_1000: +			phydev->supported |= PHY_1000BT_FEATURES; +		case SPEED_100: +			phydev->supported |= PHY_100BT_FEATURES; +		case SPEED_10: +			phydev->supported |= PHY_10BT_FEATURES; +		} +	} +} +  /**   * phy_probe - probe and init a PHY device   * @dev: device to probe and init @@ -999,22 +1222,18 @@ EXPORT_SYMBOL(genphy_resume);   */  static int phy_probe(struct device *dev)  { -	struct phy_device *phydev; -	struct phy_driver *phydrv; -	struct device_driver *drv; +	struct phy_device *phydev = to_phy_device(dev); +	struct device_driver *drv = phydev->dev.driver; +	struct phy_driver *phydrv = to_phy_driver(drv);  	int err = 0; -	phydev = to_phy_device(dev); - -	drv = phydev->dev.driver; -	phydrv = to_phy_driver(drv);  	phydev->drv = phydrv;  	/* Disable the interrupt if the PHY doesn't support it  	 * but the interrupt is still a valid one  	 */  	if (!(phydrv->flags & PHY_HAS_INTERRUPT) && -			phy_interrupt_is_valid(phydev)) +	    phy_interrupt_is_valid(phydev))  		phydev->irq = PHY_POLL;  	if (phydrv->flags & PHY_IS_INTERNAL) @@ -1024,9 +1243,11 @@ static int phy_probe(struct device *dev)  	/* Start out supporting everything. Eventually,  	 * a controller will attach, and may modify one -	 * or both of these values */ +	 * or both of these values +	 */  	phydev->supported = phydrv->features; -	phydev->advertising = phydrv->features; +	of_set_phy_supported(phydev); +	phydev->advertising = phydev->supported;  	/* Set the state to READY by default */  	phydev->state = PHY_READY; @@ -1037,14 +1258,11 @@ static int phy_probe(struct device *dev)  	mutex_unlock(&phydev->lock);  	return err; -  }  static int phy_remove(struct device *dev)  { -	struct phy_device *phydev; - -	phydev = to_phy_device(dev); +	struct phy_device *phydev = to_phy_device(dev);  	mutex_lock(&phydev->lock);  	phydev->state = PHY_DOWN; @@ -1071,7 +1289,6 @@ int phy_driver_register(struct phy_driver *new_driver)  	new_driver->driver.remove = phy_remove;  	retval = driver_register(&new_driver->driver); -  	if (retval) {  		pr_err("%s: Error %d in registering driver\n",  		       new_driver->name, retval); @@ -1110,24 +1327,41 @@ EXPORT_SYMBOL(phy_driver_unregister);  void phy_drivers_unregister(struct phy_driver *drv, int n)  {  	int i; -	for (i = 0; i < n; i++) { + +	for (i = 0; i < n; i++)  		phy_driver_unregister(drv + i); -	}  }  EXPORT_SYMBOL(phy_drivers_unregister); -static struct phy_driver genphy_driver = { +static struct phy_driver genphy_driver[] = { +{  	.phy_id		= 0xffffffff,  	.phy_id_mask	= 0xffffffff,  	.name		= "Generic PHY", +	.soft_reset	= genphy_soft_reset,  	.config_init	= genphy_config_init, -	.features	= 0, +	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII | +			  SUPPORTED_AUI | SUPPORTED_FIBRE | +			  SUPPORTED_BNC,  	.config_aneg	= genphy_config_aneg, +	.aneg_done	= genphy_aneg_done,  	.read_status	= genphy_read_status,  	.suspend	= genphy_suspend,  	.resume		= genphy_resume, -	.driver		= {.owner= THIS_MODULE, }, -}; +	.driver		= { .owner = THIS_MODULE, }, +}, { +	.phy_id         = 0xffffffff, +	.phy_id_mask    = 0xffffffff, +	.name           = "Generic 10G PHY", +	.soft_reset	= gen10g_soft_reset, +	.config_init    = gen10g_config_init, +	.features       = 0, +	.config_aneg    = gen10g_config_aneg, +	.read_status    = gen10g_read_status, +	.suspend        = gen10g_suspend, +	.resume         = gen10g_resume, +	.driver         = {.owner = THIS_MODULE, }, +} };  static int __init phy_init(void)  { @@ -1137,7 +1371,8 @@ static int __init phy_init(void)  	if (rc)  		return rc; -	rc = phy_driver_register(&genphy_driver); +	rc = phy_drivers_register(genphy_driver, +				  ARRAY_SIZE(genphy_driver));  	if (rc)  		mdio_bus_exit(); @@ -1146,7 +1381,8 @@ static int __init phy_init(void)  static void __exit phy_exit(void)  { -	phy_driver_unregister(&genphy_driver); +	phy_drivers_unregister(genphy_driver, +			       ARRAY_SIZE(genphy_driver));  	mdio_bus_exit();  }  | 
