phy驱动


bus_find_device_by_name

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
         */
        d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id);
        if (!d) {
                pr_err("PHY %s not found\n", bus_id);
                return ERR_PTR(-ENODEV);
        }
        phydev = to_phy_device(d);

        rc = phy_connect_direct(dev, phydev, handler, interface);
        put_device(d);
        if (rc)
                return ERR_PTR(rc);

        return phydev;
}

struct mdio_device

struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
{
        struct mdio_device *mdiodev = bus->mdio_map[addr];

        if (!mdiodev)
                return NULL;

        if (!(mdiodev->flags & MDIO_DEVICE_FLAG_PHY))
                return NULL;

        return container_of(mdiodev, struct phy_device, mdio);
}


int mdiobus_register_device(struct mdio_device *mdiodev)
{
        int err;

        if (mdiodev->bus->mdio_map[mdiodev->addr])
                return -EBUSY;

        if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) {
                err = mdiobus_register_gpiod(mdiodev);
                if (err)
                        return err;

                err = mdiobus_register_reset(mdiodev);
                if (err)
                        return err;

                /* Assert the reset signal */
                mdio_device_reset(mdiodev, 1);
        }

        mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev;

        return 0;
}
mdiobus_setup_mdiodev_from_board_info(bus, mdiobus_create_device);
static int mdiobus_create_device(struct mii_bus *bus,
                                 struct mdio_board_info *bi)
{
        struct mdio_device *mdiodev;
        int ret = 0;

        mdiodev = mdio_device_create(bus, bi->mdio_addr);
        if (IS_ERR(mdiodev))
                return -ENODEV;

        strncpy(mdiodev->modalias, bi->modalias,
                sizeof(mdiodev->modalias));
        mdiodev->bus_match = mdio_device_bus_match;
        mdiodev->dev.platform_data = (void *)bi->platform_data;

        ret = mdio_device_register(mdiodev);
        if (ret)
                mdio_device_free(mdiodev);

        return ret;
}

int mdio_device_register(struct mdio_device *mdiodev)
{
        int err;

        dev_dbg(&mdiodev->dev, "%s\n", __func__);

        err = mdiobus_register_device(mdiodev);
        if (err)
                return err;

        err = device_add(&mdiodev->dev);
        if (err) {
                pr_err("MDIO %d failed to add\n", mdiodev->addr);
                goto out;
        }


}
struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
{
        struct mdio_device *mdiodev;

        /* We allocate the device, and initialize the default values */
        mdiodev = kzalloc(sizeof(*mdiodev), GFP_KERNEL);
        if (!mdiodev)
                return ERR_PTR(-ENOMEM);

        mdiodev->dev.release = mdio_device_release;
        mdiodev->dev.parent = &bus->dev;
        mdiodev->dev.bus = &mdio_bus_type;
        mdiodev->device_free = mdio_device_free;
        mdiodev->device_remove = mdio_device_remove;
        mdiodev->bus = bus;
        mdiodev->addr = addr;

        dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);

        device_initialize(&mdiodev->dev);

        return mdiodev;
}

phylink_create

struct phy_device {
        struct mdio_device mdio;

        /* Information about the PHY type */
        /* And management functions */
        struct phy_driver *drv;
/* based on au1000_eth. c*/
static int macb_mii_probe(struct net_device *dev)
{
        struct macb *bp = netdev_priv(dev);

        bp->phylink_config.dev = &dev->dev;
        bp->phylink_config.type = PHYLINK_NETDEV;

        if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
                bp->phylink_config.poll_fixed_state = true;
                bp->phylink_config.get_fixed_state = macb_get_pcs_fixed_state;
        }

        bp->phylink = phylink_create(&bp->phylink_config, bp->pdev->dev.fwnode,
                                     bp->phy_interface, &macb_phylink_ops);
        if (IS_ERR(bp->phylink)) {
                netdev_err(dev, "Could not create a phylink instance (%ld)\n",
                           PTR_ERR(bp->phylink));
                return PTR_ERR(bp->phylink);
        }

