[Oneiric][PATCH 1/1] UBUNTU: SAUCE: x86, x2apic: enable the bios request for x2apic optout

Leann Ogasawara leann.ogasawara at canonical.com
Wed Sep 7 20:56:47 UTC 2011


Hi All,

BugLink: http://bugs.launchpad.net/bugs/797548

It's been requested that we apply the following patch to Oneiric to
allow platforms which are x2apic and interrupt-remapping capable to opt
out of x2apic mode.  A more detailed justification can be read in the
commit message below.  We've been informed this is critical for some
OEM's wanting to leverage Romley platforms.  The patch has been
submitted upstream but not yet accepted:

https://lkml.org/lkml/2011/7/29/414

There's been minor upstream feedback to reformat strings and to also
rebase on top of some newer patches, but nothing major to rework.

I've tried to thoroughly test, but only have access to test systems
which are xapic and intremap capable or test systems which intremap init
fails and thus x2apic is not enabled.  That being said, I have not seen
any regressions on these existing systems.

I've subsequently placed a test kernel at the following location in case
others have access to the right combination and want to test:

http://people.canonical.com/~ogasawara/lp797548/

Yingying, would you be able to help test more thoroughly or can you at
least comment to the testing which this patch has already received?  I'd
like to try to get this in prior to Kernel Freeze next Thurs Sept 15 to
avoid having to do an SRU for this.

Thanks,
Leann

>From a6a2bb5f1b90dc3e938f07c5160233defeb52b44 Mon Sep 17 00:00:00 2001
From: Youquan Song <youquan.song at intel.com>
Date: Mon, 1 Aug 2011 03:01:01 +0000
Subject: [PATCH] UBUNTU: SAUCE: x86, x2apic: enable the bios request for x2apic optout

BugLink: http://bugs.launchpad.net/bugs/797548

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 at intel.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha at intel.com>
Signed-off-by: Leann Ogasawara <leann.ogasawara at canonical.com>
---
 Documentation/kernel-parameters.txt |    3 +-
 arch/x86/kernel/apic/apic.c         |   31 ++++++++++++------------
 drivers/pci/dmar.c                  |    2 +-
 drivers/pci/intr_remapping.c        |   44 ++++++++++++++++++++++++++++------
 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 f2d3824..670694f 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1007,10 +1007,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			has the capability. With this option, super page will
 			not be supported.
 	intremap=	[X86-64, Intel-IOMMU]
-			Format: { on (default) | off | nosid }
 			on	enable Interrupt Remapping (default)
 			off	disable Interrupt Remapping
 			nosid	disable Source ID checking
+			no_x2apic_optout
+				BIOS x2APIC opt-out request will be ignored
 
 	inttest=	[IA64]
 
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index b9338b8..9802bdf 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1439,24 +1439,18 @@ int __init enable_IR(void)
 #ifdef CONFIG_INTR_REMAP
 	if (!intr_remapping_supported()) {
 		pr_debug("intr-remapping not supported\n");
-		return 0;
+		return -1;
 	}
 
 	if (!x2apic_preenabled && skip_ioapic_setup) {
 		pr_info("Skipped enabling intr-remap because of skipping "
 			"io-apic setup\n");
-		return 0;
+		return -1;
 	}
 
-	if (enable_intr_remapping(x2apic_supported()))
-		return 0;
-
-	pr_info("Enabled Interrupt-remapping\n");
-
-	return 1;
-
+	return enable_intr_remapping();
 #endif
-	return 0;
+	return -1;
 }
 
 void __init enable_IR_x2apic(void)
@@ -1480,11 +1474,11 @@ void __init enable_IR_x2apic(void)
 	mask_ioapic_entries();
 
 	if (dmar_table_init_ret)
-		ret = 0;
+		ret = -1;
 	else
 		ret = enable_IR();
 
-	if (!ret) {
+	if (ret < 0) {
 		/* IR is required if there is APIC ID > 255 even when running
 		 * under KVM
 		 */
@@ -1498,6 +1492,9 @@ void __init enable_IR_x2apic(void)
 		x2apic_force_phys();
 	}
 
+	if (ret == IRQ_REMAP_XAPIC_MODE)
+		goto nox2apic;
+
 	x2apic_enabled = 1;
 
 	if (x2apic_supported() && !x2apic_mode) {
@@ -1507,19 +1504,21 @@ void __init enable_IR_x2apic(void)
 	}
 
 nox2apic:
-	if (!ret) /* IR enabling failed */
+	if (ret < 0) /* IR enabling failed */
 		restore_ioapic_entries();
 	legacy_pic->restore_mask();
 	local_irq_restore(flags);
 
 out:
-	if (x2apic_enabled)
+	if (x2apic_enabled || !x2apic_supported())
 		return;
 
 	if (x2apic_preenabled)
 		panic("x2apic: enabled by BIOS but kernel init failed.");
-	else if (cpu_has_x2apic)
-		pr_info("Not enabling x2apic, Intr-remapping init failed.\n");
+	else if (ret == IRQ_REMAP_XAPIC_MODE)
+		pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n");
+	else if (ret < 0)
+		pr_info("x2apic not enabled, IRQ remapping init failed\n");
 }
 
 #ifdef CONFIG_X86_64
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 3dc9bef..d633f28 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -46,7 +46,7 @@
  */
 LIST_HEAD(dmar_drhd_units);
 
