Linux学习第52天:Linux网络驱动实验(三):一往(网)情深

Linux版本号4.1.15   芯片I.MX6ULL                                 大叔学Linux    品人间百味  思文短情长


        许久没有更新,的确是最近有点懈怠了。没有任何借口,接受所有的批评。接下来无论如何也要坚持下去,不管处于什么境地、什么原因,没有任何借口。一时的中断可能都要重新开始学,教训啊。万里长征也算走过了八千里路,接下来一鼓作气,每天一更。

        先来一张本章的思维导图:

3.fec_netdev_ops操作集

        fec_probe 函数设置了网卡驱动的 net_dev_ops 操作集为 fec_netdev_ops,如下:

1 static const struct net_device_ops fec_netdev_ops = {
2 .ndo_open = fec_enet_open,
3 .ndo_stop = fec_enet_close,
4 .ndo_start_xmit = fec_enet_start_xmit,
5 .ndo_select_queue = fec_enet_select_queue,
6 .ndo_set_rx_mode = set_multicast_list,
7 .ndo_change_mtu = eth_change_mtu,
8 .ndo_validate_addr = eth_validate_addr,
9 .ndo_tx_timeout = fec_timeout,
10 .ndo_set_mac_address = fec_set_mac_address,
11 .ndo_do_ioctl = fec_enet_ioctl,
12 #ifdef CONFIG_NET_POLL_CONTROLLER
13 .ndo_poll_controller = fec_poll_controller,
14 #endif

        1)打开一个网卡的时候 fec_enet_open 函数就会执行

ret = fec_enet_clk_enable(ndev, true);//调用 fec_enet_clk_enable 函数使能 enet 时钟。
ret = fec_enet_alloc_buffers(ndev);/*调用 fec_enet_alloc_buffers 函数申请环形缓冲区 buffer,此函数里面会调用
fec_enet_alloc_rxq_buffers 和 fec_enet_alloc_txq_buffers 这两个函数分别实现发送队列和接收队
列缓冲区的申请。*/
fec_restart(ndev);/*重启网络,一般连接状态改变、传输超时或者配置网络的时候都会调用 fec_restart
函数。*/
ret = fec_enet_mii_probe(ndev);/*  重启网络,一般连接状态改变、传输超时或者配置网络的时候都会调用 fec_restart
函数。*/
29 napi_enable(&fep->napi);//调用 napi_enable 函数使能 NAPI 调度
30 phy_start(fep->phy_dev);//调用 phy_start 函数开启 PHY 设备。
31 netif_tx_start_all_queues(ndev);//调用 netif_tx_start_all_queues 函数来激活发送队列。

        2)关闭网卡的时候 fec_enet_close 函数就会执行

phy_stop(fep->phy_dev);//调用 phy_stop 函数停止 PHY 设备。
napi_disable(&fep->napi);//调用 napi_disable 函数关闭 NAPI 调度。
netif_tx_disable(ndev);//调用 netif_tx_disable 函数关闭 NAPI 的发送队列。
1fec_stop(ndev);//调用 fec_stop 函数关闭 I.MX6ULL 的 ENET 外设。
phy_disconnect(fep->phy_dev);//调用 phy_disconnect 函数断开与 PHY 设备的连接。
fec_enet_clk_enable(ndev, false);//调用 fec_enet_clk_enable 函数关闭 ENET 外设时钟。
fec_enet_free_buffers(ndev);//调用 fec_enet_free_buffers 函数释放发送和接收的环形缓冲区内存。

        3)I.MX6ULL 的网络数据发送是通过 fec_enet_start_xmit 函数来完成的,这个函数将上层传递过来的 sk_buff 中的数据通过硬件发送出去.

static netdev_tx_t fec_enet_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
/* 
skb 就是上层应用传递下来的要发送的网络数据
ndev 就是要发送数据的设备
*/
if (skb_is_gso(skb))/* 判断 skb 是否为 GSO(Generic Segmentation Offload),如果是 GSO 的话就通过fec_enet_txq_submit_tso 函数发送,如果不是的话就通过 fec_enet_txq_submit_skb 发送。*/
ret = fec_enet_txq_submit_tso(txq, skb, ndev);
else
ret = fec_enet_txq_submit_skb(txq, skb, ndev);
if (ret)
return ret;


