]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.arch/x2APIC_PATCH_09_of_41_2ae21010694e56461a63bfc80e960090ce0a5ed9
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / x2APIC_PATCH_09_of_41_2ae21010694e56461a63bfc80e960090ce0a5ed9
CommitLineData
2cb7cef9
BS
1From: Suresh Siddha <suresh.b.siddha@intel.com>
2Subject: x64, x2apic/intr-remap: Interrupt remapping infrastructure
3References: fate #303948 and fate #303984
4Patch-Mainline: queued for .28
5Commit-ID: 2ae21010694e56461a63bfc80e960090ce0a5ed9
6
7Signed-off-by: Thomas Renninger <trenn@suse.de>
8
9Interrupt remapping (part of Intel Virtualization Tech for directed I/O)
10infrastructure.
11
12Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
13Cc: akpm@linux-foundation.org
14Cc: arjan@linux.intel.com
15Cc: andi@firstfloor.org
16Cc: ebiederm@xmission.com
17Cc: jbarnes@virtuousgeek.org
18Cc: steiner@sgi.com
19Signed-off-by: Ingo Molnar <mingo@elte.hu>
20
21---
22 drivers/pci/dma_remapping.h | 2
23 drivers/pci/dmar.c | 16 +++++
24 drivers/pci/intel-iommu.c | 25 ++-----
25 drivers/pci/intel-iommu.h | 24 ++++++-
26 drivers/pci/intr_remapping.c | 137 +++++++++++++++++++++++++++++++++++++++++++
27 drivers/pci/intr_remapping.h | 2
28 include/linux/dmar.h | 120 ++++++++++++++++++++++++++-----------
29 7 files changed, 272 insertions(+), 54 deletions(-)
30
31--- a/drivers/pci/dmar.c
32+++ b/drivers/pci/dmar.c
33@@ -451,6 +451,22 @@ int __init early_dmar_detect(void)
34 return (ACPI_SUCCESS(status) ? 1 : 0);
35 }
36
37+void __init detect_intel_iommu(void)
38+{
39+ int ret;
40+
41+ ret = early_dmar_detect();
42+
43+#ifdef CONFIG_DMAR
44+ {
45+ if (ret && !no_iommu && !iommu_detected && !swiotlb &&
46+ !dmar_disabled)
47+ iommu_detected = 1;
48+ }
49+#endif
50+}
51+
52+
53 int alloc_iommu(struct dmar_drhd_unit *drhd)
54 {
55 struct intel_iommu *iommu;
56--- a/drivers/pci/dma_remapping.h
57+++ b/drivers/pci/dma_remapping.h
58@@ -145,6 +145,8 @@ struct device_domain_info {
59 extern int init_dmars(void);
60 extern void free_dmar_iommu(struct intel_iommu *iommu);
61
62+extern int dmar_disabled;
63+
64 #ifndef CONFIG_DMAR_GFX_WA
65 static inline void iommu_prepare_gfx_mapping(void)
66 {
67--- a/drivers/pci/intel-iommu.c
68+++ b/drivers/pci/intel-iommu.c
69@@ -78,7 +78,7 @@ static long list_size;
70
71 static void domain_remove_dev_info(struct dmar_domain *domain);
72
73-static int dmar_disabled;
74+int dmar_disabled;
75 static int __initdata dmar_map_gfx = 1;
76 static int dmar_forcedac;
77 static int intel_iommu_strict;
78@@ -2259,19 +2259,6 @@ static struct dmi_system_id __initdata i
79 { }
80 };
81
82-
83-void __init detect_intel_iommu(void)
84-{
85- if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
86- return;
87- if (early_dmar_detect()) {
88- dmi_check_system(intel_iommu_dmi_table);
89- if (dmar_disabled)
90- return;
91- iommu_detected = 1;
92- }
93-}
94-
95 static void __init init_no_remapping_devices(void)
96 {
97 struct dmar_drhd_unit *drhd;
98@@ -2318,15 +2305,19 @@ int __init intel_iommu_init(void)
99 {
100 int ret = 0;
101
102- if (no_iommu || swiotlb || dmar_disabled)
103- return -ENODEV;
104-
105 if (dmar_table_init())
106 return -ENODEV;
107
108 if (dmar_dev_scope_init())
109 return -ENODEV;
110
111+ /*
112+ * Check the need for DMA-remapping initialization now.
113+ * Above initialization will also be used by Interrupt-remapping.
114+ */
115+ if (no_iommu || swiotlb || dmar_disabled)
116+ return -ENODEV;
117+
118 iommu_init_mempool();
119 dmar_init_reserved_ranges();
120
121--- a/drivers/pci/intel-iommu.h
122+++ b/drivers/pci/intel-iommu.h
123@@ -56,6 +56,7 @@
124 #define DMAR_IQT_REG 0x88 /* Invalidation queue tail register */
125 #define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */
126 #define DMAR_ICS_REG 0x98 /* Invalidation complete status register */
127+#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */
128
129 #define OFFSET_STRIDE (9)
130 /*
131@@ -157,16 +158,20 @@ static inline void dmar_writeq(void __io
132 #define DMA_GCMD_SRTP (((u32)1) << 30)
133 #define DMA_GCMD_SFL (((u32)1) << 29)
134 #define DMA_GCMD_EAFL (((u32)1) << 28)
135-#define DMA_GCMD_QIE (((u32)1) << 26)
136 #define DMA_GCMD_WBF (((u32)1) << 27)
137+#define DMA_GCMD_QIE (((u32)1) << 26)
138+#define DMA_GCMD_SIRTP (((u32)1) << 24)
139+#define DMA_GCMD_IRE (((u32) 1) << 25)
140
141 /* GSTS_REG */
142 #define DMA_GSTS_TES (((u32)1) << 31)
143 #define DMA_GSTS_RTPS (((u32)1) << 30)
144 #define DMA_GSTS_FLS (((u32)1) << 29)
145 #define DMA_GSTS_AFLS (((u32)1) << 28)
146-#define DMA_GSTS_QIES (((u32)1) << 26)
147 #define DMA_GSTS_WBFS (((u32)1) << 27)
148+#define DMA_GSTS_QIES (((u32)1) << 26)
149+#define DMA_GSTS_IRTPS (((u32)1) << 24)
150+#define DMA_GSTS_IRES (((u32)1) << 25)
151
152 /* CCMD_REG */
153 #define DMA_CCMD_ICC (((u64)1) << 63)
154@@ -245,6 +250,16 @@ struct q_inval {
155 int free_cnt;
156 };
157
158+#ifdef CONFIG_INTR_REMAP
159+/* 1MB - maximum possible interrupt remapping table size */
160+#define INTR_REMAP_PAGE_ORDER 8
161+#define INTR_REMAP_TABLE_REG_SIZE 0xf
162+
163+struct ir_table {
164+ struct irte *base;
165+};
166+#endif
167+
168 struct intel_iommu {
169 void __iomem *reg; /* Pointer to hardware regs, virtual addr */
170 u64 cap;
171@@ -266,6 +281,9 @@ struct intel_iommu {
172 struct sys_device sysdev;
173 #endif
174 struct q_inval *qi; /* Queued invalidation info */
175+#ifdef CONFIG_INTR_REMAP
176+ struct ir_table *ir_table; /* Interrupt remapping info */
177+#endif
178 };
179
180 static inline void __iommu_flush_cache(
181@@ -279,5 +297,7 @@ extern struct dmar_drhd_unit * dmar_find
182
183 extern int alloc_iommu(struct dmar_drhd_unit *drhd);
184 extern void free_iommu(struct intel_iommu *iommu);
185+extern int dmar_enable_qi(struct intel_iommu *iommu);
186+extern void qi_global_iec(struct intel_iommu *iommu);
187
188 #endif
189--- a/drivers/pci/intr_remapping.c
190+++ b/drivers/pci/intr_remapping.c
191@@ -1,10 +1,147 @@
192 #include <linux/dmar.h>
193+#include <linux/spinlock.h>
194+#include <linux/jiffies.h>
195+#include <linux/pci.h>
196 #include <asm/io_apic.h>
197 #include "intel-iommu.h"
198 #include "intr_remapping.h"
199
200 static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
201 static int ir_ioapic_num;
202+int intr_remapping_enabled;
203+
204+static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
205+{
206+ u64 addr;
207+ u32 cmd, sts;
208+ unsigned long flags;
209+
210+ addr = virt_to_phys((void *)iommu->ir_table->base);
211+
212+ spin_lock_irqsave(&iommu->register_lock, flags);
213+
214+ dmar_writeq(iommu->reg + DMAR_IRTA_REG,
215+ (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE);
216+
217+ /* Set interrupt-remapping table pointer */
218+ cmd = iommu->gcmd | DMA_GCMD_SIRTP;
219+ writel(cmd, iommu->reg + DMAR_GCMD_REG);
220+
221+ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
222+ readl, (sts & DMA_GSTS_IRTPS), sts);
223+ spin_unlock_irqrestore(&iommu->register_lock, flags);
224+
225+ /*
226+ * global invalidation of interrupt entry cache before enabling
227+ * interrupt-remapping.
228+ */
229+ qi_global_iec(iommu);
230+
231+ spin_lock_irqsave(&iommu->register_lock, flags);
232+
233+ /* Enable interrupt-remapping */
234+ cmd = iommu->gcmd | DMA_GCMD_IRE;
235+ iommu->gcmd |= DMA_GCMD_IRE;
236+ writel(cmd, iommu->reg + DMAR_GCMD_REG);
237+
238+ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
239+ readl, (sts & DMA_GSTS_IRES), sts);
240+
241+ spin_unlock_irqrestore(&iommu->register_lock, flags);
242+}
243+
244+
245+static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
246+{
247+ struct ir_table *ir_table;
248+ struct page *pages;
249+
250+ ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
251+ GFP_KERNEL);
252+
253+ if (!iommu->ir_table)
254+ return -ENOMEM;
255+
256+ pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER);
257+
258+ if (!pages) {
259+ printk(KERN_ERR "failed to allocate pages of order %d\n",
260+ INTR_REMAP_PAGE_ORDER);
261+ kfree(iommu->ir_table);
262+ return -ENOMEM;
263+ }
264+
265+ ir_table->base = page_address(pages);
266+
267+ iommu_set_intr_remapping(iommu, mode);
268+ return 0;
269+}
270+
271+int __init enable_intr_remapping(int eim)
272+{
273+ struct dmar_drhd_unit *drhd;
274+ int setup = 0;
275+
276+ /*
277+ * check for the Interrupt-remapping support
278+ */
279+ for_each_drhd_unit(drhd) {
280+ struct intel_iommu *iommu = drhd->iommu;
281+
282+ if (!ecap_ir_support(iommu->ecap))
283+ continue;
284+
285+ if (eim && !ecap_eim_support(iommu->ecap)) {
286+ printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
287+ " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
288+ return -1;
289+ }
290+ }
291+
292+ /*
293+ * Enable queued invalidation for all the DRHD's.
294+ */
295+ for_each_drhd_unit(drhd) {
296+ int ret;
297+ struct intel_iommu *iommu = drhd->iommu;
298+ ret = dmar_enable_qi(iommu);
299+
300+ if (ret) {
301+ printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
302+ " invalidation, ecap %Lx, ret %d\n",
303+ drhd->reg_base_addr, iommu->ecap, ret);
304+ return -1;
305+ }
306+ }
307+
308+ /*
309+ * Setup Interrupt-remapping for all the DRHD's now.
310+ */
311+ for_each_drhd_unit(drhd) {
312+ struct intel_iommu *iommu = drhd->iommu;
313+
314+ if (!ecap_ir_support(iommu->ecap))
315+ continue;
316+
317+ if (setup_intr_remapping(iommu, eim))
318+ goto error;
319+
320+ setup = 1;
321+ }
322+
323+ if (!setup)
324+ goto error;
325+
326+ intr_remapping_enabled = 1;
327+
328+ return 0;
329+
330+error:
331+ /*
332+ * handle error condition gracefully here!
333+ */
334+ return -1;
335+}
336
337 static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
338 struct intel_iommu *iommu)
339--- a/drivers/pci/intr_remapping.h
340+++ b/drivers/pci/intr_remapping.h
341@@ -4,3 +4,5 @@ struct ioapic_scope {
342 struct intel_iommu *iommu;
343 unsigned int id;
344 };
345+
346+#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
347--- a/include/linux/dmar.h
348+++ b/include/linux/dmar.h
349@@ -25,9 +25,85 @@
350 #include <linux/types.h>
351 #include <linux/msi.h>
352
353-#ifdef CONFIG_DMAR
354+#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
355 struct intel_iommu;
356
357+struct dmar_drhd_unit {
358+ struct list_head list; /* list of drhd units */
359+ struct acpi_dmar_header *hdr; /* ACPI header */
360+ u64 reg_base_addr; /* register base address*/
361+ struct pci_dev **devices; /* target device array */
362+ int devices_cnt; /* target device count */
363+ u8 ignored:1; /* ignore drhd */
364+ u8 include_all:1;
365+ struct intel_iommu *iommu;
366+};
367+
368+extern struct list_head dmar_drhd_units;
369+
370+#define for_each_drhd_unit(drhd) \
371+ list_for_each_entry(drhd, &dmar_drhd_units, list)
372+
373+extern int dmar_table_init(void);
374+extern int early_dmar_detect(void);
375+extern int dmar_dev_scope_init(void);
376+
377+/* Intel IOMMU detection */
378+extern void detect_intel_iommu(void);
379+
380+
381+extern int parse_ioapics_under_ir(void);
382+extern int alloc_iommu(struct dmar_drhd_unit *);
383+#else
384+static inline void detect_intel_iommu(void)
385+{
386+ return;
387+}
388+
389+static inline int dmar_table_init(void)
390+{
391+ return -ENODEV;
392+}
393+#endif /* !CONFIG_DMAR && !CONFIG_INTR_REMAP */
394+
395+#ifdef CONFIG_INTR_REMAP
396+extern int intr_remapping_enabled;
397+extern int enable_intr_remapping(int);
398+
399+struct irte {
400+ union {
401+ struct {
402+ __u64 present : 1,
403+ fpd : 1,
404+ dst_mode : 1,
405+ redir_hint : 1,
406+ trigger_mode : 1,
407+ dlvry_mode : 3,
408+ avail : 4,
409+ __reserved_1 : 4,
410+ vector : 8,
411+ __reserved_2 : 8,
412+ dest_id : 32;
413+ };
414+ __u64 low;
415+ };
416+
417+ union {
418+ struct {
419+ __u64 sid : 16,
420+ sq : 2,
421+ svt : 2,
422+ __reserved_3 : 44;
423+ };
424+ __u64 high;
425+ };
426+};
427+#else
428+#define enable_intr_remapping(mode) (-1)
429+#define intr_remapping_enabled (0)
430+#endif
431+
432+#ifdef CONFIG_DMAR
433 extern const char *dmar_get_fault_reason(u8 fault_reason);
434
435 /* Can't use the common MSI interrupt functions
436@@ -40,29 +116,8 @@ extern void dmar_msi_write(int irq, stru
437 extern int dmar_set_interrupt(struct intel_iommu *iommu);
438 extern int arch_setup_dmar_msi(unsigned int irq);
439
440-/* Intel IOMMU detection and initialization functions */
441-extern void detect_intel_iommu(void);
442-extern int intel_iommu_init(void);
443-
444-extern int dmar_table_init(void);
445-extern int early_dmar_detect(void);
446-extern int dmar_dev_scope_init(void);
447-extern int parse_ioapics_under_ir(void);
448-
449-extern struct list_head dmar_drhd_units;
450+extern int iommu_detected, no_iommu;
451 extern struct list_head dmar_rmrr_units;
452-
453-struct dmar_drhd_unit {
454- struct list_head list; /* list of drhd units */
455- struct acpi_dmar_header *hdr; /* ACPI header */
456- u64 reg_base_addr; /* register base address*/
457- struct pci_dev **devices; /* target device array */
458- int devices_cnt; /* target device count */
459- u8 ignored:1; /* ignore drhd */
460- u8 include_all:1;
461- struct intel_iommu *iommu;
462-};
463-
464 struct dmar_rmrr_unit {
465 struct list_head list; /* list of rmrr units */
466 struct acpi_dmar_header *hdr; /* ACPI header */
467@@ -72,24 +127,19 @@ struct dmar_rmrr_unit {
468 int devices_cnt; /* target device count */
469 };
470
471-#define for_each_drhd_unit(drhd) \
472- list_for_each_entry(drhd, &dmar_drhd_units, list)
473 #define for_each_rmrr_units(rmrr) \
474 list_for_each_entry(rmrr, &dmar_rmrr_units, list)
475-
476-extern int alloc_iommu(struct dmar_drhd_unit *);
477+/* Intel DMAR initialization functions */
478+extern int intel_iommu_init(void);
479+extern int dmar_disabled;
480 #else
481-static inline void detect_intel_iommu(void)
482-{
483- return;
484-}
485 static inline int intel_iommu_init(void)
486 {
487+#ifdef CONFIG_INTR_REMAP
488+ return dmar_dev_scope_init();
489+#else
490 return -ENODEV;
491-}
492-static inline int dmar_table_init(void)
493-{
494- return -ENODEV;
495+#endif
496 }
497 #endif /* !CONFIG_DMAR */
498 #endif /* __DMAR_H__ */