diff options
Diffstat (limited to 'drivers/pci/intr_remapping.c')
| -rw-r--r-- | drivers/pci/intr_remapping.c | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 2de5a3238c94..f78371b22529 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
| 6 | #include <linux/irq.h> | 6 | #include <linux/irq.h> |
| 7 | #include <asm/io_apic.h> | 7 | #include <asm/io_apic.h> |
| 8 | #include <asm/smp.h> | ||
| 8 | #include <linux/intel-iommu.h> | 9 | #include <linux/intel-iommu.h> |
| 9 | #include "intr_remapping.h" | 10 | #include "intr_remapping.h" |
| 10 | 11 | ||
| @@ -19,17 +20,75 @@ struct irq_2_iommu { | |||
| 19 | u8 irte_mask; | 20 | u8 irte_mask; |
| 20 | }; | 21 | }; |
| 21 | 22 | ||
| 22 | static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; | 23 | #ifdef CONFIG_SPARSE_IRQ |
| 24 | static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu) | ||
| 25 | { | ||
| 26 | struct irq_2_iommu *iommu; | ||
| 27 | int node; | ||
| 28 | |||
| 29 | node = cpu_to_node(cpu); | ||
| 30 | |||
| 31 | iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node); | ||
| 32 | printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node); | ||
| 33 | |||
| 34 | return iommu; | ||
| 35 | } | ||
| 23 | 36 | ||
| 24 | static struct irq_2_iommu *irq_2_iommu(unsigned int irq) | 37 | static struct irq_2_iommu *irq_2_iommu(unsigned int irq) |
| 25 | { | 38 | { |
| 26 | return (irq < nr_irqs) ? irq_2_iommuX + irq : NULL; | 39 | struct irq_desc *desc; |
| 40 | |||
| 41 | desc = irq_to_desc(irq); | ||
| 42 | |||
| 43 | if (WARN_ON_ONCE(!desc)) | ||
| 44 | return NULL; | ||
| 45 | |||
| 46 | return desc->irq_2_iommu; | ||
| 47 | } | ||
| 48 | |||
| 49 | static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) | ||
| 50 | { | ||
| 51 | struct irq_desc *desc; | ||
| 52 | struct irq_2_iommu *irq_iommu; | ||
| 53 | |||
| 54 | /* | ||
| 55 | * alloc irq desc if not allocated already. | ||
| 56 | */ | ||
| 57 | desc = irq_to_desc_alloc_cpu(irq, cpu); | ||
| 58 | if (!desc) { | ||
| 59 | printk(KERN_INFO "can not get irq_desc for %d\n", irq); | ||
| 60 | return NULL; | ||
| 61 | } | ||
| 62 | |||
| 63 | irq_iommu = desc->irq_2_iommu; | ||
| 64 | |||
| 65 | if (!irq_iommu) | ||
| 66 | desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu); | ||
| 67 | |||
| 68 | return desc->irq_2_iommu; | ||
| 27 | } | 69 | } |
| 28 | 70 | ||
| 29 | static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) | 71 | static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) |
| 30 | { | 72 | { |
| 73 | return irq_2_iommu_alloc_cpu(irq, boot_cpu_id); | ||
| 74 | } | ||
| 75 | |||
| 76 | #else /* !CONFIG_SPARSE_IRQ */ | ||
| 77 | |||
| 78 | static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; | ||
| 79 | |||
| 80 | static struct irq_2_iommu *irq_2_iommu(unsigned int irq) | ||
| 81 | { | ||
| 82 | if (irq < nr_irqs) | ||
| 83 | return &irq_2_iommuX[irq]; | ||
| 84 | |||
| 85 | return NULL; | ||
| 86 | } | ||
| 87 | static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) | ||
| 88 | { | ||
| 31 | return irq_2_iommu(irq); | 89 | return irq_2_iommu(irq); |
| 32 | } | 90 | } |
| 91 | #endif | ||
| 33 | 92 | ||
| 34 | static DEFINE_SPINLOCK(irq_2_ir_lock); | 93 | static DEFINE_SPINLOCK(irq_2_ir_lock); |
| 35 | 94 | ||
| @@ -86,9 +145,11 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
| 86 | if (!count) | 145 | if (!count) |
| 87 | return -1; | 146 | return -1; |
| 88 | 147 | ||
| 148 | #ifndef CONFIG_SPARSE_IRQ | ||
| 89 | /* protect irq_2_iommu_alloc later */ | 149 | /* protect irq_2_iommu_alloc later */ |
| 90 | if (irq >= nr_irqs) | 150 | if (irq >= nr_irqs) |
| 91 | return -1; | 151 | return -1; |
| 152 | #endif | ||
| 92 | 153 | ||
| 93 | /* | 154 | /* |
| 94 | * start the IRTE search from index 0. | 155 | * start the IRTE search from index 0. |
| @@ -130,6 +191,12 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
| 130 | table->base[i].present = 1; | 191 | table->base[i].present = 1; |
| 131 | 192 | ||
| 132 | irq_iommu = irq_2_iommu_alloc(irq); | 193 | irq_iommu = irq_2_iommu_alloc(irq); |
| 194 | if (!irq_iommu) { | ||
| 195 | spin_unlock(&irq_2_ir_lock); | ||
| 196 | printk(KERN_ERR "can't allocate irq_2_iommu\n"); | ||
| 197 | return -1; | ||
| 198 | } | ||
| 199 | |||
| 133 | irq_iommu->iommu = iommu; | 200 | irq_iommu->iommu = iommu; |
| 134 | irq_iommu->irte_index = index; | 201 | irq_iommu->irte_index = index; |
| 135 | irq_iommu->sub_handle = 0; | 202 | irq_iommu->sub_handle = 0; |
| @@ -177,6 +244,12 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | |||
| 177 | 244 | ||
| 178 | irq_iommu = irq_2_iommu_alloc(irq); | 245 | irq_iommu = irq_2_iommu_alloc(irq); |
| 179 | 246 | ||
| 247 | if (!irq_iommu) { | ||
| 248 | spin_unlock(&irq_2_ir_lock); | ||
| 249 | printk(KERN_ERR "can't allocate irq_2_iommu\n"); | ||
| 250 | return -1; | ||
| 251 | } | ||
| 252 | |||
| 180 | irq_iommu->iommu = iommu; | 253 | irq_iommu->iommu = iommu; |
| 181 | irq_iommu->irte_index = index; | 254 | irq_iommu->irte_index = index; |
| 182 | irq_iommu->sub_handle = subhandle; | 255 | irq_iommu->sub_handle = subhandle; |
