diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2012-03-30 14:47:02 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2012-05-07 08:34:59 -0400 |
commit | 0c3f173a88c4ae3e4253427cf574a59ad5352918 (patch) | |
tree | d34364dc8d7926de75ec486ce579b478d23098e3 | |
parent | 4f3d8b67ad3090f9fb72f8235d21cde53cd24b79 (diff) |
iommu/vt-d: Convert IR ioapic-setup to use remap_ops
The IOAPIC setup routine for interrupt remapping is VT-d
specific. Move it to the irq_remap_ops and add a call helper
function.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Acked-by: Yinghai Lu <yinghai@kernel.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
-rw-r--r-- | arch/x86/include/asm/intr_remapping.h | 15 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 68 | ||||
-rw-r--r-- | drivers/iommu/intel_intr_remapping.c | 89 | ||||
-rw-r--r-- | drivers/iommu/intr_remapping.c | 12 | ||||
-rw-r--r-- | drivers/iommu/intr_remapping.h | 8 |
5 files changed, 125 insertions, 67 deletions
diff --git a/arch/x86/include/asm/intr_remapping.h b/arch/x86/include/asm/intr_remapping.h index 55aa892a53e3..a22e1f1ac7ec 100644 --- a/arch/x86/include/asm/intr_remapping.h +++ b/arch/x86/include/asm/intr_remapping.h | |||
@@ -24,6 +24,9 @@ | |||
24 | 24 | ||
25 | #ifdef CONFIG_IRQ_REMAP | 25 | #ifdef CONFIG_IRQ_REMAP |
26 | 26 | ||
27 | struct IO_APIC_route_entry; | ||
28 | struct io_apic_irq_attr; | ||
29 | |||
27 | extern int intr_remapping_enabled; | 30 | extern int intr_remapping_enabled; |
28 | 31 | ||
29 | extern void setup_intr_remapping(void); | 32 | extern void setup_intr_remapping(void); |
@@ -33,6 +36,10 @@ extern int intr_hardware_enable(void); | |||
33 | extern void intr_hardware_disable(void); | 36 | extern void intr_hardware_disable(void); |
34 | extern int intr_hardware_reenable(int); | 37 | extern int intr_hardware_reenable(int); |
35 | extern int intr_enable_fault_handling(void); | 38 | extern int intr_enable_fault_handling(void); |
39 | extern int intr_setup_ioapic_entry(int irq, | ||
40 | struct IO_APIC_route_entry *entry, | ||
41 | unsigned int destination, int vector, | ||
42 | struct io_apic_irq_attr *attr); | ||
36 | 43 | ||
37 | #else /* CONFIG_IRQ_REMAP */ | 44 | #else /* CONFIG_IRQ_REMAP */ |
38 | 45 | ||
@@ -45,7 +52,13 @@ static inline int intr_hardware_enable(void) { return -ENODEV; } | |||
45 | static inline void intr_hardware_disable(void) { } | 52 | static inline void intr_hardware_disable(void) { } |
46 | static inline int intr_hardware_reenable(int eim) { return -ENODEV; } | 53 | static inline int intr_hardware_reenable(int eim) { return -ENODEV; } |
47 | static inline int intr_enable_fault_handling(void) { return -ENODEV; } | 54 | static inline int intr_enable_fault_handling(void) { return -ENODEV; } |
48 | 55 | static inline int intr_setup_ioapic_entry(int irq, | |
56 | struct IO_APIC_route_entry *entry, | ||
57 | unsigned int destination, int vector, | ||
58 | struct io_apic_irq_attr *attr) | ||
59 | { | ||
60 | return -ENODEV; | ||
61 | } | ||
49 | #endif /* CONFIG_IRQ_REMAP */ | 62 | #endif /* CONFIG_IRQ_REMAP */ |
50 | 63 | ||
51 | #endif /* __X86_INTR_REMAPPING_H */ | 64 | #endif /* __X86_INTR_REMAPPING_H */ |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 1151fdccaad6..e1ab625fb9ca 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -1362,77 +1362,13 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg, | |||
1362 | fasteoi ? "fasteoi" : "edge"); | 1362 | fasteoi ? "fasteoi" : "edge"); |
1363 | } | 1363 | } |
1364 | 1364 | ||
1365 | |||
1366 | static int setup_ir_ioapic_entry(int irq, | ||
1367 | struct IR_IO_APIC_route_entry *entry, | ||
1368 | unsigned int destination, int vector, | ||
1369 | struct io_apic_irq_attr *attr) | ||
1370 | { | ||
1371 | int index; | ||
1372 | struct irte irte; | ||
1373 | int ioapic_id = mpc_ioapic_id(attr->ioapic); | ||
1374 | struct intel_iommu *iommu = map_ioapic_to_ir(ioapic_id); | ||
1375 | |||
1376 | if (!iommu) { | ||
1377 | pr_warn("No mapping iommu for ioapic %d\n", ioapic_id); | ||
1378 | return -ENODEV; | ||
1379 | } | ||
1380 | |||
1381 | index = alloc_irte(iommu, irq, 1); | ||
1382 | if (index < 0) { | ||
1383 | pr_warn("Failed to allocate IRTE for ioapic %d\n", ioapic_id); | ||
1384 | return -ENOMEM; | ||
1385 | } | ||
1386 | |||
1387 | prepare_irte(&irte, vector, destination); | ||
1388 | |||
1389 | /* Set source-id of interrupt request */ | ||
1390 | set_ioapic_sid(&irte, ioapic_id); | ||
1391 | |||
1392 | modify_irte(irq, &irte); | ||
1393 | |||
1394 | apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: " | ||
1395 | "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d " | ||
1396 | "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X " | ||
1397 | "Avail:%X Vector:%02X Dest:%08X " | ||
1398 | "SID:%04X SQ:%X SVT:%X)\n", | ||
1399 | attr->ioapic, irte.present, irte.fpd, irte.dst_mode, | ||
1400 | irte.redir_hint, irte.trigger_mode, irte.dlvry_mode, | ||
1401 | irte.avail, irte.vector, irte.dest_id, | ||
1402 | irte.sid, irte.sq, irte.svt); | ||
1403 | |||
1404 | memset(entry, 0, sizeof(*entry)); | ||
1405 | |||
1406 | entry->index2 = (index >> 15) & 0x1; | ||
1407 | entry->zero = 0; | ||
1408 | entry->format = 1; | ||
1409 | entry->index = (index & 0x7fff); | ||
1410 | /* | ||
1411 | * IO-APIC RTE will be configured with virtual vector. | ||
1412 | * irq handler will do the explicit EOI to the io-apic. | ||
1413 | */ | ||
1414 | entry->vector = attr->ioapic_pin; | ||
1415 | entry->mask = 0; /* enable IRQ */ | ||
1416 | entry->trigger = attr->trigger; | ||
1417 | entry->polarity = attr->polarity; | ||
1418 | |||
1419 | /* Mask level triggered irqs. | ||
1420 | * Use IRQ_DELAYED_DISABLE for edge triggered irqs. | ||
1421 | */ | ||
1422 | if (attr->trigger) | ||
1423 | entry->mask = 1; | ||
1424 | |||
1425 | return 0; | ||
1426 | } | ||
1427 | |||
1428 | static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, | 1365 | static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, |
1429 | unsigned int destination, int vector, | 1366 | unsigned int destination, int vector, |
1430 | struct io_apic_irq_attr *attr) | 1367 | struct io_apic_irq_attr *attr) |
1431 | { | 1368 | { |
1432 | if (intr_remapping_enabled) | 1369 | if (intr_remapping_enabled) |
1433 | return setup_ir_ioapic_entry(irq, | 1370 | return intr_setup_ioapic_entry(irq, entry, destination, |
1434 | (struct IR_IO_APIC_route_entry *)entry, | 1371 | vector, attr); |
1435 | destination, vector, attr); | ||
1436 | 1372 | ||
1437 | memset(entry, 0, sizeof(*entry)); | 1373 | memset(entry, 0, sizeof(*entry)); |
1438 | 1374 | ||
diff --git a/drivers/iommu/intel_intr_remapping.c b/drivers/iommu/intel_intr_remapping.c index 610b75b66c07..f495eba4b6ab 100644 --- a/drivers/iommu/intel_intr_remapping.c +++ b/drivers/iommu/intel_intr_remapping.c | |||
@@ -31,6 +31,7 @@ struct hpet_scope { | |||
31 | }; | 31 | }; |
32 | 32 | ||
33 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) | 33 | #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) |
34 | #define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8) | ||
34 | 35 | ||
35 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; | 36 | static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; |
36 | static struct hpet_scope ir_hpet[MAX_HPET_TBS]; | 37 | static struct hpet_scope ir_hpet[MAX_HPET_TBS]; |
@@ -814,6 +815,93 @@ error: | |||
814 | return -1; | 815 | return -1; |
815 | } | 816 | } |
816 | 817 | ||
818 | static void prepare_irte(struct irte *irte, int vector, | ||
819 | unsigned int dest) | ||
820 | { | ||
821 | memset(irte, 0, sizeof(*irte)); | ||
822 | |||
823 | irte->present = 1; | ||
824 | irte->dst_mode = apic->irq_dest_mode; | ||
825 | /* | ||
826 | * Trigger mode in the IRTE will always be edge, and for IO-APIC, the | ||
827 | * actual level or edge trigger will be setup in the IO-APIC | ||
828 | * RTE. This will help simplify level triggered irq migration. | ||
829 | * For more details, see the comments (in io_apic.c) explainig IO-APIC | ||
830 | * irq migration in the presence of interrupt-remapping. | ||
831 | */ | ||
832 | irte->trigger_mode = 0; | ||
833 | irte->dlvry_mode = apic->irq_delivery_mode; | ||
834 | irte->vector = vector; | ||
835 | irte->dest_id = IRTE_DEST(dest); | ||
836 | irte->redir_hint = 1; | ||
837 | } | ||
838 | |||
839 | static int intel_setup_ioapic_entry(int irq, | ||
840 | struct IO_APIC_route_entry *route_entry, | ||
841 | unsigned int destination, int vector, | ||
842 | struct io_apic_irq_attr *attr) | ||
843 | { | ||
844 | int ioapic_id = mpc_ioapic_id(attr->ioapic); | ||
845 | struct intel_iommu *iommu = map_ioapic_to_ir(ioapic_id); | ||
846 | struct IR_IO_APIC_route_entry *entry; | ||
847 | struct irte irte; | ||
848 | int index; | ||
849 | |||
850 | if (!iommu) { | ||
851 | pr_warn("No mapping iommu for ioapic %d\n", ioapic_id); | ||
852 | return -ENODEV; | ||
853 | } | ||
854 | |||
855 | entry = (struct IR_IO_APIC_route_entry *)route_entry; | ||
856 | |||
857 | index = alloc_irte(iommu, irq, 1); | ||
858 | if (index < 0) { | ||
859 | pr_warn("Failed to allocate IRTE for ioapic %d\n", ioapic_id); | ||
860 | return -ENOMEM; | ||
861 | } | ||
862 | |||
863 | prepare_irte(&irte, vector, destination); | ||
864 | |||
865 | /* Set source-id of interrupt request */ | ||
866 | set_ioapic_sid(&irte, ioapic_id); | ||
867 | |||
868 | modify_irte(irq, &irte); | ||
869 | |||
870 | apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: " | ||
871 | "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d " | ||
872 | "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X " | ||
873 | "Avail:%X Vector:%02X Dest:%08X " | ||
874 | "SID:%04X SQ:%X SVT:%X)\n", | ||
875 | attr->ioapic, irte.present, irte.fpd, irte.dst_mode, | ||
876 | irte.redir_hint, irte.trigger_mode, irte.dlvry_mode, | ||
877 | irte.avail, irte.vector, irte.dest_id, | ||
878 | irte.sid, irte.sq, irte.svt); | ||
879 | |||
880 | memset(entry, 0, sizeof(*entry)); | ||
881 | |||
882 | entry->index2 = (index >> 15) & 0x1; | ||
883 | entry->zero = 0; | ||
884 | entry->format = 1; | ||
885 | entry->index = (index & 0x7fff); | ||
886 | /* | ||
887 | * IO-APIC RTE will be configured with virtual vector. | ||
888 | * irq handler will do the explicit EOI to the io-apic. | ||
889 | */ | ||
890 | entry->vector = attr->ioapic_pin; | ||
891 | entry->mask = 0; /* enable IRQ */ | ||
892 | entry->trigger = attr->trigger; | ||
893 | entry->polarity = attr->polarity; | ||
894 | |||
895 | /* Mask level triggered irqs. | ||
896 | * Use IRQ_DELAYED_DISABLE for edge triggered irqs. | ||
897 | */ | ||
898 | if (attr->trigger) | ||
899 | entry->mask = 1; | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | |||
817 | struct irq_remap_ops intel_irq_remap_ops = { | 905 | struct irq_remap_ops intel_irq_remap_ops = { |
818 | .supported = intel_intr_remapping_supported, | 906 | .supported = intel_intr_remapping_supported, |
819 | .hardware_init = dmar_table_init, | 907 | .hardware_init = dmar_table_init, |
@@ -821,4 +909,5 @@ struct irq_remap_ops intel_irq_remap_ops = { | |||
821 | .hardware_disable = disable_intr_remapping, | 909 | .hardware_disable = disable_intr_remapping, |
822 | .hardware_reenable = reenable_intr_remapping, | 910 | .hardware_reenable = reenable_intr_remapping, |
823 | .enable_faulting = enable_drhd_fault_handling, | 911 | .enable_faulting = enable_drhd_fault_handling, |
912 | .setup_ioapic_entry = intel_setup_ioapic_entry, | ||
824 | }; | 913 | }; |
diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intr_remapping.c index 9aabed7c0320..739148ab2538 100644 --- a/drivers/iommu/intr_remapping.c +++ b/drivers/iommu/intr_remapping.c | |||
@@ -98,3 +98,15 @@ int __init intr_enable_fault_handling(void) | |||
98 | 98 | ||
99 | return remap_ops->enable_faulting(); | 99 | return remap_ops->enable_faulting(); |
100 | } | 100 | } |
101 | |||
102 | int intr_setup_ioapic_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 | } | ||
diff --git a/drivers/iommu/intr_remapping.h b/drivers/iommu/intr_remapping.h index 2744c9ae4aec..e8994f2b3bbe 100644 --- a/drivers/iommu/intr_remapping.h +++ b/drivers/iommu/intr_remapping.h | |||
@@ -24,6 +24,9 @@ | |||
24 | 24 | ||
25 | #ifdef CONFIG_IRQ_REMAP | 25 | #ifdef CONFIG_IRQ_REMAP |
26 | 26 | ||
27 | struct IO_APIC_route_entry; | ||
28 | struct io_apic_irq_attr; | ||
29 | |||
27 | extern int disable_intremap; | 30 | extern int disable_intremap; |
28 | extern int disable_sourceid_checking; | 31 | extern int disable_sourceid_checking; |
29 | extern int no_x2apic_optout; | 32 | extern int no_x2apic_optout; |
@@ -46,6 +49,11 @@ struct irq_remap_ops { | |||
46 | 49 | ||
47 | /* Enable fault handling */ | 50 | /* Enable fault handling */ |
48 | int (*enable_faulting)(void); | 51 | int (*enable_faulting)(void); |
52 | |||
53 | /* IO-APIC setup routine */ | ||
54 | int (*setup_ioapic_entry)(int irq, struct IO_APIC_route_entry *, | ||
55 | unsigned int, int, | ||
56 | struct io_apic_irq_attr *); | ||
49 | }; | 57 | }; |
50 | 58 | ||
51 | extern struct irq_remap_ops intel_irq_remap_ops; | 59 | extern struct irq_remap_ops intel_irq_remap_ops; |