diff options
-rw-r--r-- | arch/ia64/include/asm/irq_remapping.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/irq_remapping.h | 118 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 30 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 297 | ||||
-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 | ||||
-rw-r--r-- | include/linux/dmar.h | 85 |
12 files changed, 731 insertions, 451 deletions
diff --git a/arch/ia64/include/asm/irq_remapping.h b/arch/ia64/include/asm/irq_remapping.h new file mode 100644 index 000000000000..a8687b1d8906 --- /dev/null +++ b/arch/ia64/include/asm/irq_remapping.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef __IA64_INTR_REMAPPING_H | ||
2 | #define __IA64_INTR_REMAPPING_H | ||
3 | #define irq_remapping_enabled 0 | ||
4 | #endif | ||
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index 47d99934580f..5fb9bbbd2f14 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h | |||
@@ -1,45 +1,101 @@ | |||
1 | #ifndef _ASM_X86_IRQ_REMAPPING_H | 1 | /* |
2 | #define _ASM_X86_IRQ_REMAPPING_H | 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 the interface of the interrupt remapping code to | ||
19 | * the x86 interrupt management code. | ||
20 | */ | ||
3 | 21 | ||
4 | #define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8) | 22 | #ifndef __X86_IRQ_REMAPPING_H |
23 | #define __X86_IRQ_REMAPPING_H | ||
24 | |||
25 | #include <asm/io_apic.h> | ||
5 | 26 | ||
6 | #ifdef CONFIG_IRQ_REMAP | 27 | #ifdef CONFIG_IRQ_REMAP |
7 | static void irq_remap_modify_chip_defaults(struct irq_chip *chip); | 28 | |
8 | static inline void prepare_irte(struct irte *irte, int vector, | 29 | extern int irq_remapping_enabled; |
9 | unsigned int dest) | 30 | |
31 | extern void setup_irq_remapping_ops(void); | ||
32 | extern int irq_remapping_supported(void); | ||
33 | extern int irq_remapping_prepare(void); | ||
34 | extern int irq_remapping_enable(void); | ||
35 | extern void irq_remapping_disable(void); | ||
36 | extern int irq_remapping_reenable(int); | ||
37 | extern int irq_remap_enable_fault_handling(void); | ||
38 | extern int setup_ioapic_remapped_entry(int irq, | ||
39 | struct IO_APIC_route_entry *entry, | ||
40 | unsigned int destination, | ||
41 | int vector, | ||
42 | struct io_apic_irq_attr *attr); | ||
43 | extern int set_remapped_irq_affinity(struct irq_data *data, | ||
44 | const struct cpumask *mask, | ||
45 | bool force); | ||
46 | extern void free_remapped_irq(int irq); | ||
47 | extern void compose_remapped_msi_msg(struct pci_dev *pdev, | ||
48 | unsigned int irq, unsigned int dest, | ||
49 | struct msi_msg *msg, u8 hpet_id); | ||
50 | extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); | ||
51 | extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | ||
52 | int index, int sub_handle); | ||
53 | extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id); | ||
54 | |||
55 | #else /* CONFIG_IRQ_REMAP */ | ||
56 | |||
57 | #define irq_remapping_enabled 0 | ||
58 | |||
59 | static inline void setup_irq_remapping_ops(void) { } | ||
60 | static inline int irq_remapping_supported(void) { return 0; } | ||
61 | static inline int irq_remapping_prepare(void) { return -ENODEV; } | ||
62 | static inline int irq_remapping_enable(void) { return -ENODEV; } | ||
63 | static inline void irq_remapping_disable(void) { } | ||
64 | static inline int irq_remapping_reenable(int eim) { return -ENODEV; } | ||
65 | static inline int irq_remap_enable_fault_handling(void) { return -ENODEV; } | ||
66 | static inline int setup_ioapic_remapped_entry(int irq, | ||
67 | struct IO_APIC_route_entry *entry, | ||
68 | unsigned int destination, | ||
69 | int vector, | ||
70 | struct io_apic_irq_attr *attr) | ||
71 | { | ||
72 | return -ENODEV; | ||
73 | } | ||
74 | static inline int set_remapped_irq_affinity(struct irq_data *data, | ||
75 | const struct cpumask *mask, | ||
76 | bool force) | ||
10 | { | 77 | { |
11 | memset(irte, 0, sizeof(*irte)); | 78 | return 0; |
12 | |||
13 | irte->present = 1; | ||
14 | irte->dst_mode = apic->irq_dest_mode; | ||
15 | /* | ||
16 | * Trigger mode in the IRTE will always be edge, and for IO-APIC, the | ||
17 | * actual level or edge trigger will be setup in the IO-APIC | ||
18 | * RTE. This will help simplify level triggered irq migration. | ||
19 | * For more details, see the comments (in io_apic.c) explainig IO-APIC | ||
20 | * irq migration in the presence of interrupt-remapping. | ||
21 | */ | ||
22 | irte->trigger_mode = 0; | ||
23 | irte->dlvry_mode = apic->irq_delivery_mode; | ||
24 | irte->vector = vector; | ||
25 | irte->dest_id = IRTE_DEST(dest); | ||
26 | irte->redir_hint = 1; | ||
27 | } | 79 | } |
28 | static inline bool irq_remapped(struct irq_cfg *cfg) | 80 | static inline void free_remapped_irq(int irq) { } |
81 | static inline void compose_remapped_msi_msg(struct pci_dev *pdev, | ||
82 | unsigned int irq, unsigned int dest, | ||
83 | struct msi_msg *msg, u8 hpet_id) | ||
29 | { | 84 | { |
30 | return cfg->irq_2_iommu.iommu != NULL; | ||
31 | } | 85 | } |
32 | #else | 86 | static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) |
33 | static void prepare_irte(struct irte *irte, int vector, unsigned int dest) | ||
34 | { | 87 | { |
88 | return -ENODEV; | ||
35 | } | 89 | } |
36 | static inline bool irq_remapped(struct irq_cfg *cfg) | 90 | static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, |
91 | int index, int sub_handle) | ||
37 | { | 92 | { |
38 | return false; | 93 | return -ENODEV; |
39 | } | 94 | } |
40 | static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip) | 95 | static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) |
41 | { | 96 | { |
97 | return -ENODEV; | ||
42 | } | 98 | } |
43 | #endif | 99 | #endif /* CONFIG_IRQ_REMAP */ |
44 | 100 | ||
45 | #endif /* _ASM_X86_IRQ_REMAPPING_H */ | 101 | #endif /* __X86_IRQ_REMAPPING_H */ |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index edc24480469f..3722179a49db 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/smp.h> | 35 | #include <linux/smp.h> |
36 | #include <linux/mm.h> | 36 | #include <linux/mm.h> |
37 | 37 | ||
38 | #include <asm/irq_remapping.h> | ||
38 | #include <asm/perf_event.h> | 39 | #include <asm/perf_event.h> |
39 | #include <asm/x86_init.h> | 40 | #include <asm/x86_init.h> |
40 | #include <asm/pgalloc.h> | 41 | #include <asm/pgalloc.h> |
@@ -1441,8 +1442,8 @@ void __init bsp_end_local_APIC_setup(void) | |||
1441 | * Now that local APIC setup is completed for BP, configure the fault | 1442 | * Now that local APIC setup is completed for BP, configure the fault |
1442 | * handling for interrupt remapping. | 1443 | * handling for interrupt remapping. |
1443 | */ | 1444 | */ |
1444 | if (intr_remapping_enabled) | 1445 | if (irq_remapping_enabled) |
1445 | enable_drhd_fault_handling(); | 1446 | irq_remap_enable_fault_handling(); |
1446 | 1447 | ||
1447 | } | 1448 | } |
1448 | 1449 | ||
@@ -1517,7 +1518,7 @@ void enable_x2apic(void) | |||
1517 | int __init enable_IR(void) | 1518 | int __init enable_IR(void) |
1518 | { | 1519 | { |
1519 | #ifdef CONFIG_IRQ_REMAP | 1520 | #ifdef CONFIG_IRQ_REMAP |
1520 | if (!intr_remapping_supported()) { | 1521 | if (!irq_remapping_supported()) { |
1521 | pr_debug("intr-remapping not supported\n"); | 1522 | pr_debug("intr-remapping not supported\n"); |
1522 | return -1; | 1523 | return -1; |
1523 | } | 1524 | } |
@@ -1528,7 +1529,7 @@ int __init enable_IR(void) | |||
1528 | return -1; | 1529 | return -1; |
1529 | } | 1530 | } |
1530 | 1531 | ||
1531 | return enable_intr_remapping(); | 1532 | return irq_remapping_enable(); |
1532 | #endif | 1533 | #endif |
1533 | return -1; | 1534 | return -1; |
1534 | } | 1535 | } |
@@ -1537,10 +1538,13 @@ void __init enable_IR_x2apic(void) | |||
1537 | { | 1538 | { |
1538 | unsigned long flags; | 1539 | unsigned long flags; |
1539 | int ret, x2apic_enabled = 0; | 1540 | int ret, x2apic_enabled = 0; |
1540 | int dmar_table_init_ret; | 1541 | int hardware_init_ret; |
1541 | 1542 | ||
1542 | dmar_table_init_ret = dmar_table_init(); | 1543 | /* Make sure irq_remap_ops are initialized */ |
1543 | if (dmar_table_init_ret && !x2apic_supported()) | 1544 | setup_irq_remapping_ops(); |
1545 | |||
1546 | hardware_init_ret = irq_remapping_prepare(); | ||
1547 | if (hardware_init_ret && !x2apic_supported()) | ||
1544 | return; | 1548 | return; |
1545 | 1549 | ||
1546 | ret = save_ioapic_entries(); | 1550 | ret = save_ioapic_entries(); |
@@ -1556,7 +1560,7 @@ void __init enable_IR_x2apic(void) | |||
1556 | if (x2apic_preenabled && nox2apic) | 1560 | if (x2apic_preenabled && nox2apic) |
1557 | disable_x2apic(); | 1561 | disable_x2apic(); |
1558 | 1562 | ||
1559 | if (dmar_table_init_ret) | 1563 | if (hardware_init_ret) |
1560 | ret = -1; | 1564 | ret = -1; |
1561 | else | 1565 | else |
1562 | ret = enable_IR(); | 1566 | ret = enable_IR(); |
@@ -2176,8 +2180,8 @@ static int lapic_suspend(void) | |||
2176 | local_irq_save(flags); | 2180 | local_irq_save(flags); |
2177 | disable_local_APIC(); | 2181 | disable_local_APIC(); |
2178 | 2182 | ||
2179 | if (intr_remapping_enabled) | 2183 | if (irq_remapping_enabled) |
2180 | disable_intr_remapping(); | 2184 | irq_remapping_disable(); |
2181 | 2185 | ||
2182 | local_irq_restore(flags); | 2186 | local_irq_restore(flags); |
2183 | return 0; | 2187 | return 0; |
@@ -2193,7 +2197,7 @@ static void lapic_resume(void) | |||
2193 | return; | 2197 | return; |
2194 | 2198 | ||
2195 | local_irq_save(flags); | 2199 | local_irq_save(flags); |
2196 | if (intr_remapping_enabled) { | 2200 | if (irq_remapping_enabled) { |
2197 | /* | 2201 | /* |
2198 | * IO-APIC and PIC have their own resume routines. | 2202 | * IO-APIC and PIC have their own resume routines. |
2199 | * We just mask them here to make sure the interrupt | 2203 | * We just mask them here to make sure the interrupt |
@@ -2245,8 +2249,8 @@ static void lapic_resume(void) | |||
2245 | apic_write(APIC_ESR, 0); | 2249 | apic_write(APIC_ESR, 0); |
2246 | apic_read(APIC_ESR); | 2250 | apic_read(APIC_ESR); |
2247 | 2251 | ||
2248 | if (intr_remapping_enabled) | 2252 | if (irq_remapping_enabled) |
2249 | reenable_intr_remapping(x2apic_mode); | 2253 | irq_remapping_reenable(x2apic_mode); |
2250 | 2254 | ||
2251 | local_irq_restore(flags); | 2255 | local_irq_restore(flags); |
2252 | } | 2256 | } |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e88300d8e80a..ef0648cd7084 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -86,6 +86,22 @@ void __init set_io_apic_ops(const struct io_apic_ops *ops) | |||
86 | io_apic_ops = *ops; | 86 | io_apic_ops = *ops; |
87 | } | 87 | } |
88 | 88 | ||
89 | #ifdef CONFIG_IRQ_REMAP | ||
90 | static void irq_remap_modify_chip_defaults(struct irq_chip *chip); | ||
91 | static inline bool irq_remapped(struct irq_cfg *cfg) | ||
92 | { | ||
93 | return cfg->irq_2_iommu.iommu != NULL; | ||
94 | } | ||
95 | #else | ||
96 | static inline bool irq_remapped(struct irq_cfg *cfg) | ||
97 | { | ||
98 | return false; | ||
99 | } | ||
100 | static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip) | ||
101 | { | ||
102 | } | ||
103 | #endif | ||
104 | |||
89 | /* | 105 | /* |
90 | * Is the SiS APIC rmw bug present ? | 106 | * Is the SiS APIC rmw bug present ? |
91 | * -1 = don't know, 0 = no, 1 = yes | 107 | * -1 = don't know, 0 = no, 1 = yes |
@@ -1361,77 +1377,13 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg, | |||
1361 | fasteoi ? "fasteoi" : "edge"); | 1377 | fasteoi ? "fasteoi" : "edge"); |
1362 | } | 1378 | } |
1363 | 1379 | ||
1364 | |||
1365 | static int setup_ir_ioapic_entry(int irq, | ||
1366 | struct IR_IO_APIC_route_entry *entry, | ||
1367 | unsigned int destination, int vector, | ||
1368 | struct io_apic_irq_attr *attr) | ||
1369 | { | ||
1370 | int index; | ||
1371 | struct irte irte; | ||
1372 | int ioapic_id = mpc_ioapic_id(attr->ioapic); | ||
1373 | struct intel_iommu *iommu = map_ioapic_to_ir(ioapic_id); | ||
1374 | |||
1375 | if (!iommu) { | ||
1376 | pr_warn("No mapping iommu for ioapic %d\n", ioapic_id); | ||
1377 | return -ENODEV; | ||
1378 | } | ||
1379 | |||
1380 | index = alloc_irte(iommu, irq, 1); | ||
1381 | if (index < 0) { | ||
1382 | pr_warn("Failed to allocate IRTE for ioapic %d\n", ioapic_id); | ||
1383 | return -ENOMEM; | ||
1384 | } | ||
1385 | |||
1386 | prepare_irte(&irte, vector, destination); | ||
1387 | |||
1388 | /* Set source-id of interrupt request */ | ||
1389 | set_ioapic_sid(&irte, ioapic_id); | ||
1390 | |||
1391 | modify_irte(irq, &irte); | ||
1392 | |||
1393 | apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: " | ||
1394 | "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d " | ||
1395 | "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X " | ||
1396 | "Avail:%X Vector:%02X Dest:%08X " | ||
1397 | "SID:%04X SQ:%X SVT:%X)\n", | ||
1398 | attr->ioapic, irte.present, irte.fpd, irte.dst_mode, | ||
1399 | irte.redir_hint, irte.trigger_mode, irte.dlvry_mode, | ||
1400 | irte.avail, irte.vector, irte.dest_id, | ||
1401 | irte.sid, irte.sq, irte.svt); | ||
1402 | |||
1403 | memset(entry, 0, sizeof(*entry)); | ||
1404 | |||
1405 | entry->index2 = (index >> 15) & 0x1; | ||
1406 | entry->zero = 0; | ||
1407 | entry->format = 1; | ||
1408 | entry->index = (index & 0x7fff); | ||
1409 | /* | ||
1410 | * IO-APIC RTE will be configured with virtual vector. | ||
1411 | * irq handler will do the explicit EOI to the io-apic. | ||
1412 | */ | ||
1413 | entry->vector = attr->ioapic_pin; | ||
1414 | entry->mask = 0; /* enable IRQ */ | ||
1415 | entry->trigger = attr->trigger; | ||
1416 | entry->polarity = attr->polarity; | ||
1417 | |||
1418 | /* Mask level triggered irqs. | ||
1419 | * Use IRQ_DELAYED_DISABLE for edge triggered irqs. | ||
1420 | */ | ||
1421 | if (attr->trigger) | ||
1422 | entry->mask = 1; | ||
1423 | |||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, | 1380 | static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, |
1428 | unsigned int destination, int vector, | 1381 | unsigned int destination, int vector, |
1429 | struct io_apic_irq_attr *attr) | 1382 | struct io_apic_irq_attr *attr) |
1430 | { | 1383 | { |
1431 | if (intr_remapping_enabled) | 1384 | if (irq_remapping_enabled) |
1432 | return setup_ir_ioapic_entry(irq, | 1385 | return setup_ioapic_remapped_entry(irq, entry, destination, |
1433 | (struct IR_IO_APIC_route_entry *)entry, | 1386 | vector, attr); |
1434 | destination, vector, attr); | ||
1435 | 1387 | ||
1436 | memset(entry, 0, sizeof(*entry)); | 1388 | memset(entry, 0, sizeof(*entry)); |
1437 | 1389 | ||
@@ -1588,7 +1540,7 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx, | |||
1588 | { | 1540 | { |
1589 | struct IO_APIC_route_entry entry; | 1541 | struct IO_APIC_route_entry entry; |
1590 | 1542 | ||
1591 | if (intr_remapping_enabled) | 1543 | if (irq_remapping_enabled) |
1592 | return; | 1544 | return; |
1593 | 1545 | ||
1594 | memset(&entry, 0, sizeof(entry)); | 1546 | memset(&entry, 0, sizeof(entry)); |
@@ -1674,7 +1626,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx) | |||
1674 | 1626 | ||
1675 | printk(KERN_DEBUG ".... IRQ redirection table:\n"); | 1627 | printk(KERN_DEBUG ".... IRQ redirection table:\n"); |
1676 | 1628 | ||
1677 | if (intr_remapping_enabled) { | 1629 | if (irq_remapping_enabled) { |
1678 | printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR" | 1630 | printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR" |
1679 | " Pol Stat Indx2 Zero Vect:\n"); | 1631 | " Pol Stat Indx2 Zero Vect:\n"); |
1680 | } else { | 1632 | } else { |
@@ -1683,7 +1635,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx) | |||
1683 | } | 1635 | } |
1684 | 1636 | ||
1685 | for (i = 0; i <= reg_01.bits.entries; i++) { | 1637 | for (i = 0; i <= reg_01.bits.entries; i++) { |
1686 | if (intr_remapping_enabled) { | 1638 | if (irq_remapping_enabled) { |
1687 | struct IO_APIC_route_entry entry; | 1639 | struct IO_APIC_route_entry entry; |
1688 | struct IR_IO_APIC_route_entry *ir_entry; | 1640 | struct IR_IO_APIC_route_entry *ir_entry; |
1689 | 1641 | ||
@@ -2050,7 +2002,7 @@ void disable_IO_APIC(void) | |||
2050 | * IOAPIC RTE as well as interrupt-remapping table entry). | 2002 | * IOAPIC RTE as well as interrupt-remapping table entry). |
2051 | * As this gets called during crash dump, keep this simple for now. | 2003 | * As this gets called during crash dump, keep this simple for now. |
2052 | */ | 2004 | */ |
2053 | if (ioapic_i8259.pin != -1 && !intr_remapping_enabled) { | 2005 | if (ioapic_i8259.pin != -1 && !irq_remapping_enabled) { |
2054 | struct IO_APIC_route_entry entry; | 2006 | struct IO_APIC_route_entry entry; |
2055 | 2007 | ||
2056 | memset(&entry, 0, sizeof(entry)); | 2008 | memset(&entry, 0, sizeof(entry)); |
@@ -2074,7 +2026,7 @@ void disable_IO_APIC(void) | |||
2074 | * Use virtual wire A mode when interrupt remapping is enabled. | 2026 | * Use virtual wire A mode when interrupt remapping is enabled. |
2075 | */ | 2027 | */ |
2076 | if (cpu_has_apic || apic_from_smp_config()) | 2028 | if (cpu_has_apic || apic_from_smp_config()) |
2077 | disconnect_bsp_APIC(!intr_remapping_enabled && | 2029 | disconnect_bsp_APIC(!irq_remapping_enabled && |
2078 | ioapic_i8259.pin != -1); | 2030 | ioapic_i8259.pin != -1); |
2079 | } | 2031 | } |
2080 | 2032 | ||
@@ -2390,71 +2342,6 @@ ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | |||
2390 | return ret; | 2342 | return ret; |
2391 | } | 2343 | } |
2392 | 2344 | ||
2393 | #ifdef CONFIG_IRQ_REMAP | ||
2394 | |||
2395 | /* | ||
2396 | * Migrate the IO-APIC irq in the presence of intr-remapping. | ||
2397 | * | ||
2398 | * For both level and edge triggered, irq migration is a simple atomic | ||
2399 | * update(of vector and cpu destination) of IRTE and flush the hardware cache. | ||
2400 | * | ||
2401 | * For level triggered, we eliminate the io-apic RTE modification (with the | ||
2402 | * updated vector information), by using a virtual vector (io-apic pin number). | ||
2403 | * Real vector that is used for interrupting cpu will be coming from | ||
2404 | * the interrupt-remapping table entry. | ||
2405 | * | ||
2406 | * As the migration is a simple atomic update of IRTE, the same mechanism | ||
2407 | * is used to migrate MSI irq's in the presence of interrupt-remapping. | ||
2408 | */ | ||
2409 | static int | ||
2410 | ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
2411 | bool force) | ||
2412 | { | ||
2413 | struct irq_cfg *cfg = data->chip_data; | ||
2414 | unsigned int dest, irq = data->irq; | ||
2415 | struct irte irte; | ||
2416 | |||
2417 | if (!cpumask_intersects(mask, cpu_online_mask)) | ||
2418 | return -EINVAL; | ||
2419 | |||
2420 | if (get_irte(irq, &irte)) | ||
2421 | return -EBUSY; | ||
2422 | |||
2423 | if (assign_irq_vector(irq, cfg, mask)) | ||
2424 | return -EBUSY; | ||
2425 | |||
2426 | dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask); | ||
2427 | |||
2428 | irte.vector = cfg->vector; | ||
2429 | irte.dest_id = IRTE_DEST(dest); | ||
2430 | |||
2431 | /* | ||
2432 | * Atomically updates the IRTE with the new destination, vector | ||
2433 | * and flushes the interrupt entry cache. | ||
2434 | */ | ||
2435 | modify_irte(irq, &irte); | ||
2436 | |||
2437 | /* | ||
2438 | * After this point, all the interrupts will start arriving | ||
2439 | * at the new destination. So, time to cleanup the previous | ||
2440 | * vector allocation. | ||
2441 | */ | ||
2442 | if (cfg->move_in_progress) | ||
2443 | send_cleanup_vector(cfg); | ||
2444 | |||
2445 | cpumask_copy(data->affinity, mask); | ||
2446 | return 0; | ||
2447 | } | ||
2448 | |||
2449 | #else | ||
2450 | static inline int | ||
2451 | ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | ||
2452 | bool force) | ||
2453 | { | ||
2454 | return 0; | ||
2455 | } | ||
2456 | #endif | ||
2457 | |||
2458 | asmlinkage void smp_irq_move_cleanup_interrupt(void) | 2345 | asmlinkage void smp_irq_move_cleanup_interrupt(void) |
2459 | { | 2346 | { |
2460 | unsigned vector, me; | 2347 | unsigned vector, me; |
@@ -2699,7 +2586,7 @@ static void irq_remap_modify_chip_defaults(struct irq_chip *chip) | |||
2699 | chip->irq_eoi = ir_ack_apic_level; | 2586 | chip->irq_eoi = ir_ack_apic_level; |
2700 | 2587 | ||
2701 | #ifdef CONFIG_SMP | 2588 | #ifdef CONFIG_SMP |
2702 | chip->irq_set_affinity = ir_ioapic_set_affinity; | 2589 | chip->irq_set_affinity = set_remapped_irq_affinity; |
2703 | #endif | 2590 | #endif |
2704 | } | 2591 | } |
2705 | #endif /* CONFIG_IRQ_REMAP */ | 2592 | #endif /* CONFIG_IRQ_REMAP */ |
@@ -2912,7 +2799,7 @@ static inline void __init check_timer(void) | |||
2912 | * 8259A. | 2799 | * 8259A. |
2913 | */ | 2800 | */ |
2914 | if (pin1 == -1) { | 2801 | if (pin1 == -1) { |
2915 | if (intr_remapping_enabled) | 2802 | if (irq_remapping_enabled) |
2916 | panic("BIOS bug: timer not connected to IO-APIC"); | 2803 | panic("BIOS bug: timer not connected to IO-APIC"); |
2917 | pin1 = pin2; | 2804 | pin1 = pin2; |
2918 | apic1 = apic2; | 2805 | apic1 = apic2; |
@@ -2945,7 +2832,7 @@ static inline void __init check_timer(void) | |||
2945 | clear_IO_APIC_pin(0, pin1); | 2832 | clear_IO_APIC_pin(0, pin1); |
2946 | goto out; | 2833 | goto out; |
2947 | } | 2834 | } |
2948 | if (intr_remapping_enabled) | 2835 | if (irq_remapping_enabled) |
2949 | panic("timer doesn't work through Interrupt-remapped IO-APIC"); | 2836 | panic("timer doesn't work through Interrupt-remapped IO-APIC"); |
2950 | local_irq_disable(); | 2837 | local_irq_disable(); |
2951 | clear_IO_APIC_pin(apic1, pin1); | 2838 | clear_IO_APIC_pin(apic1, pin1); |
@@ -3169,7 +3056,7 @@ void destroy_irq(unsigned int irq) | |||
3169 | irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); | 3056 | irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); |
3170 | 3057 | ||
3171 | if (irq_remapped(cfg)) | 3058 | if (irq_remapped(cfg)) |
3172 | free_irte(irq); | 3059 | free_remapped_irq(irq); |
3173 | raw_spin_lock_irqsave(&vector_lock, flags); | 3060 | raw_spin_lock_irqsave(&vector_lock, flags); |
3174 | __clear_irq_vector(irq, cfg); | 3061 | __clear_irq_vector(irq, cfg); |
3175 | raw_spin_unlock_irqrestore(&vector_lock, flags); | 3062 | raw_spin_unlock_irqrestore(&vector_lock, flags); |
@@ -3198,54 +3085,34 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, | |||
3198 | dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus()); | 3085 | dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus()); |
3199 | 3086 | ||
3200 | if (irq_remapped(cfg)) { | 3087 | if (irq_remapped(cfg)) { |
3201 | struct irte irte; | 3088 | compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id); |
3202 | int ir_index; | 3089 | return err; |
3203 | u16 sub_handle; | 3090 | } |
3204 | |||
3205 | ir_index = map_irq_to_irte_handle(irq, &sub_handle); | ||
3206 | BUG_ON(ir_index == -1); | ||
3207 | |||
3208 | prepare_irte(&irte, cfg->vector, dest); | ||
3209 | |||
3210 | /* Set source-id of interrupt request */ | ||
3211 | if (pdev) | ||
3212 | set_msi_sid(&irte, pdev); | ||
3213 | else | ||
3214 | set_hpet_sid(&irte, hpet_id); | ||
3215 | |||
3216 | modify_irte(irq, &irte); | ||
3217 | 3091 | ||
3092 | if (x2apic_enabled()) | ||
3093 | msg->address_hi = MSI_ADDR_BASE_HI | | ||
3094 | MSI_ADDR_EXT_DEST_ID(dest); | ||
3095 | else | ||
3218 | msg->address_hi = MSI_ADDR_BASE_HI; | 3096 | msg->address_hi = MSI_ADDR_BASE_HI; |
3219 | msg->data = sub_handle; | ||
3220 | msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT | | ||
3221 | MSI_ADDR_IR_SHV | | ||
3222 | MSI_ADDR_IR_INDEX1(ir_index) | | ||
3223 | MSI_ADDR_IR_INDEX2(ir_index); | ||
3224 | } else { | ||
3225 | if (x2apic_enabled()) | ||
3226 | msg->address_hi = MSI_ADDR_BASE_HI | | ||
3227 | MSI_ADDR_EXT_DEST_ID(dest); | ||
3228 | else | ||
3229 | msg->address_hi = MSI_ADDR_BASE_HI; | ||
3230 | 3097 | ||
3231 | msg->address_lo = | 3098 | msg->address_lo = |
3232 | MSI_ADDR_BASE_LO | | 3099 | MSI_ADDR_BASE_LO | |
3233 | ((apic->irq_dest_mode == 0) ? | 3100 | ((apic->irq_dest_mode == 0) ? |
3234 | MSI_ADDR_DEST_MODE_PHYSICAL: | 3101 | MSI_ADDR_DEST_MODE_PHYSICAL: |
3235 | MSI_ADDR_DEST_MODE_LOGICAL) | | 3102 | MSI_ADDR_DEST_MODE_LOGICAL) | |
3236 | ((apic->irq_delivery_mode != dest_LowestPrio) ? | 3103 | ((apic->irq_delivery_mode != dest_LowestPrio) ? |
3237 | MSI_ADDR_REDIRECTION_CPU: | 3104 | MSI_ADDR_REDIRECTION_CPU: |
3238 | MSI_ADDR_REDIRECTION_LOWPRI) | | 3105 | MSI_ADDR_REDIRECTION_LOWPRI) | |
3239 | MSI_ADDR_DEST_ID(dest); | 3106 | MSI_ADDR_DEST_ID(dest); |
3107 | |||
3108 | msg->data = | ||
3109 | MSI_DATA_TRIGGER_EDGE | | ||
3110 | MSI_DATA_LEVEL_ASSERT | | ||
3111 | ((apic->irq_delivery_mode != dest_LowestPrio) ? | ||
3112 | MSI_DATA_DELIVERY_FIXED: | ||
3113 | MSI_DATA_DELIVERY_LOWPRI) | | ||
3114 | MSI_DATA_VECTOR(cfg->vector); | ||
3240 | 3115 | ||
3241 | msg->data = | ||
3242 | MSI_DATA_TRIGGER_EDGE | | ||
3243 | MSI_DATA_LEVEL_ASSERT | | ||
3244 | ((apic->irq_delivery_mode != dest_LowestPrio) ? | ||
3245 | MSI_DATA_DELIVERY_FIXED: | ||
3246 | MSI_DATA_DELIVERY_LOWPRI) | | ||
3247 | MSI_DATA_VECTOR(cfg->vector); | ||
3248 | } | ||
3249 | return err; | 3116 | return err; |
3250 | } | 3117 | } |
3251 | 3118 | ||
@@ -3288,33 +3155,6 @@ static struct irq_chip msi_chip = { | |||
3288 | .irq_retrigger = ioapic_retrigger_irq, | 3155 | .irq_retrigger = ioapic_retrigger_irq, |
3289 | }; | 3156 | }; |
3290 | 3157 | ||
3291 | /* | ||
3292 | * Map the PCI dev to the corresponding remapping hardware unit | ||
3293 | * and allocate 'nvec' consecutive interrupt-remapping table entries | ||
3294 | * in it. | ||
3295 | */ | ||
3296 | static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec) | ||
3297 | { | ||
3298 | struct intel_iommu *iommu; | ||
3299 | int index; | ||
3300 | |||
3301 | iommu = map_dev_to_ir(dev); | ||
3302 | if (!iommu) { | ||
3303 | printk(KERN_ERR | ||
3304 | "Unable to map PCI %s to iommu\n", pci_name(dev)); | ||
3305 | return -ENOENT; | ||
3306 | } | ||
3307 | |||
3308 | index = alloc_irte(iommu, irq, nvec); | ||
3309 | if (index < 0) { | ||
3310 | printk(KERN_ERR | ||
3311 | "Unable to allocate %d IRTE for PCI %s\n", nvec, | ||
3312 | pci_name(dev)); | ||
3313 | return -ENOSPC; | ||
3314 | } | ||
3315 | return index; | ||
3316 | } | ||
3317 | |||
3318 | static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq) | 3158 | static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq) |
3319 | { | 3159 | { |
3320 | struct irq_chip *chip = &msi_chip; | 3160 | struct irq_chip *chip = &msi_chip; |
@@ -3345,7 +3185,6 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
3345 | int node, ret, sub_handle, index = 0; | 3185 | int node, ret, sub_handle, index = 0; |
3346 | unsigned int irq, irq_want; | 3186 | unsigned int irq, irq_want; |
3347 | struct msi_desc *msidesc; | 3187 | struct msi_desc *msidesc; |
3348 | struct intel_iommu *iommu = NULL; | ||
3349 | 3188 | ||
3350 | /* x86 doesn't support multiple MSI yet */ | 3189 | /* x86 doesn't support multiple MSI yet */ |
3351 | if (type == PCI_CAP_ID_MSI && nvec > 1) | 3190 | if (type == PCI_CAP_ID_MSI && nvec > 1) |
@@ -3359,7 +3198,7 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
3359 | if (irq == 0) | 3198 | if (irq == 0) |
3360 | return -1; | 3199 | return -1; |
3361 | irq_want = irq + 1; | 3200 | irq_want = irq + 1; |
3362 | if (!intr_remapping_enabled) | 3201 | if (!irq_remapping_enabled) |
3363 | goto no_ir; | 3202 | goto no_ir; |
3364 | 3203 | ||
3365 | if (!sub_handle) { | 3204 | if (!sub_handle) { |
@@ -3367,23 +3206,16 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
3367 | * allocate the consecutive block of IRTE's | 3206 | * allocate the consecutive block of IRTE's |
3368 | * for 'nvec' | 3207 | * for 'nvec' |
3369 | */ | 3208 | */ |
3370 | index = msi_alloc_irte(dev, irq, nvec); | 3209 | index = msi_alloc_remapped_irq(dev, irq, nvec); |
3371 | if (index < 0) { | 3210 | if (index < 0) { |
3372 | ret = index; | 3211 | ret = index; |
3373 | goto error; | 3212 | goto error; |
3374 | } | 3213 | } |
3375 | } else { | 3214 | } else { |
3376 | iommu = map_dev_to_ir(dev); | 3215 | ret = msi_setup_remapped_irq(dev, irq, index, |
3377 | if (!iommu) { | 3216 | sub_handle); |
3378 | ret = -ENOENT; | 3217 | if (ret < 0) |
3379 | goto error; | 3218 | goto error; |
3380 | } | ||
3381 | /* | ||
3382 | * setup the mapping between the irq and the IRTE | ||
3383 | * base index, the sub_handle pointing to the | ||
3384 | * appropriate interrupt remap table entry. | ||
3385 | */ | ||
3386 | set_irte_irq(irq, iommu, index, sub_handle); | ||
3387 | } | 3219 | } |
3388 | no_ir: | 3220 | no_ir: |
3389 | ret = setup_msi_irq(dev, msidesc, irq); | 3221 | ret = setup_msi_irq(dev, msidesc, irq); |
@@ -3501,15 +3333,8 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id) | |||
3501 | struct msi_msg msg; | 3333 | struct msi_msg msg; |
3502 | int ret; | 3334 | int ret; |
3503 | 3335 | ||
3504 | if (intr_remapping_enabled) { | 3336 | if (irq_remapping_enabled) { |
3505 | struct intel_iommu *iommu = map_hpet_to_ir(id); | 3337 | if (!setup_hpet_msi_remapped(irq, id)) |
3506 | int index; | ||
3507 | |||
3508 | if (!iommu) | ||
3509 | return -1; | ||
3510 | |||
3511 | index = alloc_irte(iommu, irq, 1); | ||
3512 | if (index < 0) | ||
3513 | return -1; | 3338 | return -1; |
3514 | } | 3339 | } |
3515 | 3340 | ||
@@ -3888,8 +3713,8 @@ void __init setup_ioapic_dest(void) | |||
3888 | else | 3713 | else |
3889 | mask = apic->target_cpus(); | 3714 | mask = apic->target_cpus(); |
3890 | 3715 | ||
3891 | if (intr_remapping_enabled) | 3716 | if (irq_remapping_enabled) |
3892 | ir_ioapic_set_affinity(idata, mask, false); | 3717 | set_remapped_irq_affinity(idata, mask, false); |
3893 | else | 3718 | else |
3894 | ioapic_set_affinity(idata, mask, false); | 3719 | ioapic_set_affinity(idata, mask, false); |
3895 | } | 3720 | } |
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 */ | ||
diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 731a60975101..b029d1aa2d12 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h | |||
@@ -114,91 +114,6 @@ struct irte { | |||
114 | }; | 114 | }; |
115 | }; | 115 | }; |
116 | 116 | ||
117 | #ifdef CONFIG_IRQ_REMAP | ||
118 | extern int intr_remapping_enabled; | ||
119 | extern int intr_remapping_supported(void); | ||
120 | extern int enable_intr_remapping(void); | ||
121 | extern void disable_intr_remapping(void); | ||
122 | extern int reenable_intr_remapping(int); | ||
123 | |||
124 | extern int get_irte(int irq, struct irte *entry); | ||
125 | extern int modify_irte(int irq, struct irte *irte_modified); | ||
126 | extern int alloc_irte(struct intel_iommu *iommu, int irq, u16 count); | ||
127 | extern int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, | ||
128 | u16 sub_handle); | ||
129 | extern int map_irq_to_irte_handle(int irq, u16 *sub_handle); | ||
130 | extern int free_irte(int irq); | ||
131 | |||
132 | extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); | ||
133 | extern struct intel_iommu *map_ioapic_to_ir(int apic); | ||
134 | extern struct intel_iommu *map_hpet_to_ir(u8 id); | ||
135 | extern int set_ioapic_sid(struct irte *irte, int apic); | ||
136 | extern int set_hpet_sid(struct irte *irte, u8 id); | ||
137 | extern int set_msi_sid(struct irte *irte, struct pci_dev *dev); | ||
138 | #else | ||
139 | static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | ||
140 | { | ||
141 | return -1; | ||
142 | } | ||
143 | static inline int modify_irte(int irq, struct irte *irte_modified) | ||
144 | { | ||
145 | return -1; | ||
146 | } | ||
147 | static inline int free_irte(int irq) | ||
148 | { | ||
149 | return -1; | ||
150 | } | ||
151 | static inline int map_irq_to_irte_handle(int irq, u16 *sub_handle) | ||
152 | { | ||
153 | return -1; | ||
154 | } | ||
155 | static inline int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, | ||
156 | u16 sub_handle) | ||
157 | { | ||
158 | return -1; | ||
159 | } | ||
160 | static inline struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) | ||
161 | { | ||
162 | return NULL; | ||
163 | } | ||
164 | static inline struct intel_iommu *map_ioapic_to_ir(int apic) | ||
165 | { | ||
166 | return NULL; | ||
167 | } | ||
168 | static inline struct intel_iommu *map_hpet_to_ir(unsigned int hpet_id) | ||
169 | { | ||
170 | return NULL; | ||
171 | } | ||
172 | static inline int set_ioapic_sid(struct irte *irte, int apic) | ||
173 | { | ||
174 | return 0; | ||
175 | } | ||
176 | static inline int set_hpet_sid(struct irte *irte, u8 id) | ||
177 | { | ||
178 | return -1; | ||
179 | } | ||
180 | static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) | ||
181 | { | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | #define intr_remapping_enabled (0) | ||
186 | |||
187 | static inline int enable_intr_remapping(void) | ||
188 | { | ||
189 | return -1; | ||
190 | } | ||
191 | |||
192 | static inline void disable_intr_remapping(void) | ||
193 | { | ||
194 | } | ||
195 | |||
196 | static inline int reenable_intr_remapping(int eim) | ||
197 | { | ||
198 | return 0; | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | enum { | 117 | enum { |
203 | IRQ_REMAP_XAPIC_MODE, | 118 | IRQ_REMAP_XAPIC_MODE, |
204 | IRQ_REMAP_X2APIC_MODE, | 119 | IRQ_REMAP_X2APIC_MODE, |