Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 1 | .. SPDX-License-Identifier: GPL-2.0 |
| 2 | .. include:: <isonum.txt> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 4 | =========================================== |
| 5 | The PCI Express Port Bus Driver Guide HOWTO |
| 6 | =========================================== |
| 7 | |
| 8 | :Author: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004 |
| 9 | :Copyright: |copy| 2004 Intel Corporation |
| 10 | |
| 11 | About this guide |
| 12 | ================ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | |
| 14 | This guide describes the basics of the PCI Express Port Bus driver |
| 15 | and provides information on how to enable the service drivers to |
| 16 | register/unregister with the PCI Express Port Bus Driver. |
| 17 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 19 | What is the PCI Express Port Bus Driver |
| 20 | ======================================= |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 | |
| 22 | A PCI Express Port is a logical PCI-PCI Bridge structure. There |
| 23 | are two types of PCI Express Port: the Root Port and the Switch |
| 24 | Port. The Root Port originates a PCI Express link from a PCI Express |
| 25 | Root Complex and the Switch Port connects PCI Express links to |
| 26 | internal logical PCI buses. The Switch Port, which has its secondary |
| 27 | bus representing the switch's internal routing logic, is called the |
| 28 | switch's Upstream Port. The switch's Downstream Port is bridging from |
| 29 | switch's internal routing bus to a bus representing the downstream |
| 30 | PCI Express link from the PCI Express Switch. |
| 31 | |
| 32 | A PCI Express Port can provide up to four distinct functions, |
| 33 | referred to in this document as services, depending on its port type. |
| 34 | PCI Express Port's services include native hotplug support (HP), |
| 35 | power management event support (PME), advanced error reporting |
| 36 | support (AER), and virtual channel support (VC). These services may |
| 37 | be handled by a single complex driver or be individually distributed |
| 38 | and handled by corresponding service drivers. |
| 39 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 40 | Why use the PCI Express Port Bus Driver? |
| 41 | ======================================== |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | |
| 43 | In existing Linux kernels, the Linux Device Driver Model allows a |
| 44 | physical device to be handled by only a single driver. The PCI |
| 45 | Express Port is a PCI-PCI Bridge device with multiple distinct |
| 46 | services. To maintain a clean and simple solution each service |
| 47 | may have its own software service driver. In this case several |
| 48 | service drivers will compete for a single PCI-PCI Bridge device. |
| 49 | For example, if the PCI Express Root Port native hotplug service |
| 50 | driver is loaded first, it claims a PCI-PCI Bridge Root Port. The |
| 51 | kernel therefore does not load other service drivers for that Root |
| 52 | Port. In other words, it is impossible to have multiple service |
| 53 | drivers load and run on a PCI-PCI Bridge device simultaneously |
| 54 | using the current driver model. |
| 55 | |
| 56 | To enable multiple service drivers running simultaneously requires |
| 57 | having a PCI Express Port Bus driver, which manages all populated |
| 58 | PCI Express Ports and distributes all provided service requests |
| 59 | to the corresponding service drivers as required. Some key |
| 60 | advantages of using the PCI Express Port Bus driver are listed below: |
| 61 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 62 | - Allow multiple service drivers to run simultaneously on |
| 63 | a PCI-PCI Bridge Port device. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 64 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 65 | - Allow service drivers implemented in an independent |
| 66 | staged approach. |
Randy Dunlap | 4b5ff46 | 2008-03-10 17:16:32 -0700 | [diff] [blame] | 67 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 68 | - Allow one service driver to run on multiple PCI-PCI Bridge |
| 69 | Port devices. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 71 | - Manage and distribute resources of a PCI-PCI Bridge Port |
| 72 | device to requested service drivers. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 74 | Configuring the PCI Express Port Bus Driver vs. Service Drivers |
| 75 | =============================================================== |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 77 | Including the PCI Express Port Bus Driver Support into the Kernel |
| 78 | ----------------------------------------------------------------- |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 79 | |
| 80 | Including the PCI Express Port Bus driver depends on whether the PCI |
| 81 | Express support is included in the kernel config. The kernel will |
| 82 | automatically include the PCI Express Port Bus driver as a kernel |
| 83 | driver when the PCI Express support is enabled in the kernel. |
| 84 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 85 | Enabling Service Driver Support |
| 86 | ------------------------------- |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | |
| 88 | PCI device drivers are implemented based on Linux Device Driver Model. |
| 89 | All service drivers are PCI device drivers. As discussed above, it is |
| 90 | impossible to load any service driver once the kernel has loaded the |
| 91 | PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver |
| 92 | Model requires some minimal changes on existing service drivers that |
| 93 | imposes no impact on the functionality of existing service drivers. |
| 94 | |
| 95 | A service driver is required to use the two APIs shown below to |
Randy Dunlap | 4b5ff46 | 2008-03-10 17:16:32 -0700 | [diff] [blame] | 96 | register its service with the PCI Express Port Bus driver (see |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | section 5.2.1 & 5.2.2). It is important that a service driver |
| 98 | initializes the pcie_port_service_driver data structure, included in |
| 99 | header file /include/linux/pcieport_if.h, before calling these APIs. |
| 100 | Failure to do so will result an identity mismatch, which prevents |
| 101 | the PCI Express Port Bus driver from loading a service driver. |
| 102 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 103 | pcie_port_service_register |
| 104 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 105 | :: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 107 | int pcie_port_service_register(struct pcie_port_service_driver *new) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | |
Alex Chiang | a08f6e0 | 2009-02-13 12:03:17 -0700 | [diff] [blame] | 109 | This API replaces the Linux Driver Model's pci_register_driver API. A |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | service driver should always calls pcie_port_service_register at |
| 111 | module init. Note that after service driver being loaded, calls |
| 112 | such as pci_enable_device(dev) and pci_set_master(dev) are no longer |
| 113 | necessary since these calls are executed by the PCI Port Bus driver. |
| 114 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 115 | pcie_port_service_unregister |
| 116 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 117 | :: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 119 | void pcie_port_service_unregister(struct pcie_port_service_driver *new) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | |
| 121 | pcie_port_service_unregister replaces the Linux Driver Model's |
| 122 | pci_unregister_driver. It's always called by service driver when a |
| 123 | module exits. |
| 124 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 125 | Sample Code |
| 126 | ~~~~~~~~~~~ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | |
| 128 | Below is sample service driver code to initialize the port service |
| 129 | driver data structure. |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 130 | :: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 132 | static struct pcie_port_service_id service_id[] = { { |
| 133 | .vendor = PCI_ANY_ID, |
| 134 | .device = PCI_ANY_ID, |
| 135 | .port_type = PCIE_RC_PORT, |
| 136 | .service_type = PCIE_PORT_SERVICE_AER, |
| 137 | }, { /* end: all zeroes */ } |
| 138 | }; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 139 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 140 | static struct pcie_port_service_driver root_aerdrv = { |
| 141 | .name = (char *)device_name, |
| 142 | .id_table = &service_id[0], |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 144 | .probe = aerdrv_load, |
| 145 | .remove = aerdrv_unload, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 147 | .suspend = aerdrv_suspend, |
| 148 | .resume = aerdrv_resume, |
| 149 | }; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | |
| 151 | Below is a sample code for registering/unregistering a service |
| 152 | driver. |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 153 | :: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 154 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 155 | static int __init aerdrv_service_init(void) |
| 156 | { |
| 157 | int retval = 0; |
Randy Dunlap | 4b5ff46 | 2008-03-10 17:16:32 -0700 | [diff] [blame] | 158 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 159 | retval = pcie_port_service_register(&root_aerdrv); |
| 160 | if (!retval) { |
| 161 | /* |
| 162 | * FIX ME |
| 163 | */ |
| 164 | } |
| 165 | return retval; |
| 166 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 168 | static void __exit aerdrv_service_exit(void) |
| 169 | { |
| 170 | pcie_port_service_unregister(&root_aerdrv); |
| 171 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 173 | module_init(aerdrv_service_init); |
| 174 | module_exit(aerdrv_service_exit); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 175 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 176 | Possible Resource Conflicts |
| 177 | =========================== |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 178 | |
| 179 | Since all service drivers of a PCI-PCI Bridge Port device are |
| 180 | allowed to run simultaneously, below lists a few of possible resource |
| 181 | conflicts with proposed solutions. |
| 182 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 183 | MSI and MSI-X Vector Resource |
| 184 | ----------------------------- |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 185 | |
Christoph Hellwig | e4e7d597 | 2017-02-15 08:58:23 +0100 | [diff] [blame] | 186 | Once MSI or MSI-X interrupts are enabled on a device, it stays in this |
| 187 | mode until they are disabled again. Since service drivers of the same |
| 188 | PCI-PCI Bridge port share the same physical device, if an individual |
| 189 | service driver enables or disables MSI/MSI-X mode it may result |
| 190 | unpredictable behavior. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 191 | |
| 192 | To avoid this situation all service drivers are not permitted to |
| 193 | switch interrupt mode on its device. The PCI Express Port Bus driver |
| 194 | is responsible for determining the interrupt mode and this should be |
| 195 | transparent to service drivers. Service drivers need to know only |
| 196 | the vector IRQ assigned to the field irq of struct pcie_device, which |
| 197 | is passed in when the PCI Express Port Bus driver probes each service |
| 198 | driver. Service drivers should use (struct pcie_device*)dev->irq to |
| 199 | call request_irq/free_irq. In addition, the interrupt mode is stored |
| 200 | in the field interrupt_mode of struct pcie_device. |
| 201 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 202 | PCI Memory/IO Mapped Regions |
| 203 | ---------------------------- |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 204 | |
| 205 | Service drivers for PCI Express Power Management (PME), Advanced |
| 206 | Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access |
| 207 | PCI configuration space on the PCI Express port. In all cases the |
| 208 | registers accessed are independent of each other. This patch assumes |
| 209 | that all service drivers will be well behaved and not overwrite |
| 210 | other service driver's configuration settings. |
| 211 | |
Changbin Du | 2e64224 | 2019-05-14 22:47:25 +0800 | [diff] [blame] | 212 | PCI Config Registers |
| 213 | -------------------- |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 | |
| 215 | Each service driver runs its PCI config operations on its own |
| 216 | capability structure except the PCI Express capability structure, in |
| 217 | which Root Control register and Device Control register are shared |
| 218 | between PME and AER. This patch assumes that all service drivers |
| 219 | will be well behaved and not overwrite other service driver's |
| 220 | configuration settings. |