diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 3 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 31 | ||||
-rw-r--r-- | drivers/iommu/dmar.c | 2 | ||||
-rw-r--r-- | drivers/iommu/intr_remapping.c | 44 | ||||
-rw-r--r-- | include/linux/dmar.h | 14 |
5 files changed, 66 insertions, 28 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 854ed5ca7e3f..13865568809e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1014,10 +1014,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
1014 | has the capability. With this option, super page will | 1014 | has the capability. With this option, super page will |
1015 | not be supported. | 1015 | not be supported. |
1016 | intremap= [X86-64, Intel-IOMMU] | 1016 | intremap= [X86-64, Intel-IOMMU] |
1017 | Format: { on (default) | off | nosid } | ||
1018 | on enable Interrupt Remapping (default) | 1017 | on enable Interrupt Remapping (default) |
1019 | off disable Interrupt Remapping | 1018 | off disable Interrupt Remapping |
1020 | nosid disable Source ID checking | 1019 | nosid disable Source ID checking |
1020 | no_x2apic_optout | ||
1021 | BIOS x2APIC opt-out request will be ignored | ||
1021 | 1022 | ||
1022 | inttest= [IA-64] | 1023 | inttest= [IA-64] |
1023 | 1024 | ||
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 52fa56399a50..6b9874a5c7af 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -1440,24 +1440,18 @@ int __init enable_IR(void) | |||
1440 | #ifdef CONFIG_INTR_REMAP | 1440 | #ifdef CONFIG_INTR_REMAP |
1441 | if (!intr_remapping_supported()) { | 1441 | if (!intr_remapping_supported()) { |
1442 | pr_debug("intr-remapping not supported\n"); | 1442 | pr_debug("intr-remapping not supported\n"); |
1443 | return 0; | 1443 | return -1; |
1444 | } | 1444 | } |
1445 | 1445 | ||
1446 | if (!x2apic_preenabled && skip_ioapic_setup) { | 1446 | if (!x2apic_preenabled && skip_ioapic_setup) { |
1447 | pr_info("Skipped enabling intr-remap because of skipping " | 1447 | pr_info("Skipped enabling intr-remap because of skipping " |
1448 | "io-apic setup\n"); | 1448 | "io-apic setup\n"); |
1449 | return 0; | 1449 | return -1; |
1450 | } | 1450 | } |
1451 | 1451 | ||
1452 | if (enable_intr_remapping(x2apic_supported())) | 1452 | return enable_intr_remapping(); |
1453 | return 0; | ||
1454 | |||
1455 | pr_info("Enabled Interrupt-remapping\n"); | ||
1456 | |||
1457 | return 1; | ||
1458 | |||
1459 | #endif | 1453 | #endif |
1460 | return 0; | 1454 | return -1; |
1461 | } | 1455 | } |
1462 | 1456 | ||
1463 | void __init enable_IR_x2apic(void) | 1457 | void __init enable_IR_x2apic(void) |
@@ -1481,11 +1475,11 @@ void __init enable_IR_x2apic(void) | |||
1481 | mask_ioapic_entries(); | 1475 | mask_ioapic_entries(); |
1482 | 1476 | ||
1483 | if (dmar_table_init_ret) | 1477 | if (dmar_table_init_ret) |
1484 | ret = 0; | 1478 | ret = -1; |
1485 | else | 1479 | else |
1486 | ret = enable_IR(); | 1480 | ret = enable_IR(); |
1487 | 1481 | ||
1488 | if (!ret) { | 1482 | if (ret < 0) { |
1489 | /* IR is required if there is APIC ID > 255 even when running | 1483 | /* IR is required if there is APIC ID > 255 even when running |
1490 | * under KVM | 1484 | * under KVM |
1491 | */ | 1485 | */ |
@@ -1499,6 +1493,9 @@ void __init enable_IR_x2apic(void) | |||
1499 | x2apic_force_phys(); | 1493 | x2apic_force_phys(); |
1500 | } | 1494 | } |
1501 | 1495 | ||
1496 | if (ret == IRQ_REMAP_XAPIC_MODE) | ||
1497 | goto nox2apic; | ||
1498 | |||
1502 | x2apic_enabled = 1; | 1499 | x2apic_enabled = 1; |
1503 | 1500 | ||
1504 | if (x2apic_supported() && !x2apic_mode) { | 1501 | if (x2apic_supported() && !x2apic_mode) { |
@@ -1508,19 +1505,21 @@ void __init enable_IR_x2apic(void) | |||
1508 | } | 1505 | } |
1509 | 1506 | ||
1510 | nox2apic: | 1507 | nox2apic: |
1511 | if (!ret) /* IR enabling failed */ | 1508 | if (ret < 0) /* IR enabling failed */ |
1512 | restore_ioapic_entries(); | 1509 | restore_ioapic_entries(); |
1513 | legacy_pic->restore_mask(); | 1510 | legacy_pic->restore_mask(); |
1514 | local_irq_restore(flags); | 1511 | local_irq_restore(flags); |
1515 | 1512 | ||
1516 | out: | 1513 | out: |
1517 | if (x2apic_enabled) | 1514 | if (x2apic_enabled || !x2apic_supported()) |
1518 | return; | 1515 | return; |
1519 | 1516 | ||
1520 | if (x2apic_preenabled) | 1517 | if (x2apic_preenabled) |
1521 | panic("x2apic: enabled by BIOS but kernel init failed."); | 1518 | panic("x2apic: enabled by BIOS but kernel init failed."); |
1522 | else if (cpu_has_x2apic) | 1519 | else if (ret == IRQ_REMAP_XAPIC_MODE) |
1523 | pr_info("Not enabling x2apic, Intr-remapping init failed.\n"); | 1520 | pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n"); |
1521 | else if (ret < 0) | ||
1522 | pr_info("x2apic not enabled, IRQ remapping init failed\n"); | ||
1524 | } | 1523 | } |
1525 | 1524 | ||
1526 | #ifdef CONFIG_X86_64 | 1525 | #ifdef CONFIG_X86_64 |
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 6dcc7e2d54de..c4a0235a4fdb 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c | |||
@@ -46,7 +46,7 @@ | |||
46 | */ | 46 | */ |
47 | LIST_HEAD(dmar_drhd_units); | 47 | LIST_HEAD(dmar_drhd_units); |
48 | 48 | ||
49 | static struct acpi_table_header * __initdata dmar_tbl; | 49 | struct acpi_table_header * __initdata dmar_tbl; |
50 | static acpi_size dmar_tbl_size; | 50 | static acpi_size dmar_tbl_size; |
51 | 51 | ||
52 | static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) | 52 | static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) |
diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intr_remapping.c index 1a89d4a2cadf..51a2ce9b8789 100644 --- a/drivers/iommu/intr_remapping.c +++ b/drivers/iommu/intr_remapping.c | |||
@@ -21,6 +21,7 @@ int intr_remapping_enabled; | |||
21 | 21 | ||
22 | static int disable_intremap; | 22 | static int disable_intremap; |
23 | static int disable_sourceid_checking; | 23 | static int disable_sourceid_checking; |
24 | static int no_x2apic_optout; | ||
24 | 25 | ||
25 | static __init int setup_nointremap(char *str) | 26 | static __init int setup_nointremap(char *str) |
26 | { | 27 | { |
@@ -34,12 +35,20 @@ static __init int setup_intremap(char *str) | |||
34 | if (!str) | 35 | if (!str) |
35 | return -EINVAL; | 36 | return -EINVAL; |
36 | 37 | ||
37 | if (!strncmp(str, "on", 2)) | 38 | while (*str) { |
38 | disable_intremap = 0; | 39 | if (!strncmp(str, "on", 2)) |
39 | else if (!strncmp(str, "off", 3)) | 40 | disable_intremap = 0; |
40 | disable_intremap = 1; | 41 | else if (!strncmp(str, "off", 3)) |
41 | else if (!strncmp(str, "nosid", 5)) | 42 | disable_intremap = 1; |
42 | disable_sourceid_checking = 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 | } | ||
43 | 52 | ||
44 | return 0; | 53 | return 0; |
45 | } | 54 | } |
@@ -501,6 +510,15 @@ end: | |||
501 | spin_unlock_irqrestore(&iommu->register_lock, flags); | 510 | spin_unlock_irqrestore(&iommu->register_lock, flags); |
502 | } | 511 | } |
503 | 512 | ||
513 | static int __init dmar_x2apic_optout(void) | ||
514 | { | ||
515 | struct acpi_table_dmar *dmar; | ||
516 | dmar = (struct acpi_table_dmar *)dmar_tbl; | ||
517 | if (!dmar || no_x2apic_optout) | ||
518 | return 0; | ||
519 | return dmar->flags & DMAR_X2APIC_OPT_OUT; | ||
520 | } | ||
521 | |||
504 | int __init intr_remapping_supported(void) | 522 | int __init intr_remapping_supported(void) |
505 | { | 523 | { |
506 | struct dmar_drhd_unit *drhd; | 524 | struct dmar_drhd_unit *drhd; |
@@ -521,16 +539,25 @@ int __init intr_remapping_supported(void) | |||
521 | return 1; | 539 | return 1; |
522 | } | 540 | } |
523 | 541 | ||
524 | int __init enable_intr_remapping(int eim) | 542 | int __init enable_intr_remapping(void) |
525 | { | 543 | { |
526 | struct dmar_drhd_unit *drhd; | 544 | struct dmar_drhd_unit *drhd; |
527 | int setup = 0; | 545 | int setup = 0; |
546 | int eim = 0; | ||
528 | 547 | ||
529 | if (parse_ioapics_under_ir() != 1) { | 548 | if (parse_ioapics_under_ir() != 1) { |
530 | printk(KERN_INFO "Not enable interrupt remapping\n"); | 549 | printk(KERN_INFO "Not enable interrupt remapping\n"); |
531 | return -1; | 550 | return -1; |
532 | } | 551 | } |
533 | 552 | ||
553 | if (x2apic_supported()) { | ||
554 | eim = !dmar_x2apic_optout(); | ||
555 | WARN(!eim, KERN_WARNING | ||
556 | "Your BIOS is broken and requested that x2apic be disabled\n" | ||
557 | "This will leave your machine vulnerable to irq-injection attacks\n" | ||
558 | "Use 'intremap=no_x2apic_optout' to override BIOS request\n"); | ||
559 | } | ||
560 | |||
534 | for_each_drhd_unit(drhd) { | 561 | for_each_drhd_unit(drhd) { |
535 | struct intel_iommu *iommu = drhd->iommu; | 562 | struct intel_iommu *iommu = drhd->iommu; |
536 | 563 | ||
@@ -606,8 +633,9 @@ int __init enable_intr_remapping(int eim) | |||
606 | goto error; | 633 | goto error; |
607 | 634 | ||
608 | intr_remapping_enabled = 1; | 635 | intr_remapping_enabled = 1; |
636 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); | ||
609 | 637 | ||
610 | return 0; | 638 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; |
611 | 639 | ||
612 | error: | 640 | error: |
613 | /* | 641 | /* |
diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 7b776d71d36d..2dc810e35dd0 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h | |||
@@ -26,8 +26,13 @@ | |||
26 | #include <linux/msi.h> | 26 | #include <linux/msi.h> |
27 | #include <linux/irqreturn.h> | 27 | #include <linux/irqreturn.h> |
28 | 28 | ||
29 | /* DMAR Flags */ | ||
30 | #define DMAR_INTR_REMAP 0x1 | ||
31 | #define DMAR_X2APIC_OPT_OUT 0x2 | ||
32 | |||
29 | struct intel_iommu; | 33 | struct intel_iommu; |
30 | #if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP) | 34 | #if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP) |
35 | extern struct acpi_table_header *dmar_tbl; | ||
31 | struct dmar_drhd_unit { | 36 | struct dmar_drhd_unit { |
32 | struct list_head list; /* list of drhd units */ | 37 | struct list_head list; /* list of drhd units */ |
33 | struct acpi_dmar_header *hdr; /* ACPI header */ | 38 | struct acpi_dmar_header *hdr; /* ACPI header */ |
@@ -110,7 +115,7 @@ struct irte { | |||
110 | #ifdef CONFIG_INTR_REMAP | 115 | #ifdef CONFIG_INTR_REMAP |
111 | extern int intr_remapping_enabled; | 116 | extern int intr_remapping_enabled; |
112 | extern int intr_remapping_supported(void); | 117 | extern int intr_remapping_supported(void); |
113 | extern int enable_intr_remapping(int); | 118 | extern int enable_intr_remapping(void); |
114 | extern void disable_intr_remapping(void); | 119 | extern void disable_intr_remapping(void); |
115 | extern int reenable_intr_remapping(int); | 120 | extern int reenable_intr_remapping(int); |
116 | 121 | ||
@@ -177,7 +182,7 @@ static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) | |||
177 | 182 | ||
178 | #define intr_remapping_enabled (0) | 183 | #define intr_remapping_enabled (0) |
179 | 184 | ||
180 | static inline int enable_intr_remapping(int eim) | 185 | static inline int enable_intr_remapping(void) |
181 | { | 186 | { |
182 | return -1; | 187 | return -1; |
183 | } | 188 | } |
@@ -192,6 +197,11 @@ static inline int reenable_intr_remapping(int eim) | |||
192 | } | 197 | } |
193 | #endif | 198 | #endif |
194 | 199 | ||
200 | enum { | ||
201 | IRQ_REMAP_XAPIC_MODE, | ||
202 | IRQ_REMAP_X2APIC_MODE, | ||
203 | }; | ||
204 | |||
195 | /* Can't use the common MSI interrupt functions | 205 | /* Can't use the common MSI interrupt functions |
196 | * since DMAR is not a pci device | 206 | * since DMAR is not a pci device |
197 | */ | 207 | */ |