当前位置: 首页 > news >正文

Linux网络设备驱动程序深度理解

文章目录

    • 1)概述
    • 2)网络设备驱动程序位于哪个层级?
      • 1、Linux内核体系结构
      • 2、Linux内核体系结构(源码视图)
    • 3)网络设备对比块设备/字符设备
    • 4)硬件模型
      • 1、硬件实现哪个层级?
      • 2、常见的硬件模型(以太网)
    • 5)数据结构及接口
      • 1、sk_buff (socket buffer)
      • 2、驱动中对网络数据的操作接口
    • 6)DM9000驱动程序(以太网)
      • 1)功能逻辑框图
      • 2)硬件模型
      • 3)驱动代码分析
      • 4)MII/MDIO
      • 5)驱动目录phy和ethenet

往期文章,Linux内核网络子系统框架介绍:https://blog.csdn.net/STCNXPARM/article/details/151253176

1)概述

1、网络设备驱动模型(Network Device Driver Model):适用于网络设备驱动的模型。驱动程序通过网络设备驱动接口(Network Device Driver Interface)与网络设备进行通信。

2、有了字符设备驱动程序的基础,学习网络驱动程序应该进行差异化学习线路

3、网络上很多教程都只是简单介绍?由于linux网络协议栈内容非常庞大,要讲清楚极其困难,系统协议栈已经非常稳定和成熟,对于新增一个网络设备驱动程序,只需要实现对应接口即可。

4、多个应用同时申请网络数据,怎么区分?

使用port来分区应用程序,IP用来识别哪台机器;

5、一个应用申请连续的数据,怎么实现?

站在驱动的角度,我们更关注单次的数据往返逻辑,连续的数据无非就是单次的循环过程。

6、这里介绍通用的网络驱动程序框架(即无论是有线网络还是无线网络都适用),部分以 “以太网设备”为例子;

2)网络设备驱动程序位于哪个层级?

1、Linux内核体系结构

1)网络设备驱动程序位于设备驱动功能层;

2)linux驱动就是 实现网络设备接口层定义的接口,以及硬件的初始化;

2、Linux内核体系结构(源码视图)

在这里插入图片描述

1)dev.c 是由内核实现的稳定框架;

2)驱动开发者 实现填充dev.c对应的接口即可,如8390.c;

3)网络设备对比块设备/字符设备

在这里插入图片描述

1)对于网络设备,没有open,没有/dev/设备文件,取而代之是socket;

2)网络设备的read/write同样会经过VFS,但之后转入到内核的网络协议栈,没有直接对接到设备驱动程序;

4)硬件模型

1、硬件实现哪个层级?

1)一般协议中的各层软件实现和硬件实现(不一定完全对应,尤其是数据链路层,软件实现或硬件实现 具体情况具体分析);

2)对于PHY,一定是硬件实现,软件工程师可简单了解即可;

3)MAC 是一组用于决定如何访问介质与传送数据的规则(数据帧格式-MAC帧),即发出的数据如何给对方正确接收;

2、常见的硬件模型(以太网)

在这里插入图片描述

1)不同产品采用的集成方案不同,对应的驱动实现也有所不同,但对接上一层级的接口不会变化;

2)芯片举例:DM9000(集成MAC层和PHY层)、DM9161(PHY层);

3)现代产品大多数CPU集成MAC层;

5)数据结构及接口

1、sk_buff (socket buffer)

/android/vendor/amlogic/common/kernel/common_5.4/include/linux/skbuff.h
struct sk_buff {struct sk_buff *next;struct sk_buff *prev;struct net_device *dev;struct sock *sk;unsigned int len, data_len;__u16 mac_len, hdr_len;__u32 priority;__u16 protocol;__be16		inner_protocol;__u16 inner_transport_header;__u16 inner_network_header;__u16 inner_mac_header;sk_buff_data_t tail;sk_buff_data_t end;unsigned char *head, *data;
}

在这里插入图片描述

1、sk_buff结构体是套接字缓冲区,是内核网络数据传输的基本单位,用于Linux网络子系统中的各层之间的传递数据(head、data、tail、end这些指针在传递过程不断变化),是linux网络子系统数据传递的“中枢神经”;