entries_free = fec_enet_get_free_txdesc_num(fep, txq);//获取剩余的发送描述符数量
if (entries_free <= txq->tx_stop_threshold)
netif_tx_stop_queue(nq);/*如果剩余的发送描述符的数量小于设置的阈值(tx_stop_threshold)的话就调用函数netif_tx_stop_queue 来暂停发送,通过暂停发送来通知应用层停止向网络发送 skb,发送中断中
会重新开启的。 */

        4)中断服务函数为 fec_enet_interrupt
 

int_events = readl(fep->hwp + FEC_IEVENT);//读取 NENT 的中断状态寄存器 EIR,获取中断状态,
writel(int_events, fep->hwp + FEC_IEVENT);//清除中断状态寄存器。
fec_enet_collect_events(fep, int_events);//统计都发生了哪些中断
if (napi_schedule_prep(&fep->napi)) {//调用 napi_schedule_prep 函数检查 NAPI 是否可以进行调度
/* Disable the NAPI interrupts */
writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);/*如果使能了相关中断就要先关闭这些中断,向 EIMR 寄存器的 bit23 写 1 即可关闭相关中断。*/
__napi_schedule(&fep->napi);/*调用__napi_schedule 函数来启动 NAPI 调度,这个时候 napi 的 poll 函数就会执行,在本网络驱动中就是 fec_enet_rx_napi 函数。*/
 }

        具体的网络数据收发是在 NAPI 的 poll 函数中完成的.


        5)fec_enet_interrupt 中断服务函数

        fec_enet_init 函数初始化网络的时候会调用 netif_napi_add 来设置 NAPI 的 poll 函数为
fec_enet_rx_napi。

1 static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
2 {
3 struct net_device *ndev = napi->dev;
4 struct fec_enet_private *fep = netdev_priv(ndev);
5 int pkts;
6 
7 pkts = fec_enet_rx(ndev, budget);//调用 fec_enet_rx 函数进行真正的数据接收。
8 
9 fec_enet_tx(ndev);//调用 fec_enet_tx 函数进行数据发送。
10
11 if (pkts < budget) {
12 napi_complete(napi);//调用 napi_complete 函数来宣布一次轮询结束,
13 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);//设置 ENET 的 EIMR 寄存器,重新使能中断。
14 }
15 return pkts;
16 }

4.Linux内核PHY子系统与MDIO总线简析

1)PHY 设备

        使用 phy_device 结构体来表示 PHY 设备,结构体定义如下:

1 struct phy_device {
2 /* Information about the PHY type */
3 /* And management functions */
4 struct phy_driver *drv; /* PHY 设备驱动 */
5 struct mii_bus *bus; /* 对应的 MII 总线 */
6 struct device dev; /* 设备文件 */
7 u32 phy_id; /* PHY ID */
8 9
struct phy_c45_device_ids c45_ids;
10 bool is_c45;
11 bool is_internal;
12 bool has_fixups;
13 bool suspended;
14
15 enum phy_state state; /* PHY 状态 */
16 u32 dev_flags;
17 phy_interface_t interface; /* PHY 接口 */
18
19 /* Bus address of the PHY (0-31) */
20 int addr; /* PHY 地址(0~31) */
21
22 /*
23 * forced speed & duplex (no autoneg)
24 * partner speed & duplex & pause (autoneg)
25 */
26 int speed; /* 速度 */
27 int duplex; /* 双共模式 */
28 int pause;
29 int asym_pause;
30
31 /* The most recently read link state */
32 int link;
33
34 /* Enabled Interrupts */
35 u32 interrupts; /* 中断使能标志 */
36
37 /* Union of PHY and Attached devices' supported modes */
38 /* See mii.h for more info */
39 u32 supported;
40 u32 advertising;
41 u32 lp_advertising;
42 int autoneg;
43 int link_timeout;
44
45 /*
46 * Interrupt number for this PHY
47 * -1 means no interrupt
48 */
49 int irq; /* 中断号 */
50
51 /* private data pointer */
52 /* For use by PHYs to maintain extra state */
53 void *priv; /* 私有数据 */
54
55 /* Interrupt and Polling infrastructure */
56 struct work_struct phy_queue;
57 struct delayed_work state_queue;
58 atomic_t irq_disable;
59 struct mutex lock;
60 struct net_device *attached_dev; /* PHY 芯片对应的网络设备 */
61 void (*adjust_link)(struct net_device *dev);
62 };

一个 PHY 设备对应一个 phy_device 实例,然后需要向 Linux 内核注册这个实例。使用
phy_device_register 函数完成 PHY 设备的注册:

int phy_device_register(struct phy_device *phy)//phy: 需要注册的 PHY 设备。

PHY 设备的注册过程一般是先调用 get_phy_device 函数获取 PHY 设备.
 