        return 0;
}

phylink_mac_ops

static const struct phylink_mac_ops macb_phylink_ops = {
        .validate = macb_validate,
        .mac_prepare = macb_mac_prepare,
        .mac_config = macb_mac_config,
        .mac_link_down = macb_mac_link_down,
        .mac_link_up = macb_mac_link_up,
};

phy_device_create

struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
 
struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
{
    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->addr = addr;
    dev->phy_id = phy_id;
    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);

    /* 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));

    return dev;
}
Starting network: [    0.174025] macb 43080000.ethernet eth0: tracing fwnode_get_phy_node IS_ERR(phy_fwnode) 0
[    0.174025] macb 43080000.ethernet eth0: tracing  fwnode_phy_find_device 0
[    0.174025] Generic PHY 43080000.ethernet-ffffffff:07: trace using_genphy  1 
[    0.174025] macb: tracing macb_mdio_wait_for_idle -110
[    0.174025] macb 43080000.ethernet eth0: tracing  phy_attach_direct -110
[    0.174025] macb 43080000.ethernet eth0: Could not attach PHY (-110) and NULL == dn 0 
ip: SIOCSIFFLAGS: Connection timed out
FAIL
Starting dropbear sshd: [    0.174025] random: dropbear: uninitialized urandom read (32 bytes read)
OK

Welcome to Buildroot
buildroot login: root
Password: 
# ip a
1: lo:  mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc noop qlen 1000
    link/ether d6:4e:43:b5:42:1c brd ff:ff:ff:ff:ff:ff
3: sit0@NONE:  mtu 1480 qdisc noop qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
# ip link set eth0 up
[    0.174025] macb 43080000.ethernet eth0: tracing fwnode_get_phy_node IS_ERR(phy_fwnode) 0
[    0.174025] macb 43080000.ethernet eth0: tracing  fwnode_phy_find_device 0
[    0.174025] Generic PHY 43080000.ethernet-ffffffff:07: trace using_genphy  0 
[    0.174025] Generic PHY 43080000.ethernet-ffffffff:07: tracing phy_init_hw 0 
[    0.174025] Generic PHY 43080000.ethernet-ffffffff:07: tracing phy_disable_interrupts 0 
[    0.174025] tracing phy_modify phydev->mdio.addr 7 
[    0.174025] macb: tracing macb_mdio_wait_for_idle -110
[    0.174025] macb 43080000.ethernet eth0: tracing  phy_attach_direct 0
[    0.174025] macb 43080000.ethernet eth0: validation of rgmii with support 0000000,00000000,000002c0 and advertisement 0000000,00000000,00000000 failed: -22
[    0.174025] macb 43080000.ethernet eth0: tracing  phylink_bringup_phy -22
[    0.174025] tracing phy_modify phydev->mdio.addr 7 
[    0.174025] macb: tracing macb_mdio_wait_for_idle -110
[    0.174025] Unable to handle kernel access to user memory without uaccess routines at virtual address 0000000000000030
[    0.174025] Oops [#1]
[    0.174025] Modules linked in:
[    0.174025] CPU: 1 PID: 113 Comm: ip Not tainted 5.14.0 #102
[    0.174025] Hardware name: sifive,hifive-unleashed-a00 (DT)
[    0.174025] epc : klist_put+0x1a/0x84
[    0.174025]  ra : klist_remove+0x86/0xe8
[    0.174025] epc : ffffffff80269146 ra : ffffffff80269274 sp : ffffffd0042cb9b0
[    0.174025]  gp : ffffffff816dc9a0 tp : ffffffe07ffe4600 t0 : ffffffd0042cbd28
[    0.174025]  t1 : 0000000000000063 t2 : 00000000000dc840 s0 : ffffffd0042cb9e0
[    0.174025]  s1 : 0000000000000000 a0 : 0000000000000000 a1 : 0000000000000001
[    0.174025]  a2 : ffffffff81690808 a3 : 0000000000000000 a4 : 0000000000000001
[    0.174025]  a5 : 0000000000000000 a6 : c0000000ffffefff a7 : 0000000000000033
[    0.174025]  s2 : ffffffe081210158 s3 : ffffffff81690808 s4 : 0000000000000001
[    0.174025]  s5 : 0000000000000001 s6 : 0000000000000003 s7 : 0000000000000002
[    0.174025]  s8 : ffffffe080ff87b8 s9 : ffffffe080ff8780 s10: 0000000000000000
[    0.174025]  s11: 0000003fff823d40 t3 : 0000000000000037 t4 : 0000000000000030
[    0.174025]  t5 : ffffffffffffffff t6 : 0000000000000033
[    0.174025] status: 0000000200000120 badaddr: 0000000000000030 cause: 000000000000000d
[    0.174025] [] klist_put+0x1a/0x84
[    0.174025] [] klist_remove+0x86/0xe8
[    0.174025] [] device_release_driver_internal+0xd2/0x108
[    0.174025] [] device_release_driver+0x10/0x18
[    0.174025] [] phy_detach+0x86/0xe4
[    0.174025] [] phylink_fwnode_phy_connect+0xea/0x1ea
[    0.174025] [] phylink_of_phy_connect+0x10/0x18
[    0.174025] [] macb_phylink_connect+0x32/0xc8
[    0.174025] [] macb_open+0x1fe/0x3e8
[    0.174025] [] __dev_open+0xa8/0x10e
[    0.174025] [] __dev_change_flags+0x166/0x1c0
[    0.174025] [] dev_change_flags+0x1e/0x54
[    0.174025] [] devinet_ioctl+0x1f2/0x664
[    0.174025] [] inet_ioctl+0x90/0x118
[    0.174025] [] sock_ioctl+0x1b8/0x328
[    0.174025] [] sys_ioctl+0xb4/0x7e6
[    0.174025] [] ret_from_syscall+0x0/0x2
[    0.174025] ---[ end trace daee3cfade5acdcd ]---
Segmentation fault
# ip [    0.174025] random: fast init done
a

 validation of rgmii with support 0000000,00000000,000002c0 and advertisement 0000000,00000000,00000000 failed: -22

drivers/net/phy/phylink.c

static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
                   phy_interface_t interface)
{
    struct phylink_link_state config;
    __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
    char *irq_str;
    int ret;

    /*
     * This is the new way of dealing with flow control for PHYs,
     * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
     * phy drivers should not set SUPPORTED_[Asym_]Pause") except
     * using our validate call to the MAC, we rely upon the MAC
     * clearing the bits from both supported and advertising fields.
     */
    phy_support_asym_pause(phy);

    memset(&config, 0, sizeof(config));
    linkmode_copy(supported, phy->supported);
    linkmode_copy(config.advertising, phy->advertising);

    /* Clause 45 PHYs switch their Serdes lane between several different
     * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G
     * speeds. We really need to know which interface modes the PHY and
     * MAC supports to properly work out which linkmodes can be supported.
     */
    if (phy->is_c45 &&
        interface != PHY_INTERFACE_MODE_RXAUI &&
        interface != PHY_INTERFACE_MODE_XAUI &&
        interface != PHY_INTERFACE_MODE_USXGMII)
        config.interface = PHY_INTERFACE_MODE_NA;
    else
        config.interface = interface;

    ret = phylink_validate(pl, supported, &config);
    if (ret) {
        phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %d\n",
                 phy_modes(config.interface),
                 __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported,
                 __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising,
                 ret);
        return ret;
    }

    phy->phylink = pl;
    phy->phy_link_change = phylink_phy_change;

    irq_str = phy_attached_info_irq(phy);
    phylink_info(pl,
             "PHY [%s] driver [%s] (irq=%s)\n",
             dev_name(&phy->mdio.dev), phy->drv->name, irq_str);
    kfree(irq_str);

    mutex_lock(&phy->lock);
    mutex_lock(&pl->state_mutex);
    pl->phydev = phy;
    pl->phy_state.interface = interface;
    pl->phy_state.pause = MLO_PAUSE_NONE;
    pl->phy_state.speed = SPEED_UNKNOWN;
    pl->phy_state.duplex = DUPLEX_UNKNOWN;
    linkmode_copy(pl->supported, supported);
    linkmode_copy(pl->link_config.advertising, config.advertising);

    /* Restrict the phy advertisement according to the MAC support. */
    linkmode_copy(phy->advertising, config.advertising);
    mutex_unlock(&pl->state_mutex);
    mutex_unlock(&phy->lock);

    phylink_dbg(pl,
            "phy: setting supported %*pb advertising %*pb\n",
            __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported,
            __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising);

    if (phy_interrupt_is_valid(phy))
        phy_request_interrupt(phy);

    return 0;
}
static int phylink_validate(struct phylink *pl, unsigned long *supported,
                struct phylink_link_state *state)
{
    pl->ops->validate(pl->netdev, supported, state);

