MDIO总线相关

    xiaoxiao2021-03-25  41

    ##这里主要是device端

    在drivers/net/ethernet/中有各品牌的文件,一个品牌对应一个文件夹

    一个文件夹下有多个文件,一个文件对应一个品牌下设备.

    platform_driver_register(&smsc911x_driver) static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, .remove = smsc911x_drv_remove, .driver = { .name = SMSC_CHIPNAME, .owner = THIS_MODULE, .pm = SMSC911X_PM_OPS, .of_match_table = of_match_ptr(smsc911x_dt_ids), }, };

    1/

    smsc911x_drv_probe 一个设备对应一个文件

    2/

    smsc911x_drv_remove 一个设备对应一个文件

    3/

    .name = SMSC_CHIPNAME "smsc911x"

    4/

    .pm = SMSC911X_PM_OPS, 一个设备对应一系列操作

    5/

    static const struct of_device_id smsc911x_dt_ids[] = { { .compatible = "smsc,lan9115", }, { /* sentinel */ } };

    这个好像是platfrom里面的platform,应该和那个不对头.

    估计是 phy_device,查找,果然有.但是找不到

    继续分析这个

    static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, .remove = smsc911x_drv_remove, .driver = { .name = SMSC_CHIPNAME, .owner = THIS_MODULE, .pm = SMSC911X_PM_OPS, .of_match_table = of_match_ptr(smsc911x_dt_ids), }, }; /** * platform_match - bind platform device to platform driver. * @dev: device. * @drv: driver. * * Platform device IDs are assumed to be encoded like this: * "<name><instance>", where <name> is a short description of the type of * device, like "pci" or "floppy", and <instance> is the enumerated * instance of the device, like '0' or '42'. Driver IDs are simply * "<name>". So, extract the <name> from the platform_device structure, * and compare it against the name of the driver. Return whether they match * or not. */ static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; /* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0); }

    不找platform了 我找到phy_device了

    在drivers/of/of_mdio.c中

    /** * of_mdiobus_register - Register mii_bus and create PHYs from the device tree * @mdio: pointer to mii_bus * @np: pointer to device_node of MDIO bus. * * This function registers the mii_bus structure and registers a phy_device * for each child node of @np. */ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) { struct phy_device *phy; struct device_node *child; const __be32 *paddr; u32 addr; bool is_c45, scanphys = false; int rc, i, len; /* Mask out all PHYs from auto probing. Instead the PHYs listed in * the device tree are populated after the bus has been registered */ mdio->phy_mask = ~0; /* Clear all the IRQ properties */ if (mdio->irq) for (i=0; i<PHY_MAX_ADDR; i++) mdio->irq[i] = PHY_POLL; mdio->dev.of_node = np; /* Register the MDIO bus */ rc = mdiobus_register(mdio); if (rc) return rc; /* Loop over the child nodes and register a phy_device for each one */ for_each_available_child_of_node(np, child) { /* A PHY must have a reg property in the range [0-31] */ paddr = of_get_property(child, "reg", &len); if (!paddr || len < sizeof(*paddr)) { scanphys = true; dev_err(&mdio->dev, "%s has invalid PHY address\n", child->full_name); continue; } addr = be32_to_cpup(paddr); if (addr >= 32) { dev_err(&mdio->dev, "%s PHY address %i is too large\n", child->full_name, addr); continue; } if (mdio->irq) { mdio->irq[addr] = irq_of_parse_and_map(child, 0); if (!mdio->irq[addr]) mdio->irq[addr] = PHY_POLL; } is_c45 = of_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"); phy = get_phy_device(mdio, addr, is_c45); if (!phy || IS_ERR(phy)) { dev_err(&mdio->dev, "cannot get PHY at address %i\n", addr); continue; } /* Associate the OF node with the device structure so it * can be looked up later */ of_node_get(child); phy->dev.of_node = child; /* All data is now stored in the phy struct; register it */ rc = phy_device_register(phy); if (rc) { phy_device_free(phy); of_node_put(child); continue; } dev_dbg(&mdio->dev, "registered phy %s at address %i\n", child->name, addr); } if (!scanphys) return 0; /* auto scan for PHYs with empty reg property */ for_each_available_child_of_node(np, child) { /* Skip PHYs with reg property set */ paddr = of_get_property(child, "reg", &len); if (paddr) continue; is_c45 = of_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"); for (addr = 0; addr < PHY_MAX_ADDR; addr++) { /* skip already registered PHYs */ if (mdio->phy_map[addr]) continue; /* be noisy to encourage people to set reg property */ dev_info(&mdio->dev, "scan phy %s at address %i\n", child->name, addr); phy = get_phy_device(mdio, addr, is_c45); if (!phy || IS_ERR(phy)) continue; if (mdio->irq) { mdio->irq[addr] = irq_of_parse_and_map(child, 0); if (!mdio->irq[addr]) mdio->irq[addr] = PHY_POLL; } /* Associate the OF node with the device structure so it * can be looked up later */ of_node_get(child); phy->dev.of_node = child; /* All data is now stored in the phy struct; * register it */ rc = phy_device_register(phy); if (rc) { phy_device_free(phy); of_node_put(child); continue; } dev_info(&mdio->dev, "registered phy %s at address %i\n", child->name, addr); break; } } return 0; } 其中paddr = of_get_property(child, "reg", &len); 其中addr = be32_to_cpup(paddr); 其中phy = get_phy_device(mdio, addr, is_c45); /** * 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, bool is_c45) { struct phy_c45_device_ids c45_ids = {0}; struct phy_device *dev = NULL; u32 phy_id = 0; int r; r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids); if (r) return ERR_PTR(r); /* If the phy_id is mostly Fs, there is no device there */ if ((phy_id & 0x1fffffff) == 0x1fffffff) return NULL; dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); return dev; } dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); /** * 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, bool is_c45) { struct phy_c45_device_ids c45_ids = {0}; struct phy_device *dev = NULL; u32 phy_id = 0; int r; r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids); if (r) return ERR_PTR(r); /* If the phy_id is mostly Fs, there is no device there */ if ((phy_id & 0x1fffffff) == 0x1fffffff) return NULL; dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); return dev; } dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); 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; /* 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); dev->dev.release = phy_device_release; dev->speed = 0; dev->duplex = -1; dev->pause = dev->asym_pause = 0; dev->link = 1; dev->interface = PHY_INTERFACE_MODE_GMII; 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; dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); dev->state = PHY_DOWN; mutex_init(&dev->lock); INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); /* 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. */ request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id)); device_initialize(&dev->dev); return dev; }

    ------------------然后分析最后一个函数

    phy_device结构体 /* phy_device: An instance of a PHY * * drv: Pointer to the driver for this PHY instance * bus: Pointer to the bus this PHY is on * dev: driver model device structure for this PHY * phy_id: UID for this device found during discovery * c45_ids: 802.3-c45 Device Identifers if is_c45. * is_c45: Set to true if this phy uses clause 45 addressing. * state: state of the PHY for management purposes * dev_flags: Device-specific flags used by the PHY driver. * addr: Bus address of PHY * link_timeout: The number of timer firings to wait before the * giving up on the current attempt at acquiring a link * irq: IRQ number of the PHY's interrupt (-1 if none) * phy_timer: The timer for handling the state machine * phy_queue: A work_queue for the interrupt * attached_dev: The attached enet driver's device instance ptr * adjust_link: Callback for the enet controller to respond to * changes in the link state. * adjust_state: Callback for the enet driver to respond to * changes in the state machine. * * speed, duplex, pause, supported, advertising, and * autoneg are used like in mii_if_info * * interrupts currently only supports enabled or disabled, * but could be changed in the future to support enabling * and disabling specific interrupts * * Contains some infrastructure for polling and interrupt * handling, as well as handling shifts in PHY hardware state */ struct phy_device { /* Information about the PHY type */ /* And management functions */ struct phy_driver *drv; struct mii_bus *bus; struct device dev; u32 phy_id; struct phy_c45_device_ids c45_ids; bool is_c45; enum phy_state state; u32 dev_flags; phy_interface_t interface; /* Bus address of the PHY (0-31) */ int addr; /* * forced speed & duplex (no autoneg) * partner speed & duplex & pause (autoneg) */ int speed; int duplex; int pause; int asym_pause; /* The most recently read link state */ int link; /* Enabled Interrupts */ u32 interrupts; /* Union of PHY and Attached devices' supported modes */ /* See mii.h for more info */ u32 supported; u32 advertising; int autoneg; int link_timeout; /* * Interrupt number for this PHY * -1 means no interrupt */ int irq; /* private data pointer */ /* For use by PHYs to maintain extra state */ void *priv; /* Interrupt and Polling infrastructure */ struct work_struct phy_queue; struct delayed_work state_queue; atomic_t irq_disable; struct mutex lock; struct net_device *attached_dev; void (*adjust_link)(struct net_device *dev); void (*adjust_state)(struct net_device *dev); }; 可以看到ID是get_phy_device函数给的 调用了get_phy_id得到的 r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);

    通过of_mdiobus_register找调用

    Of_mdio.c (drivers\of): * of_mdiobus_register - Register mii_bus and create PHYs from the device tree Of_mdio.c (drivers\of):int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) Of_mdio.c (drivers\of):EXPORT_SYMBOL(of_mdiobus_register); Of_mdio.h (include\linux):extern int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np); Of_mdio.h (include\linux):static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) Mdio-gpio.c (drivers\net\phy): ret = of_mdiobus_register(new_bus, pdev->dev.of_node); Mdio-mux.c (drivers\net\phy): r = of_mdiobus_register(cb->mii_bus, child_bus_node); Mdio-octeon.c (drivers\net\phy): err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node); Mdio_bus.c (drivers\net\phy): * of_mdiobus_register(), the mii_bus cannot be found before it is Mdio_bus.c (drivers\net\phy): * registered with of_mdiobus_register(). 应该不是上面的5行 应该是下面的
    转载请注明原文地址: https://ju.6miu.com/read-200169.html

    最新回复(0)