diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/iommu/Makefile | 2 | ||||
-rw-r--r-- | drivers/iommu/dmar.c | 11 | ||||
-rw-r--r-- | drivers/iommu/intel-iommu.c | 3 | ||||
-rw-r--r-- | drivers/iommu/intel_irq_remapping.c (renamed from drivers/iommu/intr_remapping.c) | 359 | ||||
-rw-r--r-- | drivers/iommu/intr_remapping.h | 17 | ||||
-rw-r--r-- | drivers/iommu/irq_remapping.c | 166 | ||||
-rw-r--r-- | drivers/iommu/irq_remapping.h | 90 |
7 files changed, 562 insertions, 86 deletions
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 7ad7a3bc1242..3e5e82ae9f0d 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile | |||
@@ -4,7 +4,7 @@ obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o | |||
4 | obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o | 4 | obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o |
5 | obj-$(CONFIG_DMAR_TABLE) += dmar.o | 5 | obj-$(CONFIG_DMAR_TABLE) += dmar.o |
6 | obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o | 6 | obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o |
7 | obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o | 7 | obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o |
8 | obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o | 8 | obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o |
9 | obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o | 9 | obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o |
10 | obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o | 10 | obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o |
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 35c1e17fce1d..3a74e4410fc0 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/tboot.h> | 36 | #include <linux/tboot.h> |
37 | #include <linux/dmi.h> | 37 | #include <linux/dmi.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <asm/irq_remapping.h> | ||
39 | #include <asm/iommu_table.h> | 40 | #include <asm/iommu_table.h> |
40 | 41 | ||
41 | #define PREFIX "DMAR: " | 42 | #define PREFIX "DMAR: " |
@@ -555,7 +556,7 @@ int __init detect_intel_iommu(void) | |||
555 | 556 | ||
556 | dmar = (struct acpi_table_dmar *) dmar_tbl; | 557 | dmar = (struct acpi_table_dmar *) dmar_tbl; |
557 | 558 | ||
558 | if (ret && intr_remapping_enabled && cpu_has_x2apic && | 559 | if (ret && irq_remapping_enabled && cpu_has_x2apic && |
559 | dmar->flags & 0x1) | 560 | dmar->flags & 0x1) |
560 | printk(KERN_INFO | 561 | printk(KERN_INFO |
561 | "Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); | 562 | "Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); |
@@ -1041,7 +1042,7 @@ static const char *dma_remap_fault_reasons[] = | |||
1041 | "non-zero reserved fields in PTE", | 1042 | "non-zero reserved fields in PTE", |
1042 | }; | 1043 | }; |
1043 | 1044 | ||
1044 | static const char *intr_remap_fault_reasons[] = | 1045 | static const char *irq_remap_fault_reasons[] = |
1045 | { | 1046 | { |
1046 | "Detected reserved fields in the decoded interrupt-remapped request", | 1047 | "Detected reserved fields in the decoded interrupt-remapped request", |
1047 | "Interrupt index exceeded the interrupt-remapping table size", | 1048 | "Interrupt index exceeded the interrupt-remapping table size", |
@@ -1056,10 +1057,10 @@ static const char *intr_remap_fault_reasons[] = | |||
1056 | 1057 | ||
1057 | const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) | 1058 | const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) |
1058 | { | 1059 | { |
1059 | if (fault_reason >= 0x20 && (fault_reason <= 0x20 + | 1060 | if (fault_reason >= 0x20 && (fault_reason - 0x20 < |
1060 | ARRAY_SIZE(intr_remap_fault_reasons))) { | 1061 | ARRAY_SIZE(irq_remap_fault_reasons))) { |
1061 | *fault_type = INTR_REMAP; | 1062 | *fault_type = INTR_REMAP; |
1062 | return intr_remap_fault_reasons[fault_reason - 0x20]; | 1063 | return irq_remap_fault_reasons[fault_reason - 0x20]; |
1063 | } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) { | 1064 | } else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) { |
1064 | *fault_type = DMA_REMAP; | 1065 | *fault_type = DMA_REMAP; |
1065 | return dma_remap_fault_reasons[fault_reason]; | 1066 | return dma_remap_fault_reasons[fault_reason]; |
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index f93d5ac8f81c..bf2fbaad5e22 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/dmi.h> | 42 | #include <linux/dmi.h> |
43 | #include <linux/pci-ats.h> | 43 | #include <linux/pci-ats.h> |
44 | #include <linux/memblock.h> | 44 | #include <linux/memblock.h> |
45 | #include <asm/irq_remapping.h> | ||
45 | #include <asm/cacheflush.h> | 46 | #include <asm/cacheflush.h> |
46 | #include <asm/iommu.h> | 47 | #include <asm/iommu.h> |
47 | 48 | ||
@@ -4082,7 +4083,7 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain, | |||
4082 | if (cap == IOMMU_CAP_CACHE_COHERENCY) | 4083 | if (cap == IOMMU_CAP_CACHE_COHERENCY) |
4083 | return dmar_domain->iommu_snooping; | 4084 | return dmar_domain->iommu_snooping; |
4084 | if (cap == IOMMU_CAP_INTR_REMAP) | 4085 | if (cap == IOMMU_CAP_INTR_REMAP) |
4085 | return intr_remapping_enabled; | 4086 | return irq_remapping_enabled; |
4086 | 4087 | ||
4087 | return 0; | 4088 | return 0; |
4088 | } | 4089 | } |
diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intel_irq_remapping.c index 6777ca049471..6d347064b8b0 100644 --- a/drivers/iommu/intr_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c | |||
@@ -10,49 +10,33 @@ | |||
10 | #include <asm/smp.h> | 10 | #include <asm/smp.h> |
11 | #include <asm/cpu.h> | 11 | #include <asm/cpu.h> |
12 | #include <linux/intel-iommu.h> | 12 | #include <linux/intel-iommu.h> |
13 | #include "intr_remapping.h" | ||
14 | #include <acpi/acpi.h> | 13 | #include <acpi/acpi.h> |
14 | #include <asm/irq_remapping.h> | ||
15 | #include <asm/pci-direct.h> | 15 | #include <asm/pci-direct.h> |
16 | #include <asm/msidef.h> | ||
16 | 17 | ||
17 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; | 18 | #include "irq_remapping.h" |
18 | static struct hpet_scope ir_hpet[MAX_HPET_TBS]; | ||
19 | static int ir_ioapic_num, ir_hpet_num; | ||
20 | int intr_remapping_enabled; | ||
21 | |||
22 | static int disable_intremap; | ||
23 | static int disable_sourceid_checking; | ||
24 | static int no_x2apic_optout; | ||
25 | 19 | ||
26 | static __init int setup_nointremap(char *str) | 20 | struct ioapic_scope { |
27 | { | 21 | struct intel_iommu *iommu; |
28 | disable_intremap = 1; | 22 | unsigned int id; |
29 | return 0; | 23 | unsigned int bus; /* PCI bus number */ |
30 | } | 24 | unsigned int devfn; /* PCI devfn number */ |
31 | early_param("nointremap", setup_nointremap); | 25 | }; |
32 | 26 | ||
33 | static __init int setup_intremap(char *str) | 27 | struct hpet_scope { |
34 | { | 28 | struct intel_iommu *iommu; |
35 | if (!str) | 29 | u8 id; |
36 | return -EINVAL; | 30 | unsigned int bus; |
31 | unsigned int devfn; | ||
32 | }; | ||
37 | 33 | ||
38 | while (*str) { | 34 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) |
39 | if (!strncmp(str, "on", 2)) | 35 | #define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8) |
40 | disable_intremap = 0; | ||
41 | else if (!strncmp(str, "off", 3)) | ||
42 | disable_intremap = 1; | ||
43 | else if (!strncmp(str, "nosid", 5)) | ||
44 | disable_sourceid_checking = 1; | ||
45 | else if (!strncmp(str, "no_x2apic_optout", 16)) | ||
46 | no_x2apic_optout = 1; | ||
47 | |||
48 | str += strcspn(str, ","); | ||
49 | while (*str == ',') | ||
50 | str++; | ||
51 | } | ||
52 | 36 | ||
53 | return 0; | 37 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; |
54 | } | 38 | static struct hpet_scope ir_hpet[MAX_HPET_TBS]; |
55 | early_param("intremap", setup_intremap); | 39 | static int ir_ioapic_num, ir_hpet_num; |
56 | 40 | ||
57 | static DEFINE_RAW_SPINLOCK(irq_2_ir_lock); | 41 | static DEFINE_RAW_SPINLOCK(irq_2_ir_lock); |
58 | 42 | ||
@@ -80,7 +64,7 @@ int get_irte(int irq, struct irte *entry) | |||
80 | return 0; | 64 | return 0; |
81 | } | 65 | } |
82 | 66 | ||
83 | int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | 67 | static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) |
84 | { | 68 | { |
85 | struct ir_table *table = iommu->ir_table; | 69 | struct ir_table *table = iommu->ir_table; |
86 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 70 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
@@ -152,7 +136,7 @@ static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask) | |||
152 | return qi_submit_sync(&desc, iommu); | 136 | return qi_submit_sync(&desc, iommu); |
153 | } | 137 | } |
154 | 138 | ||
155 | int map_irq_to_irte_handle(int irq, u16 *sub_handle) | 139 | static int map_irq_to_irte_handle(int irq, u16 *sub_handle) |
156 | { | 140 | { |
157 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 141 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
158 | unsigned long flags; | 142 | unsigned long flags; |
@@ -168,7 +152,7 @@ int map_irq_to_irte_handle(int irq, u16 *sub_handle) | |||
168 | return index; | 152 | return index; |
169 | } | 153 | } |
170 | 154 | ||
171 | int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | 155 | static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) |
172 | { | 156 | { |
173 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 157 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
174 | unsigned long flags; | 158 | unsigned long flags; |
@@ -188,7 +172,7 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | |||
188 | return 0; | 172 | return 0; |
189 | } | 173 | } |
190 | 174 | ||
191 | int modify_irte(int irq, struct irte *irte_modified) | 175 | static int modify_irte(int irq, struct irte *irte_modified) |
192 | { | 176 | { |
193 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 177 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
194 | struct intel_iommu *iommu; | 178 | struct intel_iommu *iommu; |
@@ -216,7 +200,7 @@ int modify_irte(int irq, struct irte *irte_modified) | |||
216 | return rc; | 200 | return rc; |
217 | } | 201 | } |
218 | 202 | ||
219 | struct intel_iommu *map_hpet_to_ir(u8 hpet_id) | 203 | static struct intel_iommu *map_hpet_to_ir(u8 hpet_id) |
220 | { | 204 | { |
221 | int i; | 205 | int i; |
222 | 206 | ||
@@ -226,7 +210,7 @@ struct intel_iommu *map_hpet_to_ir(u8 hpet_id) | |||
226 | return NULL; | 210 | return NULL; |
227 | } | 211 | } |
228 | 212 | ||
229 | struct intel_iommu *map_ioapic_to_ir(int apic) | 213 | static struct intel_iommu *map_ioapic_to_ir(int apic) |
230 | { | 214 | { |
231 | int i; | 215 | int i; |
232 | 216 | ||
@@ -236,7 +220,7 @@ struct intel_iommu *map_ioapic_to_ir(int apic) | |||
236 | return NULL; | 220 | return NULL; |
237 | } | 221 | } |
238 | 222 | ||
239 | struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) | 223 | static struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) |
240 | { | 224 | { |
241 | struct dmar_drhd_unit *drhd; | 225 | struct dmar_drhd_unit *drhd; |
242 | 226 | ||
@@ -270,7 +254,7 @@ static int clear_entries(struct irq_2_iommu *irq_iommu) | |||
270 | return qi_flush_iec(iommu, index, irq_iommu->irte_mask); | 254 | return qi_flush_iec(iommu, index, irq_iommu->irte_mask); |
271 | } | 255 | } |
272 | 256 | ||
273 | int free_irte(int irq) | 257 | static int free_irte(int irq) |
274 | { | 258 | { |
275 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 259 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
276 | unsigned long flags; | 260 | unsigned long flags; |
@@ -328,7 +312,7 @@ static void set_irte_sid(struct irte *irte, unsigned int svt, | |||
328 | irte->sid = sid; | 312 | irte->sid = sid; |
329 | } | 313 | } |
330 | 314 | ||
331 | int set_ioapic_sid(struct irte *irte, int apic) | 315 | static int set_ioapic_sid(struct irte *irte, int apic) |
332 | { | 316 | { |
333 | int i; | 317 | int i; |
334 | u16 sid = 0; | 318 | u16 sid = 0; |
@@ -353,7 +337,7 @@ int set_ioapic_sid(struct irte *irte, int apic) | |||
353 | return 0; | 337 | return 0; |
354 | } | 338 | } |
355 | 339 | ||
356 | int set_hpet_sid(struct irte *irte, u8 id) | 340 | static int set_hpet_sid(struct irte *irte, u8 id) |
357 | { | 341 | { |
358 | int i; | 342 | int i; |
359 | u16 sid = 0; | 343 | u16 sid = 0; |
@@ -383,7 +367,7 @@ int set_hpet_sid(struct irte *irte, u8 id) | |||
383 | return 0; | 367 | return 0; |
384 | } | 368 | } |
385 | 369 | ||
386 | int set_msi_sid(struct irte *irte, struct pci_dev *dev) | 370 | static int set_msi_sid(struct irte *irte, struct pci_dev *dev) |
387 | { | 371 | { |
388 | struct pci_dev *bridge; | 372 | struct pci_dev *bridge; |
389 | 373 | ||
@@ -410,7 +394,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev) | |||
410 | return 0; | 394 | return 0; |
411 | } | 395 | } |
412 | 396 | ||
413 | static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) | 397 | static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) |
414 | { | 398 | { |
415 | u64 addr; | 399 | u64 addr; |
416 | u32 sts; | 400 | u32 sts; |
@@ -450,7 +434,7 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) | |||
450 | } | 434 | } |
451 | 435 | ||
452 | 436 | ||
453 | static int setup_intr_remapping(struct intel_iommu *iommu, int mode) | 437 | static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode) |
454 | { | 438 | { |
455 | struct ir_table *ir_table; | 439 | struct ir_table *ir_table; |
456 | struct page *pages; | 440 | struct page *pages; |
@@ -473,14 +457,14 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode) | |||
473 | 457 | ||
474 | ir_table->base = page_address(pages); | 458 | ir_table->base = page_address(pages); |
475 | 459 | ||
476 | iommu_set_intr_remapping(iommu, mode); | 460 | iommu_set_irq_remapping(iommu, mode); |
477 | return 0; | 461 | return 0; |
478 | } | 462 | } |
479 | 463 | ||
480 | /* | 464 | /* |
481 | * Disable Interrupt Remapping. | 465 | * Disable Interrupt Remapping. |
482 | */ | 466 | */ |
483 | static void iommu_disable_intr_remapping(struct intel_iommu *iommu) | 467 | static void iommu_disable_irq_remapping(struct intel_iommu *iommu) |
484 | { | 468 | { |
485 | unsigned long flags; | 469 | unsigned long flags; |
486 | u32 sts; | 470 | u32 sts; |
@@ -519,11 +503,11 @@ static int __init dmar_x2apic_optout(void) | |||
519 | return dmar->flags & DMAR_X2APIC_OPT_OUT; | 503 | return dmar->flags & DMAR_X2APIC_OPT_OUT; |
520 | } | 504 | } |
521 | 505 | ||
522 | int __init intr_remapping_supported(void) | 506 | static int __init intel_irq_remapping_supported(void) |
523 | { | 507 | { |
524 | struct dmar_drhd_unit *drhd; | 508 | struct dmar_drhd_unit *drhd; |
525 | 509 | ||
526 | if (disable_intremap) | 510 | if (disable_irq_remap) |
527 | return 0; | 511 | return 0; |
528 | 512 | ||
529 | if (!dmar_ir_support()) | 513 | if (!dmar_ir_support()) |
@@ -539,7 +523,7 @@ int __init intr_remapping_supported(void) | |||
539 | return 1; | 523 | return 1; |
540 | } | 524 | } |
541 | 525 | ||
542 | int __init enable_intr_remapping(void) | 526 | static int __init intel_enable_irq_remapping(void) |
543 | { | 527 | { |
544 | struct dmar_drhd_unit *drhd; | 528 | struct dmar_drhd_unit *drhd; |
545 | int setup = 0; | 529 | int setup = 0; |
@@ -577,7 +561,7 @@ int __init enable_intr_remapping(void) | |||
577 | * Disable intr remapping and queued invalidation, if already | 561 | * Disable intr remapping and queued invalidation, if already |
578 | * enabled prior to OS handover. | 562 | * enabled prior to OS handover. |
579 | */ | 563 | */ |
580 | iommu_disable_intr_remapping(iommu); | 564 | iommu_disable_irq_remapping(iommu); |
581 | 565 | ||
582 | dmar_disable_qi(iommu); | 566 | dmar_disable_qi(iommu); |
583 | } | 567 | } |
@@ -623,7 +607,7 @@ int __init enable_intr_remapping(void) | |||
623 | if (!ecap_ir_support(iommu->ecap)) | 607 | if (!ecap_ir_support(iommu->ecap)) |
624 | continue; | 608 | continue; |
625 | 609 | ||
626 | if (setup_intr_remapping(iommu, eim)) | 610 | if (intel_setup_irq_remapping(iommu, eim)) |
627 | goto error; | 611 | goto error; |
628 | 612 | ||
629 | setup = 1; | 613 | setup = 1; |
@@ -632,7 +616,7 @@ int __init enable_intr_remapping(void) | |||
632 | if (!setup) | 616 | if (!setup) |
633 | goto error; | 617 | goto error; |
634 | 618 | ||
635 | intr_remapping_enabled = 1; | 619 | irq_remapping_enabled = 1; |
636 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); | 620 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); |
637 | 621 | ||
638 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; | 622 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; |
@@ -775,14 +759,14 @@ int __init parse_ioapics_under_ir(void) | |||
775 | 759 | ||
776 | int __init ir_dev_scope_init(void) | 760 | int __init ir_dev_scope_init(void) |
777 | { | 761 | { |
778 | if (!intr_remapping_enabled) | 762 | if (!irq_remapping_enabled) |
779 | return 0; | 763 | return 0; |
780 | 764 | ||
781 | return dmar_dev_scope_init(); | 765 | return dmar_dev_scope_init(); |
782 | } | 766 | } |
783 | rootfs_initcall(ir_dev_scope_init); | 767 | rootfs_initcall(ir_dev_scope_init); |
784 | 768 | ||
785 | void disable_intr_remapping(void) | 769 | static void disable_irq_remapping(void) |
786 | { | 770 | { |
787 | struct dmar_drhd_unit *drhd; | 771 | struct dmar_drhd_unit *drhd; |
788 | struct intel_iommu *iommu = NULL; | 772 | struct intel_iommu *iommu = NULL; |
@@ -794,11 +778,11 @@ void disable_intr_remapping(void) | |||
794 | if (!ecap_ir_support(iommu->ecap)) | 778 | if (!ecap_ir_support(iommu->ecap)) |
795 | continue; | 779 | continue; |
796 | 780 | ||
797 | iommu_disable_intr_remapping(iommu); | 781 | iommu_disable_irq_remapping(iommu); |
798 | } | 782 | } |
799 | } | 783 | } |
800 | 784 | ||
801 | int reenable_intr_remapping(int eim) | 785 | static int reenable_irq_remapping(int eim) |
802 | { | 786 | { |
803 | struct dmar_drhd_unit *drhd; | 787 | struct dmar_drhd_unit *drhd; |
804 | int setup = 0; | 788 | int setup = 0; |
@@ -816,7 +800,7 @@ int reenable_intr_remapping(int eim) | |||
816 | continue; | 800 | continue; |
817 | 801 | ||
818 | /* Set up interrupt remapping for iommu.*/ | 802 | /* Set up interrupt remapping for iommu.*/ |
819 | iommu_set_intr_remapping(iommu, eim); | 803 | iommu_set_irq_remapping(iommu, eim); |
820 | setup = 1; | 804 | setup = 1; |
821 | } | 805 | } |
822 | 806 | ||
@@ -832,3 +816,254 @@ error: | |||
832 | return -1; | 816 | return -1; |
833 | } | 817 | } |
834 | 818 | ||
819 | static void prepare_irte(struct irte *irte, int vector, | ||
820 | unsigned int dest) | ||
821 | { | ||
822 | memset(irte, 0, sizeof(*irte)); | ||
823 | |||
824 | irte->present = 1; | ||
825 | irte->dst_mode = apic->irq_dest_mode; | ||
826 | /* | ||
827 | * Trigger mode in the IRTE will always be edge, and for IO-APIC, the | ||
828 | * actual level or edge trigger will be setup in the IO-APIC | ||
829 | * RTE. This will help simplify level triggered irq migration. | ||
830 | * For more details, see the comments (in io_apic.c) explainig IO-APIC | ||
831 | * irq migration in the presence of interrupt-remapping. | ||
832 | */ | ||
833 | irte->trigger_mode = 0; | ||
834 | irte->dlvry_mode = apic->irq_delivery_mode; | ||
835 | irte->vector = vector; | ||
836 | irte->dest_id = IRTE_DEST(dest); | ||
837 | irte->redir_hint = 1; | ||
838 | } | ||
839 | |||
840 | static int intel_setup_ioapic_entry(int irq, | ||
841 | struct IO_APIC_route_entry *route_entry, | ||
842 | unsigned int destination, int vector, | ||
843 | struct io_apic_irq_attr *attr) | ||
844 | { | ||
845 | int ioapic_id = mpc_ioapic_id(attr->ioapic); | ||
846 | struct intel_iommu *iommu = map_ioapic_to_ir(ioapic_id); | ||
847 | struct IR_IO_APIC_route_entry *entry; | ||
848 | struct irte irte; | ||
849 | int index; | ||
850 | |||
851 | if (!iommu) { | ||
852 | pr_warn("No mapping iommu for ioapic %d\n", ioapic_id); | ||
853 | return -ENODEV; | ||
854 | } | ||
855 | |||
856 | entry = (struct IR_IO_APIC_route_entry *)route_entry; | ||
857 | |||
858 | index = alloc_irte(iommu, irq, 1); | ||
859 | if (index < 0) { | ||
860 | pr_warn("Failed to allocate IRTE for ioapic %d\n", ioapic_id); | ||
861 | return -ENOMEM; | ||
862 | } | ||
863 | |||
864 | prepare_irte(&irte, vector, destination); | ||
865 | |||
866 | /* Set source-id of interrupt request */ | ||
867 | set_ioapic_sid(&irte, ioapic_id); | ||
868 | |||
869 | modify_irte(irq, &irte); | ||
870 | |||
871 | apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: " | ||
872 | "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d " | ||
873 | "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X " | ||
874 | "Avail:%X Vector:%02X Dest:%08X " | ||
875 | "SID:%04X SQ:%X SVT:%X)\n", | ||
876 | attr->ioapic, irte.present, irte.fpd, irte.dst_mode, | ||
877 | irte.redir_hint, irte.trigger_mode, irte.dlvry_mode, | ||
878 | irte.avail, irte.vector, irte.dest_id, | ||
879 | irte.sid, irte.sq, irte.svt); | ||
880 | |||
881 | memset(entry, 0, sizeof(*entry)); | ||
882 | |||
883 | entry->index2 = (index >> 15) & 0x1; | ||
884 | entry->zero = 0; | ||
885 | entry->format = 1; | ||
886 | entry->index = (index & 0x7fff); | ||
887 | /* | ||
888 | * IO-APIC RTE will be configured with virtual vector. | ||
889 | * irq handler will do the explicit EOI to the io-apic. | ||
890 | */ | ||
891 | entry->vector = attr->ioapic_pin; | ||
892 | entry->mask = 0; /* enable IRQ */ | ||
893 | entry->trigger = attr->trigger; | ||
894 | entry->polarity = attr->polarity; | ||
895 | |||
896 | /* Mask level triggered irqs. | ||
897 | * Use IRQ_DELAYED_DISABLE for edge triggered irqs. | ||
898 | */ | ||
899 | if (attr->trigger) | ||
900 | entry->mask = 1; | ||
901 | |||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | #ifdef CONFIG_SMP | ||
906 | /* | ||
907 | * Migrate the IO-APIC irq in the presence of intr-remapping. | ||
908 | * | ||
909 | * For both level and edge triggered, irq migration is a simple atomic | ||
910 | * update(of vector and cpu destination) of IRTE and flush the hardware cache. | ||
911 | * | ||
912 | * For level triggered, we eliminate the io-apic RTE modification (with the | ||
913 | * updated vector information), by using a virtual vector (io-apic pin number). | ||
914 | * Real vector that is used for interrupting cpu will be coming from | ||
915 | * the interrupt-remapping table entry. | ||
916 | * | ||
917 | * As the migration is a simple atomic update of IRTE, the same mechanism | ||
918 | * is used to migrate MSI irq's in the presence of interrupt-remapping. | ||
919 | */ | ||
920 | static int | ||
921 | intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
922 | bool force) | ||
923 | { | ||
924 | struct irq_cfg *cfg = data->chip_data; | ||
925 | unsigned int dest, irq = data->irq; | ||
926 | struct irte irte; | ||
927 | |||
928 | if (!cpumask_intersects(mask, cpu_online_mask)) | ||
929 | return -EINVAL; | ||
930 | |||
931 | if (get_irte(irq, &irte)) | ||
932 | return -EBUSY; | ||
933 | |||
934 | if (assign_irq_vector(irq, cfg, mask)) | ||
935 | return -EBUSY; | ||
936 | |||
937 | dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask); | ||
938 | |||
939 | irte.vector = cfg->vector; | ||
940 | irte.dest_id = IRTE_DEST(dest); | ||
941 | |||
942 | /* | ||
943 | * Atomically updates the IRTE with the new destination, vector | ||
944 | * and flushes the interrupt entry cache. | ||
945 | */ | ||
946 | modify_irte(irq, &irte); | ||
947 | |||
948 | /* | ||
949 | * After this point, all the interrupts will start arriving | ||
950 | * at the new destination. So, time to cleanup the previous | ||
951 | * vector allocation. | ||
952 | */ | ||
953 | if (cfg->move_in_progress) | ||
954 | send_cleanup_vector(cfg); | ||
955 | |||
956 | cpumask_copy(data->affinity, mask); | ||
957 | return 0; | ||
958 | } | ||
959 | #endif | ||
960 | |||
961 | static void intel_compose_msi_msg(struct pci_dev *pdev, | ||
962 | unsigned int irq, unsigned int dest, | ||
963 | struct msi_msg *msg, u8 hpet_id) | ||
964 | { | ||
965 | struct irq_cfg *cfg; | ||
966 | struct irte irte; | ||
967 | u16 sub_handle = 0; | ||
968 | int ir_index; | ||
969 | |||
970 | cfg = irq_get_chip_data(irq); | ||
971 | |||
972 | ir_index = map_irq_to_irte_handle(irq, &sub_handle); | ||
973 | BUG_ON(ir_index == -1); | ||
974 | |||
975 | prepare_irte(&irte, cfg->vector, dest); | ||
976 | |||
977 | /* Set source-id of interrupt request */ | ||
978 | if (pdev) | ||
979 | set_msi_sid(&irte, pdev); | ||
980 | else | ||
981 | set_hpet_sid(&irte, hpet_id); | ||
982 | |||
983 | modify_irte(irq, &irte); | ||
984 | |||
985 | msg->address_hi = MSI_ADDR_BASE_HI; | ||
986 | msg->data = sub_handle; | ||
987 | msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT | | ||
988 | MSI_ADDR_IR_SHV | | ||
989 | MSI_ADDR_IR_INDEX1(ir_index) | | ||
990 | MSI_ADDR_IR_INDEX2(ir_index); | ||
991 | } | ||
992 | |||
993 | /* | ||
994 | * Map the PCI dev to the corresponding remapping hardware unit | ||
995 | * and allocate 'nvec' consecutive interrupt-remapping table entries | ||
996 | * in it. | ||
997 | */ | ||
998 | static int intel_msi_alloc_irq(struct pci_dev *dev, int irq, int nvec) | ||
999 | { | ||
1000 | struct intel_iommu *iommu; | ||
1001 | int index; | ||
1002 | |||
1003 | iommu = map_dev_to_ir(dev); | ||
1004 | if (!iommu) { | ||
1005 | printk(KERN_ERR | ||
1006 | "Unable to map PCI %s to iommu\n", pci_name(dev)); | ||
1007 | return -ENOENT; | ||
1008 | } | ||
1009 | |||
1010 | index = alloc_irte(iommu, irq, nvec); | ||
1011 | if (index < 0) { | ||
1012 | printk(KERN_ERR | ||
1013 | "Unable to allocate %d IRTE for PCI %s\n", nvec, | ||
1014 | pci_name(dev)); | ||
1015 | return -ENOSPC; | ||
1016 | } | ||
1017 | return index; | ||
1018 | } | ||
1019 | |||
1020 | static int intel_msi_setup_irq(struct pci_dev *pdev, unsigned int irq, | ||
1021 | int index, int sub_handle) | ||
1022 | { | ||
1023 | struct intel_iommu *iommu; | ||
1024 | |||
1025 | iommu = map_dev_to_ir(pdev); | ||
1026 | if (!iommu) | ||
1027 | return -ENOENT; | ||
1028 | /* | ||
1029 | * setup the mapping between the irq and the IRTE | ||
1030 | * base index, the sub_handle pointing to the | ||
1031 | * appropriate interrupt remap table entry. | ||
1032 | */ | ||
1033 | set_irte_irq(irq, iommu, index, sub_handle); | ||
1034 | |||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | static int intel_setup_hpet_msi(unsigned int irq, unsigned int id) | ||
1039 | { | ||
1040 | struct intel_iommu *iommu = map_hpet_to_ir(id); | ||
1041 | int index; | ||
1042 | |||
1043 | if (!iommu) | ||
1044 | return -1; | ||
1045 | |||
1046 | index = alloc_irte(iommu, irq, 1); | ||
1047 | if (index < 0) | ||
1048 | return -1; | ||
1049 | |||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | struct irq_remap_ops intel_irq_remap_ops = { | ||
1054 | .supported = intel_irq_remapping_supported, | ||
1055 | .prepare = dmar_table_init, | ||
1056 | .enable = intel_enable_irq_remapping, | ||
1057 | .disable = disable_irq_remapping, | ||
1058 | .reenable = reenable_irq_remapping, | ||
1059 | .enable_faulting = enable_drhd_fault_handling, | ||
1060 | .setup_ioapic_entry = intel_setup_ioapic_entry, | ||
1061 | #ifdef CONFIG_SMP | ||
1062 | .set_affinity = intel_ioapic_set_affinity, | ||
1063 | #endif | ||
1064 | .free_irq = free_irte, | ||
1065 | .compose_msi_msg = intel_compose_msi_msg, | ||
1066 | .msi_alloc_irq = intel_msi_alloc_irq, | ||
1067 | .msi_setup_irq = intel_msi_setup_irq, | ||
1068 | .setup_hpet_msi = intel_setup_hpet_msi, | ||
1069 | }; | ||
diff --git a/drivers/iommu/intr_remapping.h b/drivers/iommu/intr_remapping.h deleted file mode 100644 index 5662fecfee60..000000000000 --- a/drivers/iommu/intr_remapping.h +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | #include <linux/intel-iommu.h> | ||
2 | |||
3 | struct ioapic_scope { | ||
4 | struct intel_iommu *iommu; | ||
5 | unsigned int id; | ||
6 | unsigned int bus; /* PCI bus number */ | ||
7 | unsigned int devfn; /* PCI devfn number */ | ||
8 | }; | ||
9 | |||
10 | struct hpet_scope { | ||
11 | struct intel_iommu *iommu; | ||
12 | u8 id; | ||
13 | unsigned int bus; | ||
14 | unsigned int devfn; | ||
15 | }; | ||
16 | |||
17 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) | ||
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c new file mode 100644 index 000000000000..40cda8e98d87 --- /dev/null +++ b/drivers/iommu/irq_remapping.c | |||
@@ -0,0 +1,166 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/string.h> | ||
3 | #include <linux/errno.h> | ||
4 | |||
5 | #include "irq_remapping.h" | ||
6 | |||
7 | int irq_remapping_enabled; | ||
8 | |||
9 | int disable_irq_remap; | ||
10 | int disable_sourceid_checking; | ||
11 | int no_x2apic_optout; | ||
12 | |||
13 | static struct irq_remap_ops *remap_ops; | ||
14 | |||
15 | static __init int setup_nointremap(char *str) | ||
16 | { | ||
17 | disable_irq_remap = 1; | ||
18 | return 0; | ||
19 | } | ||
20 | early_param("nointremap", setup_nointremap); | ||
21 | |||
22 | static __init int setup_irqremap(char *str) | ||
23 | { | ||
24 | if (!str) | ||
25 | return -EINVAL; | ||
26 | |||
27 | while (*str) { | ||
28 | if (!strncmp(str, "on", 2)) | ||
29 | disable_irq_remap = 0; | ||
30 | else if (!strncmp(str, "off", 3)) | ||
31 | disable_irq_remap = 1; | ||
32 | else if (!strncmp(str, "nosid", 5)) | ||
33 | disable_sourceid_checking = 1; | ||
34 | else if (!strncmp(str, "no_x2apic_optout", 16)) | ||
35 | no_x2apic_optout = 1; | ||
36 | |||
37 | str += strcspn(str, ","); | ||
38 | while (*str == ',') | ||
39 | str++; | ||
40 | } | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | early_param("intremap", setup_irqremap); | ||
45 | |||
46 | void __init setup_irq_remapping_ops(void) | ||
47 | { | ||
48 | remap_ops = &intel_irq_remap_ops; | ||
49 | } | ||
50 | |||
51 | int irq_remapping_supported(void) | ||
52 | { | ||
53 | if (disable_irq_remap) | ||
54 | return 0; | ||
55 | |||
56 | if (!remap_ops || !remap_ops->supported) | ||
57 | return 0; | ||
58 | |||
59 | return remap_ops->supported(); | ||
60 | } | ||
61 | |||
62 | int __init irq_remapping_prepare(void) | ||
63 | { | ||
64 | if (!remap_ops || !remap_ops->prepare) | ||
65 | return -ENODEV; | ||
66 | |||
67 | return remap_ops->prepare(); | ||
68 | } | ||
69 | |||
70 | int __init irq_remapping_enable(void) | ||
71 | { | ||
72 | if (!remap_ops || !remap_ops->enable) | ||
73 | return -ENODEV; | ||
74 | |||
75 | return remap_ops->enable(); | ||
76 | } | ||
77 | |||
78 | void irq_remapping_disable(void) | ||
79 | { | ||
80 | if (!remap_ops || !remap_ops->disable) | ||
81 | return; | ||
82 | |||
83 | remap_ops->disable(); | ||
84 | } | ||
85 | |||
86 | int irq_remapping_reenable(int mode) | ||
87 | { | ||
88 | if (!remap_ops || !remap_ops->reenable) | ||
89 | return 0; | ||
90 | |||
91 | return remap_ops->reenable(mode); | ||
92 | } | ||
93 | |||
94 | int __init irq_remap_enable_fault_handling(void) | ||
95 | { | ||
96 | if (!remap_ops || !remap_ops->enable_faulting) | ||
97 | return -ENODEV; | ||
98 | |||
99 | return remap_ops->enable_faulting(); | ||
100 | } | ||
101 | |||
102 | int setup_ioapic_remapped_entry(int irq, | ||
103 | struct IO_APIC_route_entry *entry, | ||
104 | unsigned int destination, int vector, | ||
105 | struct io_apic_irq_attr *attr) | ||
106 | { | ||
107 | if (!remap_ops || !remap_ops->setup_ioapic_entry) | ||
108 | return -ENODEV; | ||
109 | |||
110 | return remap_ops->setup_ioapic_entry(irq, entry, destination, | ||
111 | vector, attr); | ||
112 | } | ||
113 | |||
114 | #ifdef CONFIG_SMP | ||
115 | int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, | ||
116 | bool force) | ||
117 | { | ||
118 | if (!remap_ops || !remap_ops->set_affinity) | ||
119 | return 0; | ||
120 | |||
121 | return remap_ops->set_affinity(data, mask, force); | ||
122 | } | ||
123 | #endif | ||
124 | |||
125 | void free_remapped_irq(int irq) | ||
126 | { | ||
127 | if (!remap_ops || !remap_ops->free_irq) | ||
128 | return; | ||
129 | |||
130 | remap_ops->free_irq(irq); | ||
131 | } | ||
132 | |||
133 | void compose_remapped_msi_msg(struct pci_dev *pdev, | ||
134 | unsigned int irq, unsigned int dest, | ||
135 | struct msi_msg *msg, u8 hpet_id) | ||
136 | { | ||
137 | if (!remap_ops || !remap_ops->compose_msi_msg) | ||
138 | return; | ||
139 | |||
140 | remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); | ||
141 | } | ||
142 | |||
143 | int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) | ||
144 | { | ||
145 | if (!remap_ops || !remap_ops->msi_alloc_irq) | ||
146 | return -ENODEV; | ||
147 | |||
148 | return remap_ops->msi_alloc_irq(pdev, irq, nvec); | ||
149 | } | ||
150 | |||
151 | int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | ||
152 | int index, int sub_handle) | ||
153 | { | ||
154 | if (!remap_ops || !remap_ops->msi_setup_irq) | ||
155 | return -ENODEV; | ||
156 | |||
157 | return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle); | ||
158 | } | ||
159 | |||
160 | int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) | ||
161 | { | ||
162 | if (!remap_ops || !remap_ops->setup_hpet_msi) | ||
163 | return -ENODEV; | ||
164 | |||
165 | return remap_ops->setup_hpet_msi(irq, id); | ||
166 | } | ||
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h new file mode 100644 index 000000000000..be9d72950c51 --- /dev/null +++ b/drivers/iommu/irq_remapping.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Advanced Micro Devices, Inc. | ||
3 | * Author: Joerg Roedel <joerg.roedel@amd.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published | ||
7 | * by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * This header file contains stuff that is shared between different interrupt | ||
19 | * remapping drivers but with no need to be visible outside of the IOMMU layer. | ||
20 | */ | ||
21 | |||
22 | #ifndef __IRQ_REMAPPING_H | ||
23 | #define __IRQ_REMAPPING_H | ||
24 | |||
25 | #ifdef CONFIG_IRQ_REMAP | ||
26 | |||
27 | struct IO_APIC_route_entry; | ||
28 | struct io_apic_irq_attr; | ||
29 | struct irq_data; | ||
30 | struct cpumask; | ||
31 | struct pci_dev; | ||
32 | struct msi_msg; | ||
33 | |||
34 | extern int disable_irq_remap; | ||
35 | extern int disable_sourceid_checking; | ||
36 | extern int no_x2apic_optout; | ||
37 | |||
38 | struct irq_remap_ops { | ||
39 | /* Check whether Interrupt Remapping is supported */ | ||
40 | int (*supported)(void); | ||
41 | |||
42 | /* Initializes hardware and makes it ready for remapping interrupts */ | ||
43 | int (*prepare)(void); | ||
44 | |||
45 | /* Enables the remapping hardware */ | ||
46 | int (*enable)(void); | ||
47 | |||
48 | /* Disables the remapping hardware */ | ||
49 | void (*disable)(void); | ||
50 | |||
51 | /* Reenables the remapping hardware */ | ||
52 | int (*reenable)(int); | ||
53 | |||
54 | /* Enable fault handling */ | ||
55 | int (*enable_faulting)(void); | ||
56 | |||
57 | /* IO-APIC setup routine */ | ||
58 | int (*setup_ioapic_entry)(int irq, struct IO_APIC_route_entry *, | ||
59 | unsigned int, int, | ||
60 | struct io_apic_irq_attr *); | ||
61 | |||
62 | #ifdef CONFIG_SMP | ||
63 | /* Set the CPU affinity of a remapped interrupt */ | ||
64 | int (*set_affinity)(struct irq_data *data, const struct cpumask *mask, | ||
65 | bool force); | ||
66 | #endif | ||
67 | |||
68 | /* Free an IRQ */ | ||
69 | int (*free_irq)(int); | ||
70 | |||
71 | /* Create MSI msg to use for interrupt remapping */ | ||
72 | void (*compose_msi_msg)(struct pci_dev *, | ||
73 | unsigned int, unsigned int, | ||
74 | struct msi_msg *, u8); | ||
75 | |||
76 | /* Allocate remapping resources for MSI */ | ||
77 | int (*msi_alloc_irq)(struct pci_dev *, int, int); | ||
78 | |||
79 | /* Setup the remapped MSI irq */ | ||
80 | int (*msi_setup_irq)(struct pci_dev *, unsigned int, int, int); | ||
81 | |||
82 | /* Setup interrupt remapping for an HPET MSI */ | ||
83 | int (*setup_hpet_msi)(unsigned int, unsigned int); | ||
84 | }; | ||
85 | |||
86 | extern struct irq_remap_ops intel_irq_remap_ops; | ||
87 | |||
88 | #endif /* CONFIG_IRQ_REMAP */ | ||
89 | |||
90 | #endif /* __IRQ_REMAPPING_H */ | ||