2、怎么理解 套接字?在向下传递过程中,各层会将不同各自的协议头加入到skbuff中去,组成最终的网络包发送出去;同理,向上传递,则会剥离各自的协议头直至交给用户;很形象的”套接“动作!

2、驱动中对网络数据的操作接口

1)网络协议接口层数据收发接口
/android/vendor/amlogic/common/kernel/common_5.4/net/core/dev.c
int dev_queue_xmit(struct sk_buff *skb)
int netif_rx(struct sk_buff *skb)2)网络设备的打开和释放,收发数据需要先激活
/android/vendor/amlogic/common/kernel/common_5.4/include/linux/netdevice.h
static inline void netif_start_queue(struct net_device *dev) //在驱动open中使用,激活设备发送队列
static inline void netif_stop_queue(struct net_device *dev)  //在驱动close中使用,关闭设备发送队列3)网络设备的数据发送的开启和关闭
net_device_ops->ndo_start_xmit() //上层调用驱动提供的传输函数(网络层的dev_queue_xmit方法调用)
static inline void netif_wake_queue(struct net_device *dev) //通知上层可以发送数据(当设备空闲时驱动调用,一般在发送完msg后调用)
static inline void netif_stop_queue(struct net_device *dev) //通知上层禁止发送数据(当设备忙碌时驱动调用,一般在开始发送msg时调用,避免冲突)

6)DM9000驱动程序(以太网)

1)功能逻辑框图

在这里插入图片描述

2)硬件模型

在这里插入图片描述

1、网卡与CPU的连接分三部分:控制引脚(片选、中断) 、数据引脚和地址引脚;

2、DM9000AE引脚图
在这里插入图片描述

3)驱动代码分析

