深入理解linux网络技术内幕读书笔记(六)--PCI层与网络接口卡

时间:2023-02-27 16:57:33

本章涉及的数据结构

pci_device_id结构

1:  struct pci_device_id {
2: __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
3: __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
4: __u32 class, class_mask; /* (class,subclass,prog-if) triplet */
5: kernel_ulong_t driver_data; /* Data private to the driver */
6: };

pci_device_id唯一标识一个PCI设备。它的几个成员依次分别表示:厂商号,设备号,子厂商号,子设备号,类别,类别掩码(类可分为基类,子类),私有数据。
每一个PCI设备的驱动程序都有一个pci_device_id的数组,用于告诉PCI核心自己能够驱动哪些设备。
[注] include/linux/mod_devicetable.h

pci_dev结构

  1:  /*
2: * The pci_dev structure is used to describe PCI devices.
3: */
4: struct pci_dev {
5: /* 总线设备链表元素bus_list:每一个pci_dev结构除了链接到全局设备链表中外,还会通过这个成员连接到其所属PCI总线的设备链表中。
6: 每一条PCI总线都维护一条它自己的设备链表视图,以便描述所有连接在该PCI总线上的设备,其表头由PCI总线的pci_bus结构中的 devices成员所描述t*/
7: struct list_head bus_list; /* node in per-bus list */
8: /* 总线指针bus:指向这个PCI设备所在的PCI总线的pci_bus结构。因此,对于桥设备而言,bus指针将指向桥设备的主总线(primary bus),也即指向桥设备所在的PCI总线*/
9: struct pci_bus *bus; /* bus this device is on */
10: /* 指针subordinate:指向这个PCI设备所桥接的下级总线。这个指针成员仅对桥设备才有意义,而对于一般的非桥PCI设备而言,该指针成员总是为NULL*/
11: struct pci_bus *subordinate; /* bus this device bridges to */
12:
13: /* 无类型指针sysdata:指向一片特定于系统的扩展数据*/
14: void *sysdata; /* hook for sys-specific extension */
15: /* 指针procent:指向该PCI设备在/proc文件系统中对应的目录项*/
16: struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
17: struct pci_slot *slot; /* Physical slot this device is in */
18:
19: /* devfn:这个PCI设备的设备功能号,也成为PCI逻辑设备号(0-255)。其中bit[7:3]是物理设备号(取值范围0-31),bit[2:0]是功能号(取值范围0-7)。 */
20: unsigned int devfn; /* encoded device & function index */
21: /* vendor:这是一个16无符号整数,表示PCI设备的厂商ID*/
22: unsigned short vendor;
23: /*device:这是一个16无符号整数,表示PCI设备的设备ID */
24: unsigned short device;
25: /* subsystem_vendor:这是一个16无符号整数,表示PCI设备的子系统厂商ID*/
26: unsigned short subsystem_vendor;
27: /* subsystem_device:这是一个16无符号整数,表示PCI设备的子系统设备ID。*/
28: unsigned short subsystem_device;
29: /* class:32位的无符号整数,表示该PCI设备的类别,其中,bit[7:0]为编程接口,bit[15:8]为子类别代码,bit [23:16]为基类别代码,bit[31:24]无意义。
30: 显然,class成员的低3字节刚好对应与PCI配置空间中的类代码*/
31: unsigned int class; /* 3 bytes: (base,sub,prog-if) */
32: u8 revision; /* PCI revision, low byte of class word */
33: /* hdr_type:8位符号整数,表示PCI配置空间头部的类型。其中,bit[7]=1表示这是一个多功能设备,bit[7]=0表示这是一个单功能设备。
34: Bit[6:0]则表示PCI配置空间头部的布局类型,值00h表示这是一个一般PCI设备的配置空间头部,值01h表示这是一个PCI-to-PCI桥的配置空间头部,
35: 值02h表示CardBus桥的配置空间头部*/
36: u8 hdr_type; /* PCI header type (`multi' flag masked out) */
37: u8 pcie_cap; /* PCI-E capability offset */
38: u8 pcie_type; /* PCI-E device/port type */
39: u8 rom_base_reg; /* which config register controls the ROM */
40: /* rom_base_reg:8位无符号整数,表示PCI配置空间中的ROM基地址寄存器在PCI配置空间中的位置。ROM基地址寄存器在不同类型的PCI配置空间头部的位置是不一样的,
41: 对于type 0的配置空间布局,ROM基地址寄存器的起始位置是30h,而对于PCI-to-PCI桥所用的type 1配置空间布局,ROM基地址寄存器的起始位置是38h*/
42: u8 pin; /* which interrupt pin this device uses */
43:
44: /* 指针driver:指向这个PCI设备所对应的驱动程序定义的pci_driver结构。每一个pci设备驱动程序都必须定义它自己的pci_driver结构来描述它自己。*/
45: struct pci_driver *driver; /* which driver has allocated this device */
46: /*dma_mask:用于DMA的总线地址掩码,一般来说,这个成员的值是0xffffffff。数据类型dma_addr_t定义在include/asm/types.h中,在x86平台上,
47: dma_addr_t类型就是u32类型*/
48: u64 dma_mask; /* Mask of the bits of bus address this
49: device implements. Normally this is
50: 0xffffffff. You only need to change
51: this if your device has broken DMA
52: or supports 64-bit transfers. */
53:
54: struct device_dma_parameters dma_parms;
55:
56: /* 当前操作状态 */
57: pci_power_t current_state; /* Current operating state. In ACPI-speak,
58: this is D0-D3, D0 being fully functional,
59: and D3 being off. */
60: int pm_cap; /* PM capability offset in the
61: configuration space */
62: unsigned int pme_support:; /* Bitmask of states from which PME#
63: can be generated */
64: unsigned int pme_interrupt:;
65: unsigned int d1_support:; /* Low power state D1 is supported */
66: unsigned int d2_support:; /* Low power state D2 is supported */
67: unsigned int no_d1d2:; /* Only allow D0 and D3 */
68: unsigned int wakeup_prepared:;
69: unsigned int d3_delay; /* D3->D0 transition time in ms */
70:
71: #ifdef CONFIG_PCIEASPM
72: struct pcie_link_state *link_state; /* ASPM link state. */
73: #endif
74:
75: pci_channel_state_t error_state; /* current connectivity state */
76: /* 通用的设备接口*/
77: struct device dev; /* Generic device interface */
78:
79: /* 配置空间的大小 */
80: int cfg_size; /* Size of configuration space */
81:
82: /*
83: * Instead of touching interrupt line and base address registers
84: * directly, use the values stored here. They might be different!
85: */
86: /* 无符号的整数irq:表示这个PCI设备通过哪根IRQ输入线产生中断,一般为0-15之间的某个值 */
87: unsigned int irq;
88: /*表示该设备可能用到的资源,包括:I/O断口区域、设备内存地址区域以及扩展ROM地址区域。*/
89: struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
90: resource_size_t fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */
91:
92: /* These fields are used by common fixups */
93: /* 透明 PCI 桥 */
94: unsigned int transparent:; /* Transparent PCI bridge */
95: /* 多功能设备*/
96: unsigned int multifunction:;/* Part of multi-function device */
97: /* keep track of device state */
98: unsigned int is_added:;
99: /* 设备是主设备*/
100: unsigned int is_busmaster:; /* device is busmaster */
101: /* 设备不使用msi*/
102: unsigned int no_msi:; /* device may not use msi */
103: /* 配置空间访问形式用块的形式 */
104: unsigned int block_ucfg_access:; /* userspace config space access is blocked */
105: unsigned int broken_parity_status:; /* Device generates false positive parity */
106: unsigned int irq_reroute_variant:; /* device needs IRQ rerouting variant */
107: unsigned int msi_enabled:;
108: unsigned int msix_enabled:;
109: unsigned int ari_enabled:; /* ARI forwarding */
110: unsigned int is_managed:;
111: unsigned int is_pcie:; /* Obsolete. Will be removed.
112: Use pci_is_pcie() instead */
113: unsigned int needs_freset:; /* Dev requires fundamental reset */
114: unsigned int state_saved:;
115: unsigned int is_physfn:;
116: unsigned int is_virtfn:;
117: unsigned int reset_fn:;
118: unsigned int is_hotplug_bridge:;
119: unsigned int __aer_firmware_first_valid:;
120: unsigned int __aer_firmware_first:;
121: pci_dev_flags_t dev_flags;
122: atomic_t enable_cnt; /* pci_enable_device has been called */
123:
124: /* 在挂起时保存配置空间*/
125: u32 saved_config_space[]; /* config space saved at suspend time */
126: struct hlist_head saved_cap_space;
127: /* sysfs ROM入口的属性描述*/
128: struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
129: int rom_attr_enabled; /* has display of the rom attribute been enabled? */
130: struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
131: struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
132: #ifdef CONFIG_PCI_MSI
133: struct list_head msi_list;
134: #endif
135: struct pci_vpd *vpd;
136: #ifdef CONFIG_PCI_IOV
137: union {
138: struct pci_sriov *sriov; /* SR-IOV capability related */
139: struct pci_dev *physfn; /* the PF this VF is associated with */
140: };
141: struct pci_ats *ats; /* Address Translation Service */
142: #endif
143: };

