Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2588

kernel-2.6.18-128.1.10.el5.src.rpm

From: Matthew Garrett <mjg@redhat.com>
Date: Mon, 25 Aug 2008 16:06:27 +0100
Subject: [x86_64] resume from s3 in text mode with >4GB of mem
Message-id: 20080825150627.GA10313@srcf.ucam.org
O-Subject: [RHEL5 patch] BZ#452961 - Kernel Panic after resume from s3 in text mode with PAE kernel
Bugzilla: 452961
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>

The aperture code in 2.6.18 does not restore the aperture state on
resume, leading to potential memory corruption on amd64 systems with
more than 4GB of RAM. This was fixed in upstream commit
6703f6d10dcd3316e03641a5ecaa6c8a04374d98 , and the following patch is a
backport of the relevant code. AMD report that it fixes the issue.

commit ad3678649a221bea41fcc25a8b60b54ba7168065
Author: Matthew Garrett <mjg59@srcf.ucam.org>
Date:   Wed Aug 13 12:00:46 2008 +0100

    GART resume fix

diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index 2384870..d8a434c 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -24,6 +24,8 @@
 #include <asm/dma.h>
 #include <asm/k8.h>
 
+extern void set_up_gart_resume(u32, u32);
+
 int iommu_aperture;
 int iommu_aperture_disabled __initdata = 0;
 int iommu_aperture_allowed __initdata = 0;
@@ -276,4 +278,6 @@ void __init iommu_hole_init(void)
 		write_pci_config(0, num, 3, 0x90, aper_order<<1); 
 		write_pci_config(0, num, 3, 0x94, aper_alloc>>25); 
 	} 
+	
+	set_up_gart_resume(aper_order, aper_alloc);
 } 
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 565ee9b..85c74d1 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -22,6 +22,7 @@
 #include <linux/topology.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <linux/sysdev.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
@@ -486,6 +487,86 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size)
 	return aper_base;
 } 
 
+static void enable_gart_translations(void) {
+	int i;
+	struct pci_dev *dev;
+
+	for (i = 0; i < num_k8_northbridges; i++) {
+		u32 ctl; 
+		u32 gatt_reg; 
+
+		dev = k8_northbridges[i];
+		gatt_reg = __pa(agp_gatt_table) >> 12; 
+		gatt_reg <<= 4; 
+		pci_write_config_dword(dev, 0x98, gatt_reg);
+		pci_read_config_dword(dev, 0x90, &ctl); 
+
+		ctl |= 1;
+		ctl &= ~((1<<4) | (1<<5));
+
+		pci_write_config_dword(dev, 0x90, ctl); 
+	}
+}
+
+/*
+ * If fix_up_north_bridges is set, the north bridges have to be fixed up on
+ * resume in the same way as they are handled in gart_iommu_hole_init().
+ */
+static bool fix_up_north_bridges;
+static u32 aperture_order;
+static u32 aperture_alloc;
+
+void set_up_gart_resume(u32 aper_order, u32 aper_alloc)
+{
+	fix_up_north_bridges = true;
+	aperture_order = aper_order;
+	aperture_alloc = aper_alloc;
+}
+
+static int gart_resume(struct sys_device *dev)
+{
+	printk(KERN_INFO "PCI-DMA: Resuming GART IOMMU\n");
+	
+	if (fix_up_north_bridges) {
+		int i;
+		
+		printk(KERN_INFO "PCI-DMA: Restoring GART aperture settings\n");
+		
+		for (i = 0; i < num_k8_northbridges; i++) {
+			struct pci_dev *dev = k8_northbridges[i];
+			
+			/*
+			 * Don't enable translations just yet.  That is the next
+			 * step.  Restore the pre-suspend aperture settings.
+			 */
+			pci_write_config_dword(dev, 0x90,
+					       aperture_order << 1);
+			pci_write_config_dword(dev, 0x94,
+					       aperture_alloc >> 25);
+		}
+	}
+	
+	enable_gart_translations();
+	
+	return 0;
+}
+
+static int gart_suspend(struct sys_device *dev, pm_message_t state)
+{
+	return 0;
+}
+
+static struct sysdev_class gart_sysdev_class = {
+	set_kset_name("gart"),
+	.suspend = gart_suspend,
+	.resume = gart_resume,
+};
+
+static struct sys_device device_gart = {
+	.id     = 0,
+	.cls    = &gart_sysdev_class,
+};
+
 /* 
  * Private Northbridge GATT initialization in case we cannot use the
  * AGP driver for some reason.  
@@ -496,11 +577,12 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
 	void *gatt;
 	unsigned aper_base, new_aper_base;
 	unsigned aper_size, gatt_size, new_aper_size;
-	int i;
+	int i, error;
 
 	printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
 	aper_size = aper_base = info->aper_size = 0;
 	dev = NULL;
+
 	for (i = 0; i < num_k8_northbridges; i++) {
 		dev = k8_northbridges[i];
 		new_aper_base = read_aperture(dev, &new_aper_size); 
@@ -530,21 +612,14 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
 	memset(gatt, 0, gatt_size); 
 	agp_gatt_table = gatt;
 
-	for (i = 0; i < num_k8_northbridges; i++) {
-		u32 ctl; 
-		u32 gatt_reg; 
-
-		dev = k8_northbridges[i];
-		gatt_reg = __pa(gatt) >> 12; 
-		gatt_reg <<= 4; 
-		pci_write_config_dword(dev, 0x98, gatt_reg);
-		pci_read_config_dword(dev, 0x90, &ctl); 
+	enable_gart_translations();
 
-		ctl |= 1;
-		ctl &= ~((1<<4) | (1<<5));
+	error = sysdev_class_register(&gart_sysdev_class);
+	if (!error)
+		error = sysdev_register(&device_gart);
+	if (error)
+		panic("Could not register gart_sysdev -- would corrupt data on next suspend");
 
-		pci_write_config_dword(dev, 0x90, ctl); 
-	}
 	flush_gart();
 	
 	printk("PCI-DMA: aperture base @ %x size %u KB\n",aper_base, aper_size>>10);