-static struct acpi_table_header * __initdata dmar_tbl;
+struct acpi_table_header * __initdata dmar_tbl;
 static acpi_size dmar_tbl_size;
 
 static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 3607faf..3df0752 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -22,6 +22,7 @@ int intr_remapping_enabled;
 
 static int disable_intremap;
 static int disable_sourceid_checking;
+static int no_x2apic_optout;
 
 static __init int setup_nointremap(char *str)
 {
@@ -35,12 +36,20 @@ static __init int setup_intremap(char *str)
 	if (!str)
 		return -EINVAL;
 
-	if (!strncmp(str, "on", 2))
-		disable_intremap = 0;
-	else if (!strncmp(str, "off", 3))
-		disable_intremap = 1;
-	else if (!strncmp(str, "nosid", 5))
-		disable_sourceid_checking = 1;
+	while (*str) {
+		if (!strncmp(str, "on", 2))
+			disable_intremap = 0;
+		else if (!strncmp(str, "off", 3))
+			disable_intremap = 1;
+		else if (!strncmp(str, "nosid", 5))
+			disable_sourceid_checking = 1;
+		else if (!strncmp(str, "no_x2apic_optout", 16))
+			no_x2apic_optout = 1;
+
+		str += strcspn(str, ",");
+		while (*str == ',')
+			str++;
+	}
 
 	return 0;
 }
@@ -502,6 +511,15 @@ end:
 	spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
+static int __init dmar_x2apic_optout(void)
+{
+	struct acpi_table_dmar *dmar;
+	dmar = (struct acpi_table_dmar *)dmar_tbl;
+	if (!dmar || no_x2apic_optout)
+		return 0;
+	return dmar->flags & DMAR_X2APIC_OPT_OUT;
+}
+
 int __init intr_remapping_supported(void)
 {
 	struct dmar_drhd_unit *drhd;
@@ -522,16 +540,25 @@ int __init intr_remapping_supported(void)
 	return 1;
 }
 
-int __init enable_intr_remapping(int eim)
+int __init enable_intr_remapping(void)
 {
 	struct dmar_drhd_unit *drhd;
 	int setup = 0;
+	int eim = 0;
 
 	if (parse_ioapics_under_ir() != 1) {
 		printk(KERN_INFO "Not enable interrupt remapping\n");
 		return -1;
 	}
 
+	if (x2apic_supported()) {
+		eim = !dmar_x2apic_optout();
+		WARN(!eim, KERN_WARNING
+			   "Your BIOS is broken and requested that x2apic be disabled\n"
+			   "This will leave your machine vulnerable to irq-injection attacks\n"
+			   "Use 'intremap=no_x2apic_optout' to override BIOS request\n");
+	}
+
 	for_each_drhd_unit(drhd) {
 		struct intel_iommu *iommu = drhd->iommu;
 
@@ -607,8 +634,9 @@ int __init enable_intr_remapping(int eim)
 		goto error;
 
 	intr_remapping_enabled = 1;
+	pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
 
-	return 0;
+	return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
 
 error:
 	/*
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 7b776d7..2dc810e 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -26,8 +26,13 @@
 #include <linux/msi.h>
 #include <linux/irqreturn.h>
 
+/* DMAR Flags */
+#define DMAR_INTR_REMAP		0x1
+#define DMAR_X2APIC_OPT_OUT	0x2
+
 struct intel_iommu;
 #if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP)
+extern struct acpi_table_header *dmar_tbl;
 struct dmar_drhd_unit {
 	struct list_head list;		/* list of drhd units	*/
 	struct  acpi_dmar_header *hdr;	/* ACPI header		*/
@@ -110,7 +115,7 @@ struct irte {
 #ifdef CONFIG_INTR_REMAP
 extern int intr_remapping_enabled;
 extern int intr_remapping_supported(void);
-extern int enable_intr_remapping(int);
+extern int enable_intr_remapping(void);
 extern void disable_intr_remapping(void);
 extern int reenable_intr_remapping(int);
 
@@ -177,7 +182,7 @@ static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
 
 #define intr_remapping_enabled		(0)
 
-static inline int enable_intr_remapping(int eim)
+static inline int enable_intr_remapping(void)
 {
 	return -1;
 }
@@ -192,6 +197,11 @@ static inline int reenable_intr_remapping(int eim)
 }
 #endif
 
+enum {
+	IRQ_REMAP_XAPIC_MODE,
+	IRQ_REMAP_X2APIC_MODE,
+};
+
 /* Can't use the common MSI interrupt functions
  * since DMAR is not a pci device
  */
-- 
1.7.4.1









More information about the kernel-team mailing list