Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+126 -110
-12
arch/x86/include/asm/irq_remapping.h
··· 47 47 extern void compose_remapped_msi_msg(struct pci_dev *pdev, 48 48 unsigned int irq, unsigned int dest, 49 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 50 extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id); 54 51 55 52 #else /* CONFIG_IRQ_REMAP */ ··· 79 82 unsigned int irq, unsigned int dest, 80 83 struct msi_msg *msg, u8 hpet_id) 81 84 { 82 - } 83 - static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) 84 - { 85 - return -ENODEV; 86 - } 87 - static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, 88 - int index, int sub_handle) 89 - { 90 - return -ENODEV; 91 85 } 92 86 static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) 93 87 {
+3
arch/x86/include/asm/pci.h
··· 121 121 #define arch_teardown_msi_irq x86_teardown_msi_irq 122 122 #define arch_restore_msi_irqs x86_restore_msi_irqs 123 123 /* implemented in arch/x86/kernel/apic/io_apic. */ 124 + struct msi_desc; 124 125 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); 125 126 void native_teardown_msi_irq(unsigned int irq); 126 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 130 /* default to the implementation in drivers/lib/msi.c */ 128 131 #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS 129 132 #define HAVE_DEFAULT_MSI_RESTORE_IRQS
+11 -95
arch/x86/kernel/apic/io_apic.c
··· 3066 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 3071 unsigned int i; 3072 3072 ··· 3165 3165 .irq_retrigger = ioapic_retrigger_irq, 3166 3166 }; 3167 3167 3168 - static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, 3169 - unsigned int irq_base, unsigned int irq_offset) 3168 + int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, 3169 + unsigned int irq_base, unsigned int irq_offset) 3170 3170 { 3171 3171 struct irq_chip *chip = &msi_chip; 3172 3172 struct msi_msg msg; ··· 3198 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 3203 unsigned int irq, irq_want; 3205 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 3211 node = dev_to_node(&dev->dev); 3208 3212 irq_want = nr_irqs_gsi; 3209 - sub_handle = 0; 3210 3213 list_for_each_entry(msidesc, &dev->msi_list, list) { 3211 3214 irq = create_irq_nr(irq_want, node); 3212 3215 if (irq == 0) 3213 3216 return -ENOSPC; 3214 - irq_want = irq + 1; 3215 - if (!irq_remapping_enabled) 3216 - goto no_ir; 3217 3217 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: 3218 + irq_want = irq + 1; 3219 + 3235 3220 ret = setup_msi_irq(dev, msidesc, irq, 0); 3236 3221 if (ret < 0) 3237 3222 goto error; 3238 - sub_handle++; 3239 3223 } 3240 3224 return 0; 3241 3225 3242 3226 error: 3243 3227 destroy_irq(irq); 3244 3228 return ret; 3245 - } 3246 - 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 3229 } 3314 3230 3315 3231 void native_teardown_msi_irq(unsigned int irq)
+109 -3
drivers/iommu/irq_remapping.c
··· 4 4 #include <linux/cpumask.h> 5 5 #include <linux/errno.h> 6 6 #include <linux/msi.h> 7 + #include <linux/irq.h> 8 + #include <linux/pci.h> 7 9 8 10 #include <asm/hw_irq.h> 9 11 #include <asm/irq_remapping.h> ··· 23 21 24 22 static struct irq_remap_ops *remap_ops; 25 23 24 + static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); 25 + static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, 26 + int index, int sub_handle); 27 + 26 28 static void irq_remapping_disable_io_apic(void) 27 29 { 28 30 /* ··· 40 34 disconnect_bsp_APIC(0); 41 35 } 42 36 37 + static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) 38 + { 39 + int node, ret, sub_handle, index = 0; 40 + unsigned int irq; 41 + struct msi_desc *msidesc; 42 + 43 + nvec = __roundup_pow_of_two(nvec); 44 + 45 + WARN_ON(!list_is_singular(&dev->msi_list)); 46 + msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); 47 + WARN_ON(msidesc->irq); 48 + WARN_ON(msidesc->msi_attrib.multiple); 49 + 50 + node = dev_to_node(&dev->dev); 51 + irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); 52 + if (irq == 0) 53 + return -ENOSPC; 54 + 55 + msidesc->msi_attrib.multiple = ilog2(nvec); 56 + for (sub_handle = 0; sub_handle < nvec; sub_handle++) { 57 + if (!sub_handle) { 58 + index = msi_alloc_remapped_irq(dev, irq, nvec); 59 + if (index < 0) { 60 + ret = index; 61 + goto error; 62 + } 63 + } else { 64 + ret = msi_setup_remapped_irq(dev, irq + sub_handle, 65 + index, sub_handle); 66 + if (ret < 0) 67 + goto error; 68 + } 69 + ret = setup_msi_irq(dev, msidesc, irq, sub_handle); 70 + if (ret < 0) 71 + goto error; 72 + } 73 + return 0; 74 + 75 + error: 76 + destroy_irqs(irq, nvec); 77 + 78 + /* 79 + * Restore altered MSI descriptor fields and prevent just destroyed 80 + * IRQs from tearing down again in default_teardown_msi_irqs() 81 + */ 82 + msidesc->irq = 0; 83 + msidesc->msi_attrib.multiple = 0; 84 + 85 + return ret; 86 + } 87 + 88 + static int do_setup_msix_irqs(struct pci_dev *dev, int nvec) 89 + { 90 + int node, ret, sub_handle, index = 0; 91 + struct msi_desc *msidesc; 92 + unsigned int irq; 93 + 94 + node = dev_to_node(&dev->dev); 95 + irq = get_nr_irqs_gsi(); 96 + sub_handle = 0; 97 + 98 + list_for_each_entry(msidesc, &dev->msi_list, list) { 99 + 100 + irq = create_irq_nr(irq, node); 101 + if (irq == 0) 102 + return -1; 103 + 104 + if (sub_handle == 0) 105 + ret = index = msi_alloc_remapped_irq(dev, irq, nvec); 106 + else 107 + ret = msi_setup_remapped_irq(dev, irq, index, sub_handle); 108 + 109 + if (ret < 0) 110 + goto error; 111 + 112 + ret = setup_msi_irq(dev, msidesc, irq, 0); 113 + if (ret < 0) 114 + goto error; 115 + 116 + sub_handle += 1; 117 + irq += 1; 118 + } 119 + 120 + return 0; 121 + 122 + error: 123 + destroy_irq(irq); 124 + return ret; 125 + } 126 + 127 + static int irq_remapping_setup_msi_irqs(struct pci_dev *dev, 128 + int nvec, int type) 129 + { 130 + if (type == PCI_CAP_ID_MSI) 131 + return do_setup_msi_irqs(dev, nvec); 132 + else 133 + return do_setup_msix_irqs(dev, nvec); 134 + } 135 + 43 136 static void __init irq_remapping_modify_x86_ops(void) 44 137 { 45 138 x86_io_apic_ops.disable = irq_remapping_disable_io_apic; 139 + x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; 46 140 x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; 47 141 } 48 142 ··· 292 186 remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); 293 187 } 294 188 295 - int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) 189 + static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) 296 190 { 297 191 if (!remap_ops || !remap_ops->msi_alloc_irq) 298 192 return -ENODEV; ··· 300 194 return remap_ops->msi_alloc_irq(pdev, irq, nvec); 301 195 } 302 196 303 - int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, 304 - int index, int sub_handle) 197 + static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, 198 + int index, int sub_handle) 305 199 { 306 200 if (!remap_ops || !remap_ops->msi_setup_irq) 307 201 return -ENODEV;
+3
include/linux/irq.h
··· 509 509 510 510 /* Handle dynamic irq creation and destruction */ 511 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 514 extern int create_irq(void); 513 515 extern void destroy_irq(unsigned int irq); 516 + extern void destroy_irqs(unsigned int irq, unsigned int count); 514 517 515 518 /* 516 519 * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and