    return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
}
static int phylink_is_empty_linkmode(const unsigned long *linkmode)
{
    __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = { 0, };

    phylink_set_port_modes(tmp);
    phylink_set(tmp, Autoneg);
    phylink_set(tmp, Pause);
    phylink_set(tmp, Asym_Pause);

    return linkmode_subset(linkmode, tmp);
}
static inline int linkmode_subset(const unsigned long *src1,
                                  const unsigned long *src2)
{
        return bitmap_subset(src1, src2, __ETHTOOL_LINK_MODE_MASK_NBITS);
}
static inline int bitmap_subset(const unsigned long *src1,
                        const unsigned long *src2, unsigned int nbits)
{
        if (small_const_nbits(nbits))
                return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
        else
                return __bitmap_subset(src1, src2, nbits);
}
[    0.174110] macb 43080000.ethernet eth0: tracing  fwnode_phy_find_device 0
[    0.174110] Generic PHY 43080000.ethernet-ffffffff:07: trace using_genphy  1 
[    0.174110] macb: tracing macb_mdio_wait_for_idle -110
[    0.174110] macb 43080000.ethernet eth0: tracing  phy_attach_direct -110
[    0.174110] macb 43080000.ethernet eth0: Could not attach PHY (-110) and NULL == dn 0
int phylink_fwnode_phy_connect(struct phylink *pl,
                               struct fwnode_handle *fwnode,
                               u32 flags)
{
        struct fwnode_handle *phy_fwnode;
        struct phy_device *phy_dev;
        int ret;

        /* Fixed links and 802.3z are handled without needing a PHY */
        if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
            (pl->cfg_link_an_mode == MLO_AN_INBAND &&
             phy_interface_mode_is_8023z(pl->link_interface)))
                return 0;

        phy_fwnode = fwnode_get_phy_node(fwnode);
        phylink_err(pl, "tracing fwnode_get_phy_node IS_ERR(phy_fwnode) %d",IS_ERR(phy_fwnode));
        if (IS_ERR(phy_fwnode)) {
                if (pl->cfg_link_an_mode == MLO_AN_PHY)
                        return -ENODEV;
                return 0;
        }

        phy_dev = fwnode_phy_find_device(phy_fwnode);
        /* We're done with the phy_node handle */
        fwnode_handle_put(phy_fwnode);
        phylink_err(pl, "tracing  fwnode_phy_find_device %d",NULL == phy_dev);
        if (!phy_dev)
                return -ENODEV;

        ret = phy_attach_direct(pl->netdev, phy_dev, flags,
                                pl->link_interface);
        phylink_err(pl, "tracing  phy_attach_direct %d",ret);
        if (ret) {
                phy_device_free(phy_dev);
                return ret;
        }

        ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
        phylink_err(pl, "tracing  phylink_bringup_phy %d",ret);
        if (ret)
                phy_detach(phy_dev);

        return ret;
}


