1 From: Suresh Siddha <suresh.b.siddha@intel.com>
2 Subject: x64, x2apic/intr-remap: routines managing Interrupt remapping table entries.
3 References: fate #303948 and fate #303984
4 Patch-Mainline: queued for .28
5 Commit-ID: b6fcb33ad6c05f152a672f7c96c1fab006527b80
7 Signed-off-by: Thomas Renninger <trenn@suse.de>
9 Routines handling the management of interrupt remapping table entries.
11 Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
12 Cc: akpm@linux-foundation.org
13 Cc: arjan@linux.intel.com
14 Cc: andi@firstfloor.org
15 Cc: ebiederm@xmission.com
16 Cc: jbarnes@virtuousgeek.org
18 Signed-off-by: Ingo Molnar <mingo@elte.hu>
21 drivers/pci/intel-iommu.h | 4
22 drivers/pci/intr_remapping.c | 243 +++++++++++++++++++++++++++++++++++++++++++
23 include/linux/dmar.h | 12 ++
24 3 files changed, 259 insertions(+)
26 Index: linux-2.6.26/drivers/pci/intel-iommu.h
27 ===================================================================
28 --- linux-2.6.26.orig/drivers/pci/intel-iommu.h
29 +++ linux-2.6.26/drivers/pci/intel-iommu.h
30 @@ -123,6 +123,7 @@ static inline void dmar_writeq(void __io
31 #define ecap_qis(e) ((e) & 0x2)
32 #define ecap_eim_support(e) ((e >> 4) & 0x1)
33 #define ecap_ir_support(e) ((e >> 3) & 0x1)
34 +#define ecap_max_handle_mask(e) ((e >> 20) & 0xf)
38 @@ -255,6 +256,8 @@ struct q_inval {
39 #define INTR_REMAP_PAGE_ORDER 8
40 #define INTR_REMAP_TABLE_REG_SIZE 0xf
42 +#define INTR_REMAP_TABLE_ENTRIES 65536
47 @@ -300,4 +303,5 @@ extern void free_iommu(struct intel_iomm
48 extern int dmar_enable_qi(struct intel_iommu *iommu);
49 extern void qi_global_iec(struct intel_iommu *iommu);
51 +extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
53 Index: linux-2.6.26/drivers/pci/intr_remapping.c
54 ===================================================================
55 --- linux-2.6.26.orig/drivers/pci/intr_remapping.c
56 +++ linux-2.6.26/drivers/pci/intr_remapping.c
58 #include <linux/spinlock.h>
59 #include <linux/jiffies.h>
60 #include <linux/pci.h>
61 +#include <linux/irq.h>
62 #include <asm/io_apic.h>
63 #include "intel-iommu.h"
64 #include "intr_remapping.h"
65 @@ -10,6 +11,248 @@ static struct ioapic_scope ir_ioapic[MAX
66 static int ir_ioapic_num;
67 int intr_remapping_enabled;
70 + struct intel_iommu *iommu;
74 +} irq_2_iommu[NR_IRQS];
76 +static DEFINE_SPINLOCK(irq_2_ir_lock);
78 +int irq_remapped(int irq)
83 + if (!irq_2_iommu[irq].iommu)
89 +int get_irte(int irq, struct irte *entry)
93 + if (!entry || irq > NR_IRQS)
96 + spin_lock(&irq_2_ir_lock);
97 + if (!irq_2_iommu[irq].iommu) {
98 + spin_unlock(&irq_2_ir_lock);
102 + index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
103 + *entry = *(irq_2_iommu[irq].iommu->ir_table->base + index);
105 + spin_unlock(&irq_2_ir_lock);
109 +int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
111 + struct ir_table *table = iommu->ir_table;
112 + u16 index, start_index;
113 + unsigned int mask = 0;
120 + * start the IRTE search from index 0.
122 + index = start_index = 0;
125 + count = __roundup_pow_of_two(count);
126 + mask = ilog2(count);
129 + if (mask > ecap_max_handle_mask(iommu->ecap)) {
131 + "Requested mask %x exceeds the max invalidation handle"
132 + " mask value %Lx\n", mask,
133 + ecap_max_handle_mask(iommu->ecap));
137 + spin_lock(&irq_2_ir_lock);
139 + for (i = index; i < index + count; i++)
140 + if (table->base[i].present)
142 + /* empty index found */
143 + if (i == index + count)
146 + index = (index + count) % INTR_REMAP_TABLE_ENTRIES;
148 + if (index == start_index) {
149 + spin_unlock(&irq_2_ir_lock);
150 + printk(KERN_ERR "can't allocate an IRTE\n");
155 + for (i = index; i < index + count; i++)
156 + table->base[i].present = 1;
158 + irq_2_iommu[irq].iommu = iommu;
159 + irq_2_iommu[irq].irte_index = index;
160 + irq_2_iommu[irq].sub_handle = 0;
161 + irq_2_iommu[irq].irte_mask = mask;
163 + spin_unlock(&irq_2_ir_lock);
168 +static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
170 + struct qi_desc desc;
172 + desc.low = QI_IEC_IIDEX(index) | QI_IEC_TYPE | QI_IEC_IM(mask)
173 + | QI_IEC_SELECTIVE;
176 + qi_submit_sync(&desc, iommu);
179 +int map_irq_to_irte_handle(int irq, u16 *sub_handle)
183 + spin_lock(&irq_2_ir_lock);
184 + if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
185 + spin_unlock(&irq_2_ir_lock);
189 + *sub_handle = irq_2_iommu[irq].sub_handle;
190 + index = irq_2_iommu[irq].irte_index;
191 + spin_unlock(&irq_2_ir_lock);
195 +int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
197 + spin_lock(&irq_2_ir_lock);
198 + if (irq >= NR_IRQS || irq_2_iommu[irq].iommu) {
199 + spin_unlock(&irq_2_ir_lock);
203 + irq_2_iommu[irq].iommu = iommu;
204 + irq_2_iommu[irq].irte_index = index;
205 + irq_2_iommu[irq].sub_handle = subhandle;
206 + irq_2_iommu[irq].irte_mask = 0;
208 + spin_unlock(&irq_2_ir_lock);
213 +int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
215 + spin_lock(&irq_2_ir_lock);
216 + if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
217 + spin_unlock(&irq_2_ir_lock);
221 + irq_2_iommu[irq].iommu = NULL;
222 + irq_2_iommu[irq].irte_index = 0;
223 + irq_2_iommu[irq].sub_handle = 0;
224 + irq_2_iommu[irq].irte_mask = 0;
226 + spin_unlock(&irq_2_ir_lock);
231 +int modify_irte(int irq, struct irte *irte_modified)
235 + struct intel_iommu *iommu;
237 + spin_lock(&irq_2_ir_lock);
238 + if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
239 + spin_unlock(&irq_2_ir_lock);
243 + iommu = irq_2_iommu[irq].iommu;
245 + index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
246 + irte = &iommu->ir_table->base[index];
248 + set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1));
249 + __iommu_flush_cache(iommu, irte, sizeof(*irte));
251 + qi_flush_iec(iommu, index, 0);
253 + spin_unlock(&irq_2_ir_lock);
257 +int flush_irte(int irq)
260 + struct intel_iommu *iommu;
262 + spin_lock(&irq_2_ir_lock);
263 + if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
264 + spin_unlock(&irq_2_ir_lock);
268 + iommu = irq_2_iommu[irq].iommu;
270 + index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
272 + qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
273 + spin_unlock(&irq_2_ir_lock);
278 +int free_irte(int irq)
282 + struct intel_iommu *iommu;
284 + spin_lock(&irq_2_ir_lock);
285 + if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) {
286 + spin_unlock(&irq_2_ir_lock);
290 + iommu = irq_2_iommu[irq].iommu;
292 + index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle;
293 + irte = &iommu->ir_table->base[index];
295 + if (!irq_2_iommu[irq].sub_handle) {
296 + for (i = 0; i < (1 << irq_2_iommu[irq].irte_mask); i++)
297 + set_64bit((unsigned long *)irte, 0);
298 + qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask);
301 + irq_2_iommu[irq].iommu = NULL;
302 + irq_2_iommu[irq].irte_index = 0;
303 + irq_2_iommu[irq].sub_handle = 0;
304 + irq_2_iommu[irq].irte_mask = 0;
306 + spin_unlock(&irq_2_ir_lock);
311 static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
314 Index: linux-2.6.26/include/linux/dmar.h
315 ===================================================================
316 --- linux-2.6.26.orig/include/linux/dmar.h
317 +++ linux-2.6.26/include/linux/dmar.h
318 @@ -98,7 +98,19 @@ struct irte {
322 +extern int get_irte(int irq, struct irte *entry);
323 +extern int modify_irte(int irq, struct irte *irte_modified);
324 +extern int alloc_irte(struct intel_iommu *iommu, int irq, u16 count);
325 +extern int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index,
327 +extern int map_irq_to_irte_handle(int irq, u16 *sub_handle);
328 +extern int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index);
329 +extern int flush_irte(int irq);
330 +extern int free_irte(int irq);
332 +extern int irq_remapped(int irq);
334 +#define irq_remapped(irq) (0)
335 #define enable_intr_remapping(mode) (-1)
336 #define intr_remapping_enabled (0)