每一个PCI设备都会被分派一个pci_dev实例,如同网络设备都会被分派net_device实例一样。这个结构由内核使用,以引用一个PCI设备。
[注] include/linux/pci.h

pci_driver结构

 1:  struct pci_driver {
2: struct list_head node;
3: char *name;
4: const struct pci_device_id *id_table; /* must be non-NULL for probe to be called */
5: int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
6: void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
7: int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */
8: int (*suspend_late) (struct pci_dev *dev, pm_message_t state);
9: int (*resume_early) (struct pci_dev *dev);
10: int (*resume) (struct pci_dev *dev); /* Device woken up */
11: void (*shutdown) (struct pci_dev *dev);
12: struct pci_error_handlers *err_handler;
13: struct device_driver driver;
14: struct pci_dynids dynids;
15: };

定义PCI层与设备驱动程序之间的接口。
[注] include/linux/pci.h

PCI NIC设备驱动程序的注册

注册

 1:  /**
2: * __pci_register_driver - register a new pci driver
3: * @drv: the driver structure to register
4: * @owner: owner module of drv
5: * @mod_name: module name string
6: *
7: * Adds the driver structure to the list of registered drivers.
8: * Returns a negative value on error, otherwise 0.
9: * If no error occurred, the driver remains registered even if
10: * no device was claimed during registration.
11: */
12: int __pci_register_driver(struct pci_driver *drv, struct module *owner,
13: const char *mod_name)
14: {
15: int error;
16:
17: /* initialize common driver fields */
18: drv->driver.name = drv->name;
19: drv->driver.bus = &pci_bus_type;
20: drv->driver.owner = owner;
21: drv->driver.mod_name = mod_name;
22:
23: spin_lock_init(&drv->dynids.lock);
24: INIT_LIST_HEAD(&drv->dynids.list);
25:
26: /* register with core */
27: error = driver_register(&drv->driver);
28: if (error)
29: goto out;
30:
31: error = pci_create_newid_file(drv);
32: if (error)
33: goto out_newid;
34:
35: error = pci_create_removeid_file(drv);
36: if (error)
37: goto out_removeid;
38: out:
39: return error;
40:
41: out_removeid:
42: pci_remove_newid_file(drv);
43: out_newid:
44: driver_unregister(&drv->driver);
45: goto out;
46: }