1 struct phy_device *get_phy_device(struct mii_bus *bus, int addr,
bool is_c45)
2 {
3 struct phy_c45_device_ids c45_ids = {0};
4 u32 phy_id = 0;
5 int r;
6
7 r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);/*调用 get_phy_id 函数获取 PHY ID,也就是读取 PHY 芯片的那两个 ID 寄存器,得到 PHY 芯片 ID 信息。*/
8 if (r)
9 return ERR_PTR(r);
10
11 /* If the phy_id is mostly Fs, there is no device there */
12 if ((phy_id & 0x1fffffff) == 0x1fffffff)
13 return NULL;
14
15 return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);/*调用 phy_device_create 函数创建 phy_device,此函数先申请 phy_device 内存,然后初始化 phy_device 的各个结构体成员,最终返回创建好的 phy_device。 phy_device_register 函数注册的就是这个创建好的 phy_device。*/
16 }

2)PHY驱动

        PHY 驱动使用结构体 phy_driver 表示.

①、注册 PHY 驱动 --- phy_driver_register 函数

        注册phy驱动的时候会设置驱动的总线为mdio_bus_type,也就是MDIO总线.

int phy_driver_register(struct phy_driver *new_driver)

②、连续注册多个 PHY 驱动 --- phy_drivers_register

int phy_drivers_register(struct phy_driver *new_driver, int n)

③、卸载 PHY 驱动

void phy_driver_unregister(struct phy_driver *drv)

3)MDIO 总线

         设备和驱动就是 phy_device 和phy_driver。总线就是 MDIO 总线

        MDIO 总线最主要的工作就是匹配 PHY 设备和 PHY 驱动。

if (phydrv->match_phy_device)
    return phydrv->match_phy_device(phydev);
/*
检查 PHY 驱动有没有提供匹配函数 match_phy_device,如果有的话就直接调
用 PHY 驱动提供的匹配函数完成与设备的匹配。
*/

        对比 PHY 驱动和 PHY 设备中的 phy_id 是否一致,这里需要与PHY 驱动里面的 phy_id_mask 进行与运算,如果结果一致的话就说明驱动和设备匹配。


 4)通用 PHY 驱动 --- Generic PHY

rc = phy_drivers_register(genphy_driver,
ARRAY_SIZE(genphy_driver));

5)LAN8720A 驱动

        配置路径如下:

-> Device Drivers
        -> Network device support
                -> PHY Device support and infrastructure
                        -> Drivers for SMSC PHYs

93 }, {
94 .phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
95 .phy_id_mask = 0xfffffff0,
96 .name = "SMSC LAN8710/LAN8720",
97
98 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
99 | SUPPORTED_Asym_Pause),
100 .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
101
102 /* basic functions */
103 .config_aneg = genphy_config_aneg,
104 .read_status = lan87xx_read_status,
105 .config_init = smsc_phy_config_init,
106 .soft_reset = smsc_phy_reset,
107
108 /* IRQ related */
109 .ack_interrupt = smsc_phy_ack_interrupt,
110 .config_intr = smsc_phy_config_intr,
111
112 .suspend = genphy_suspend,
113 .resume = genphy_resume,
114
115 .driver = { .owner = THIS_MODULE, }
116 } };

五、网络驱动实验测试

1.LAN8720 PHY驱动测试

2.通用PHY驱动测试

3.DHCP功能配置

        udhcpc 命令
        在 busybox 源码中找到 examples/udhcp/simple.script,将其拷贝到开发板/usr/share/udhcpc 目录下(如果没有的话请自行创建此目录),拷贝完成以后将根文件系统下的 simple.script 并且重命名为 default.script,命令如下:
cd busybox-1.29.0/examples/udhcp
cp simple.script /home/zuozhongkai/linux/nfs/rootfs/usr/share/udhcpc/default.script //拷贝并重
命名

六、单网卡使用

1.只使用ENET2网卡

1)屏蔽或删除掉 fec2 节点内容

        首先找到 fec1 节点,然后将其中的 status 属性改为“disabled”即可。

1 &fec1 {
2 pinctrl-names = "default";
3 pinctrl-0 = <&pinctrl_enet1
4 &pinctrl_enet1_reset>;
5 phy-mode = "rmii";
6 phy-handle = <&ethphy0>;
7 phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
8 phy-reset-duration = <200>;
9 status = "disabled";
10 };

2)修改 ENET1 对应的 fec1 节点信息。