int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
                      u32 flags, phy_interface_t interface)
{
        struct mii_bus *bus = phydev->mdio.bus;
        struct device *d = &phydev->mdio.dev;
        struct module *ndev_owner = NULL;
        bool using_genphy = false;
        int err;

        /* For Ethernet device drivers that register their own MDIO bus, we
         * will have bus->owner match ndev_mod, so we do not want to increment
         * 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)) {
                phydev_err(phydev, "failed to get the bus module\n");
                return -EIO;
        }

        get_device(d);

        /* Assume that if there is no driver, that it doesn't
         * exist, and we should use the genphy driver.
         */
        if (!d->driver) {
        
        
                 if (phydev->is_c45)
                        d->driver = &genphy_c45_driver.mdiodrv.driver;
                else
                        d->driver = &genphy_driver.mdiodrv.driver;

                using_genphy = true;
        }

        if (!try_module_get(d->driver->owner)) {
                phydev_err(phydev, "failed to get the device driver module\n");
                err = -EIO;
                goto error_put_device;
        }
        phydev_err(phydev, "trace using_genphy  %d \n", using_genphy);

        if (using_genphy) {
                err = d->driver->probe(d);
                if (err >= 0)
                        err = device_bind_driver(d);

                if (err)
                        goto error_module_put;
        }

phy_driver_register(&genphy_driver, THIS_MODULE);

int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
{
        int retval;

        /* Either the features are hard coded, or dynamically
         * determined. It cannot be both.
         */
        if (WARN_ON(new_driver->features && new_driver->get_features)) {
                pr_err("%s: features and get_features must not both be set\n",
                       new_driver->name);
                return -EINVAL;
        }

        new_driver->mdiodrv.flags |= MDIO_DEVICE_IS_PHY;
        new_driver->mdiodrv.driver.name = new_driver->name;
        new_driver->mdiodrv.driver.bus = &mdio_bus_type;
        new_driver->mdiodrv.driver.probe = phy_probe;
        new_driver->mdiodrv.driver.remove = phy_remove;
        new_driver->mdiodrv.driver.shutdown = phy_shutdown;
        new_driver->mdiodrv.driver.owner = owner;
        new_driver->mdiodrv.driver.probe_type = PROBE_FORCE_SYNCHRONOUS;

        retval = driver_register(&new_driver->mdiodrv.driver);
        if (retval) {
                pr_err("%s: Error %d in registering driver\n",
                       new_driver->name, retval);
        pr_err("%s: Registered new driver\n", new_driver->name);
        //pr_debug("%s: Registered new driver\n", new_driver->name);

        return 0;
}

 



[    0.174110] libphy: Generic Clause 45 PHY: Registered new driver
[    0.174110] libphy: Generic PHY: Registered new driver


[    0.174110] libphy: Marvell 88E1101: Registered new driver
[    0.174110] libphy: Marvell 88E1112: Registered new driver
[    0.174110] libphy: Marvell 88E1111: Registered new driver
[    0.174110] libphy: Marvell 88E1111 (Finisar): Registered new driver
[    0.174110] libphy: Marvell 88E1118: Registered new driver
[    0.174110] libphy: Marvell 88E1121R: Registered new driver
[    0.174110] libphy: Marvell 88E1318S: Registered new driver
[    0.174110] libphy: Marvell 88E1145: Registered new driver
[    0.174110] libphy: Marvell 88E1149R: Registered new driver
[    0.174110] libphy: Marvell 88E1240: Registered new driver
[    0.174110] libphy: Marvell 88E1116R: Registered new driver
[    0.174110] libphy: Marvell 88E1510: Registered new driver
[    0.174110] libphy: Marvell 88E1540: Registered new driver
[    0.174110] libphy: Marvell 88E1545: Registered new driver
[    0.174110] libphy: Marvell 88E3016: Registered new driver
[    0.174110] libphy: Marvell 88E6341 Family: Registered new driver
[    0.174110] libphy: Marvell 88E6390 Family: Registered new driver
[    0.174110] libphy: Marvell 88E6393 Family: Registered new driver
[    0.174110] libphy: Marvell 88E1340S: Registered new driver
[    0.174110] libphy: Marvell 88E1548P: Registered new driver

phy id匹配

static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id)
{
        int phy_reg;

        /* Grab the bits from PHYIR1, and put them in the upper half */
        phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
 if (phy_reg < 0) {
                /* returning -ENODEV doesn't stop bus scanning */
                return (phy_reg == -EIO || phy_reg == -ENODEV) ? -ENODEV : -EIO;
        }

        *phy_id = phy_reg << 16;

        /* Grab the bits from PHYIR2, and put them in the lower half */
        phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
      if (phy_reg < 0) {
                /* returning -ENODEV doesn't stop bus scanning */
                return (phy_reg == -EIO || phy_reg == -ENODEV) ? -ENODEV : -EIO;
        }

        *phy_id |= phy_reg;

        /* If the phy_id is mostly Fs, there is no device there */
        if ((*phy_id & 0x1fffffff) == 0x1fffffff)
                return -ENODEV;
                                 

 设备树

  compatible = "ethernet-phy-id2000.a231", "ethernet-phy-ieee802.3-c22";

int fwnode_get_phy_id(struct fwnode_handle *fwnode, u32 *phy_id)
{
        unsigned int upper, lower;
        const char *cp;
        int ret;

        ret = fwnode_property_read_string(fwnode, "compatible", &cp);
        pr_err("tracing fwnode_get_phy_id %s and  %d",cp , ret);
        if (ret)
                return ret;

        if (sscanf(cp, "ethernet-phy-id%4x.%4x", &upper, &lower) != 2)
                return -EINVAL;

        *phy_id = ((upper & GENMASK(15, 0)) << 16) | (lower & GENMASK(15, 0));
        return 0;
}

驱动match

struct bus_type mdio_bus_type = {
        .name           = "mdio_bus",
        .dev_groups     = mdio_bus_dev_groups,
        .match          = mdio_bus_match,
        .uevent         = mdio_uevent,
};

    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 & phydrv->phy_id_mask)       
            (phydev->phy_id & phydrv->phy_id_mask));           
    } 
 

