diff options
author | Joerg Roedel <joro@8bytes.org> | 2012-09-26 06:44:38 -0400 |
---|---|---|
committer | Joerg Roedel <joro@8bytes.org> | 2013-01-28 06:17:25 -0500 |
commit | 5afba62cc8a16716508605e02c1b02ee5f969184 (patch) | |
tree | ea92242734bb94960f215a352b1774938f578cc3 /drivers/iommu/irq_remapping.c | |
parent | 71054d8841b442bb3d8be60bde2bfac0483c19da (diff) |
x86, msi: Use IRQ remapping specific setup_msi_irqs routine
Use seperate routines to setup MSI IRQs for both
irq_remapping_enabled cases.
Signed-off-by: Joerg Roedel <joro@8bytes.org>
Acked-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/iommu/irq_remapping.c')
-rw-r--r-- | drivers/iommu/irq_remapping.c | 112 |
1 files changed, 109 insertions, 3 deletions
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 0baad3b9ecba..20f04b67efd2 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c | |||
@@ -4,6 +4,8 @@ | |||
4 | #include <linux/cpumask.h> | 4 | #include <linux/cpumask.h> |
5 | #include <linux/errno.h> | 5 | #include <linux/errno.h> |
6 | #include <linux/msi.h> | 6 | #include <linux/msi.h> |
7 | #include <linux/irq.h> | ||
8 | #include <linux/pci.h> | ||
7 | 9 | ||
8 | #include <asm/hw_irq.h> | 10 | #include <asm/hw_irq.h> |
9 | #include <asm/irq_remapping.h> | 11 | #include <asm/irq_remapping.h> |
@@ -21,6 +23,10 @@ int no_x2apic_optout; | |||
21 | 23 | ||
22 | static struct irq_remap_ops *remap_ops; | 24 | static struct irq_remap_ops *remap_ops; |
23 | 25 | ||
26 | static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); | ||
27 | static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | ||
28 | int index, int sub_handle); | ||
29 | |||
24 | static void irq_remapping_disable_io_apic(void) | 30 | static void irq_remapping_disable_io_apic(void) |
25 | { | 31 | { |
26 | /* | 32 | /* |
@@ -34,9 +40,109 @@ static void irq_remapping_disable_io_apic(void) | |||
34 | disconnect_bsp_APIC(0); | 40 | disconnect_bsp_APIC(0); |
35 | } | 41 | } |
36 | 42 | ||
43 | static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) | ||
44 | { | ||
45 | int node, ret, sub_handle, index = 0; | ||
46 | unsigned int irq; | ||
47 | struct msi_desc *msidesc; | ||
48 | |||
49 | nvec = __roundup_pow_of_two(nvec); | ||
50 | |||
51 | WARN_ON(!list_is_singular(&dev->msi_list)); | ||
52 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
53 | WARN_ON(msidesc->irq); | ||
54 | WARN_ON(msidesc->msi_attrib.multiple); | ||
55 | |||
56 | node = dev_to_node(&dev->dev); | ||
57 | irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); | ||
58 | if (irq == 0) | ||
59 | return -ENOSPC; | ||
60 | |||
61 | msidesc->msi_attrib.multiple = ilog2(nvec); | ||
62 | for (sub_handle = 0; sub_handle < nvec; sub_handle++) { | ||
63 | if (!sub_handle) { | ||
64 | index = msi_alloc_remapped_irq(dev, irq, nvec); | ||
65 | if (index < 0) { | ||
66 | ret = index; | ||
67 | goto error; | ||
68 | } | ||
69 | } else { | ||
70 | ret = msi_setup_remapped_irq(dev, irq + sub_handle, | ||
71 | index, sub_handle); | ||
72 | if (ret < 0) | ||
73 | goto error; | ||
74 | } | ||
75 | ret = setup_msi_irq(dev, msidesc, irq, sub_handle); | ||
76 | if (ret < 0) | ||
77 | goto error; | ||
78 | } | ||
79 | return 0; | ||
80 | |||
81 | error: | ||
82 | destroy_irqs(irq, nvec); | ||
83 | |||
84 | /* | ||
85 | * Restore altered MSI descriptor fields and prevent just destroyed | ||
86 | * IRQs from tearing down again in default_teardown_msi_irqs() | ||
87 | */ | ||
88 | msidesc->irq = 0; | ||
89 | msidesc->msi_attrib.multiple = 0; | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static int do_setup_msix_irqs(struct pci_dev *dev, int nvec) | ||
95 | { | ||
96 | int node, ret, sub_handle, index = 0; | ||
97 | struct msi_desc *msidesc; | ||
98 | unsigned int irq; | ||
99 | |||
100 | node = dev_to_node(&dev->dev); | ||
101 | irq = get_nr_irqs_gsi(); | ||
102 | sub_handle = 0; | ||
103 | |||
104 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
105 | |||
106 | irq = create_irq_nr(irq, node); | ||
107 | if (irq == 0) | ||
108 | return -1; | ||
109 | |||
110 | if (sub_handle == 0) | ||
111 | ret = index = msi_alloc_remapped_irq(dev, irq, nvec); | ||
112 | else | ||
113 | ret = msi_setup_remapped_irq(dev, irq, index, sub_handle); | ||
114 | |||
115 | if (ret < 0) | ||
116 | goto error; | ||
117 | |||
118 | ret = setup_msi_irq(dev, msidesc, irq, 0); | ||
119 | if (ret < 0) | ||
120 | goto error; | ||
121 | |||
122 | sub_handle += 1; | ||
123 | irq += 1; | ||
124 | } | ||
125 | |||
126 | return 0; | ||
127 | |||
128 | error: | ||
129 | destroy_irq(irq); | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static int irq_remapping_setup_msi_irqs(struct pci_dev *dev, | ||
134 | int nvec, int type) | ||
135 | { | ||
136 | if (type == PCI_CAP_ID_MSI) | ||
137 | return do_setup_msi_irqs(dev, nvec); | ||
138 | else | ||
139 | return do_setup_msix_irqs(dev, nvec); | ||
140 | } | ||
141 | |||
37 | static void __init irq_remapping_modify_x86_ops(void) | 142 | static void __init irq_remapping_modify_x86_ops(void) |
38 | { | 143 | { |
39 | x86_io_apic_ops.disable = irq_remapping_disable_io_apic; | 144 | x86_io_apic_ops.disable = irq_remapping_disable_io_apic; |
145 | x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; | ||
40 | x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; | 146 | x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; |
41 | } | 147 | } |
42 | 148 | ||
@@ -186,7 +292,7 @@ void compose_remapped_msi_msg(struct pci_dev *pdev, | |||
186 | remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); | 292 | remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); |
187 | } | 293 | } |
188 | 294 | ||
189 | int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) | 295 | static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) |
190 | { | 296 | { |
191 | if (!remap_ops || !remap_ops->msi_alloc_irq) | 297 | if (!remap_ops || !remap_ops->msi_alloc_irq) |
192 | return -ENODEV; | 298 | return -ENODEV; |
@@ -194,8 +300,8 @@ int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) | |||
194 | return remap_ops->msi_alloc_irq(pdev, irq, nvec); | 300 | return remap_ops->msi_alloc_irq(pdev, irq, nvec); |
195 | } | 301 | } |
196 | 302 | ||
197 | int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | 303 | static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, |
198 | int index, int sub_handle) | 304 | int index, int sub_handle) |
199 | { | 305 | { |
200 | if (!remap_ops || !remap_ops->msi_setup_irq) | 306 | if (!remap_ops || !remap_ops->msi_setup_irq) |
201 | return -ENODEV; | 307 | return -ENODEV; |