rpms/kernel/devel linux-2.6-intel-agp-clear-gtt.patch, NONE, 1.1 linux-2.6-iommu-updates.patch, NONE, 1.1 kernel.spec, 1.1860, 1.1861

David Woodhouse dwmw2 at fedoraproject.org
Wed Dec 2 11:12:06 UTC 2009


Author: dwmw2

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv31119

Modified Files:
	kernel.spec 
Added Files:
	linux-2.6-intel-agp-clear-gtt.patch 
	linux-2.6-iommu-updates.patch 
Log Message:
2.6.32 iommu fixes

linux-2.6-intel-agp-clear-gtt.patch:
 intel-agp.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

--- NEW FILE linux-2.6-intel-agp-clear-gtt.patch ---
Some BIOSes fail to initialise the GTT, which will cause DMA faults when
the IOMMU is enabled. We need to clear the whole thing, not just the
part that Linux is going to use.

Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>

diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 10e1f03..6ab8173 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -176,6 +176,7 @@ static struct _intel_private {
 	 * popup and for the GTT.
 	 */
 	int gtt_entries;			/* i830+ */
+	int gtt_total_size;
 	union {
 		void __iomem *i9xx_flush_page;
 		void *i8xx_flush_page;
@@ -1151,7 +1152,7 @@ static int intel_i915_configure(void)
 	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
 
 	if (agp_bridge->driver->needs_scratch_page) {
-		for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
+		for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
 			writel(agp_bridge->scratch_page, intel_private.gtt+i);
 		}
 		readl(intel_private.gtt+i-1);	/* PCI Posting. */
@@ -1306,6 +1307,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
 	if (!intel_private.gtt)
 		return -ENOMEM;
 
+	intel_private.gtt_total_size = gtt_map_size / 4;
+
 	temp &= 0xfff80000;
 
 	intel_private.registers = ioremap(temp, 128 * 4096);
@@ -1392,6 +1395,8 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
 	if (!intel_private.gtt)
 		return -ENOMEM;
 
+	intel_private.gtt_total_size = gtt_size / 4;
+
 	intel_private.registers = ioremap(temp, 128 * 4096);
 	if (!intel_private.registers) {
 		iounmap(intel_private.gtt);

linux-2.6-iommu-updates.patch:
 dmar.c        |   67 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 intel-iommu.c |   13 +++++++++++
 2 files changed, 68 insertions(+), 12 deletions(-)

--- NEW FILE linux-2.6-iommu-updates.patch ---
commit 15d841769b5c921ac5502086399b0e786eeb22ea
Author: David Woodhouse <David.Woodhouse at intel.com>
Date:   Wed Dec 2 10:18:30 2009 +0000

    intel-iommu: Fix oops with intel_iommu=igfx_off
    
    The hotplug notifier will call find_domain() to see if the device in
    question has been assigned an IOMMU domain. However, this should never
    be called for devices with a "dummy" domain, such as graphics devices
    when intel_iommu=igfx_off is set and the corresponding IOMMU isn't even
    initialised. If you do that, it'll oops as it dereferences the (-1)
    pointer.
    
    The notifier function should check iommu_no_mapping() for the
    device before doing anything else.
    
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>

commit 5282435ae48edd3414211fe14eead5fea736f18f
Author: David Woodhouse <David.Woodhouse at intel.com>
Date:   Wed Dec 2 09:21:55 2009 +0000

    intel-iommu: Check for an RMRR which ends before it starts.
    
    Some HP BIOSes report an RMRR region (a region which needs a 1:1 mapping
    in the IOMMU for a given device) which has an end address lower than its
    start address. Detect that and warn, rather than triggering the
    BUG() in dma_pte_clear_range().
    
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>

commit a02d870f40a516297754d0db0abc17e168f2b494
Author: David Woodhouse <David.Woodhouse at intel.com>
Date:   Wed Dec 2 09:20:27 2009 +0000

    intel-iommu: Apply BIOS sanity checks for interrupt remapping too.
    
    The BIOS errors where an IOMMU is reported either at zero or a bogus
    address are causing problems even when the IOMMU is disabled -- because
    interrupt remapping uses the same hardware. Ensure that the checks get
    applied for the interrupt remapping initialisation too.
    
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>

commit 90053c711bd4c6cd692a096bc6be1c74d8fcab03
Author: Chris Wright <chrisw at sous-sol.org>
Date:   Wed Dec 2 09:17:13 2009 +0000

    intel-iommu: Detect DMAR in hyperspace at probe time.
    
    Many BIOSes will lie to us about the existence of an IOMMU, and claim
    that there is one at an address which actually returns all 0xFF.
    
    We need to detect this early, so that we know we don't have a viable
    IOMMU and can set up swiotlb before it's too late.
    
    Patch from Chris Wright in Fedora 12 kernel.
    
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index b952ebc..5753036 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -582,6 +582,8 @@ int __init dmar_table_init(void)
 	return 0;
 }
 
+static int bios_warned;
+
 int __init check_zero_address(void)
 {
 	struct acpi_table_dmar *dmar;
@@ -601,6 +603,9 @@ int __init check_zero_address(void)
 		}
 
 		if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
+			void __iomem *addr;
+			u64 cap, ecap;
+
 			drhd = (void *)entry_header;
 			if (!drhd->address) {
 				/* Promote an attitude of violence to a BIOS engineer today */
@@ -609,17 +614,40 @@ int __init check_zero_address(void)
 				     dmi_get_system_info(DMI_BIOS_VENDOR),
 				     dmi_get_system_info(DMI_BIOS_VERSION),
 				     dmi_get_system_info(DMI_PRODUCT_VERSION));
-#ifdef CONFIG_DMAR
-				dmar_disabled = 1;
-#endif
-				return 0;
+				bios_warned = 1;
+				goto failed;
+			}
+
+			addr = early_ioremap(drhd->address, VTD_PAGE_SIZE);
+			if (!addr ) {
+				printk("IOMMU: can't validate: %llx\n", drhd->address);
+				goto failed;
+			}
+			cap = dmar_readq(addr + DMAR_CAP_REG);
+			ecap = dmar_readq(addr + DMAR_ECAP_REG);
+			early_iounmap(addr, VTD_PAGE_SIZE);
+			if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
+				/* Promote an attitude of violence to a BIOS engineer today */
+				WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
+				     "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+				      drhd->address,
+				      dmi_get_system_info(DMI_BIOS_VENDOR),
+				      dmi_get_system_info(DMI_BIOS_VERSION),
+				      dmi_get_system_info(DMI_PRODUCT_VERSION));
+				bios_warned = 1;
+				goto failed;
 			}
