/* mdio_bus_match * * description: Given a PHY device, and a PHY driver, return 1 if * the driver supports the device. Otherwise, return 0 */ static int mdio_bus_match(struct device *dev, struct device_driver *drv) { struct phy_device *phydev = to_phy_device(dev); struct phy_driver *phydrv = to_phy_driver(drv); return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask)); }
/** * phy_attach - attach a network device to a particular PHY device * @dev: network device to attach * @phy_id: PHY device to attach * @flags: PHY device's dev_flags * @interface: PHY device's interface * * 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 * the attaching device, and given a callback for link status * change. The phy_device is returned to the attaching driver. */ struct phy_device *phy_attach(struct net_device *dev, const char *phy_id, u32 flags, phy_interface_t interface) { struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; struct device *d; /* Search the list of PHY devices on the mdio bus for the * PHY with the requested name */ d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id); if (d) { phydev = to_phy_device(d); } else { printk(KERN_ERR "%s not found\n", phy_id); return ERR_PTR(-ENODEV); } /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ if (NULL == d->driver) { int err; d->driver = &genphy_driver.driver; err = d->driver->probe(d); if (err >= 0) err = device_bind_driver(d); if (err) return ERR_PTR(err); } if (phydev->attached_dev) { printk(KERN_ERR "%s: %s already attached\n", dev->name, phy_id); return ERR_PTR(-EBUSY); } phydev->attached_dev = dev; phydev->dev_flags = flags; phydev->interface = interface; /* Do initial configuration here, now that * we have certain key parameters * (dev_flags and interface) */ if (phydev->drv->config_init) { int err; err = phydev->drv->config_init(phydev); if (err < 0) return ERR_PTR(err); } return phydev; }
struct phy_device *of_phy_find_device(struct device_node *phy_np) { struct device *d; if (!phy_np) return NULL; d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match); return d ? to_phy_device(d) : NULL; }
static void mdio_bus_remove(struct device_d *_dev) { struct phy_device *dev = to_phy_device(_dev); struct phy_driver *drv = to_phy_driver(_dev->driver); if (drv->remove) drv->remove(dev); free(dev->cdev.name); devfs_remove(&dev->cdev); }
static int mdio_bus_probe(struct device_d *_dev) { struct phy_device *dev = to_phy_device(_dev); struct phy_driver *drv = to_phy_driver(_dev->driver); int ret; if (drv->probe) { ret = drv->probe(dev); if (ret) goto err; } if (dev->dev_flags) { if (dev->dev_flags & PHYLIB_FORCE_10) { dev->speed = SPEED_10; dev->duplex = DUPLEX_FULL; dev->autoneg = !AUTONEG_ENABLE; dev->force = 1; dev->link = 1; } else if (dev->dev_flags & PHYLIB_FORCE_100) { dev->speed = SPEED_100; dev->duplex = DUPLEX_FULL; dev->autoneg = !AUTONEG_ENABLE; dev->force = 1; dev->link = 1; } } /* Start out supporting everything. Eventually, * a controller will attach, and may modify one * or both of these values */ dev->supported = drv->features; dev->advertising = drv->features; dev_add_param_int_ro(&dev->dev, "phy_addr", dev->addr, "%d"); dev_add_param_int_ro(&dev->dev, "phy_id", dev->phy_id, "0x%08x"); dev->cdev.name = asprintf("phy%d", _dev->id); dev->cdev.size = 64; dev->cdev.ops = &phydev_ops; dev->cdev.priv = dev; dev->cdev.dev = _dev; devfs_create(&dev->cdev); return 0; err: return ret; }
struct phy_device *phy_attach(struct net_device *dev, const char *phy_id, u32 flags) { struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; struct device *d; /* Search the list of PHY devices on the mdio bus for the * PHY with the requested name */ d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id); if (d) { phydev = to_phy_device(d); } else { printk(KERN_ERR "%s not found\n", phy_id); return ERR_PTR(-ENODEV); } /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ if (NULL == d->driver) { int err; down_write(&d->bus->subsys.rwsem); d->driver = &genphy_driver.driver; err = d->driver->probe(d); if (err < 0) return ERR_PTR(err); device_bind_driver(d); up_write(&d->bus->subsys.rwsem); } if (phydev->attached_dev) { printk(KERN_ERR "%s: %s already attached\n", dev->name, phy_id); return ERR_PTR(-EBUSY); } phydev->attached_dev = dev; phydev->dev_flags = flags; return phydev; }
static int phy_remove(struct device *dev) { struct phy_device *phydev; phydev = to_phy_device(dev); mutex_lock(&phydev->lock); phydev->state = PHY_DOWN; mutex_unlock(&phydev->lock); if (phydev->drv->remove) phydev->drv->remove(phydev); put_driver(dev->driver); phydev->drv = NULL; return 0; }
/* phy_probe * * description: Take care of setting up the phy_device structure, * set the state to READY (the driver's init function should * set it to STARTING if needed). */ static int phy_probe(struct device *dev) { struct phy_device *phydev; struct phy_driver *phydrv; struct device_driver *drv; int err = 0; phydev = to_phy_device(dev); /* Make sure the driver is held. * XXX -- Is this correct? */ drv = get_driver(phydev->dev.driver); phydrv = to_phy_driver(drv); phydev->drv = phydrv; /* Disable the interrupt if the PHY doesn't support it */ if (!(phydrv->flags & PHY_HAS_INTERRUPT)) phydev->irq = PHY_POLL; spin_lock(&phydev->lock); /* Start out supporting everything. Eventually, * a controller will attach, and may modify one * or both of these values */ phydev->supported = phydrv->features; phydev->advertising = phydrv->features; /* Set the state to READY by default */ phydev->state = PHY_READY; if (phydev->drv->probe) err = phydev->drv->probe(phydev); spin_unlock(&phydev->lock); if (err < 0) return err; if (phydev->drv->config_init) err = phydev->drv->config_init(phydev); return err; }
static void phy_device_release(struct device *dev) { phy_device_free(to_phy_device(dev)); }
static int mdio_bus_probe(struct device_d *_dev) { struct phy_device *dev = to_phy_device(_dev); struct phy_driver *drv = to_phy_driver(_dev->driver); int ret; char str[16]; dev->attached_dev->phydev = dev; if (drv->probe) { ret = drv->probe(dev); if (ret) goto err; } if (dev->dev_flags) { if (dev->dev_flags & PHYLIB_FORCE_10) { dev->speed = SPEED_10; dev->duplex = DUPLEX_FULL; dev->autoneg = !AUTONEG_ENABLE; dev->force = 1; dev->link = 1; } else if (dev->dev_flags & PHYLIB_FORCE_100) { dev->speed = SPEED_100; dev->duplex = DUPLEX_FULL; dev->autoneg = !AUTONEG_ENABLE; dev->force = 1; dev->link = 1; } } /* Start out supporting everything. Eventually, * a controller will attach, and may modify one * or both of these values */ dev->supported = drv->features; dev->advertising = drv->features; ret = phy_init_hw(dev); if (ret) goto err; /* Sanitize settings based on PHY capabilities */ if ((dev->supported & SUPPORTED_Autoneg) == 0) dev->autoneg = AUTONEG_DISABLE; sprintf(str, "%d", dev->addr); dev_add_param_fixed(&dev->dev, "phy_addr", str); sprintf(str, "0x%08x", dev->phy_id); dev_add_param_fixed(&dev->dev, "phy_id", str); dev->cdev.name = asprintf("phy%d", _dev->id); dev->cdev.size = 64; dev->cdev.ops = &phydev_ops; dev->cdev.priv = dev; dev->cdev.dev = _dev; devfs_create(&dev->cdev); return 0; err: dev->attached_dev->phydev = NULL; dev->attached_dev = NULL; return ret; }