IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux网络设备驱动框架 -> 正文阅读

[系统运维]Linux网络设备驱动框架

**

一、基本概念

**

网络设备硬件是由 mac 和phy 两部分组成。

1、我们一般说某个 SOC 支持网络,说的就是他内部集成网络 MAC 外设,此时我们还需要外接一个网络 PHY 芯片。
一般常见的通用 SOC 都会集成网络 MAC 外设,比如 STM32F4/F7/H7 系列、 NXP 的 I.MX系列,内部集成网络 MAC 的优点如下:

  • 内部 MAC 外设会有专用的加速模块,比如专用的 DMA,加速网速数据的处理。
  • 网速快,可以支持 10/100/1000M 网速。
  • 外接 PHY 可选择性多,成本低。

2、内部的 MAC 外设会通过 MII 或者 RMII 接口来连接外部的 PHY 芯片, MII/RMII 接口用来传输网络数据。
另外主控需要配置或读取 PHY 芯片,也就是读写 PHY 的内部寄存器,所以还需要一个控制接口,叫做 MDIO, MDIO 很类似 IIC,也是两根线,一根数据线叫做 MDIO,一根时钟线叫做 MDC。

SOC 内部 MAC 外设与外部 PHY 芯片的连接如图 69.1.1.2 所示:
MII/RMII 用于传输数据,MDIO 用于读写phy内部寄存器,控制phy芯片。

在这里插入图片描述

3、MDIO 接口
MDIO 全称是 Management Data Input/Output,直译过来就是管理数据输入输出接口,是一个简单的两线串行接口,一根 MDIO 数据线,一根 MDC 时钟线。
驱动程序可以通过 MDIO 和MDC 这两根线访问 PHY 芯片的任意一个寄存器。 MDIO 接口支持多达 32 个 PHY。同一时刻内只能对一个 PHY 进行操作,那么如何区分这 32 个 PHY 芯片呢?和 IIC 一样,使用器件地址即可。同一 MDIO 接口下的所有 PHY 芯片,其器件地址不能冲突,必须保证唯一,具体器件地址值要查阅相应的 PHY 数据手册。(通常可以使用硬件来决定phy地址)

4、RJ45 接口
网络设备是通过网线连接起来的,插入网线的叫做 RJ45 座.
RJ45 座要与 PHY 芯片连接在一起,但是中间需要一个网络变压器,网络编译器用于隔离以及滤波等,网络变压器也是一个芯片,外形一般如图 69.1.4.2 所示:
在这里插入图片描述
完整的网络接口硬件:
在这里插入图片描述
5、Linux网络子系统

在这里插入图片描述

我们这里研究内核空间即可,在内核空间分成5层,分别是:

  • 1、系统调用接口,它面向的客户是应用层序,为应用程序提供访问网络子系统的统一方法,比如说socket,send等函数的系统调用
  • 2、协议无关接口,它提供通用的方法来使用传输层协议,把所有的协议统一起来
  • 3、网络协议,它的作用就是实现具体的网络协议
  • 4、设备无关接口,这个接口是为了屏蔽底层硬件的差异
  • 5、设备驱动,这里实现具体的网卡驱动

**

二、网络设备驱动框架

**

1、Linux 内核用一个 net_device 结构体来描述一个网络设备。

网络驱动的核心就是初始化 net_device 结构体中的各个成员变量,然后将初始化完成以后的 net_device 注册到 Linux 内核中。
net_device 结构体定义在 include/linux/netdevice.h 中,net_device 是一个庞大的结构体,内容如下(有缩减):