-			break;
 		}
 
 		entry_header = ((void *)entry_header + entry_header->length);
 	}
 	return 1;
+
+failed:
+#ifdef CONFIG_DMAR
+	dmar_disabled = 1;
+#endif
+	return 0;
 }
 
 void __init detect_intel_iommu(void)
@@ -664,6 +692,18 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 	int agaw = 0;
 	int msagaw = 0;
 
+	if (!drhd->reg_base_addr) {
+		if (!bios_warned) {
+			WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
+			     "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+			     dmi_get_system_info(DMI_BIOS_VENDOR),
+			     dmi_get_system_info(DMI_BIOS_VERSION),
+			     dmi_get_system_info(DMI_PRODUCT_VERSION));
+			bios_warned = 1;
+		}
+		return -EINVAL;
+	}
+
 	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
 	if (!iommu)
 		return -ENOMEM;
@@ -680,13 +720,16 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 	iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
 
 	if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
-		/* Promote an attitude of violence to a BIOS engineer today */
-		WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
-		     "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-		     drhd->reg_base_addr,
-		     dmi_get_system_info(DMI_BIOS_VENDOR),
-		     dmi_get_system_info(DMI_BIOS_VERSION),
-		     dmi_get_system_info(DMI_PRODUCT_VERSION));
+		if (!bios_warned) {
+			/* Promote an attitude of violence to a BIOS engineer today */
+			WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
+			     "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+			     drhd->reg_base_addr,
+			     dmi_get_system_info(DMI_BIOS_VENDOR),
+			     dmi_get_system_info(DMI_BIOS_VERSION),
+			     dmi_get_system_info(DMI_PRODUCT_VERSION));
+			bios_warned = 1;
+		}
 		goto err_unmap;
 	}
 
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 1840a05..1b9f76f 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1991,6 +1991,16 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev,
 	       "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
 	       pci_name(pdev), start, end);
 	
