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

news2024/11/19 3:27:28

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.coloradmin.cn/o/1863870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3 Cesium 离线地图

1、vite-plugin-cesium 是一个专门为 Vite 构建工具定制的插件&#xff0c;用于在 Vite 项目中轻松使用 Cesium 库。它简化了在 Vite 项目中集成 Cesium 的过程。 npm i cesium vite-plugin-cesium vite -D 2、配置vite.config.js import cesium from vite-plugin-cesiumexp…

生产环境:CentOS 7 Docker 20.10.19离线部署(为离线部署k8s做准备)

背景描述&#xff1a;离线部署Docker环境 在现代IT基础设施中&#xff0c;Docker已经成为应用容器化的标准工具。它简化了应用程序的部署和管理&#xff0c;使开发者和运维工程师能够以更高的效率和一致性进行工作。然而&#xff0c;在某些场景下&#xff0c;由于安全性、网络…

WMS在发展过程中会遇到哪些挑战?

在仓库管理系统&#xff08;Warehouse Management System, WMS&#xff09;的发展过程中&#xff0c;会遇到以下一些挑战&#xff1a; 1、技术整合&#xff1a; 将WMS与现有的ERP&#xff08;企业资源计划&#xff09;、TMS&#xff08;运输管理系统&#xff09;等系统进行有效…

uniapp 小程序 堆叠轮播图 左滑 右滑 自动翻页 点击停止自动翻页

uniapp 小程序 堆叠轮播图 左滑 右滑 自动翻页 点击停止自动翻页 超过指定时间未点击滑动 则继续开始滚动 直接上代码 componentSwiper.vue 需要注意页面切换时清除计时器 <template><view><view class"swiperPanel" touchstart"startMove"…

1.Orange Zero2介绍及刷机启动

Orangepi Zero2 1.Orangepi Zero2简介2.刷机和系统启动 1.Orangepi Zero2简介 为什么学 学习目标依然是Linux系统&#xff0c;平台是ARM架构蜂巢快递柜&#xff0c;配送机器人&#xff0c;这些应用场景用C51,STM32单片机无法实现第三方介入库的局限性&#xff0c;比如刷脸支付…

C++ 教程 - 06 类的封装、继承、多态

文章目录 封装继承多态 封装 在private/protected 模块放置数据或者底层算法实现&#xff1b;在public块提供对外接口&#xff0c;实现相应的功能调用&#xff1b;类的封装案例 #include <iostream> using namespace std;// 类的定义 一般放在头文件 class Stu {public…

STM32中五个时钟源:HSI、HSE、LSI、LSE、PLL

时钟系统是处理器的核心&#xff0c;或者说时钟是单片机的心脏。 1.单片机内部需要储存器、累加器&#xff0c;这些都需要逻辑门电路。比如锁存器就是一个D触发器&#xff0c;而触发器的置1、清0、置数的功能都需要跳变沿。D触发器就是上升沿后存入数据&#xff0c;而这个上升…

Linux 安装ElasticSearch + FSCrawler 扫描本地的文件资源

文章目录 0. 前言1. 安装ElasticSearch1.1 下载安装包1.2 新增用户1.3 解压安装包1.4 更改文件夹用户1.5 修改配置文件1.6 修改系统配置1.7 启动集群 2. 安装FSCrawler2.1 下载安装包2.2 创建配置文件2.3 修改配置文件2.4 启动2.5 验证是否被索引 0. 前言 Elasticsearch 是一个…

职业本科院校电子信息类专业教学解决方案

引言 随着信息技术的飞速进步和全球经济的深度融合&#xff0c;电子信息领域已成为推动社会发展的核心动力。职业本科教育作为培养高素质技能型人才的主阵地&#xff0c;面临着前所未有的挑战与机遇。特别是在电子信息类专业领域&#xff0c;如何培养出既掌握前沿理论知识&…

mac配置修改host文件

