diff options
Diffstat (limited to 'Documentation/PCI/MSI-HOWTO.txt')
| -rw-r--r-- | Documentation/PCI/MSI-HOWTO.txt | 119 |
1 files changed, 109 insertions, 10 deletions
diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index a8d01005f480..10a93696e55a 100644 --- a/Documentation/PCI/MSI-HOWTO.txt +++ b/Documentation/PCI/MSI-HOWTO.txt | |||
| @@ -82,7 +82,19 @@ Most of the hard work is done for the driver in the PCI layer. It simply | |||
| 82 | has to request that the PCI layer set up the MSI capability for this | 82 | has to request that the PCI layer set up the MSI capability for this |
| 83 | device. | 83 | device. |
| 84 | 84 | ||
| 85 | 4.2.1 pci_enable_msi_range | 85 | 4.2.1 pci_enable_msi |
| 86 | |||
| 87 | int pci_enable_msi(struct pci_dev *dev) | ||
| 88 | |||
| 89 | A successful call allocates ONE interrupt to the device, regardless | ||
| 90 | of how many MSIs the device supports. The device is switched from | ||
| 91 | pin-based interrupt mode to MSI mode. The dev->irq number is changed | ||
| 92 | to a new number which represents the message signaled interrupt; | ||
| 93 | consequently, this function should be called before the driver calls | ||
| 94 | request_irq(), because an MSI is delivered via a vector that is | ||
| 95 | different from the vector of a pin-based interrupt. | ||
| 96 | |||
| 97 | 4.2.2 pci_enable_msi_range | ||
| 86 | 98 | ||
| 87 | int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) | 99 | int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) |
| 88 | 100 | ||
| @@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec) | |||
| 147 | return pci_enable_msi_range(pdev, nvec, nvec); | 159 | return pci_enable_msi_range(pdev, nvec, nvec); |
| 148 | } | 160 | } |
| 149 | 161 | ||
| 162 | Note, unlike pci_enable_msi_exact() function, which could be also used to | ||
| 163 | enable a particular number of MSI-X interrupts, pci_enable_msi_range() | ||
| 164 | returns either a negative errno or 'nvec' (not negative errno or 0 - as | ||
| 165 | pci_enable_msi_exact() does). | ||
| 166 | |||
| 150 | 4.2.1.3 Single MSI mode | 167 | 4.2.1.3 Single MSI mode |
| 151 | 168 | ||
| 152 | The most notorious example of the request type described above is | 169 | The most notorious example of the request type described above is |
| @@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev) | |||
| 158 | return pci_enable_msi_range(pdev, 1, 1); | 175 | return pci_enable_msi_range(pdev, 1, 1); |
| 159 | } | 176 | } |
| 160 | 177 | ||
| 161 | 4.2.2 pci_disable_msi | 178 | Note, unlike pci_enable_msi() function, which could be also used to |
| 179 | enable the single MSI mode, pci_enable_msi_range() returns either a | ||
| 180 | negative errno or 1 (not negative errno or 0 - as pci_enable_msi() | ||
| 181 | does). | ||
| 182 | |||
| 183 | 4.2.3 pci_enable_msi_exact | ||
| 184 | |||
| 185 | int pci_enable_msi_exact(struct pci_dev *dev, int nvec) | ||
| 186 | |||
| 187 | This variation on pci_enable_msi_range() call allows a device driver to | ||
| 188 | request exactly 'nvec' MSIs. | ||
| 189 | |||
| 190 | If this function returns a negative number, it indicates an error and | ||
| 191 | the driver should not attempt to request any more MSI interrupts for | ||
| 192 | this device. | ||
| 193 | |||
| 194 | By contrast with pci_enable_msi_range() function, pci_enable_msi_exact() | ||
| 195 | returns zero in case of success, which indicates MSI interrupts have been | ||
| 196 | successfully allocated. | ||
| 197 | |||
| 198 | 4.2.4 pci_disable_msi | ||
| 162 | 199 | ||
| 163 | void pci_disable_msi(struct pci_dev *dev) | 200 | void pci_disable_msi(struct pci_dev *dev) |
| 164 | 201 | ||
| @@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq(). | |||
| 172 | Failure to do so results in a BUG_ON(), leaving the device with | 209 | Failure to do so results in a BUG_ON(), leaving the device with |
| 173 | MSI enabled and thus leaking its vector. | 210 | MSI enabled and thus leaking its vector. |
| 174 | 211 | ||
| 175 | 4.2.3 pci_msi_vec_count | 212 | 4.2.4 pci_msi_vec_count |
| 176 | 213 | ||
| 177 | int pci_msi_vec_count(struct pci_dev *dev) | 214 | int pci_msi_vec_count(struct pci_dev *dev) |
| 178 | 215 | ||
| @@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function: | |||
| 257 | 294 | ||
| 258 | static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) | 295 | static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) |
| 259 | { | 296 | { |
| 260 | return pci_enable_msi_range(adapter->pdev, adapter->msix_entries, | 297 | return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, |
| 261 | 1, nvec); | 298 | 1, nvec); |
| 262 | } | 299 | } |
| 263 | 300 | ||
| 264 | Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive, | 301 | Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive, |
| @@ -269,8 +306,8 @@ In this case the function could look like this: | |||
| 269 | 306 | ||
| 270 | static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) | 307 | static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) |
| 271 | { | 308 | { |
| 272 | return pci_enable_msi_range(adapter->pdev, adapter->msix_entries, | 309 | return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, |
| 273 | FOO_DRIVER_MINIMUM_NVEC, nvec); | 310 | FOO_DRIVER_MINIMUM_NVEC, nvec); |
| 274 | } | 311 | } |
| 275 | 312 | ||
| 276 | 4.3.1.2 Exact number of MSI-X interrupts | 313 | 4.3.1.2 Exact number of MSI-X interrupts |
| @@ -282,10 +319,15 @@ parameters: | |||
| 282 | 319 | ||
| 283 | static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) | 320 | static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) |
| 284 | { | 321 | { |
| 285 | return pci_enable_msi_range(adapter->pdev, adapter->msix_entries, | 322 | return pci_enable_msix_range(adapter->pdev, adapter->msix_entries, |
| 286 | nvec, nvec); | 323 | nvec, nvec); |
| 287 | } | 324 | } |
| 288 | 325 | ||
| 326 | Note, unlike pci_enable_msix_exact() function, which could be also used to | ||
| 327 | enable a particular number of MSI-X interrupts, pci_enable_msix_range() | ||
| 328 | returns either a negative errno or 'nvec' (not negative errno or 0 - as | ||
| 329 | pci_enable_msix_exact() does). | ||
| 330 | |||
| 289 | 4.3.1.3 Specific requirements to the number of MSI-X interrupts | 331 | 4.3.1.3 Specific requirements to the number of MSI-X interrupts |
| 290 | 332 | ||
| 291 | As noted above, there could be devices that can not operate with just any | 333 | As noted above, there could be devices that can not operate with just any |
| @@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback - | |||
| 332 | any error code other than -ENOSPC indicates a fatal error and should not | 374 | any error code other than -ENOSPC indicates a fatal error and should not |
| 333 | be retried. | 375 | be retried. |
| 334 | 376 | ||
| 335 | 4.3.2 pci_disable_msix | 377 | 4.3.2 pci_enable_msix_exact |
| 378 | |||
| 379 | int pci_enable_msix_exact(struct pci_dev *dev, | ||
| 380 | struct msix_entry *entries, int nvec) | ||
| 381 | |||
| 382 | This variation on pci_enable_msix_range() call allows a device driver to | ||
| 383 | request exactly 'nvec' MSI-Xs. | ||
| 384 | |||
| 385 | If this function returns a negative number, it indicates an error and | ||
| 386 | the driver should not attempt to allocate any more MSI-X interrupts for | ||
| 387 | this device. | ||
| 388 | |||
| 389 | By contrast with pci_enable_msix_range() function, pci_enable_msix_exact() | ||
| 390 | returns zero in case of success, which indicates MSI-X interrupts have been | ||
| 391 | successfully allocated. | ||
| 392 | |||
| 393 | Another version of a routine that enables MSI-X mode for a device with | ||
| 394 | specific requirements described in chapter 4.3.1.3 might look like this: | ||
| 395 | |||
| 396 | /* | ||
| 397 | * Assume 'minvec' and 'maxvec' are non-zero | ||
| 398 | */ | ||
| 399 | static int foo_driver_enable_msix(struct foo_adapter *adapter, | ||
| 400 | int minvec, int maxvec) | ||
| 401 | { | ||
| 402 | int rc; | ||
| 403 | |||
| 404 | minvec = roundup_pow_of_two(minvec); | ||
| 405 | maxvec = rounddown_pow_of_two(maxvec); | ||
| 406 | |||
| 407 | if (minvec > maxvec) | ||
| 408 | return -ERANGE; | ||
| 409 | |||
| 410 | retry: | ||
| 411 | rc = pci_enable_msix_exact(adapter->pdev, | ||
| 412 | adapter->msix_entries, maxvec); | ||
| 413 | |||
| 414 | /* | ||
| 415 | * -ENOSPC is the only error code allowed to be analyzed | ||
| 416 | */ | ||
| 417 | if (rc == -ENOSPC) { | ||
| 418 | if (maxvec == 1) | ||
| 419 | return -ENOSPC; | ||
| 420 | |||
| 421 | maxvec /= 2; | ||
| 422 | |||
| 423 | if (minvec > maxvec) | ||
| 424 | return -ENOSPC; | ||
| 425 | |||
| 426 | goto retry; | ||
| 427 | } else if (rc < 0) { | ||
| 428 | return rc; | ||
| 429 | } | ||
| 430 | |||
| 431 | return maxvec; | ||
| 432 | } | ||
| 433 | |||
| 434 | 4.3.3 pci_disable_msix | ||
| 336 | 435 | ||
| 337 | void pci_disable_msix(struct pci_dev *dev) | 436 | void pci_disable_msix(struct pci_dev *dev) |
| 338 | 437 | ||
