linux 以太网卡驱动 您所在的位置:网站首页 linux安装设备驱动 linux 以太网卡驱动

linux 以太网卡驱动

2024-04-13 13:47| 来源: 网络整理| 查看: 265

一、网络设备基本结构

  网络设备的系统框图如下所示:

  

 

  mac:工作在网络模型的数据链路层,通过rgmii或rmii接口连接phy,mac控制器中的mdio控制器提供mdio接口,用于访问phy寄存器。

  phy:工作在网络模型的物理层,是IEEE802.3规定的一个标准模块。IEEE802.3规定了 地址0~15共16个通用寄存器,只要配置好这些通用寄存器就能保证phy芯片正常工作。16~31地址的寄存器有厂家自行定义。

 

二、linux中关于网络设备概述   总要结构体

  struct phy_device:phy

  struct phy_driver:phy驱动

  struct mdio_device:mdio从设备,指的就是phy设备

  struct bus_type mdio_bus_type:mdio总线

  struct mii_bus:mdio总线,定义了mdio接口读写方法

 

  linux通过设备、总线、驱动模型来管理设备和驱动,mac控制器通过mdio总线来管理phy设备,mdio总线与i2c总线类似,可以一个主机对应多个从设备,每个从设备都有地址。mdio最多接32个phy设备。内核中用mdio_bus_type代表mdio总线。是struct bus_type结构体,对应的目录是/sys/mdio,在/sys/mdio/devices目录中会有挂载在mdio的phy设备,在/sys/mdio/drivers中会有phy设备的驱动。hi3559对应的/sys/bus/mdio 目录如下所示:

  

  

 

 

