diff options
Diffstat (limited to 'drivers/net/phy/phy_device.c')
-rw-r--r-- | drivers/net/phy/phy_device.c | 109 |
1 files changed, 82 insertions, 27 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index dcc93a873174..53878908adf4 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(phy_10_100_features_array); const int phy_basic_t1_features_array[2] = { ETHTOOL_LINK_MODE_TP_BIT, - ETHTOOL_LINK_MODE_100baseT_Full_BIT, + ETHTOOL_LINK_MODE_100baseT1_Full_BIT, }; EXPORT_SYMBOL_GPL(phy_basic_t1_features_array); @@ -948,6 +948,9 @@ int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, { int rc; + if (!dev) + return -EINVAL; + rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface); if (rc) return rc; @@ -1013,7 +1016,7 @@ void phy_disconnect(struct phy_device *phydev) phy_stop(phydev); if (phy_interrupt_is_valid(phydev)) - free_irq(phydev->irq, phydev); + phy_free_interrupt(phydev); phydev->adjust_link = NULL; @@ -1133,6 +1136,44 @@ void phy_attached_print(struct phy_device *phydev, const char *fmt, ...) } EXPORT_SYMBOL(phy_attached_print); +static void phy_sysfs_create_links(struct phy_device *phydev) +{ + struct net_device *dev = phydev->attached_dev; + int err; + + if (!dev) + return; + + err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj, + "attached_dev"); + if (err) + return; + + err = sysfs_create_link_nowarn(&dev->dev.kobj, + &phydev->mdio.dev.kobj, + "phydev"); + if (err) { + dev_err(&dev->dev, "could not add device link to %s err %d\n", + kobject_name(&phydev->mdio.dev.kobj), + err); + /* non-fatal - some net drivers can use one netdevice + * with more then one phy + */ + } + + phydev->sysfs_links = true; +} + +static ssize_t +phy_standalone_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct phy_device *phydev = to_phy_device(dev); + + return sprintf(buf, "%d\n", !phydev->attached_dev); +} +static DEVICE_ATTR_RO(phy_standalone); + /** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach @@ -1151,9 +1192,9 @@ EXPORT_SYMBOL(phy_attached_print); int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, u32 flags, phy_interface_t interface) { - struct module *ndev_owner = dev->dev.parent->driver->owner; struct mii_bus *bus = phydev->mdio.bus; struct device *d = &phydev->mdio.dev; + struct module *ndev_owner = NULL; bool using_genphy = false; int err; @@ -1162,8 +1203,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, * our own module->refcnt here, otherwise we would not be able to * unload later on. */ + if (dev) + ndev_owner = dev->dev.parent->driver->owner; if (ndev_owner != bus->owner && !try_module_get(bus->owner)) { - dev_err(&dev->dev, "failed to get the bus module\n"); + phydev_err(phydev, "failed to get the bus module\n"); return -EIO; } @@ -1182,7 +1225,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, } if (!try_module_get(d->driver->owner)) { - dev_err(&dev->dev, "failed to get the device driver module\n"); + phydev_err(phydev, "failed to get the device driver module\n"); err = -EIO; goto error_put_device; } @@ -1203,8 +1246,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, } phydev->phy_link_change = phy_link_change; - phydev->attached_dev = dev; - dev->phydev = phydev; + if (dev) { + phydev->attached_dev = dev; + dev->phydev = phydev; + } /* Some Ethernet drivers try to connect to a PHY device before * calling register_netdevice() -> netdev_register_kobject() and @@ -1216,22 +1261,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, */ phydev->sysfs_links = false; - err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj, - "attached_dev"); - if (!err) { - err = sysfs_create_link_nowarn(&dev->dev.kobj, - &phydev->mdio.dev.kobj, - "phydev"); - if (err) { - dev_err(&dev->dev, "could not add device link to %s err %d\n", - kobject_name(&phydev->mdio.dev.kobj), - err); - /* non-fatal - some net drivers can use one netdevice - * with more then one phy - */ - } + phy_sysfs_create_links(phydev); - phydev->sysfs_links = true; + if (!phydev->attached_dev) { + err = sysfs_create_file(&phydev->mdio.dev.kobj, + &dev_attr_phy_standalone.attr); + if (err) + phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n"); } phydev->dev_flags = flags; @@ -1243,7 +1279,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, /* Initial carrier state is off as the phy is about to be * (re)initialized. */ - netif_carrier_off(phydev->attached_dev); + if (dev) + netif_carrier_off(phydev->attached_dev); /* Do initial configuration here, now that * we have certain key parameters @@ -1290,6 +1327,9 @@ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, struct device *d; int rc; + if (!dev) + return ERR_PTR(-EINVAL); + /* Search the list of PHY devices on the mdio bus for the * PHY with the requested name */ @@ -1349,16 +1389,24 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g); void phy_detach(struct phy_device *phydev) { struct net_device *dev = phydev->attached_dev; - struct module *ndev_owner = dev->dev.parent->driver->owner; + struct module *ndev_owner = NULL; struct mii_bus *bus; if (phydev->sysfs_links) { - sysfs_remove_link(&dev->dev.kobj, "phydev"); + if (dev) + sysfs_remove_link(&dev->dev.kobj, "phydev"); sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev"); } + + if (!phydev->attached_dev) + sysfs_remove_file(&phydev->mdio.dev.kobj, + &dev_attr_phy_standalone.attr); + phy_suspend(phydev); - phydev->attached_dev->phydev = NULL; - phydev->attached_dev = NULL; + if (dev) { + phydev->attached_dev->phydev = NULL; + phydev->attached_dev = NULL; + } phydev->phylink = NULL; phy_led_triggers_unregister(phydev); @@ -1381,6 +1429,8 @@ void phy_detach(struct phy_device *phydev) bus = phydev->mdio.bus; put_device(&phydev->mdio.dev); + if (dev) + ndev_owner = dev->dev.parent->driver->owner; if (ndev_owner != bus->owner) module_put(bus->owner); @@ -1880,6 +1930,9 @@ int genphy_config_init(struct phy_device *phydev) if (val & ESTATUS_1000_THALF) linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, features); + if (val & ESTATUS_1000_XFULL) + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + features); } linkmode_and(phydev->supported, phydev->supported, features); @@ -1931,6 +1984,8 @@ int genphy_read_abilities(struct phy_device *phydev) phydev->supported, val & ESTATUS_1000_TFULL); linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, phydev->supported, val & ESTATUS_1000_THALF); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->supported, val & ESTATUS_1000_XFULL); } return 0; |