summaryrefslogtreecommitdiff
path: root/drivers/pci/msi.c
diff options
context:
space:
mode:
authorAlexander Gordeev <agordeev@redhat.com>2013-05-13 09:05:48 (GMT)
committerBjorn Helgaas <bhelgaas@google.com>2013-05-28 17:31:16 (GMT)
commit65f6ae66a6fb44f614a1226c398fcb38e94b3c59 (patch)
tree15c6f443e875f85c6194936adb26959dfa6cf685 /drivers/pci/msi.c
parentf722406faae2d073cc1d01063d1123c35425939e (diff)
downloadlinux-65f6ae66a6fb44f614a1226c398fcb38e94b3c59.tar.xz
PCI: Allocate only as many MSI vectors as requested by driver
Because of the encoding of the "Multiple Message Capable" and "Multiple Message Enable" fields, a device can only advertise that it's capable of a power-of-two number of vectors, and the OS can only enable a power-of-two number. For example, a device that's limited internally to using 18 vectors would have to advertise that it's capable of 32. The 14 extra vectors consume vector numbers and IRQ descriptors even though the device can't actually use them. This fix introduces a 'msi_desc::nvec_used' field to address this issue. When non-zero, it is the actual number of MSIs the device will send, as requested by the device driver. This value should be used by architectures to set up and tear down only as many interrupt resources as the device will actually use. Note, although the existing 'msi_desc::multiple' field might seem redundant, in fact it is not. The number of MSIs advertised need not be the smallest power-of-two larger than the number of MSIs the device will send. Thus, it is not always possible to derive the former from the latter, so we need to keep them both to handle this case. [bhelgaas: changelog, rename to "nvec_used"] Signed-off-by: Alexander Gordeev <agordeev@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r--drivers/pci/msi.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 2c10752..aca7578 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -81,7 +81,10 @@ void default_teardown_msi_irqs(struct pci_dev *dev)
int i, nvec;
if (entry->irq == 0)
continue;
- nvec = 1 << entry->msi_attrib.multiple;
+ if (entry->nvec_used)
+ nvec = entry->nvec_used;
+ else
+ nvec = 1 << entry->msi_attrib.multiple;
for (i = 0; i < nvec; i++)
arch_teardown_msi_irq(entry->irq + i);
}
@@ -336,7 +339,10 @@ static void free_msi_irqs(struct pci_dev *dev)
int i, nvec;
if (!entry->irq)
continue;
- nvec = 1 << entry->msi_attrib.multiple;
+ if (entry->nvec_used)
+ nvec = entry->nvec_used;
+ else
+ nvec = 1 << entry->msi_attrib.multiple;
#ifdef CONFIG_GENERIC_HARDIRQS
for (i = 0; i < nvec; i++)
BUG_ON(irq_has_action(entry->irq + i));