深入理解Linux网络技术内幕——PCI层和网络接口卡
概述
- struct pci_driver {
- struct list_head node;
- char *name; //驱动程序名字
- const struct pci_device_id *id_table; /* ID向量,内核用于把设备关联到此驱动程序 */
- int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
- void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
- int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */
- int (*suspend_late) (struct pci_dev *dev, pm_message_t state);
- int (*resume_early) (struct pci_dev *dev);
- int (*resume) (struct pci_dev *dev); /* Device woken up */
- void (*shutdown) (struct pci_dev *dev);
- struct pci_error_handlers *err_handler;
- struct device_driver driver;
- struct pci_dynids dynids;
- };
PCI NIC设备的注册
- struct pci_device_id {
- __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ //通常 vendor, device就足以标识设备
- __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID *///很少用到
- __u32 class, class_mask; /* (class,subclass,prog-if) triplet *///设备所属的类,如network类
- kernel_ulong_t driver_data; /* Data private to the driver *///不属于PCI标识部分,而是驱动私有参数
- };
实例的向量(即一系列的pci_device_id 实例),这个向量包含了该驱动程序所能处理的设备的ID。
- int __pci_register_driver(struct pci_driver *drv, struct module *owner, const char *mod_name)
- void pci_unregister_driver(struct pci_driver *drv)
- pci_module_init()//在一些驱动程序上作为__pci_register_driver别名
电源管理和网络唤醒
PCI NIC驱动程序注册范例
以Intel PRO/100 Ethernet驱动程序说明NIC设备驱动程序的注册,源文件为drivers/net/e100.c。
初始化pci_device_id内容:
- #define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
- PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
- PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
- /****************************************************************************************/
- #define DEFINE_PCI_DEVICE_TABLE(_table) \
- const struct pci_device_id _table[] __devinitconst
- /***************************************************************************************/
- static DEFINE_PCI_DEVICE_TABLE(e100_id_table) = {
- INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
- INTEL_8255X_ETHERNET_DEVICE(0x1030, 0),
- INTEL_8255X_ETHERNET_DEVICE(0x1031, 3),
- INTEL_8255X_ETHERNET_DEVICE(0x1032, 3),
- INTEL_8255X_ETHERNET_DEVICE(0x1033, 3),
- INTEL_8255X_ETHERNET_DEVICE(0x1034, 3),
- INTEL_8255X_ETHERNET_DEVICE(0x1038, 3),
- INTEL_8255X_ETHERNET_DEVICE(0x1039, 4),
- INTEL_8255X_ETHERNET_DEVICE(0x103A, 4),
- INTEL_8255X_ETHERNET_DEVICE(0x103B, 4),
- INTEL_8255X_ETHERNET_DEVICE(0x103C, 4),
- INTEL_8255X_ETHERNET_DEVICE(0x103D, 4),
- INTEL_8255X_ETHERNET_DEVICE(0x103E, 4),
- INTEL_8255X_ETHERNET_DEVICE(0x1050, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1051, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1052, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1053, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1054, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1055, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1056, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1057, 5),
- INTEL_8255X_ETHERNET_DEVICE(0x1059, 0),
- INTEL_8255X_ETHERNET_DEVICE(0x1064, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x1065, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x1066, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x1067, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x1068, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x1069, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x106A, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x106B, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x1091, 7),
- INTEL_8255X_ETHERNET_DEVICE(0x1092, 7),
- INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
- INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
- INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
- INTEL_8255X_ETHERNET_DEVICE(0x10fe, 7),
- INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
- INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
- INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
- INTEL_8255X_ETHERNET_DEVICE(0x2459, 2),
- INTEL_8255X_ETHERNET_DEVICE(0x245D, 2),
- INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7),
- { 0, }
- };
在模块的初始化和卸载接口中完成PCI设备驱动程序的注册和注销:
- static struct pci_driver e100_driver = {
- .name = DRV_NAME,
- .id_table = e100_id_table,
- .probe = e100_probe,
- .remove = __devexit_p(e100_remove),
- #ifdef CONFIG_PM
- /* Power Management hooks */
- .suspend = e100_suspend,
- .resume = e100_resume,
- #endif
- .shutdown = e100_shutdown,
- .err_handler = &e100_err_handler,
- };
- static int __init e100_init_module(void)
- {
- if (((1 << debug) - 1) & NETIF_MSG_DRV) {
- pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
- pr_info("%s\n", DRV_COPYRIGHT);
- }
- return pci_register_driver(&e100_driver);
- }
- static void __exit e100_cleanup_module(void)
- {
- pci_unregister_driver(&e100_driver);
- }
- module_init(e100_init_module);
- module_exit(e100_cleanup_module);
其中的一些函数指针原型:
- #define DRV_NAME "e100"
- static int __devinit e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- {
- struct net_device *netdev;
- struct nic *nic;
- int err;
- if (!(netdev = alloc_etherdev(sizeof(struct nic)))) {
- if (((1 << debug) - 1) & NETIF_MSG_PROBE)
- pr_err("Etherdev alloc failed, aborting\n");
- return -ENOMEM;
- }
- ……
- ……
- }
PCI子系统总览
(a)在系统引导时,会建立一个数据库,把每个总线都关联到一份已侦测到而使用该总线的设备列表。PCI总线的描述符处理其他参数外,还包括一个已侦测PCI设备的列表。
(b)当驱动程序被加载,调用pci_register_driver注册pci_driver到PCI层时,PCI会使用pci_driver结构中的PCI设备ID参数id_table与已侦测到的PCI设备列表匹配,若匹配到就会建立该驱动程序的设备列表。对于每个匹配到的设备,PCI层会调用相匹配的驱动程序中的pci_driver结构中的probe函数,建立并注册相关联的网络设备。
/proc/pci文件包含了已注册的PCI设备的信息。pciutils套件中的lspci命令会输出有关本地PCI设备的信息,其中有些信息取自/sys。
深入理解Linux网络技术内幕——PCI层和网络接口卡的更多相关文章
- 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口
Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...
- 深入理解linux网络技术内幕读书笔记(六)--PCI层与网络接口卡
Table of Contents 1 本章涉及的数据结构 1.1 pci_device_id结构 1.2 pci_dev结构 1.3 pci_driver结构 2 PCI NIC设备驱动程序的注册 ...
- 《深入理解Linux网络技术内幕》阅读笔记 --- 邻居子系统
1.封包从L3至L2的传送过程如下所示: 本地主机的路由子系统选择L3目的地址(下一个跃点). 根据路由表,如果下一个跃点在同一个网络中,邻居层就把目的L3地址解析为跃点的L2地址.这个关联会被放入缓 ...
- 深入理解Linux网络技术内幕——网络设备初始化
概述 内核的初始化过程过程中,与网络相关的工作如下所示: 内核引导时执行start_kernel,start_kernel结束之前会调用rest_init,rest_init初始化内核线 ...
- 深入理解linux网络技术内幕读书笔记(五)--网络设备初始化
Table of Contents 1 简介 2 系统初始化概论 2.1 引导期间选项 2.2 中断和定时器 2.3 初始化函数 3 设备注册和初始化 3.1 硬件初始化 3.2 软件初始化 3.3 ...
- 《深入理解Linux网络技术内幕》阅读笔记 --- 路由基本概念
一.路由的基本概念 1.一条路由就是一组参数,这些参数存储了往一个给定目的地转发流量所需的信息,而一条路由所需的最少的参数集合为:(1)目的网络,(2)出口设备,(3)下一跳网关 2.路由中的相关术语 ...
- 深入理解linux网络技术内幕读书笔记(十)--帧的接收
Table of Contents 1 概述 1.1 帧接收的中断处理 2 设备的开启与关闭 3 队列 4 通知内核帧已接收:NAPI和netif_rx 4.1 NAPI简介 4.1.1 NAPI优点 ...
- 深入理解linux网络技术内幕读书笔记(九)--中断与网络驱动程序
Table of Contents 1 接收到帧时通知驱动程序 1.1 轮询 1.2 中断 2 中断处理程序 3 抢占功能 4 下半部函数 4.1 内核2.4版本以后的下半部函数: 引入软IRQ 5 ...
- 深入理解linux网络技术内幕读书笔记(八)--设备注册与初始化
Table of Contents 1 设备注册之时 2 设备除名之时 3 分配net_device结构 4 NIC注册和除名架构 4.1 注册 4.2 除名 5 设备初始化 6 设备类型初始化: x ...
随机推荐
- json获取元素数量
var keleyijson={"plug1":"myslider","plug2":"zonemenu"} funct ...
- MVC ---- 如何使用Predicate以及如何自定定义Predicate委托
微软公司提供只能返回bool值,接受一个参数的委托类型(Predicate). //Predicate委托 public static class PredicateDemo{ //内置方法 publ ...
- 【转】Windows Server 2008 R2怎样设置自动登陆
Windows Server 2008 R2是一款服务器操作系统,提升了虚拟化.系统管理弹性.网络存取方式,以及信息安全等领域的应用,Windows Server 2008 R2也是第一个只提供64位 ...
- poj 1523 SPF 无向图求割点
SPF Description Consider the two networks shown below. Assuming that data moves around these network ...
- highcharts PHP中使用
官网 https://www.hcharts.cn/demo/highcharts html <div id="container" style="min-widt ...
- 运行gulp提示:Task function must be specified
问题出在gulp版本上,以下是gulp3 VS gulp4的区别: gulp4最大的变化是不能像以前那样传递一个依赖的任务列表. gulp3中,如果有一个任务A.B和C的列表,你想在一个序列中运行 ...
- 《剑指offer》第三十四题(二叉树中和为某一值的路径)
// 面试题34:二叉树中和为某一值的路径 // 题目:输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所 // 有路径.从树的根结点开始往下一直到叶结点所经过的结点形成一条路径. #i ...
- 文件路径、File协议、FTP协议、Http协议之间简单的区别
File协议主要用于访问本地计算机中的文件,就如同在Windows资源管理器中打开文件一样,基本的格式如下:file:///文件路径. FTP是文件传输协议,可以用于互联网上.例如,你有一个网站,放在 ...
- 用EL時(el-api.jar,el-ri.jar ),要設isELIgnored="false"
用EL時(el-api.jar,el-ri.jar ),要設isELIgnored="false" 否则jstl标签不显示. 加上 <%@page isELIgnored="false ...
- 3-8《Ruby元编程》第二章对象模型
<Ruby元编程> 第二章 对象模型 类定义揭秘inside class definitions: class关键字更像一个作用域操作符,核心作用是可以在里面随时定义方法. [].meth ...