aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2011-08-23 20:05:18 -0400
committerIngo Molnar <mingo@elte.hu>2011-09-21 04:21:50 -0400
commit41750d31fc9599fd81763e685a6b7b42d298c4f8 (patch)
tree6cacc746aa159c8bd08f151270f0bffe126caa9d
parent9d037a777695993ec7437e5f451647dea7919d4c (diff)
x86, x2apic: Enable the bios request for x2apic optout
On the platforms which are x2apic and interrupt-remapping capable, Linux kernel is enabling x2apic even if the BIOS doesn't. This is to take advantage of the features that x2apic brings in. Some of the OEM platforms are running into issues because of this, as their bios is not x2apic aware. For example, this was resulting in interrupt migration issues on one of the platforms. Also if the BIOS SMI handling uses APIC interface to send SMI's, then the BIOS need to be aware of x2apic mode that OS has enabled. On some of these platforms, BIOS doesn't have a HW mechanism to turnoff the x2apic feature to prevent OS from enabling it. To resolve this mess, recent changes to the VT-d2 specification: http://download.intel.com/technology/computing/vptech/Intel(r)_VT_for_Direct_IO.pdf includes a mechanism that provides BIOS a way to request system software to opt out of enabling x2apic mode. Look at the x2apic optout flag in the DMAR tables before enabling the x2apic mode in the platform. Also print a warning that we have disabled x2apic based on the BIOS request. Kernel boot parameter "intremap=no_x2apic_optout" can be used to override the BIOS x2apic optout request. Signed-off-by: Youquan Song <youquan.song@intel.com> Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: yinghai@kernel.org Cc: joerg.roedel@amd.com Cc: tony.luck@intel.com Cc: dwmw2@infradead.org Link: http://lkml.kernel.org/r/20110824001456.171766616@sbsiddha-desk.sc.intel.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--Documentation/kernel-parameters.txt3
-rw-r--r--arch/x86/kernel/apic/apic.c31
-rw-r--r--drivers/iommu/dmar.c2
-rw-r--r--drivers/iommu/intr_remapping.c44
-rw-r--r--include/linux/dmar.h14
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
1463void __init enable_IR_x2apic(void) 1457void __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
1510nox2apic: 1507nox2apic:
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
1516out: 1513out:
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 */
47LIST_HEAD(dmar_drhd_units); 47LIST_HEAD(dmar_drhd_units);
48 48
49static struct acpi_table_header * __initdata dmar_tbl; 49struct acpi_table_header * __initdata dmar_tbl;
50static acpi_size dmar_tbl_size; 50static acpi_size dmar_tbl_size;
51 51
52static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) 52static 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
22static int disable_intremap; 22static int disable_intremap;
23static int disable_sourceid_checking; 23static int disable_sourceid_checking;
24static int no_x2apic_optout;
24 25
25static __init int setup_nointremap(char *str) 26static __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
513static 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
504int __init intr_remapping_supported(void) 522int __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
524int __init enable_intr_remapping(int eim) 542int __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
612error: 640error:
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
29struct intel_iommu; 33struct intel_iommu;
30#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP) 34#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
35extern struct acpi_table_header *dmar_tbl;
31struct dmar_drhd_unit { 36struct 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
111extern int intr_remapping_enabled; 116extern int intr_remapping_enabled;
112extern int intr_remapping_supported(void); 117extern int intr_remapping_supported(void);
113extern int enable_intr_remapping(int); 118extern int enable_intr_remapping(void);
114extern void disable_intr_remapping(void); 119extern void disable_intr_remapping(void);
115extern int reenable_intr_remapping(int); 120extern 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
180static inline int enable_intr_remapping(int eim) 185static 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
200enum {
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 */