[注] net/core/dev.c

解除

 1:  /**
2: * pci_unregister_driver - unregister a pci driver
3: * @drv: the driver structure to unregister
4: *
5: * Deletes the driver structure from the list of registered PCI drivers,
6: * gives it a chance to clean up by calling its remove() function for
7: * each device it was responsible for, and marks those devices as
8: * driverless.
9: */
10:
11: void
12: pci_unregister_driver(struct pci_driver *drv)
13: {
14: pci_remove_removeid_file(drv);
15: pci_remove_newid_file(drv);
16: driver_unregister(&drv->driver);
17: pci_free_dynids(drv);
18: }

[注] driver/pci/pci-driver.c

电源管理与网络唤醒

PCI电源管理事件由pci_driver数据结构的suspend和resume函数处理。除了分别负责PCIa状态的保存与恢复之外,这些函数遇到NIC的情况时还需采取特殊步骤:

  • suspend主要停止设备的出口队列,使得该设备无法再传输。
  • resume重启出口i队列,使得该设备得以再次传输。

网络唤醒(Wake-on-Lan, WOL)允许NIC在接收到一种特殊类型的帧时候唤醒处于待命状态的系统,WOL默认是关闭的。 此功能可以用pci_enable_wake打开或关上。
唤醒系统的魔术封包特性:

  • 目的MAC地址属于正在接收的NIC(无论单播/多播/广播)。
  • 帧中的某处(任何地方)会设置一段48位序列(也就是FF:FF:FF:FF:FF:FF),后面再接NIC MAC地址,在一行中至少连续重复16次。

