diff options
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r-- | drivers/pci/msi.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 34087af68833..5902c00f4fce 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -459,15 +459,17 @@ static int msix_capability_init(struct pci_dev *dev, | |||
459 | /** | 459 | /** |
460 | * pci_msi_check_device - check whether MSI may be enabled on a device | 460 | * pci_msi_check_device - check whether MSI may be enabled on a device |
461 | * @dev: pointer to the pci_dev data structure of MSI device function | 461 | * @dev: pointer to the pci_dev data structure of MSI device function |
462 | * @nvec: how many MSIs have been requested ? | ||
462 | * @type: are we checking for MSI or MSI-X ? | 463 | * @type: are we checking for MSI or MSI-X ? |
463 | * | 464 | * |
464 | * Look at global flags, the device itself, and its parent busses | 465 | * Look at global flags, the device itself, and its parent busses |
465 | * to determine if MSI/-X are supported for the device. If MSI/-X is | 466 | * to determine if MSI/-X are supported for the device. If MSI/-X is |
466 | * supported return 0, else return an error code. | 467 | * supported return 0, else return an error code. |
467 | **/ | 468 | **/ |
468 | static int pci_msi_check_device(struct pci_dev * dev, int type) | 469 | static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) |
469 | { | 470 | { |
470 | struct pci_bus *bus; | 471 | struct pci_bus *bus; |
472 | int ret; | ||
471 | 473 | ||
472 | /* MSI must be globally enabled and supported by the device */ | 474 | /* MSI must be globally enabled and supported by the device */ |
473 | if (!pci_msi_enable || !dev || dev->no_msi) | 475 | if (!pci_msi_enable || !dev || dev->no_msi) |
@@ -483,6 +485,10 @@ static int pci_msi_check_device(struct pci_dev * dev, int type) | |||
483 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | 485 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) |
484 | return -EINVAL; | 486 | return -EINVAL; |
485 | 487 | ||
488 | ret = arch_msi_check_device(dev, nvec, type); | ||
489 | if (ret) | ||
490 | return ret; | ||
491 | |||
486 | if (!pci_find_capability(dev, type)) | 492 | if (!pci_find_capability(dev, type)) |
487 | return -EINVAL; | 493 | return -EINVAL; |
488 | 494 | ||
@@ -503,8 +509,9 @@ int pci_enable_msi(struct pci_dev* dev) | |||
503 | { | 509 | { |
504 | int status; | 510 | int status; |
505 | 511 | ||
506 | if (pci_msi_check_device(dev, PCI_CAP_ID_MSI)) | 512 | status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); |
507 | return -EINVAL; | 513 | if (status) |
514 | return status; | ||
508 | 515 | ||
509 | WARN_ON(!!dev->msi_enabled); | 516 | WARN_ON(!!dev->msi_enabled); |
510 | 517 | ||
@@ -601,9 +608,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
601 | int i, j; | 608 | int i, j; |
602 | u16 control; | 609 | u16 control; |
603 | 610 | ||
604 | if (!entries || pci_msi_check_device(dev, PCI_CAP_ID_MSIX)) | 611 | if (!entries) |
605 | return -EINVAL; | 612 | return -EINVAL; |
606 | 613 | ||
614 | status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); | ||
615 | if (status) | ||
616 | return status; | ||
617 | |||
607 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | 618 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); |
608 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 619 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
609 | nr_entries = multi_msix_capable(control); | 620 | nr_entries = multi_msix_capable(control); |
@@ -687,3 +698,13 @@ void pci_no_msi(void) | |||
687 | { | 698 | { |
688 | pci_msi_enable = 0; | 699 | pci_msi_enable = 0; |
689 | } | 700 | } |
701 | |||
702 | |||
703 | /* Arch hooks */ | ||
704 | |||
705 | int __attribute__ ((weak)) | ||
706 | arch_msi_check_device(struct pci_dev* dev, int nvec, int type) | ||
707 | { | ||
708 | return 0; | ||
709 | } | ||
710 | |||