1 .. SPDX-License-Identifier: GPL-2.0 1 .. SPDX-License-Identifier: GPL-2.0 2 .. include:: <isonum.txt> 2 .. include:: <isonum.txt> 3 .. include:: ../disclaimer-zh_CN.rst 3 .. include:: ../disclaimer-zh_CN.rst 4 4 5 :Original: Documentation/PCI/pciebus-howto.rst 5 :Original: Documentation/PCI/pciebus-howto.rst 6 6 7 :翻译: 7 :翻译: 8 8 9 司延腾 Yanteng Si <siyanteng@loongson.cn> 9 司延腾 Yanteng Si <siyanteng@loongson.cn> 10 10 11 :校译: 11 :校译: 12 12 13 13 14 14 15 .. _cn_pciebus-howto: 15 .. _cn_pciebus-howto: 16 16 17 =========================== 17 =========================== 18 PCI Express端口总线驱动指南 18 PCI Express端口总线驱动指南 19 =========================== 19 =========================== 20 20 21 :作者: Tom L Nguyen tom.l.nguyen@intel.com 1 21 :作者: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004 22 :版权: |copy| 2004 Intel Corporation 22 :版权: |copy| 2004 Intel Corporation 23 23 24 关于本指南 24 关于本指南 25 ========== 25 ========== 26 26 27 本指南介绍了PCI Express端口总线驱 27 本指南介绍了PCI Express端口总线驱动程序的基本知识,并提供了如何使服务驱 28 动程序在PCI Express端口总线驱动程 28 动程序在PCI Express端口总线驱动程序中注册/取消注册的介绍。 29 29 30 30 31 什么是PCI Express端口总线驱动程序 31 什么是PCI Express端口总线驱动程序 32 ================================= 32 ================================= 33 33 34 一个PCI Express端口是一个逻辑的PCI-P 34 一个PCI Express端口是一个逻辑的PCI-PCI桥结构。有两种类型的PCI Express端 35 口:根端口和交换端口。根端口从P 35 口:根端口和交换端口。根端口从PCI Express根综合体发起一个PCI Express链接, 36 交换端口将PCI Express链接连接到内 36 交换端口将PCI Express链接连接到内部逻辑PCI总线。交换机端口,其二级总线代表 37 交换机的内部路由逻辑,被称为交 37 交换机的内部路由逻辑,被称为交换机的上行端口。交换机的下行端口是从交换机的内部 38 路由总线桥接到代表来自PCI Express 38 路由总线桥接到代表来自PCI Express交换机的下游PCI Express链接的总线。 39 39 40 一个PCI Express端口可以提供多达四 40 一个PCI Express端口可以提供多达四个不同的功能,在本文中被称为服务,这取决于 41 其端口类型。PCI Express端口的服务 41 其端口类型。PCI Express端口的服务包括本地热拔插支持(HP)、电源管理事件支持(PME)、 42 高级错误报告支持(AER)和虚拟通 42 高级错误报告支持(AER)和虚拟通道支持(VC)。这些服务可以由一个复杂的驱动程序 43 处理,也可以单独分布并由相应的 43 处理,也可以单独分布并由相应的服务驱动程序处理。 44 44 45 为什么要使用PCI Express端口总线驱 45 为什么要使用PCI Express端口总线驱动程序? 46 ========================================= 46 ========================================= 47 47 48 在现有的Linux内核中,Linux设备驱动 48 在现有的Linux内核中,Linux设备驱动模型允许一个物理设备只由一个驱动处理。 49 PCI Express端口是一个具有多个不同 49 PCI Express端口是一个具有多个不同服务的PCI-PCI桥设备。为了保持一个干净和简 50 单的解决方案,每个服务都可以有 50 单的解决方案,每个服务都可以有自己的软件服务驱动。在这种情况下,几个服务驱动将 51 竞争一个PCI-PCI桥设备。例如,如果 51 竞争一个PCI-PCI桥设备。例如,如果PCI Express根端口的本机热拔插服务驱动程序 52 首先被加载,它就会要求一个PCI-PCI 52 首先被加载,它就会要求一个PCI-PCI桥根端口。因此,内核不会为该根端口加载其他服 53 务驱动。换句话说,使用当前的驱 53 务驱动。换句话说,使用当前的驱动模型,不可能让多个服务驱动同时加载并运行在 54 PCI-PCI桥设备上。 54 PCI-PCI桥设备上。 55 55 56 为了使多个服务驱动程序同时运行 56 为了使多个服务驱动程序同时运行,需要有一个PCI Express端口总线驱动程序,它管 57 理所有填充的PCI Express端口,并根 57 理所有填充的PCI Express端口,并根据需要将所有提供的服务请求分配给相应的服务 58 驱动程序。下面列出了使用PCI Expres 58 驱动程序。下面列出了使用PCI Express端口总线驱动程序的一些关键优势: 59 59 60 - 允许在一个PCI-PCI桥接端口设备 60 - 允许在一个PCI-PCI桥接端口设备上同时运行多个服务驱动。 61 61 62 - 允许以独立的分阶段方式实施服 62 - 允许以独立的分阶段方式实施服务驱动程序。 63 63 64 - 允许一个服务驱动程序在多个PCI 64 - 允许一个服务驱动程序在多个PCI-PCI桥接端口设备上运行。 65 65 66 - 管理和分配PCI-PCI桥接端口设备 66 - 管理和分配PCI-PCI桥接端口设备的资源给要求的服务驱动程序。 67 67 68 配置PCI Express端口总线驱动程序与 68 配置PCI Express端口总线驱动程序与服务驱动程序 69 ============================================= 69 ============================================= 70 70 71 将PCI Express端口总线驱动支持纳入 71 将PCI Express端口总线驱动支持纳入内核 72 ------------------------------------- 72 ------------------------------------- 73 73 74 包括PCI Express端口总线驱动程序取 74 包括PCI Express端口总线驱动程序取决于内核配置中是否包含PCI Express支持。当内核 75 中的PCI Express支持被启用时,内核 75 中的PCI Express支持被启用时,内核将自动包含PCI Express端口总线驱动程序作为内核 76 驱动程序。 76 驱动程序。 77 77 78 启用服务驱动支持 78 启用服务驱动支持 79 ---------------- 79 ---------------- 80 80 81 PCI设备驱动是基于Linux设备驱动模 81 PCI设备驱动是基于Linux设备驱动模型实现的。所有的服务驱动都是PCI设备驱动。如上所述, 82 一旦内核加载了PCI Express端口总线 82 一旦内核加载了PCI Express端口总线驱动程序,就不可能再加载任何服务驱动程序。为了满 83 足PCI Express端口总线驱动程序模型 83 足PCI Express端口总线驱动程序模型,需要对现有的服务驱动程序进行一些最小的改变,其 84 对现有的服务驱动程序的功能没有 84 对现有的服务驱动程序的功能没有影响。 85 85 86 服务驱动程序需要使用下面所示的 86 服务驱动程序需要使用下面所示的两个API,将其服务注册到PCI Express端口总线驱动程 87 序中(见第5.2.1和5.2.2节)。在调用 87 序中(见第5.2.1和5.2.2节)。在调用这些API之前,服务驱动程序必须初始化头文件 88 /include/linux/pcieport_if.h中的pcie_port_se 88 /include/linux/pcieport_if.h中的pcie_port_service_driver数据结构。如果不这 89 样做,将导致身份不匹配,从而使P 89 样做,将导致身份不匹配,从而使PCI Express端口总线驱动程序无法加载服务驱动程序。 90 90 91 pcie_port_service_register 91 pcie_port_service_register 92 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 92 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 93 :: 93 :: 94 94 95 int pcie_port_service_register(struct pcie_p 95 int pcie_port_service_register(struct pcie_port_service_driver *new) 96 96 97 这个API取代了Linux驱动模型的 pci_reg 97 这个API取代了Linux驱动模型的 pci_register_driver API。一个服务驱动应该总是在模 98 块启动时调用 pcie_port_service_register 98 块启动时调用 pcie_port_service_register。请注意,在服务驱动被加载后,诸如 99 pci_enable_device(dev) 和 pci_set_master(dev) 99 pci_enable_device(dev) 和 pci_set_master(dev) 的调用不再需要,因为这些调用由 100 PCI端口总线驱动执行。 100 PCI端口总线驱动执行。 101 101 102 pcie_port_service_unregister 102 pcie_port_service_unregister 103 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 103 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 104 :: 104 :: 105 105 106 void pcie_port_service_unregister(struct pci 106 void pcie_port_service_unregister(struct pcie_port_service_driver *new) 107 107 108 pcie_port_service_unregister取代了Linux驱 108 pcie_port_service_unregister取代了Linux驱动模型的pci_unregister_driver。当一 109 个模块退出时,它总是被服务驱动 109 个模块退出时,它总是被服务驱动调用。 110 110 111 示例代码 111 示例代码 112 ~~~~~~~~ 112 ~~~~~~~~ 113 113 114 下面是服务驱动代码示例,用于初 114 下面是服务驱动代码示例,用于初始化端口服务的驱动程序数据结构。 115 :: 115 :: 116 116 117 static struct pcie_port_service_id service_i 117 static struct pcie_port_service_id service_id[] = { { 118 .vendor = PCI_ANY_ID, 118 .vendor = PCI_ANY_ID, 119 .device = PCI_ANY_ID, 119 .device = PCI_ANY_ID, 120 .port_type = PCIE_RC_PORT, 120 .port_type = PCIE_RC_PORT, 121 .service_type = PCIE_PORT_SERVICE_AER, 121 .service_type = PCIE_PORT_SERVICE_AER, 122 }, { /* end: all zeroes */ } 122 }, { /* end: all zeroes */ } 123 }; 123 }; 124 124 125 static struct pcie_port_service_driver root_ 125 static struct pcie_port_service_driver root_aerdrv = { 126 .name = (char *)device_name, 126 .name = (char *)device_name, 127 .id_table = service_id, !! 127 .id_table = &service_id[0], 128 128 129 .probe = aerdrv_load, 129 .probe = aerdrv_load, 130 .remove = aerdrv_unload, 130 .remove = aerdrv_unload, 131 131 132 .suspend = aerdrv_suspend, 132 .suspend = aerdrv_suspend, 133 .resume = aerdrv_resume, 133 .resume = aerdrv_resume, 134 }; 134 }; 135 135 136 下面是一个注册/取消注册服务驱动 136 下面是一个注册/取消注册服务驱动的示例代码。 137 :: 137 :: 138 138 139 static int __init aerdrv_service_init(void) 139 static int __init aerdrv_service_init(void) 140 { 140 { 141 int retval = 0; 141 int retval = 0; 142 142 143 retval = pcie_port_service_register(&root_ 143 retval = pcie_port_service_register(&root_aerdrv); 144 if (!retval) { 144 if (!retval) { 145 /* 145 /* 146 * FIX ME 146 * FIX ME 147 */ 147 */ 148 } 148 } 149 return retval; 149 return retval; 150 } 150 } 151 151 152 static void __exit aerdrv_service_exit(void) 152 static void __exit aerdrv_service_exit(void) 153 { 153 { 154 pcie_port_service_unregister(&root_aerdrv) 154 pcie_port_service_unregister(&root_aerdrv); 155 } 155 } 156 156 157 module_init(aerdrv_service_init); 157 module_init(aerdrv_service_init); 158 module_exit(aerdrv_service_exit); 158 module_exit(aerdrv_service_exit); 159 159 160 可能的资源冲突 160 可能的资源冲突 161 ============== 161 ============== 162 162 163 由于PCI-PCI桥接端口设备的所有服务 163 由于PCI-PCI桥接端口设备的所有服务驱动被允许同时运行,下面列出了一些可能的资源冲突和 164 建议的解决方案。 164 建议的解决方案。 165 165 166 MSI 和 MSI-X 向量资源 166 MSI 和 MSI-X 向量资源 167 --------------------- 167 --------------------- 168 168 169 一旦设备上的MSI或MSI-X中断被启用 169 一旦设备上的MSI或MSI-X中断被启用,它就会一直保持这种模式,直到它们再次被禁用。由于同 170 一个PCI-PCI桥接端口的服务驱动程序 170 一个PCI-PCI桥接端口的服务驱动程序共享同一个物理设备,如果一个单独的服务驱动程序启用或 171 禁用MSI/MSI-X模式,可能会导致不可 171 禁用MSI/MSI-X模式,可能会导致不可预知的行为。 172 172 173 为了避免这种情况,所有的服务驱 173 为了避免这种情况,所有的服务驱动程序都不允许在其设备上切换中断模式。PCI Express端口 174 总线驱动程序负责确定中断模式, 174 总线驱动程序负责确定中断模式,这对服务驱动程序来说应该是透明的。服务驱动程序只需要知道 175 分配给结构体pcie_device的字段irq的 175 分配给结构体pcie_device的字段irq的向量IRQ,当PCI Express端口总线驱动程序探测每 176 个服务驱动程序时,它被传入。服 176 个服务驱动程序时,它被传入。服务驱动应该使用(struct pcie_device*)dev->irq来调用 177 request_irq/free_irq。此外,中断模式 177 request_irq/free_irq。此外,中断模式被存储在struct pcie_device的interrupt_mode 178 字段中。 178 字段中。 179 179 180 PCI内存/IO映射的区域 180 PCI内存/IO映射的区域 181 -------------------- 181 -------------------- 182 182 183 PCI Express电源管理(PME)、高级错 183 PCI Express电源管理(PME)、高级错误报告(AER)、热插拔(HP)和虚拟通道(VC)的服务 184 驱动程序访问PCI Express端口的PCI配 184 驱动程序访问PCI Express端口的PCI配置空间。在所有情况下,访问的寄存器是相互独立的。这 185 个补丁假定所有的服务驱动程序都 185 个补丁假定所有的服务驱动程序都会表现良好,不会覆盖其他服务驱动程序的配置设置。 186 186 187 PCI配置寄存器 187 PCI配置寄存器 188 ------------- 188 ------------- 189 189 190 每个服务驱动都在自己的功能结构 190 每个服务驱动都在自己的功能结构体上运行PCI配置操作,除了PCI Express功能结构体,其中根控制 191 寄存器和设备控制寄存器是在PME和A 191 寄存器和设备控制寄存器是在PME和AER之间共享。这个补丁假定所有的服务驱动都会表现良好,不会 192 覆盖其他服务驱动的配置设置。 192 覆盖其他服务驱动的配置设置。
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.