+	if (end < start) {
+		WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
+			"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+			dmi_get_system_info(DMI_BIOS_VENDOR),
+			dmi_get_system_info(DMI_BIOS_VERSION),
+		     dmi_get_system_info(DMI_PRODUCT_VERSION));
+		ret = -EIO;
+		goto error;
+	}
+
 	if (end >> agaw_to_width(domain->agaw)) {
 		WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
 		     "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
@@ -3228,6 +3238,9 @@ static int device_notifier(struct notifier_block *nb,
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct dmar_domain *domain;
 
+	if (iommu_no_mapping(dev))
+		return 0;
+
 	domain = find_domain(pdev);
 	if (!domain)
 		return 0;


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.1860
retrieving revision 1.1861
diff -u -p -r1.1860 -r1.1861
--- kernel.spec	2 Dec 2009 01:53:59 -0000	1.1860
+++ kernel.spec	2 Dec 2009 11:12:05 -0000	1.1861
@@ -618,6 +618,9 @@ Patch20: linux-2.6-hotfixes.patch
 Patch21: linux-2.6-tracehook.patch
 Patch22: linux-2.6-utrace.patch
 
+# More workaround for BIOS brokenness, fix intel_iommu=igfx_off oops
+Patch100: linux-2.6-iommu-updates.patch
+
 Patch141: linux-2.6-ps3-storage-alias.patch
 Patch143: linux-2.6-g5-therm-shutdown.patch
 Patch144: linux-2.6-vio-modalias.patch
@@ -690,6 +693,7 @@ Patch1821: drm-page-flip.patch
 Patch1824: drm-intel-next.patch
 Patch1825: drm-intel-pm.patch
 Patch1826: drm-i915-fix-sync-to-vbl-when-vga-is-off.patch
+Patch1827: linux-2.6-intel-agp-clear-gtt.patch
 
 # kludge to make ich9 e1000 work
 Patch2000: linux-2.6-e1000-ich9.patch
@@ -1152,6 +1156,7 @@ ApplyPatch linux-2.6-dell-laptop-rfkill-
 #
 # Intel IOMMU
 #
+ApplyPatch linux-2.6-iommu-updates.patch
 
 #
 # PowerPC
@@ -1314,6 +1319,8 @@ ApplyOptionalPatch drm-intel-next.patch
 #this appears to be upstream - mjg59?
 #ApplyPatch drm-intel-pm.patch
 ApplyPatch drm-i915-fix-sync-to-vbl-when-vga-is-off.patch
+# Some BIOSes don't clear the whole GTT, and it causes IOMMU faults
+ApplyPatch linux-2.6-intel-agp-clear-gtt.patch
 
 # linux1394 git patches
 #ApplyPatch linux-2.6-firewire-git-update.patch
@@ -1989,6 +1996,11 @@ fi
 # and build.
 
 %changelog
+* Wed Dec 02 2009 David Woodhouse <David.Woodhouse at intel.com> 2.6.32-0.63.rc8.git2
+- forward port IOMMU fixes from F-12 for HP BIOS brokenness
+- Fix oops with intel_iommu=igfx_off
+- agp/intel: Clear full GTT at startup
+
 * Wed Dec 02 2009 Dave Airlie <airlied at redhat.com> 2.6.32-0.62.rc8.git2
 - forward port radeon fixes from F-12 + add radeon display port support
 




More information about the scm-commits mailing list