1、网卡DM9000裸机驱动详解
https://zhuanlan.zhihu.com/p/3749418342、uboot对网络的支持
/android/bootloader/uboot-repo/bl33/v2015/net/eth.c
/android/bootloader/uboot-repo/bl33/v2019/drivers/net/dm9000x.c
int dm9000_initialize(bd_t *bit) //在对应的board里面调用3、内核中对ethernet的支持
/android/vendor/amlogic/common/kernel/common_5.4/include/linux/etherdevice.h
/android/vendor/amlogic/common/kernel/common_5.4/net/ethernet/eth.c4、dm9000驱动程序采用platform平台设备驱动模型
/android/vendor/amlogic/common/kernel/common_5.4/drivers/net/ethernet/davicom/dm9000.c
static struct platform_driver dm9000_driver = {.driver	= {.name    = "dm9000",.pm	 = &dm9000_drv_pm_ops,.of_match_table = of_match_ptr(dm9000_of_matches),},.probe   = dm9000_probe,.remove  = dm9000_drv_remove,
};1)probe
int dm9000_probe()
{1.定义“对象”struct board_info *db;	/* Point a board information structure */struct net_device *ndev;struct device *dev = &pdev->dev;2.分配并初始化各类硬件资源3.Allocates and sets up an Ethernet devicendev = alloc_etherdev(sizeof(struct board_info));4.将实现的接口挂接到net_device中去ndev->netdev_ops	= &dm9000_netdev_ops;ndev->watchdog_timeo	= msecs_to_jiffies(watchdog);ndev->ethtool_ops	= &dm9000_ethtool_ops;db->mii.mdio_read    = dm9000_phy_read; //mii接口db->mii.mdio_write   = dm9000_phy_write;5.最后挂接到系统体系中去(链表结构),等待系统调用platform_set_drvdata(pdev, ndev);register_netdev(ndev);
}2)eth功能接口
static const struct net_device_ops dm9000_netdev_ops = {.ndo_open		= dm9000_open,  //当ifconfig eth0 up会调用到.ndo_stop		= dm9000_stop,  //当ifconfig eth0 down会调用到.ndo_start_xmit		= dm9000_start_xmit, //当app发送数据时,会被调用到.ndo_tx_timeout		= dm9000_timeout,.ndo_set_rx_mode	= dm9000_hash_table,.ndo_do_ioctl		= dm9000_ioctl,.ndo_set_features	= dm9000_set_features,.ndo_validate_addr	= eth_validate_addr,.ndo_set_mac_address	= eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER.ndo_poll_controller	= dm9000_poll_controller,
#endif
};3)eth管理接口
static const struct ethtool_ops dm9000_ethtool_ops = {.get_drvinfo		= dm9000_get_drvinfo,.get_msglevel		= dm9000_get_msglevel,.set_msglevel		= dm9000_set_msglevel,.nway_reset		= dm9000_nway_reset,.get_link		= dm9000_get_link,.get_wol		= dm9000_get_wol,.set_wol		= dm9000_set_wol,.get_eeprom_len		= dm9000_get_eeprom_len,.get_eeprom		= dm9000_get_eeprom,.set_eeprom		= dm9000_set_eeprom,.get_link_ksettings	= dm9000_get_link_ksettings,.set_link_ksettings	= dm9000_set_link_ksettings,
};4)待机、开机时由内核调用
static const struct dev_pm_ops dm9000_drv_pm_ops = {.suspend	= dm9000_drv_suspend,.resume		= dm9000_drv_resume,
};5)alloc_etherdev 分配接口
#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)/android/vendor/amlogic/common/kernel/common_5.4/net/ethernet/eth.c
struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,unsigned int rxqs)
{return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN,ether_setup, txqs, rxqs);
}
EXPORT_SYMBOL(alloc_etherdev_mqs);6)获取私有数据
struct board_info *db;
db = netdev_priv(ndev); //把挂接在ndev上的board_info结构体取出来7)register_netdev调用栈
/android/vendor/amlogic/common/kernel/common_5.4/net/core/dev.c
register_netdev()
--register_netdevice()
----call_netdevice_notifiers(NETDEV_POST_INIT, dev);
----netdev_register_kobject(dev); //在/sys/class/net目录下创建sysfs条目
----list_netdevice(dev); //将设备插入到其网络命名空间的全局设备列表中
----call_netdevice_notifiers(NETDEV_REGISTER, dev); //发送注册事件,内核的其它模块可以获悉并响应
----kobject_put(&dev->dev.kobj); //增加kobject引用计数
----rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL); //向用户空间发送netlink消息7)网卡设备接收网络数据
当网卡接收到数据包,会触发中断,进入驱动中断处理函数接收
/android/vendor/amlogic/common/kernel/common_5.4/drivers/net/ethernet/davicom/dm9000.c
--request_irq(dev->irq, dm9000_interrupt, irq_flags, dev->name, dev) //dm9000_open()里注册
----dm9000_interrupt(int irq, void *dev_id)
------dm9000_rx(dev)
--------netif_rx(skb);8)数据线和地址线的gpio配置
/android/vendor/amlogic/common/kernel/common_5.4/arch/arm/include/asm/io.h
db->io_addr = ioremap(db->addr_res->start, iosize);
db->io_data = ioremap(db->data_res->start, iosize);
writeb(reg_save, db->io_addr);
readb(db->io_addr);

4)MII/MDIO

1、MII(Media Independent Interface): 一个标准接口,将 MAC(在处理器或交换机中)连接到物理层收发器(PHY)。它定义了数据帧的传输和接收。
2、MDIO(Management Data Input/Output): 一个简单的两线串行总线(时钟线 MDC 和数据线 MDIO),是 MII 的一部分,专门用于 MAC 和 PHY 之间的管理通信。MAC 通过它来读写 PHY 芯片的内部寄存器,从而配置 PHY、监控链路状态、诊断故障。3、linux/mii.h 这个头文件提供了 以太网 PHY (物理层) 芯片 和 MAC (媒体访问控制) 控制器 之间进行管理和控制的标准化编程接口, 并定义了 IEEE 802.3 标准中规定的通用 PHY 寄存器地址。这些是任何 PHY 芯片都必须支持的基本寄存器。

5)驱动目录phy和ethenet