11 mdio {
12 #address-cells = <1>;
13 #size-cells = <0>;
14
15 ethphy0: ethernet-phy@0 {
16 compatible = "ethernet-phy-ieee802.3-c22";
17 reg = <0>;
18 };

 3)屏蔽或删除掉 ENET2 对应的 pinctrl 节点

4)在 ENET1 网卡对应的 pinctrl 节点中添加 MDIO 和 MDC 引脚配置

MX6UL_PAD_GPIO1_IO07__ENET1_MDC 0x1b0b0
MX6UL_PAD_GPIO1_IO06__ENET1_MDIO 0x1b0b0

2.只使用ENET1网卡

总结:

关于 Linux 的网络驱动,整体比较复杂,但是实际使用起来确实非常简单的,尤其是对这种内置 MAC+外置 PHY 的网络方案而言,几乎不需要我们修改驱动,因为内核已经继承了通用 PHY 驱动了。
 


本笔记为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/745351.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.NET C# 使用GDAL将mdb转换gdb数据

.NET C# 使用GDAL将mdb转换gdb数据 目录 .NET C# 使用GDAL将mdb转换gdb数据1 环境2 Nuget3 Code 1 环境 VisualStudio2022 .NET6 GDAL 3.8.5 2 Nuget 3 Code FeatureExtension.cs public static class FeatureExtension {[DllImport("gdal.dll", EntryPoint &…

前端-echarts tooltip展示多项自定义数据

效果如图&#xff0c;鼠标滑动到某一个柱子的时候&#xff0c;出现这一项数据的多个自定义数据&#xff0c;外加自己的模板样式渲染。 希望能展示每一列中的多个自定义数据 代码部分 主要是在data中&#xff0c;value就是实际展示的主数据&#xff0c;其他字段名为自定义的数…

Matlab进阶绘图第61期—滑珠散点图

滑珠散点图也是一种在《Nature》中常见的数据图。 其功能类似于柱状图&#xff0c;但更加简洁易读。 由于Matlab中没有现成的函数绘制滑珠散点图&#xff0c;因此需要大家自行解决。 本文利用自己制作的BubbleScatter工具&#xff0c;进行滑珠散点图的绘制&#xff0c;先来看…

等保测评初级简答题试题

基本要求&#xff0c;在应用安全层面的访问控制要求中&#xff0c;三级系统较二级系统增加的措施有哪些&#xff1f; 答&#xff1a;三级比二级增加的要求项有&#xff1a; 应提供对重要信息资源设置敏感标记的功能&#xff1b; 应按照安全策略严格控制用户对有敏感标记重要…

贝壳找房基于Flink+Paimon进行全量数据实时分组排序的实践

摘要&#xff1a;本文投稿自贝壳家装数仓团队&#xff0c;在结合家装业务场景下所探索出的一种基于 FlinkPaimon 的排序方案。这种方案可以在实时环境对全量数据进行准确的分组排序&#xff0c;同时减少对内存资源的消耗。在这一方案中&#xff0c;引入了“事件时间分段”的概念…

上涨至13.6分!当之无愧的顶级期刊,影响因子“狂飙”,门槛较低,2个月可录!

本期解析 1、2024年6月20日&#xff0c;科睿唯安正式公布2024年度《期刊引证报告》。 2、本次主要解析Elsevier旗下一本TOP顶刊&#xff0c;期刊表现优秀&#xff0c;在最新的影响因子更新中由12.8上涨至13.6&#xff0c;是一本妥妥评职高分宝刊&#xff01;接下来看看它是否…

Stable Diffusion【真人模型】:人像光影摄影极限写实真实感大模型

大家好&#xff0c;我是极客菌 今天和大家分享一个基于SD1.5的真人大模型&#xff1a;人像光影摄影极限写实真实感大模型。 该模型具有以下特点&#xff1a; 真实肤感&#xff08;在面部肌理和皮肤肌理上均有加强学习&#xff0c;拒绝ai出图假的问题&#xff09; 永不脱妆&a…

经典老动画电影大全,老动画片大全集全部百度网盘,资源下载百度云

当今社会越来越重视学前教育了&#xff0c;今儿童启蒙的教育也越来越受人们的关注和重视。为了满足社会对未来人才的需要&#xff0c;学前教育成为当今教育领域重要角色的一环。当今动画篇是主流&#xff0c;内容精彩纷呈&#xff0c;越来越受到儿童的喜爱。 儿童的语言敏感期&…

ee trade:黄金投资是选择短线交易还是长线投资

