【S32V234】|【BSP23.1】 (一)Ethernet 驱动 --- Mac 驱动详解

一、前言

以下为 S32V234 的 Ethernet 驱动的大致框架和 Mac 驱动详解。

二、硬件框架

Ethernet 驱动分为两部分:Mac 驱动和 Phy 驱动。

Mac 模块一般集成在芯片内部,Phy 模块一般外挂在芯片外,两者通过 RMII/GRMII 进行通信,S32V234 可以通过寄存器 SRC_GPR3[ENET_MODE] 来选择 RMII 还是 GRMII


RMII/GRMII 接口分为两部分:数据接口和控制接口。

其中控制接口有另外的 MDIO 控制器来控制, MDIO 控制器是 Mac 控制器里的一部分,通过 MDIO 总线来控制 Phy 芯片。数据接口由 Mac 控制器控制,通过 RMII/GRMII的其他接和口Phy 进行数据传输。

三、device & driver

根据 datasheet 和 设备树,找到了 Mac 的 device 节点是 fec: ethernet@40032000(以下 fec 可与 Mac 等同),对应的驱动文件是 drivers/net/ethernet/freescale/fec_main.c

 

四、MAC 驱动(fec_main.c)

注册为平台总线设备:

static struct platform_driver fec_driver = {

    .driver = {

        .name   = DRIVER_NAME,

        .owner  = THIS_MODULE,

        .pm = &fec_pm_ops,

        .of_match_table = fec_dt_ids,

    },

    .id_table = fec_devtype,

    .probe  = fec_probe,

    .remove = fec_drv_remove,

};

module_platform_driver(fec_driver);

通过 platform 总线匹配 device 和 driver 成功之后,进入 fec_probe 函数。

1.     fec_probe 函数

在 probe 里面主要完成以下几件事:

  1. 获取设备信息,申请各项资源
  2. 从 fec的设备树节点中获取phy子节点和 phy 模式(phy-mode = "rgmii")
  3. 设置时钟、电源管理
  4. 重启并初始化 fec,申请队列和DMA,设置MAC地址,设置 mii_bus->read/mii_bus->write 函数(fec_enet_init)
  5. 申请中断(发送完成中断,mii 中断等处理函数)
  6. 初始化核心数据结构mii_bus,注册 MDIO bus,注册 phy 设备(fec_enet_mii_init)
  7. 向内核注册net_device

2.     fec_enet_init 函数

定义在 drivers/net/ethernet/freescale/fec_main.c 中,被 fec_probe 调用。

它主要完成以下动作:

  1. tx、rx 的 dma 队列申请
  2. 获取mac地址,设置mac地址,写入mac寄存器
  3. 设置 tx、rx 的队列地址
  4. 初始化网卡操作函数和 ethtool_ops
  5. 重启 mac

网卡操作函数:

static const struct net_device_ops fec_netdev_ops = {

    .ndo_open       = fec_enet_open,

    .ndo_stop       = fec_enet_close,

    .ndo_start_xmit     = fec_enet_start_xmit,//发包函数

    .ndo_set_rx_mode    = set_multicast_list,

    .ndo_validate_addr  = eth_validate_addr,

    .ndo_tx_timeout     = fec_timeout,

    .ndo_set_mac_address    = fec_set_mac_address,

    .ndo_do_ioctl       = fec_enet_ioctl,

#ifdef CONFIG_NET_POLL_CONTROLLER

    .ndo_poll_controller    = fec_poll_controller,

#endif

    .ndo_set_features   = fec_set_features,

};

ethtool_ops:

static const struct ethtool_ops fec_enet_ethtool_ops = {

    .get_drvinfo        = fec_enet_get_drvinfo,

    .get_regs_len       = fec_enet_get_regs_len,

    .get_regs       = fec_enet_get_regs,

    .nway_reset     = phy_ethtool_nway_reset,

    .get_link       = ethtool_op_get_link,

    .get_coalesce       = fec_enet_get_coalesce,

    .set_coalesce       = fec_enet_set_coalesce,

#ifndef CONFIG_M5272

    .get_pauseparam     = fec_enet_get_pauseparam,

    .set_pauseparam     = fec_enet_set_pauseparam,

    .get_strings        = fec_enet_get_strings,

    .get_ethtool_stats  = fec_enet_get_ethtool_stats,

    .get_sset_count     = fec_enet_get_sset_count,

#endif

    .get_ts_info        = fec_enet_get_ts_info,

    .get_tunable        = fec_enet_get_tunable,

    .set_tunable        = fec_enet_set_tunable,

    .get_wol        = fec_enet_get_wol,

    .set_wol        = fec_enet_set_wol,

    .get_link_ksettings = phy_ethtool_get_link_ksettings,

    .set_link_ksettings = phy_ethtool_set_link_ksettings,

};

3.     fec_enet_mii_init 函数

定义在 drivers/net/ethernet/freescale/fec_main.c 中,被 fec_probe 调用。

它主要完成以下动作:

  • 初始化核心数据结构mii_bus(调用 mdiobus_register,初始化 mii_speed、mii_bus->read、mii_bus->write 接口等)
  • 获取设备树“mdio”节点,注册 MDIO bus(of_mdiobus_register,这个函数里注册 MDIO bus和phy 设备)

主要调用流程:

fec_probe -> fec_enet_mii_init -> of_mdiobus_register -> mdiobus_register

-> of_mdio_parse_addr
 
-> of_mdiobus_register_phy


 

4.     mdiobus_register(__mdiobus_register)

位于 drivers/net/phy/mdio_bus.c,被 of_mdiobus_register 调用,没有条件,进入 of_mdiobus_register 即执行。

主要完成:

  • device_register(&bus->dev):注册 mdio bus
  • mdiobus_scan(bus, i):探测时被忽略的 phy 地址将不执行此函数(if ((bus->phy_mask & (1 << i)) != 0))
获取总线上的 phy 设备:(get_phy_device:reads the specified PHY device and returns its @phy_device)

                           get_phy_id -> phy_device_create

创建 phy 设备:(phy_device_register - Register the phy device on the MDIO bus)

                            mdiobus_register_device -> phy_device_reset -> phy_scan_fixups -> device_add

5.     of_mdiobus_register_phy

位于 drivers/of/of_mdio.c,被 of_mdiobus_register 调用,为遍历设备树匹配到的每个 phy 节点执行以下函数

主要完成:

获取 phy id,创建 phy device,功能与 mdiobus_scan 相似。

of_get_phy_id -> phy_device_create (如果 of_get_phy_id 失败则调用 get_phy_device)  -> phy_device_register


在 mac 驱动根据 phy id 匹配到 phy 节点并注册 phy 设备后(phy_device_register),成功把 phy device 注册到 mdiobus 上(device_add),那么 phy_probe(phy 驱动部分) 就会被调用



总结:以上就是 S32V234 bsp23.1 版本的 Mac 驱动详解。

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★博文作者未开放评论功能