DWC Ethernet QOS U-Boot Driver 之驱动探测与卸载

本文基于 U-Boot v2025.10 中 DWC Ethernet QOS 驱动相关代码。

eqos_probe & eqos_remove

    eqos->dev = dev;
    eqos->config = (void *)dev_get_driver_data(dev);

    eqos->regs = dev_read_addr(dev);
    if (eqos->regs == FDT_ADDR_T_NONE) {
        pr_err("dev_read_addr() failed\n");
        return -ENODEV;
    }
    eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE);
    eqos->mtl_regs = (void *)(eqos->regs + EQOS_MTL_REGS_BASE);
    eqos->dma_regs = (void *)(eqos->regs + EQOS_DMA_REGS_BASE);
    eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE);

    eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0);

在 probe 函数的一开始,首先对驱动私有数据结构进行了进行初始化,主要是“绑定”了一些关键的结构体以及获取设备树中的一些信息进行填充,依次为:

  • 与 device 绑定;
  • 与 driver data 绑定 (struct eqos_config);
  • 从设备树中获取设备基地址
  • 根据设备基地址与各个寄存器段的偏移获取 mac_regsmtl_regsdma_regstegra186_regs
  • 从设备树中获取网卡支持的最大速度;

之后,在 eqos_probe_resources_core() 中申请并分配了接收发送描述符 (Descriptor) 以及数据缓冲区,Descriptor 与 DMA 是以太网驱动的核心。以太网描述符与 DMA 结合使用,是 CPU 与 MAC 之间实现高效以太网帧传输的“桥梁”,它为控制器提供有关数据位置(缓冲区地址)以及如何处理数据(缓冲区大小、状态等)的信息。

    ret = eqos->config->ops->eqos_probe_resources(dev);
    if (ret < 0) {
        pr_err("eqos_probe_resources() failed: %d\n", ret);
        goto err_remove_resources_core;
    }

    ret = eqos->config->ops->eqos_start_clks(dev);
    if (ret < 0) {
        pr_err("eqos_start_clks() failed: %d\n", ret);
        goto err_remove_resources_tegra;
    }

为了适配不同的平台,驱动里对平台相关的操作分离,并以函数指针结构体 (struct eqos_ops) 的形式方便调用。eqos_probe_resources() 中进一步的对设备树进行了解析,获取时钟信息、复位引脚等平台相关配置。eqos_start_clks() 中则是对设备所需的时钟进行配置以及使能等操作。

#ifdef CONFIG_DM_ETH_PHY
    eqos->mii = eth_phy_get_mdio_bus(dev);
#endif
    if (!eqos->mii) {
        eqos->mii = mdio_alloc();
        if (!eqos->mii) {
            pr_err("mdio_alloc() failed\n");
            ret = -ENOMEM;
            goto err_stop_clks;
        }
        eqos->mii->read = eqos_mdio_read;
        eqos->mii->write = eqos_mdio_write;
        eqos->mii->priv = eqos;
        strcpy(eqos->mii->name, dev->name);

        ret = mdio_register(eqos->mii);
        if (ret < 0) {
            pr_err("mdio_register() failed: %d\n", ret);
            goto err_free_mdio;
        }
    }

#ifdef CONFIG_DM_ETH_PHY
    eth_phy_set_mdio_bus(dev, eqos->mii);
#endif

这里是为该设备准备 MDIO 总线接口(struct mii_dev),主要是将驱动中提供的 MDIO 读写接口绑定到总线设备上,以便 PHY 驱动可以通过 MDIO 访问物理层设备,并且对非 Driver Model 和 Driver Model 两种模型做了兼容处理。

如果开启了 Driver Model 的以太网 PHY 支持 (CONFIG_DM_ETH_PHY),首先会在 eth_phy_get_mdio_bus() 通过设备树中的 phy-handle 节点找到 MDIO 总线设备 (struct mii_dev),并在最后将 MDIO 总线设备与以太网设备绑定,以使 Driver Model 的 PHY 驱动后续能够找到正确的 MDIO 总线。

对于没有开启 Driver Model 或者获取 MDIO 总线失败的情况,会手动创建总线设备并绑定驱动中提供的读写接口,最后注册到总线中(将刚创建的设备添加到 struct list_head mii_devs 中。

到此,驱动的 Probe 操作就全部完成了,总结来说就是创建和初始化了驱动所需的数据结构、获取设备树中的一些配置信息、初始化时钟以及绑定了 MDIO 总线。

而 Remove 操作如下,主要就是一些清理操作,这里就不赘述了。

    mdio_unregister(eqos->mii);
    mdio_free(eqos->mii);
    eqos->config->ops->eqos_stop_clks(dev);
    eqos->config->ops->eqos_remove_resources(dev);

    eqos_remove_resources_core(dev);
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