diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2013-06-05 13:15:41 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-06-05 13:15:41 -0400 |
commit | 06886e8043877d5c439f5e2a3bcf23761bc1ae9d (patch) | |
tree | b0e0eb507d3b4d615395a2661879428af237915b | |
parent | b1267d60ce106be38a136b51a9edbf7c172b9dae (diff) | |
parent | 5fec945105448b958b8418b7e5d043d630ec3155 (diff) |
Merge branch 'pci/alexander-msi' into next
* pci/alexander-msi:
x86/MSI: Conserve interrupt resources when using multiple-MSIs
PCI: Allocate only as many MSI vectors as requested by driver
-rw-r--r-- | drivers/iommu/irq_remapping.c | 12 | ||||
-rw-r--r-- | drivers/pci/msi.c | 10 | ||||
-rw-r--r-- | include/linux/msi.h | 1 |
3 files changed, 16 insertions, 7 deletions
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index dcfea4e39be7..39f81aeefcd6 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c | |||
@@ -51,26 +51,27 @@ static void irq_remapping_disable_io_apic(void) | |||
51 | 51 | ||
52 | static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) | 52 | static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) |
53 | { | 53 | { |
54 | int node, ret, sub_handle, index = 0; | 54 | int node, ret, sub_handle, nvec_pow2, index = 0; |
55 | unsigned int irq; | 55 | unsigned int irq; |
56 | struct msi_desc *msidesc; | 56 | struct msi_desc *msidesc; |
57 | 57 | ||
58 | nvec = __roundup_pow_of_two(nvec); | ||
59 | |||
60 | WARN_ON(!list_is_singular(&dev->msi_list)); | 58 | WARN_ON(!list_is_singular(&dev->msi_list)); |
61 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); | 59 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); |
62 | WARN_ON(msidesc->irq); | 60 | WARN_ON(msidesc->irq); |
63 | WARN_ON(msidesc->msi_attrib.multiple); | 61 | WARN_ON(msidesc->msi_attrib.multiple); |
62 | WARN_ON(msidesc->nvec_used); | ||
64 | 63 | ||
65 | node = dev_to_node(&dev->dev); | 64 | node = dev_to_node(&dev->dev); |
66 | irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); | 65 | irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); |
67 | if (irq == 0) | 66 | if (irq == 0) |
68 | return -ENOSPC; | 67 | return -ENOSPC; |
69 | 68 | ||
70 | msidesc->msi_attrib.multiple = ilog2(nvec); | 69 | nvec_pow2 = __roundup_pow_of_two(nvec); |
70 | msidesc->nvec_used = nvec; | ||
71 | msidesc->msi_attrib.multiple = ilog2(nvec_pow2); | ||
71 | for (sub_handle = 0; sub_handle < nvec; sub_handle++) { | 72 | for (sub_handle = 0; sub_handle < nvec; sub_handle++) { |
72 | if (!sub_handle) { | 73 | if (!sub_handle) { |
73 | index = msi_alloc_remapped_irq(dev, irq, nvec); | 74 | index = msi_alloc_remapped_irq(dev, irq, nvec_pow2); |
74 | if (index < 0) { | 75 | if (index < 0) { |
75 | ret = index; | 76 | ret = index; |
76 | goto error; | 77 | goto error; |
@@ -95,6 +96,7 @@ error: | |||
95 | * IRQs from tearing down again in default_teardown_msi_irqs() | 96 | * IRQs from tearing down again in default_teardown_msi_irqs() |
96 | */ | 97 | */ |
97 | msidesc->irq = 0; | 98 | msidesc->irq = 0; |
99 | msidesc->nvec_used = 0; | ||
98 | msidesc->msi_attrib.multiple = 0; | 100 | msidesc->msi_attrib.multiple = 0; |
99 | 101 | ||
100 | return ret; | 102 | return ret; |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 2c1075213bec..aca7578b05e5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -81,7 +81,10 @@ void default_teardown_msi_irqs(struct pci_dev *dev) | |||
81 | int i, nvec; | 81 | int i, nvec; |
82 | if (entry->irq == 0) | 82 | if (entry->irq == 0) |
83 | continue; | 83 | continue; |
84 | nvec = 1 << entry->msi_attrib.multiple; | 84 | if (entry->nvec_used) |
85 | nvec = entry->nvec_used; | ||
86 | else | ||
87 | nvec = 1 << entry->msi_attrib.multiple; | ||
85 | for (i = 0; i < nvec; i++) | 88 | for (i = 0; i < nvec; i++) |
86 | arch_teardown_msi_irq(entry->irq + i); | 89 | arch_teardown_msi_irq(entry->irq + i); |
87 | } | 90 | } |
@@ -336,7 +339,10 @@ static void free_msi_irqs(struct pci_dev *dev) | |||
336 | int i, nvec; | 339 | int i, nvec; |
337 | if (!entry->irq) | 340 | if (!entry->irq) |
338 | continue; | 341 | continue; |
339 | nvec = 1 << entry->msi_attrib.multiple; | 342 | if (entry->nvec_used) |
343 | nvec = entry->nvec_used; | ||
344 | else | ||
345 | nvec = 1 << entry->msi_attrib.multiple; | ||
340 | #ifdef CONFIG_GENERIC_HARDIRQS | 346 | #ifdef CONFIG_GENERIC_HARDIRQS |
341 | for (i = 0; i < nvec; i++) | 347 | for (i = 0; i < nvec; i++) |
342 | BUG_ON(irq_has_action(entry->irq + i)); | 348 | BUG_ON(irq_has_action(entry->irq + i)); |
diff --git a/include/linux/msi.h b/include/linux/msi.h index 20c2d6dd5d25..ee66f3a12fb6 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h | |||
@@ -35,6 +35,7 @@ struct msi_desc { | |||
35 | 35 | ||
36 | u32 masked; /* mask bits */ | 36 | u32 masked; /* mask bits */ |
37 | unsigned int irq; | 37 | unsigned int irq; |
38 | unsigned int nvec_used; /* number of messages */ | ||
38 | struct list_head list; | 39 | struct list_head list; |
39 | 40 | ||
40 | union { | 41 | union { |