深入理解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 ...
随机推荐
- YOLOv3-darknet 内容解析
目录 Yolov3-darknet 内容解析 多标签分类预测 跨尺度预测 网络结构改变 reference Yolov3-darknet 内容解析 YOLOv3是到目前为止,速度和精度最均衡的目标检测 ...
- Ubuntu 14.04 下 OF-Config安装
参考: Github of-config configure.ac - configure file issue OF-Config安装 1.安装OvS v2.3.1: Releases $ tar ...
- 【Coursera】Technology :Fifth Week(2)
The Ethernet Story Bob Metcalfe Bob 参与了 Xerox 研究项目,着手解决建造一个处处连接个人计算机的架构.当时,他们刚刚完成了 Internet 的开端 -具有 ...
- 03_Spark集群部署
[安装前的环境准备] Hadoop:2.6.1Java:jdk-1.7.0Spark: spark-1.6.0-bin-hadoop2.6.tgzScala: scala-2.11.4.tgz虚拟机: ...
- 为什么我的电脑win系统没有便笺功能?为什么我在开始菜单里找不到便笺功能?
有些网友表示,为什么我的电脑没有便笺功能?为什么我在开始菜单里找不到便笺功能? 从问题可以基本判断出来,这些网友使用的Win7版本有可能是买笔记本或者台式电脑时预装的Win7家庭普通版或者Win7精简 ...
- Jmeter Connect to Cassandra
https://github.com/Netflix/CassJMeter/wiki https://stackoverflow.com/questions/40974407/connecting-c ...
- 微信小程序发起支付流程
小程序调起支付API 需要参数 邮件中参数 API参数名 详细说明 APPID appid appid是微信小程序后台APP的唯一标识,在小程序后台申请小程序账号后,微信会自动分配对应的appid,用 ...
- MongoDB(课时22 过期索引)
3.6.2 过期索引 在一些程序的站点会出现若干秒之后信息被删除的情况,例如:手机信息验证码,那么在MongoDB里面可以轻松实现过期索引.但这个时间往往不怎么准确. 范例:设置过期索引(实现过期索引 ...
- 使用R内置函数操作数据框
我们已经学习了数据框的基础,这里回顾一下用于筛选数据框的内置函数.尽管数据框本质上是一个由向量构成的列表,由于各列长度相同,所以可以将其看作矩阵进行访问和操作.选择满足特定条件的行,需要为 [ ] 的 ...
- C++学习笔记(一)——一个字符串分割和统计的工具(TextUtils)
第一讲先从一个实例开始——我们需要完成一个遍历文件并统计单词出现次数的任务.分解功能:首先,按行读取文件并舍弃可能的空行.其次,将每一行都按照空格划分单词.因为可能存在标点符号,我们还需要将标点符号都 ...