device_add触发驱动probe

[    0.174275] macb 43080000.ethernet: tracing macb probe call  init 0.
[    0.174275] libphy:  fwnode_get_phy_id ethernet-phy-id2000.a231 and  0
[    0.174275] of_mdiobus_register 
[    0.174275] libphy: MACB_mii_bus: probed
[    0.174275] mdio_bus 43080000.ethernet-ffffffff: phy@0 h PHY address 12
[    0.174275] of_mdiobus_register addr 12 
[    0.174275] libphy:  fwnode_get_phy_id ethernet-phy-id2000.a231 and  0
[    0.174275] libphy:  fwnode_get_phy_id ethernet-phy-id2000.a231 and  0
[    0.174275] mdio_bus 43080000.ethernet-ffffffff:0c: ret 256 loading PHY driver module for ID 0x2000a231
[    0.174275] libphy: tracing phy_request_driver_module ret 0
[    0.174275] tracing phy IS_ERR(phy) 0
[    0.174275] bus: 'mdio_bus': tracing bus_probe_device  43080000.ethernet-ffffffff:0c
[    0.174275] __device_attach_driver  drv Generic Clause 45 PHY  match device 43080000.ethernet-ffffffff:0c : 0
[    0.174275] __device_attach_driver  drv Generic PHY  match device 43080000.ethernet-ffffffff:0c : 0
[    0.174275]__device_attach_driver  drv TI DP83867  match device 43080000.ethernet-ffffffff:0c : 1
[    0.174275] bus: 'mdio_bus': __driver_probe_device: matched device 43080000.ethernet-ffffffff:0c with driver TI DP83867
[    0.174275] TI DP83867: call_driver_probe of 43080000.ethernet-ffffffff:0c 
[    0.174275] macb: tracing macb_mdio_wait_for_idle -110
[    0.174275] TI DP83867: probe of 43080000.ethernet-ffffffff:0c failed with error -110
mdiobus_setup_mdiodev_from_board_info(bus, mdiobus_create_device);
       -->mdio_device_create
         -->mdio_device_register  
               -->device_add
                 -->device_add()函数中还调用了bus_probe_device