1、目录1:/drivers/net/phy/:负责 物理层 (PHY) 驱动。它直接管理硬件层面上的以太网PHY芯片,负责最基础的链路建立、信号转换和介质相关功能。
代表(DM9161)
/android/vendor/amlogic/common/kernel/common_5.4/drivers/net/phy/davicom.c2、目录2:/drivers/net/ethernet/:负责 以太网控制器 (MAC) 驱动。它管理数据链路层中的MAC控制器,处理数据帧的组装、发送、接收以及更上层的协议交互。
代表(DM9000)
/android/vendor/amlogic/common/kernel/common_5.4/drivers/net/ethernet/davicom/dm9000.c3、以太网通信芯片(DM9000AE、DM9161、LAN8720 的区别与联系)
https://blog.csdn.net/ftdlk/article/details/146011053
DM9000和DM9161的比较
https://blog.csdn.net/jackyard/article/details/8654809

文章转载自:

http://4VCgkhcG.rzdpd.cn
http://fELv8UfA.rzdpd.cn
http://5NtJX59L.rzdpd.cn
http://wATpwEfk.rzdpd.cn
http://SIvUEQ1k.rzdpd.cn
http://7lNcy5O0.rzdpd.cn
http://NyJRkDQf.rzdpd.cn
http://cKSAOJjW.rzdpd.cn
http://Zq5T3RZ3.rzdpd.cn
http://rg2jckjD.rzdpd.cn
http://3QW2bI3K.rzdpd.cn
http://nRNbnQ1z.rzdpd.cn
http://JrMDFZ3i.rzdpd.cn
http://v7CKIH8n.rzdpd.cn
http://7pXIR7VN.rzdpd.cn
http://nRU6sR1B.rzdpd.cn
http://ayFPpGey.rzdpd.cn
http://mr6xcURq.rzdpd.cn
http://L8fnsoYh.rzdpd.cn
http://XC67WpXG.rzdpd.cn
http://PqRUhi37.rzdpd.cn
http://ntUQzlsg.rzdpd.cn
http://BenzFXIy.rzdpd.cn
http://PAq7bOAn.rzdpd.cn
http://iB3fuUUQ.rzdpd.cn
http://S8CMX2hx.rzdpd.cn
http://PYZmikY5.rzdpd.cn
http://2m0dih1p.rzdpd.cn
http://IjjjVQjr.rzdpd.cn
http://UpbAJ38s.rzdpd.cn
http://www.dtcms.com/a/371619.html

相关文章:

  • Unity AssetBundle详解
  • 小白AIGC短视频生成的第一课之混元AI视频
  • 通义万相wan2.2视频模型的基础模型与安装应用详解
  • JavaEE 进阶第三期:开启前端入门之旅(三)
  • Linux:NTP服务
  • 【多模态学习】QA3:FFN的作用?Embedding生成方法的BERT和Word2Vec?非线性引入的作用?
  • Tomcat 日志文件名的命名规范
  • 基于单片机的可燃性气体泄漏智能报警系统
  • Ubuntu系统下Python连接国产KingbaseES数据库实现增删改查
  • 【linux kernel 常用数据结构和设计模式】【数据结构 2】【通过一个案例属性list、hlist、rbtree、xarray数据结构使用】
  • 论文阅读:DMD | Improved Distribution Matching Distillation for Fast Image Synthesis
  • 深入解析三色标记算法
  • Python struct模块 | 使用pack函数进行字节序打包
  • 二叉树的前中后序遍历(迭代法)
  • Camx-系统默认创建camxoverridesettings.txt
  • SQL面试题及详细答案150道(101-115) --- 数据操纵与定义篇
  • Adobe Premiere Pro(Pr)2022视频编辑软件安装教程与下载地址
  • 18.4 查看订单
  • 【考研C语言编程题】数组元素批量插入实现(含图示+三部曲拆解)
  • 九.弗洛伊德(Floyd)算法
  • pytorch非线性回归
  • Java 大视界 -- Java 大数据机器学习模型在金融市场风险评估与投资组合优化中的应用(407)
  • Python快速入门专业版(十一):布尔值与None:Python中的“真假”与“空值”(附逻辑判断案例)
  • 鸿蒙NEXT应用数据持久化全面解析:从用户首选项到分布式数据库
  • Linux笔记---封装套接字
  • 轻松Linux-8.动静态库的制作及原理
  • LeetCode 面试经典 150 题:移除元素(双指针思想优化解法详解)
  • 【TypeScript】闭包
  • 后端(fastAPI)学习笔记(CLASS 1):扩展基础
  • Spring Boot @RestController 注解详解