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 | |
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>
-rw-r--r-- | arch/x86/include/asm/irq_remapping.h | 12 | ||||
-rw-r--r-- | arch/x86/include/asm/pci.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 104 | ||||
-rw-r--r-- | drivers/iommu/irq_remapping.c | 112 | ||||
-rw-r--r-- | include/linux/irq.h | 3 |
5 files changed, 125 insertions, 109 deletions
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index 5fb9bbbd2f14..0ee1e88bd17a 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h | |||
@@ -47,9 +47,6 @@ extern void free_remapped_irq(int irq); | |||
47 | extern void compose_remapped_msi_msg(struct pci_dev *pdev, | 47 | extern void compose_remapped_msi_msg(struct pci_dev *pdev, |
48 | unsigned int irq, unsigned int dest, | 48 | unsigned int irq, unsigned int dest, |
49 | struct msi_msg *msg, u8 hpet_id); | 49 | struct msi_msg *msg, u8 hpet_id); |
50 | extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); | ||
51 | extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | ||
52 | int index, int sub_handle); | ||
53 | extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id); | 50 | extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id); |
54 | 51 | ||
55 | #else /* CONFIG_IRQ_REMAP */ | 52 | #else /* CONFIG_IRQ_REMAP */ |
@@ -83,15 +80,6 @@ static inline void compose_remapped_msi_msg(struct pci_dev *pdev, | |||
83 | struct msi_msg *msg, u8 hpet_id) | 80 | struct msi_msg *msg, u8 hpet_id) |
84 | { | 81 | { |
85 | } | 82 | } |
86 | static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) | ||
87 | { | ||
88 | return -ENODEV; | ||
89 | } | ||
90 | static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | ||
91 | int index, int sub_handle) | ||
92 | { | ||
93 | return -ENODEV; | ||
94 | } | ||
95 | static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) | 83 | static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) |
96 | { | 84 | { |
97 | return -ENODEV; | 85 | return -ENODEV; |
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index dba7805176bf..c28fd02f4bf7 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h | |||
@@ -121,9 +121,12 @@ static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq) | |||
121 | #define arch_teardown_msi_irq x86_teardown_msi_irq | 121 | #define arch_teardown_msi_irq x86_teardown_msi_irq |
122 | #define arch_restore_msi_irqs x86_restore_msi_irqs | 122 | #define arch_restore_msi_irqs x86_restore_msi_irqs |
123 | /* implemented in arch/x86/kernel/apic/io_apic. */ | 123 | /* implemented in arch/x86/kernel/apic/io_apic. */ |
124 | struct msi_desc; | ||
124 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); | 125 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); |
125 | void native_teardown_msi_irq(unsigned int irq); | 126 | void native_teardown_msi_irq(unsigned int irq); |
126 | void native_restore_msi_irqs(struct pci_dev *dev, int irq); | 127 | void native_restore_msi_irqs(struct pci_dev *dev, int irq); |
128 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | ||
129 | unsigned int irq_base, unsigned int irq_offset); | ||
127 | /* default to the implementation in drivers/lib/msi.c */ | 130 | /* default to the implementation in drivers/lib/msi.c */ |
128 | #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS | 131 | #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS |
129 | #define HAVE_DEFAULT_MSI_RESTORE_IRQS | 132 | #define HAVE_DEFAULT_MSI_RESTORE_IRQS |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e7b87630c13d..d4b045e018fb 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -3066,7 +3066,7 @@ void destroy_irq(unsigned int irq) | |||
3066 | free_irq_at(irq, cfg); | 3066 | free_irq_at(irq, cfg); |
3067 | } | 3067 | } |
3068 | 3068 | ||
3069 | static inline void destroy_irqs(unsigned int irq, unsigned int count) | 3069 | void destroy_irqs(unsigned int irq, unsigned int count) |
3070 | { | 3070 | { |
3071 | unsigned int i; | 3071 | unsigned int i; |
3072 | 3072 | ||
@@ -3165,8 +3165,8 @@ static struct irq_chip msi_chip = { | |||
3165 | .irq_retrigger = ioapic_retrigger_irq, | 3165 | .irq_retrigger = ioapic_retrigger_irq, |
3166 | }; | 3166 | }; |
3167 | 3167 | ||
3168 | static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | 3168 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
3169 | unsigned int irq_base, unsigned int irq_offset) | 3169 | unsigned int irq_base, unsigned int irq_offset) |
3170 | { | 3170 | { |
3171 | struct irq_chip *chip = &msi_chip; | 3171 | struct irq_chip *chip = &msi_chip; |
3172 | struct msi_msg msg; | 3172 | struct msi_msg msg; |
@@ -3198,44 +3198,28 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | |||
3198 | return 0; | 3198 | return 0; |
3199 | } | 3199 | } |
3200 | 3200 | ||
3201 | int setup_msix_irqs(struct pci_dev *dev, int nvec) | 3201 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
3202 | { | 3202 | { |
3203 | int node, ret, sub_handle, index = 0; | ||
3204 | unsigned int irq, irq_want; | 3203 | unsigned int irq, irq_want; |
3205 | struct msi_desc *msidesc; | 3204 | struct msi_desc *msidesc; |
3205 | int node, ret; | ||
3206 | |||
3207 | /* Multiple MSI vectors only supported with interrupt remapping */ | ||
3208 | if (type == PCI_CAP_ID_MSI && nvec > 1) | ||
3209 | return 1; | ||
3206 | 3210 | ||
3207 | node = dev_to_node(&dev->dev); | 3211 | node = dev_to_node(&dev->dev); |
3208 | irq_want = nr_irqs_gsi; | 3212 | irq_want = nr_irqs_gsi; |
3209 | sub_handle = 0; | ||
3210 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 3213 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
3211 | irq = create_irq_nr(irq_want, node); | 3214 | irq = create_irq_nr(irq_want, node); |
3212 | if (irq == 0) | 3215 | if (irq == 0) |
3213 | return -ENOSPC; | 3216 | return -ENOSPC; |
3217 | |||
3214 | irq_want = irq + 1; | 3218 | irq_want = irq + 1; |
3215 | if (!irq_remapping_enabled) | ||
3216 | goto no_ir; | ||
3217 | 3219 | ||
3218 | if (!sub_handle) { | ||
3219 | /* | ||
3220 | * allocate the consecutive block of IRTE's | ||
3221 | * for 'nvec' | ||
3222 | */ | ||
3223 | index = msi_alloc_remapped_irq(dev, irq, nvec); | ||
3224 | if (index < 0) { | ||
3225 | ret = index; | ||
3226 | goto error; | ||
3227 | } | ||
3228 | } else { | ||
3229 | ret = msi_setup_remapped_irq(dev, irq, index, | ||
3230 | sub_handle); | ||
3231 | if (ret < 0) | ||
3232 | goto error; | ||
3233 | } | ||
3234 | no_ir: | ||
3235 | ret = setup_msi_irq(dev, msidesc, irq, 0); | 3220 | ret = setup_msi_irq(dev, msidesc, irq, 0); |
3236 | if (ret < 0) | 3221 | if (ret < 0) |
3237 | goto error; | 3222 | goto error; |
3238 | sub_handle++; | ||
3239 | } | 3223 | } |
3240 | return 0; | 3224 | return 0; |
3241 | 3225 | ||
@@ -3244,74 +3228,6 @@ error: | |||
3244 | return ret; | 3228 | return ret; |
3245 | } | 3229 | } |
3246 | 3230 | ||
3247 | int setup_msi_irqs(struct pci_dev *dev, int nvec) | ||
3248 | { | ||
3249 | int node, ret, sub_handle, index = 0; | ||
3250 | unsigned int irq; | ||
3251 | struct msi_desc *msidesc; | ||
3252 | |||
3253 | if (nvec > 1 && !irq_remapping_enabled) | ||
3254 | return 1; | ||
3255 | |||
3256 | nvec = __roundup_pow_of_two(nvec); | ||
3257 | |||
3258 | WARN_ON(!list_is_singular(&dev->msi_list)); | ||
3259 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
3260 | WARN_ON(msidesc->irq); | ||
3261 | WARN_ON(msidesc->msi_attrib.multiple); | ||
3262 | |||
3263 | node = dev_to_node(&dev->dev); | ||
3264 | irq = __create_irqs(nr_irqs_gsi, nvec, node); | ||
3265 | if (irq == 0) | ||
3266 | return -ENOSPC; | ||
3267 | |||
3268 | if (!irq_remapping_enabled) { | ||
3269 | ret = setup_msi_irq(dev, msidesc, irq, 0); | ||
3270 | if (ret < 0) | ||
3271 | goto error; | ||
3272 | return 0; | ||
3273 | } | ||
3274 | |||
3275 | msidesc->msi_attrib.multiple = ilog2(nvec); | ||
3276 | for (sub_handle = 0; sub_handle < nvec; sub_handle++) { | ||
3277 | if (!sub_handle) { | ||
3278 | index = msi_alloc_remapped_irq(dev, irq, nvec); | ||
3279 | if (index < 0) { | ||
3280 | ret = index; | ||
3281 | goto error; | ||
3282 | } | ||
3283 | } else { | ||
3284 | ret = msi_setup_remapped_irq(dev, irq + sub_handle, | ||
3285 | index, sub_handle); | ||
3286 | if (ret < 0) | ||
3287 | goto error; | ||
3288 | } | ||
3289 | ret = setup_msi_irq(dev, msidesc, irq, sub_handle); | ||
3290 | if (ret < 0) | ||
3291 | goto error; | ||
3292 | } | ||
3293 | return 0; | ||
3294 | |||
3295 | error: | ||
3296 | destroy_irqs(irq, nvec); | ||
3297 | |||
3298 | /* | ||
3299 | * Restore altered MSI descriptor fields and prevent just destroyed | ||
3300 | * IRQs from tearing down again in default_teardown_msi_irqs() | ||
3301 | */ | ||
3302 | msidesc->irq = 0; | ||
3303 | msidesc->msi_attrib.multiple = 0; | ||
3304 | |||
3305 | return ret; | ||
3306 | } | ||
3307 | |||
3308 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
3309 | { | ||
3310 | if (type == PCI_CAP_ID_MSI) | ||
3311 | return setup_msi_irqs(dev, nvec); | ||
3312 | return setup_msix_irqs(dev, nvec); | ||
3313 | } | ||
3314 | |||
3315 | void native_teardown_msi_irq(unsigned int irq) | 3231 | void native_teardown_msi_irq(unsigned int irq) |
3316 | { | 3232 | { |
3317 | destroy_irq(irq); | 3233 | destroy_irq(irq); |
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; |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 1eab99111e94..bc4e06611958 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -509,8 +509,11 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq) | |||
509 | 509 | ||
510 | /* Handle dynamic irq creation and destruction */ | 510 | /* Handle dynamic irq creation and destruction */ |
511 | extern unsigned int create_irq_nr(unsigned int irq_want, int node); | 511 | extern unsigned int create_irq_nr(unsigned int irq_want, int node); |
512 | extern unsigned int __create_irqs(unsigned int from, unsigned int count, | ||
513 | int node); | ||
512 | extern int create_irq(void); | 514 | extern int create_irq(void); |
513 | extern void destroy_irq(unsigned int irq); | 515 | extern void destroy_irq(unsigned int irq); |
516 | extern void destroy_irqs(unsigned int irq, unsigned int count); | ||
514 | 517 | ||
515 | /* | 518 | /* |
516 | * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and | 519 | * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and |