driver_regitster触发驱动probe

bus_for_each_dev

phy_driver_regitster -->driver_register-->bus_add_driver-->driver_attach-->bus_for_each_dev-->__driver_attach(经过bus_for_each_dev参数回调)-->driver_probe_device(drv, dev)-->really_probe(dev, drv)-->drv->probe(dev).

int phy_driver_register(struct phy_driver *new_driver)
{
    int retval;
    new_driver->driver.name = new_driver->name;
    new_driver->driver.bus = &mdio_bus_type;
    new_driver->driver.probe = phy_probe;
    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);
        return retval;
    }
    pr_debug("%s: Registered new driver\n", new_driver->name);
    return 0;
}

可见phy的driver是挂载在mdio_bus上的。
driver_register(struct device_driver *drv):检测mdio_bus_type上是否已经注册该设备了。
bus_add_driver(struct device_driver *drv):Add a driver to the bus.
driver_attach(struct device_driver *drv):让总线上的设备与驱动匹配.
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach): 回调函数__driver_attach.
 __driver_attach(struct device *dev, void *data):
    if (!driver_match_device(drv, dev))
return 0;
driver_match_device(drv, dev)就是匹配driver 与 device。

static inline int driver_match_device(struct device_driver *drv,
                      struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
drv->bus->match 匹配函数 源码:

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);


    if (of_driver_match_device(dev, drv))
        return 1;

    if (phydrv->match_phy_device)
        return phydrv->match_phy_device(phydev);

    return ((phydrv->phy_id & phydrv->phy_id_mask) ==
            (phydev->phy_id & phydrv->phy_id_mask));
}