深入理解linux网络技术内幕读书笔记(六)--PCI层与网络接口卡的更多相关文章

  1. 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口

    Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...

  2. 深入理解linux网络技术内幕读书笔记(十)--帧的接收

    Table of Contents 1 概述 1.1 帧接收的中断处理 2 设备的开启与关闭 3 队列 4 通知内核帧已接收:NAPI和netif_rx 4.1 NAPI简介 4.1.1 NAPI优点 ...

  3. 深入理解linux网络技术内幕读书笔记(九)--中断与网络驱动程序

    Table of Contents 1 接收到帧时通知驱动程序 1.1 轮询 1.2 中断 2 中断处理程序 3 抢占功能 4 下半部函数 4.1 内核2.4版本以后的下半部函数: 引入软IRQ 5 ...

  4. 深入理解linux网络技术内幕读书笔记(四)--通知链

    Table of Contents 1 概述 2 定义链 3 链注册 4 链上的通知事件 5 网络子系统的通知链 5.1 包裹函数 5.2 范例 6 测试实例 概述 [注意] 通知链只在内核子系统之间 ...

  5. 深入理解linux网络技术内幕读书笔记(二)--关键数据结构

    Table of Contents 1 套接字缓冲区: sk_buff结构 1.1 网络选项及内核结构 1.2 结构说明及操作函数 2 net_device结构 2.1 MTU 2.2 结构说明及操作 ...

  6. 深入理解linux网络技术内幕读书笔记(八)--设备注册与初始化

    Table of Contents 1 设备注册之时 2 设备除名之时 3 分配net_device结构 4 NIC注册和除名架构 4.1 注册 4.2 除名 5 设备初始化 6 设备类型初始化: x ...

  7. 深入理解linux网络技术内幕读书笔记(七)--组件初始化的内核基础架构

    Table of Contents 1 引导期间的内核选项 2 注册关键字 3 模块初始化代码 引导期间的内核选项 linux运行用户把内核配置选项传给引导记录,然后引导记录再把选项传给内核. 在引导 ...

  8. 深入理解linux网络技术内幕读书笔记(五)--网络设备初始化

    Table of Contents 1 简介 2 系统初始化概论 2.1 引导期间选项 2.2 中断和定时器 2.3 初始化函数 3 设备注册和初始化 3.1 硬件初始化 3.2 软件初始化 3.3 ...

  9. 深入理解linux网络技术内幕读书笔记(一)--简介

    Table of Contents 1 基本术语 1.1 本书常用的缩写 2 引用计数 2.1 引用计数函数 3 垃圾回收 3.1 异步 3.2 同步 4 函数指针 4.1 缺点 5 goto语句 5 ...

随机推荐

  1. 枚举类valueOf方法的疑问

    枚举类中valueOf方法只有一个参数而Enum类中有两个参数,请问Enum实例类中的valueOf方法是从何处继承而来?   答案:jvm进行编译的时候添加的.

  2. java去中文

    java 去中文 package a.b; public class TrimCNTool { public static boolean checkCNChar(char oneChar) { if ...

  3. Express4--说明

    express4.*;(1) var app = express(): 生成一个express实例 app. (2) app.set('views', path.join(__dirname, 'vi ...

  4. kappa系数在评测中的应用

    ◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/7091315.html 前言 最近打算把翻译质量的人工评测好 ...

  5. Unix 的缺陷 - 王垠

    我想通过这篇文章解释一下我对 Unix 哲学本质的理解.我虽然指出 Unix 的一个设计问题,但目的并不是打击人们对 Unix 的兴趣.虽然 Unix 在基础概念上有一个挺严重的问题,但是经过多年的发 ...

  6. AJAX-wamp安装的“橙色”问题

    安装wamp可能会出现的问题 ##1 正常安装wamp后,打开wamp可以在右下角看到一个图片,绿色即正常,红色或者橙色即意味着Apache+Mysql/MariaDB+Perl/PHP/Python ...

  7. 42.OC中instancetype与id的区别

    区别: 在ARC(Auto Reference Count)环境下: instancetype用来在编译期确定实例的类型,而使用id的话,编译器不检查类型,运行时检查类型 在MRC(Manual Re ...

  8. static 和 no static Member function学习

    以下是做实验的一段代码: #include <iostream> using namespace std; typedef void (*p)(); class Object { publ ...

  9. 〖Android〗把CM&lpar;Android&rpar;源代码导入eclipse的正确方法&lpar;2013-7-3&rpar;

    1. 首先应当使CM代码成功编译过一次: cd /path/to/cm . build/envsetup lunch full-eng mka 2. 配置eclipse开发的基本环境 cd /path ...

  10. pycharm使用技巧。(mac版本)

    一.pycharm使用中的一些快捷键 1.cmd  + b 跳转到声明处(cmd加鼠标) 2.option + c 复制光标当前行,剪切同理 3.option + v 粘贴复制的行 4.option ...