示例代码 69.3.1.1 net_device 结构体
1 struct net_device {
2 char name[IFNAMSIZ];
3 struct hlist_node name_hlist;
4 char *ifalias;
5 /*
6 * I/O specific fields
7 * FIXME: Merge these and struct ifmap into one
8 */
9 unsigned long mem_end;
10 unsigned long mem_start;
11 unsigned long base_addr;
12 int irq;
13
14 atomic_t carrier_changes;
15
16 /*
17 * Some hardware also needs these fields (state,dev_list,
18 * napi_list,unreg_list,close_list) but they are not
19 * part of the usual set specified in Space.c.
20 */
21
22 unsigned long state;
23
24 struct list_head dev_list;
25 struct list_head napi_list;
26 struct list_head unreg_list;
27 struct list_head close_list;
......
60 const struct net_device_ops *netdev_ops;
61 const struct ethtool_ops *ethtool_ops;
62 #ifdef CONFIG_NET_SWITCHDEV
63 const struct swdev_ops *swdev_ops;
64 #endif
65
66 const struct header_ops *header_ops;
67
68 unsigned int flags;
......
77 unsigned char if_port;
78 unsigned char dma;
79
80 unsigned int mtu;
81 unsigned short type;
82 unsigned short hard_header_len;
83
84 unsigned short needed_headroom;
85 unsigned short needed_tailroom;
86
87 /* Interface address info. */
88 unsigned char perm_addr[MAX_ADDR_LEN];
89 unsigned char addr_assign_type;
90 unsigned char addr_len;
......
130 /*
131 * Cache lines mostly used on receive path (including
eth_type_trans())
132 */
133 unsigned long last_rx;
134
135 /* Interface address info used in eth_type_trans() */
136 unsigned char *dev_addr;
137
138
139 #ifdef CONFIG_SYSFS
140 struct netdev_rx_queue *_rx;
141
142 unsigned int num_rx_queues;
143 unsigned int real_num_rx_queues;
144
145 #endif
......
158 /*
159 * Cache lines mostly used on transmit path
160 */
161 struct netdev_queue *_tx ____cacheline_aligned_in_smp;
162 unsigned int num_tx_queues;
163 unsigned int real_num_tx_queues;
164 struct Qdisc *qdisc;
165 unsigned long tx_queue_len;
166 spinlock_t tx_global_lock;
167 int watchdog_timeo;
......
173 /* These may be needed for future network-power-down code. */
174
175 /*
176 * trans_start here is expensive for high speed devices on SMP,
177 * please use netdev_queue->trans_start instead.
178 */
179 unsigned long trans_start;
......
248 struct phy_device *phydev;
249 struct lock_class_key *qdisc_tx_busylock;
250 };

下面介绍一些关键的成员变量,如下:
第 2 行: name 是网络设备的名字。
第 9 行: mem_end 是共享内存结束地址。
第 10 行: mem_start 是共享内存起始地址。
第 11 行: base_addr 是网络设备 I/O 地址。
第 12 行: irq 是网络设备的中断号。
第 24 行: dev_list 是全局网络设备列表。
第 25 行: napi_list 是 napi 网络设备的列表入口。
第 26 行: unreg_list 是注销(unregister)的网络设备列表入口。
第 27 行: close_list 是关闭的网络设备列表入口。
第 60 行: netdev_ops 是网络设备的操作集函数,包含了一系列的网络设备操作回调函数,类似字符设备中的 file_operations。
第 61 行: ethtool_ops 是网络管理工具相关函数集,用户空间网络管理工具会调用此结构体中的相关函数获取网卡状态或者配置网卡。
第 66 行: header_ops 是头部的相关操作函数集,比如创建、解析、缓冲等。
第 68 行: flags 是网络接口标志 ,标志类型定义在 include/uapi/linux/if.h 文件中,为一个枚举类型 ,内容如下:

示例代码 69.3.1.2 网络标志类型
1 enum net_device_flags {
2 IFF_UP = 1<<0, /* sysfs */
3 IFF_BROADCAST = 1<<1, /* volatile */
4 IFF_DEBUG = 1<<2, /* sysfs */
5 IFF_LOOPBACK = 1<<3, /* volatile */
6 IFF_POINTOPOINT = 1<<4, /* volatile */
7 IFF_NOTRAILERS = 1<<5, /* sysfs */
8 IFF_RUNNING = 1<<6, /* volatile */
9 IFF_NOARP = 1<<7, /* sysfs */
10 IFF_PROMISC = 1<<8, /* sysfs */
11 IFF_ALLMULTI = 1<<9, /* sysfs */
12 IFF_MASTER = 1<<10, /* volatile */
13 IFF_SLAVE = 1<<11, /* volatile */
14 IFF_MULTICAST = 1<<12, /* sysfs */
15 IFF_PORTSEL = 1<<13, /* sysfs */
16 IFF_AUTOMEDIA = 1<<14, /* sysfs */
17 IFF_DYNAMIC = 1<<15, /* sysfs */
18 IFF_LOWER_UP = 1<<16, /* volatile */
19 IFF_DORMANT = 1<<17, /* volatile */
20 IFF_ECHO = 1<<18, /* volatile */
21 };

第 77 行: **if_port 指定接口的端口类型,如果设备支持多端口的话就通过 if_port 来指定所使用的端口类型。**可选的端口类型定义在 include/uapi/linux/netdevice.h 中,为一个枚举类型,如下所示:

示例代码 69.3.1.3 端口类型
1 enum {
2 IF_PORT_UNKNOWN = 0,
3 IF_PORT_10BASE2,
4 IF_PORT_10BASET,
5 IF_PORT_AUI,
6 IF_PORT_100BASET,
7 IF_PORT_100BASETX,
8 IF_PORT_100BASEFX
9 };

第 78 行: dma 是网络设备所使用的 DMA 通道,不是所有的设备都会用到 DMA。
第 80 行: mtu 是网络最大传输单元,为 1500。
第 81 行: type 用于指定 ARP 模块的类型,以太网的 ARP 接口为 ARPHRD_ETHER, Linux内核所支持的 ARP 协议定义在 include/uapi/linux/if_arp.h 中,大家自行查阅。
第 88 行: perm_addr 是永久的硬件地址,如果某个网卡设备有永久的硬件地址,那么就会填充 perm_addr。
第 90 行: addr_len 是硬件地址长度。
第 133 行: last_rx 是最后接收的数据包时间戳,记录的是 jiffies。
第 136 行: dev_addr 也是硬件地址,是当前分配的 MAC 地址,可以通过软件修改。
第 140 行: ** _rx 是接收队列。**
第 142 行: num_rx_queues 是接收队列数量,在调用 register_netdev 注册网络设备的时候会分配指定数量的接收队列。
第 143 行: real_num_rx_queues 是当前有效的队列数量。
第 161 行: ** _tx 是发送队列。**
第 162 行: num_tx_queues 是发送队列数量,通过 alloc_netdev_mq 函数分配指定数量的发送队列。
第 163 行: real_num_tx_queues 是当前有效的发送队列数量。
第 179 行: trans_start 是最后的数据包发送的时间戳,记录的是 jiffies。
第 248 行: phydev 是对应的 PHY 设备。

2、注册与卸载网络驱动

内核模块初始化函数static int __init init_func() 和退出函数 static void _exit exit_func()

从中我们可以得出 __init 是告知编译器,将变量或函数放在一个特殊的区域,这个区域定义在vmlinux.lds中。__init 将函数放在代码段的一个子段 “.init.text”(初始化代码段)中,__initdata将数据放在数据段的子段".init.data"(初始化数据段)中。
标记_init的函数,表明该函数在使用一次后就会被丢掉,讲占用的内存释放。

同理也就可以知道_exit 标记的函数只有对模块才起作用,是指明函数是放在代码段的".exit.text"中,特点是只有在模块被卸载的时候该函数才会被调用

mt7915驱动入口在drivers\net\wireless\mediatek\mt_wifi\os\linux\pci_main_dev.c中int __init rt_pci_init_module(void)

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 12:16:32  更:2022-05-10 12:17:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:54:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码