能够肯定匹配是经过driver和device的phy_id & phy_id_mask, 而不是经过设备于驱动名字匹配。 driver_probe_device(drv, dev):从这里追踪代码能够找到really_probe(dev, drv),继续追踪drv->probe(dev),到此结束

CONFIG_DP83867_PHY



static struct phy_driver dp83867_driver[] = {
        {
                .phy_id         = DP83867_PHY_ID,
                .phy_id_mask    = 0xfffffff0,
                .name           = "TI DP83867",
                /* PHY_GBIT_FEATURES */

                .probe          = dp83867_probe,
                .config_init    = dp83867_config_init,
                .soft_reset     = dp83867_phy_reset,

                .read_status    = dp83867_read_status,
                .get_tunable    = dp83867_get_tunable,
                .set_tunable    = dp83867_set_tunable,

                .get_wol        = dp83867_get_wol,
                .set_wol        = dp83867_set_wol,

                /* IRQ related */
                .config_intr    = dp83867_config_intr,
                .handle_interrupt = dp83867_handle_interrupt,

                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
        },
};
module_phy_driver(dp83867_driver);


#define module_phy_driver(__phy_drivers)                                \
        phy_module_driver(__phy_drivers, ARRAY_SIZE(__phy_drivers))
        
static int __init dp83867_init(void)
{
        printk("____%s @ %s\n", __func__,__FILE__);

        return phy_driver_register(&dp83867_driver);
}
#define phy_module_driver(__phy_drivers, __count)                       \
static int __init phy_module_init(void)                                 \
{                                                                       \
        return phy_drivers_register(__phy_drivers, __count, THIS_MODULE); \
}                     

 

