三 Linux 网络驱动-MAC、PHY层驱动框架( 九 )


1 static irqreturn_t fec_enet_interrupt(int irq, void *dev_id)2 {3struct net_device *ndev = dev_id;4struct fec_enet_private *fep = netdev_priv(ndev);5uint int_events;6irqreturn_t ret = IRQ_NONE;7 8int_events = readl(fep->hwp + FEC_IEVENT);9writel(int_events, fep->hwp + FEC_IEVENT);10fec_enet_collect_events(fep, int_events);1112if ((fep->work_tx || fep->work_rx) && fep->link) {13ret = IRQ_HANDLED;1415if (napi_schedule_prep(&fep->napi)) {16/* Disable the NAPI interrupts */17writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);18__napi_schedule(&fep->napi);19}20}2122if (int_events & FEC_ENET_MII) {23ret = IRQ_HANDLED;24complete(&fep->mdio_done);25}2627if (fep->ptp_clock)28fec_ptp_check_pps_event(fep);2930return ret;31 }
可以看出中断服务函数非常短!而且也没有见到有关数据接收的处理过程 , 那是因为 I. 的网络驱动使用了 NAPI , 具体的网络数据收发是在 NAPI 的 poll 函数中完成的 , 中断里面只需要进行 napi 调度即可 , 这个就是中断的上半部和下半部处理机制 。
第 8 行 , 读取 NENT 的中断状态寄存器 EIR , 获取中断状态.
第 9 行 , 将第 8 行获取到的中断状态值又写入 EIR 寄存器 , 用于清除中断状态寄存器 。
第 10 行 , 调用 nts 函数统计中断信息 , 也就是统计都发生了哪些中断 。fep 中成员变量和的 bit0、bit1 和 bit2 用来做不同的标记 ,  的 bit2 表 示接收到数据帧 ,  的 bit2 表示发送完数据帧 。
第 15 行 , 调用函数检查 NAPI 是否可以进行调度 。
第 17 行 , 如果使能了相关中断就要先关闭这些中断 , 向 EIMR 寄存器的 bit23 写 1 即可关 闭相关中断 。

三  Linux 网络驱动-MAC、PHY层驱动框架

文章插图
第 18 行 , 调用 函数来启动 NAPI 调度 , 这个时候 napi 的 poll 函数就会执 行 , 在本网络驱动中就是函数.
中断服务函数简析
函数初始化网络的时候会调用来设置 NAPI 的 poll 函数为  , 函数内容如下:
【三Linux 网络驱动-MAC、PHY层驱动框架】1 static int fec_enet_rx_napi(struct napi_struct *napi, int budget)2 {3struct net_device *ndev = napi->dev;4struct fec_enet_private *fep = netdev_priv(ndev);5int pkts;6 7pkts = fec_enet_rx(ndev, budget);8 9fec_enet_tx(ndev);1011if (pkts < budget) {12napi_complete(napi);13writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);14}15return pkts;16 }
第 7 行 , 调用函数进行真正的数据接收 。
第 9 行 , 调用函数进行数据发送 。
第 12 行 , 调用函数来宣布一次轮询结束 。
第 13 行 , 设置 ENET 的 EIMR 寄存器 , 重新使能中断 。
Linux 内核 PHY 子系统与 MDIO 总线简析
上一小节在讲解 MDIO 总线的时候讲过 , 注册 MDIO 总线的时候也会向内核注册 PHY 设 备 , 本节我们就来简单了解一下 PHY 子系统 。PHY 子系统就是用于 PHY 设备相关内容的 , 分 为 PHY 设备和 PHY 驱动 , 和总线一样 , PHY 子系统也是一个设备、总线和驱动模型 。
1、PHY 设备
首先看一下 PHY 设备 , Linux 内核使用结构体来表示 PHY 设备 , 结构体定义 在 /linux/phy.h , 结构体内容如下:
1 struct phy_device {2/* Information about the PHY type */3/* And management functions */4struct phy_driver *drv; /* PHY 设备驱动 */5struct mii_bus *bus; /* 对应的 MII 总线 */6struct device dev; /* 设备文件 */7u32 phy_id; /* PHY ID */8 9struct phy_c45_device_ids c45_ids;10bool is_c45; 11bool is_internal;12bool has_fixups;13bool suspended;1415enum phy_state state; /* PHY 状态 */16u32 dev_flags;17phy_interface_t interface; /* PHY 接口 */1819/* Bus address of the PHY (0-31) */20int addr; /* PHY 地址(0~31) */2122/*23* forced speed & duplex (no autoneg)24* partner speed & duplex & pause (autoneg)25*/26int speed; /* 速度 */27int duplex; /* 双共模式 */28int pause; 29int asym_pause;3031/* The most recently read link state */32int link;3334/* Enabled Interrupts */35u32 interrupts; /* 中断使能标志 */3637/* Union of PHY and Attached devices' supported modes */38/* See mii.h for more info */39u32 supported;40u32 advertising;41u32 lp_advertising;42int autoneg;43int link_timeout;4445/*46* Interrupt number for this PHY47* -1 means no interrupt48*/49int irq; /* 中断号 */5051/* private data pointer */52/* For use by PHYs to maintain extra state */53void *priv; /* 私有数据 */5455/* Interrupt and Polling infrastructure */56struct work_struct phy_queue;57struct delayed_work state_queue;58atomic_t irq_disable;59struct mutex lock;60struct net_device *attached_dev; /* PHY 芯片对应的网络设备 */61void (*adjust_link)(struct net_device *dev);62 };