1command 空格 输入 terminal 选中回车进入终端控制台. command 空格 2 sudo vi /etc/hosts 输入密码,进入vi编辑器修改文件 sudo vi /etc/hosts3修改内容,:wq保存退出,重启项目即可 :wq

2025中国(宁波)出口跨境电商博览会

2025中国(宁波)出口跨境电商博览会 时间&#xff1a;2025年5月28-30日 地点&#xff1a;中国宁波国际会展中心 组织单位&#xff1a; 宁波欧德国际商务咨询服务有限公司 凤麟展览(宁波)有限公司 宁波市跨境电子商务协会 宁波市家居产业协会 详询主办方陆先生 I38&…

day21--669. 修剪二叉搜索树 +108.将有序数组转换为二叉搜索树+538.把二叉搜索树转换为累加树

一、669. 修剪二叉搜索树 题目链接&#xff1a;https://leetcode.cn/problems/trim-a-binary-search-tree/ 文章讲解&#xff1a;https://programmercarl.com/0669.%E4%BF%AE%E5%89%AA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html 视频讲解&#xff1a;https://www.bi…

二、大模型原理(Transformer )

Transformer是一种基于自注意力机制&#xff08;Self-Attention Mechanism&#xff09;的深度学习模型&#xff0c;它在2017年由Vaswani等人在论文《Attention Is All You Need》中提出。Transformer模型的出现极大地推动了自然语言处理&#xff08;NLP&#xff09;领域的发展&…

零知识学习之DPDK与RDMA(1)—— 认识DPDK(1)

接前一篇文章&#xff1a;零知识学习之DPDK与RDMA&#xff08;1&#xff09;—— 序言与初识 本文内容参考&#xff1a; 《Linux高性能网络详解 从DPDK、RDMA到XDP》 刘伟著 人民邮电出版社 DPDK首页、文档和下载 - 网络数据包转发处理 - OSCHINA - 中文开源技术交流社区 五…

【源码+文档+调试讲解】灾害应急救援平台

摘 要 灾害应急救援平台的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&…

小程序下拉刷新,加载更多数据,移动端分页

文章目录 页面结构图WXML页面代码js代码wxss代码总结备注 参考&#xff1a;https://juejin.cn/post/7222855604406796346 页面结构图 一般页面就4个结构&#xff1a;最外滚动层、数据展示层、暂无数据层、没有更多数据层。 如图&#xff1a; WXML页面代码 <scroll-view …

Zynq7000系列FPGA中的中断

本文介绍Zynq7000系列FPGA中的系统级中断环境和中断控制器的功能&#xff08;见图7-1&#xff09;。 专用、共享和软件中断 每个CPU都有一组专用外围中断&#xff08;PPI&#xff0c;private peripheral interrupts&#xff09;&#xff0c;使用banked 寄存器可以对这些中断进…

2024年生物技术与食品科学国际会议(ICBFS 2024)

2024 International Conference on Biotechnology and Food Science 2024年生物技术与食品科学国际会议 【会议信息】 会议简称&#xff1a;ICBFS 2024 大会地点&#xff1a;中国厦门 会议邮箱&#xff1a;icbfssub-paper.com 审稿结果&#xff1a;投稿后3日左右 提交检索&…

AI视频教程下载-ChatGPT 生产力 + 时间管理

ChatGPT Productivity Time Management. ChatGPT Productivity ChatGPT 显著提升生产力 不寻常的时间管理技巧。ChatGPT 工作&#xff0c;Chat GPT 自动化&#xff0c;ChatGPT 2023&#xff01; 对关于ChatGPT的讨论感到好奇&#xff0c;想知道如何利用它为自己带来好处吗&a…

VTable导出当前页和导出所有页数据

表格导出的是当前显示的表格&#xff0c;如果是分页表格想导出全部的数据话。有两种方法可以实现 表格先显示的全量数据&#xff0c;导出后再恢复当前页。新建一个隐藏的表格实例显示全量数据导出这个隐藏的表格实例。 下面是全量代码&#xff1a; <template><div&…