phy_probe --> dp83867_probe

 
static int phy_probe(struct device *dev)
{
        struct phy_device *phydev = to_phy_device(dev);
        struct device_driver *drv = phydev->mdio.dev.driver;
        struct phy_driver *phydrv = to_phy_driver(drv);
        int err = 0;

        phydev->drv = phydrv;

        /* Disable the interrupt if the PHY doesn't support it
         * but the interrupt is still a valid one
         */
        if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev))
                phydev->irq = PHY_POLL;

        if (phydrv->flags & PHY_IS_INTERNAL)
                phydev->is_internal = true;

        mutex_lock(&phydev->lock);

        /* Deassert the reset signal */
        phy_device_reset(phydev, 0);

        if (phydev->drv->probe) {
                err = phydev->drv->probe(phydev);//调用dp83867_probe
                pr_err("tracing phydev->drv->probe %d", err); 
/*

[ 0.174251] tracing dp83867_probe
[ 0.174251] tracing dp83867_of_init not empty func !of_node = ? 0
[ 0.174251] libphy: tracing phydev->drv->probe 0
[ 0.174251] macb: tracing macb_mdio_wait_for_idle -110, 356
[ 0.174251] libphy: tracing phydev->features -110


*/
if (err) goto out; } /* Start out supporting everything. Eventually, * a controller will attach, and may modify one * or both of these values */ if (phydrv->features) linkmode_copy(phydev->supported, phydrv->features); else if (phydrv->get_features) err = phydrv->get_features(phydev); else if (phydev->is_c45) err = genphy_c45_pma_read_abilities(phydev); else err = genphy_read_abilities(phydev); pr_err("tracing phydev->features %d", err); if (err) goto out; if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported)) phydev->autoneg = 0; if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,

 phydev->drv->config_init

phy_attach_direct ---->dp83867_config_init

static struct phy_driver dp83867_driver[] = {
        {
                .phy_id         = DP83867_PHY_ID,
                .phy_id_mask    = 0xfffffff0,
                .name           = "TI DP83867",
                /* PHY_GBIT_FEATURES */

                .probe          = dp83867_probe,
                .config_init    = dp83867_config_init,
                .soft_reset     = dp83867_phy_reset,

                .read_status    = dp83867_read_status,
                .get_tunable    = dp83867_get_tunable,
                .set_tunable    = dp83867_set_tunable,

                .get_wol        = dp83867_get_wol,
                .set_wol        = dp83867_set_wol,

                /* IRQ related */
                .config_intr    = dp83867_config_intr,
                .handle_interrupt = dp83867_handle_interrupt,

                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
        },
};

 TI DP83867  etherne : ti,rx-internal-delay must be specified

       /* RX delay *must* be specified if internal delay of RX is used. */
        if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
             phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) &&
             dp83867->rx_id_delay == DP83867_RGMII_RX_CLK_DELAY_INV) {
                phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
                return -EINVAL;
        }

macb_poll

 netif_napi_add(dev, &queue->napi, macb_poll, NAPI_POLL_WEIGHT);

static int macb_poll(struct napi_struct *napi, int budget)
{
    struct macb_queue *queue = container_of(napi, struct macb_queue, napi);
    struct macb *bp = queue->bp;
    int work_done;
    u32 status;

    status = macb_readl(bp, RSR);
    macb_writel(bp, RSR, status);

    netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n",
            (unsigned long)status, budget);

    work_done = bp->macbgem_ops.mog_rx(queue, napi, budget);  //调用macb_rx
    if (work_done < budget) {
        napi_complete_done(napi, work_done);

        /* Packets received while interrupts were disabled */
        status = macb_readl(bp, RSR);
        if (status) {
            if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
                queue_writel(queue, ISR, MACB_BIT(RCOMP));
            napi_reschedule(napi);
        } else {
            queue_writel(queue, IER, bp->rx_intr_mask);
        }
    }

    /* TODO: Handle errors */

    return work_done;
}

相关