mii_bus 结构体代表mdio总线,定义了mdio总线的读写方法,这个总线和mdio_bus_type不一样,mdio_bus_type是bus_type,只是为了管理mdio设备和驱动。 struct mii_bus { struct module *owner; const char *name; char id[MII_BUS_ID_SIZE]; void *priv; int (*read)(struct mii_bus *bus, int addr, int regnum);          //mdio总线的读方法 int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);    //mdio总线写方法 int (*reset)(struct mii_bus *bus); /* * A lock to ensure that only one thing can read/write * the MDIO bus at a time */ struct mutex mdio_lock; struct device *parent; enum { MDIOBUS_ALLOCATED = 1, MDIOBUS_REGISTERED, MDIOBUS_UNREGISTERED, MDIOBUS_RELEASED, } state; struct device dev;                                //mdio总线实体 /* list of all PHYs on bus */ struct mdio_device *mdio_map[PHY_MAX_ADDR];                //挂载在mdio总线下的phy设备,最多32个,PHY_MAX_ADDR值为32 /* PHY addresses to be ignored when probing */ u32 phy_mask; /* PHY addresses to ignore the TA/read failure */ u32 phy_ignore_ta_mask; /* * An array of interrupts, each PHY's interrupt at the index * matching its address */ int irq[PHY_MAX_ADDR];                            //pyh地址 };

 

三、Hi3559以太网卡驱动加载过程 3.1 hi3559以太网设备树配置

  Hi3559以太网控制器设备树节点:Hi3559AV100_SDK_V2.0.3.0\package\osdrv\opensource\kernel\linux-4.9.y\arch\arm64\boot\dts\hisilicon\hi3559av100.dtsi:

  

  mac中mdio设备树节点:

  

  添加phy设备树节点:

  Hi3559AV100_SDK_V2.0.3.0\package\osdrv\opensource\kernel\linux-4.9.y\arch\arm64\boot\dts\hisilicon\hi3559av100-demb.dtsi:

  

3.2 mac控制器驱动加载

mac控制器入口函数为:linux-4.9.y\drivers\net\ethernet\hisilicon\higmac\higmac.c

  

  

  可以看到compatible与higmac设备树中的一致,所以higmac_dev_probe就是gmac控制器的驱动入口函数

3.3 phy设备创建

  从设备树中可以看出,phy在mdio下面,所以先要加载mdio驱动,再加载phy驱动。mdio驱动入口函数为:linux-4.9.y\drivers\net\phy\mdio-hisi-gemac.c

  

  hisi_gemac_mdio_probe

    -->of_mdiobus_register

      -->of_mdiobus_register_phy

        -->get_phy_device

        -->phy_device_register

of_mdiobus_register函数主要功能是注册mdio总线mii_bus,以及创建phy int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) { struct device_node *child; bool scanphys = false; int addr, rc; /* Do not continue if the node is disabled */ if (!of_device_is_available(np)) return -ENODEV; /* 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; mdio->dev.of_node = np; /* Register the MDIO bus */ rc = mdiobus_register(mdio);    //注册mdio总线 if (rc) return rc; /* Loop over the child nodes and register a phy_device for each phy */ for_each_available_child_of_node(np, child) {    //扫描mdio设备树节点下的所有phy芯片,一条mdio总线最多可以接32个phy芯片 addr = of_mdio_parse_addr(&mdio->dev, child);  //读取设备树中phy的地址,即reg的值 if (addr < 0) { scanphys = true; continue; } if (of_mdiobus_child_is_phy(child))        //判断mdio下面如果是phy芯片,则注册phy of_mdiobus_register_phy(mdio, child, addr); else of_mdiobus_register_device(mdio, child, addr); } if (!scanphys) return 0; /* auto scan for PHYs with empty reg property */ //如果设备树中没有定义phy地址,则自动扫描 for_each_available_child_of_node(np, child) { /* Skip PHYs with reg property set */ if (of_find_property(child, "reg", NULL)) continue; for (addr = 0; addr < PHY_MAX_ADDR; addr++) { /* skip already registered PHYs */ if (mdiobus_is_registered_device(mdio, 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); if (of_mdiobus_child_is_phy(child)) of_mdiobus_register_phy(mdio, child, addr); } } return 0; }

 

of_mdiobus_register_phy函数功能是获取phy的id并创建phy,phy id号定义在地址为02和03的寄存器中,由厂家设置。 static void of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *child, u32 addr) { struct phy_device *phy; bool is_c45; int rc; u32 phy_id; printk ("yy of_mdiobus_register_phy is run\n"); is_c45 = of_device_is_compatible(child, "ethernet-phy-ieee802.3-c45"); if (!is_c45 && !of_get_phy_id(child, &phy_id))        //如果设备上定义了phy的id就用设备树中的id,这里设备树没有定义 phy = phy_device_create(mdio, addr, phy_id, 0, NULL); else phy = get_phy_device(mdio, addr, is_c45);        //从02和03寄存器中读取phy id号,并创建phy if (IS_ERR(phy)) return; rc = irq_of_parse_and_map(child, 0); if (rc > 0) { phy->irq = rc; mdio->irq[addr] = rc; } else { phy->irq = mdio->irq[addr]; } if (of_property_read_bool(child, "broken-turn-around")) mdio->phy_ignore_ta_mask |= 1 dev, "registered phy %s at address %i\n", child->name, addr); }  3.4 phy驱动加载

phy驱动入口函数:linux-4.9.y\drivers\net\phy\phy_device.c

  

  这里加载了两个phy驱动,一个是百兆的一个是千兆的。驱动加载成功后,会在/sys/bus/mdio/drivers 目录下生成这个两个驱动目录

  

 

 phy_drivers_register

  -->phy_driver_register

    -->driver_register

      -->phy_probe

phy_driver_register函数主要是填充new_driver这个结构体,然后调用driver_register注册new_driver, int phy_driver_register(struct phy_driver *new_driver, struct module *owner) { int retval; new_driver->mdiodrv.flags |= MDIO_DEVICE_IS_PHY; new_driver->mdiodrv.driver.name = new_driver->name; new_driver->mdiodrv.driver.bus = &mdio_bus_type;    //对应的总线是/sys/bus/mdio new_driver->mdiodrv.driver.probe = phy_probe; new_driver->mdiodrv.driver.remove = phy_remove; new_driver->mdiodrv.driver.owner = owner; retval = driver_register(&new_driver->mdiodrv.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; }  3.5 mdio总线创建

  linux-4.9.y\drivers\net\phy\mdio_bus.c

  

  这个函数执行完后会在/sys/bus 目录下创建mdio_bus目录,代码mdio总线。

  



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有