aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
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 /drivers/iommu
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>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/dmar.c2
-rw-r--r--drivers/iommu/intr_remapping.c44
2 files changed, 37 insertions, 9 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 6dcc7e2d54d..c4a0235a4fd 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 1a89d4a2cad..51a2ce9b878 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 /*