黄金投资既可以通过短线交易获取快速收益&#xff0c;也可以采取长线投资策略获得稳健回报。本文将详细比较这两种策略的特点和适用性&#xff0c;为新手投资者提供参考。 短线交易 短线交易指在较短的时间内多次买卖以获取利润&#xff0c;通常交易周期为数日到数周。以下是…

PointCloudLib-KDtree-如何使用 KdTree 进行搜索

在本教程中,我们将介绍如何使用 KdTree 查找特定点或位置的 K 个最近邻,然后我们还将介绍如何查找用户指定的某个半径内的所有邻居(在本例中为随机)。 理论入门 k-d 树或 k 维树是计算机科学中使用的一种数据结构,用于在具有 k 维的空间中组织一定数量的点。它是一个二叉…

用热传感器提高散热片的效率

每天一篇行业发展资讯&#xff0c;让大家更及时了解外面的世界。 更多资讯&#xff0c;请关注B站/公众号【莱歌数字】&#xff0c;有视频教程~~ 散热器的尺寸通常是根据功率、气流、设备热约束和物理几何形状的要求进行冷却应用的。 更大的功耗需要更高性能的散热器或更大、…

记录一个Xshell使用中Xmanager...X11转发的提示问题

希望文章能给到你启发和灵感&#xff5e; 如果觉得有帮助的话&#xff0c;点赞关注收藏支持一下博主哦&#xff5e; 阅读指南 一、环境说明1.1 硬件环境1.2 软件环境 二、问题和错误三、解决四、理解和延伸一下 一、环境说明 考虑环境因素&#xff0c;大家适当的对比自己的软硬…

DBdoctor功能介绍

绍DBdoctor的主要功能&#xff0c;按照事件先后涵盖了事前、事中、事后三个阶段。事前的主动问题发现、SQL性能评估、自动巡检与报表、空间预测与诊断&#xff1b;事中的性能洞察、根因诊断、锁分析、优化建议&#xff1b;事后的审计分析、根因推导、问题快照。按照使用者包含了…

手持小风扇品牌有哪些?分享口碑最好的五款手持小风扇

手持小风扇在炎热的夏季成为了许多人解暑的好帮手。它们不仅轻便便携&#xff0c;随时随地都能为我们带来清凉和舒适。然而&#xff0c;市场上手持小风扇的品牌繁多&#xff0c;让人眼花缭乱。为了帮助大家做出更明智的选择&#xff0c;接下来我们将分享口碑最好的五款手持小风…

RAG | (ACL24规划-检索增强)PlanRAG:一种用于生成大型语言模型作为决策者的规划检索增强生成方法

原文&#xff1a;PlanRAG: A Plan-then-Retrieval Augmented Generation for Generative Large Language Models as Decision Makers 地址&#xff1a;https://arxiv.org/abs/2406.12430 代码&#xff1a;https://github.com/myeon9h/PlanRAG 出版&#xff1a;ACL 24 机构: 韩国…

MQTT自动回复消息工具

点击下载《MQTT自动回复消息工具V1.0.0》 1. 前言 在进行IoT系统开发时&#xff0c;各个小组成员通常是同步进行项目开发&#xff0c;经常会遇到设备端和前后端开发人员开发进度不协调的情况&#xff0c;此时接口还没开发完&#xff0c;也没有可以调试的环境&#xff0c;只能…

Vue - HTML基础学习

一、元素及属性 1.元素 <p>我是一级标题</p>2.嵌套元素 把元素放到其他元素之中——这被称作嵌套。 <p>我是<strong>一级</strong>标题</p>3.块级元素 块级元素在页面中以块的形式展现&#xff0c;会换行&#xff0c;可嵌套内联元素。 …

RAID详解及配置实战

目录 一、RAID磁盘阵列及详解 1.1 了解RAID 1.1.1 简单理解 1.1.2 对比了解 1.2 RAID磁盘阵列介绍 1.3 RAID功能实现 1.4 RAID实现的方式 1.5 RAID级别详解 1.5.1 RAID -0 1.5.2 RAID -1 1.5.3 RAID -5 1.5.4 RAID -10&#xff08;RAID 10&#xff09; 1.6 阵列卡…

基于Java微信小程序校园自助打印系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

《Windows API每日一练》6.2 客户区鼠标消息

第五章已经讲到&#xff0c;Windows只会把键盘消息发送到当前具有输入焦点的窗口。鼠标消息则不同&#xff1a;当鼠标经过窗口或在窗口内被单击&#xff0c;则即使该窗口是非活动窗口或不带输入焦点&#xff0c; 窗口过程还是会收到鼠标消息。Windows定义了 21种鼠标消息。不过…