]> err.no Git - linux-2.6/blobdiff - arch/x86/kernel/aperture_64.c
x86: mtrr cleanup for converting continuous to discrete layout, v8
[linux-2.6] / arch / x86 / kernel / aperture_64.c
index 250db0527f5d5e8961b01360d2f84d22cf77cfd2..479926d9e0048d242023def47b3f596550a13344 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pci.h>
 #include <linux/bitops.h>
 #include <linux/ioport.h>
+#include <linux/suspend.h>
 #include <asm/e820.h>
 #include <asm/io.h>
 #include <asm/gart.h>
 #include <asm/k8.h>
 
 int gart_iommu_aperture;
-int gart_iommu_aperture_disabled __initdata = 0;
-int gart_iommu_aperture_allowed __initdata = 0;
+int gart_iommu_aperture_disabled __initdata;
+int gart_iommu_aperture_allowed __initdata;
 
 int fallback_aper_order __initdata = 1; /* 64MB */
-int fallback_aper_force __initdata = 0;
+int fallback_aper_force __initdata;
 
 int fix_aperture __initdata = 1;
 
@@ -66,15 +67,18 @@ static u32 __init allocate_aperture(void)
         */
        p = __alloc_bootmem_nopanic(aper_size, aper_size, 0);
        if (!p || __pa(p)+aper_size > 0xffffffff) {
-               printk("Cannot allocate aperture memory hole (%p,%uK)\n",
-                      p, aper_size>>10);
+               printk(KERN_ERR
+                       "Cannot allocate aperture memory hole (%p,%uK)\n",
+                               p, aper_size>>10);
                if (p)
                        free_bootmem(__pa(p), aper_size);
                return 0;
        }
-       printk("Mapping aperture over %d KB of RAM @ %lx\n",
-              aper_size >> 10, __pa(p));
+       printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n",
+                       aper_size >> 10, __pa(p));
        insert_aperture_resource((u32)__pa(p), aper_size);
+       register_nosave_region((u32)__pa(p) >> PAGE_SHIFT,
+                               (u32)__pa(p+aper_size) >> PAGE_SHIFT);
 
        return (u32)__pa(p);
 }
@@ -83,18 +87,20 @@ static int __init aperture_valid(u64 aper_base, u32 aper_size)
 {
        if (!aper_base)
                return 0;
-       if (aper_size < 64*1024*1024) {
-               printk("Aperture too small (%d MB)\n", aper_size>>20);
-               return 0;
-       }
+
        if (aper_base + aper_size > 0x100000000UL) {
-               printk("Aperture beyond 4GB. Ignoring.\n");
+               printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n");
                return 0;
        }
        if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
-               printk("Aperture pointing to e820 RAM. Ignoring.\n");
+               printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n");
+               return 0;
+       }
+       if (aper_size < 64*1024*1024) {
+               printk(KERN_ERR "Aperture too small (%d MB)\n", aper_size>>20);
                return 0;
        }
+
        return 1;
 }
 
@@ -133,10 +139,10 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
        u32 aper_low, aper_hi;
        u64 aper;
 
-       printk("AGP bridge at %02x:%02x:%02x\n", num, slot, func);
+       printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", num, slot, func);
        apsizereg = read_pci_config_16(num, slot, func, cap + 0x14);
        if (apsizereg == 0xffffffff) {
-               printk("APSIZE in AGP bridge unreadable\n");
+               printk(KERN_ERR "APSIZE in AGP bridge unreadable\n");
                return 0;
        }
 
@@ -153,8 +159,8 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
        aper_hi = read_pci_config(num, slot, func, 0x14);
        aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
 
-       printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n",
-              aper, 32 << *order, apsizereg);
+       printk(KERN_INFO "Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n",
+                       aper, 32 << *order, apsizereg);
 
        if (!aperture_valid(aper, (32*1024*1024) << *order))
                return 0;
@@ -210,16 +216,106 @@ static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
                        }
                }
        }
-       printk("No AGP bridge found\n");
+       printk(KERN_INFO "No AGP bridge found\n");
 
        return 0;
 }
 
+static int gart_fix_e820 __initdata = 1;
+
+static int __init parse_gart_mem(char *p)
+{
+       if (!p)
+               return -EINVAL;
+
+       if (!strncmp(p, "off", 3))
+               gart_fix_e820 = 0;
+       else if (!strncmp(p, "on", 2))
+               gart_fix_e820 = 1;
+
+       return 0;
+}
+early_param("gart_fix_e820", parse_gart_mem);
+
+void __init early_gart_iommu_check(void)
+{
+       /*
+        * in case it is enabled before, esp for kexec/kdump,
+        * previous kernel already enable that. memset called
+        * by allocate_aperture/__alloc_bootmem_nopanic cause restart.
+        * or second kernel have different position for GART hole. and new
+        * kernel could use hole as RAM that is still used by GART set by
+        * first kernel
+        * or BIOS forget to put that in reserved.
+        * try to update e820 to make that region as reserved.
+        */
+       int fix, num;
+       u32 ctl;
+       u32 aper_size = 0, aper_order = 0, last_aper_order = 0;
+       u64 aper_base = 0, last_aper_base = 0;
+       int aper_enabled = 0, last_aper_enabled = 0;
+
+       if (!early_pci_allowed())
+               return;
+
+       fix = 0;
+       for (num = 24; num < 32; num++) {
+               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
+                       continue;
+
+               ctl = read_pci_config(0, num, 3, 0x90);
+               aper_enabled = ctl & 1;
+               aper_order = (ctl >> 1) & 7;
+               aper_size = (32 * 1024 * 1024) << aper_order;
+               aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
+               aper_base <<= 25;
+
+               if ((last_aper_order && aper_order != last_aper_order) ||
+                   (last_aper_base && aper_base != last_aper_base) ||
+                   (last_aper_enabled && aper_enabled != last_aper_enabled)) {
+                       fix = 1;
+                       break;
+               }
+               last_aper_order = aper_order;
+               last_aper_base = aper_base;
+               last_aper_enabled = aper_enabled;
+       }
+
+       if (!fix && !aper_enabled)
+               return;
+
+       if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL)
+               fix = 1;
+
+       if (gart_fix_e820 && !fix && aper_enabled) {
+               if (e820_any_mapped(aper_base, aper_base + aper_size,
+                                   E820_RAM)) {
+                       /* reserved it, so we can resuse it in second kernel */
+                       printk(KERN_INFO "update e820 for GART\n");
+                       add_memory_region(aper_base, aper_size, E820_RESERVED);
+                       update_e820();
+               }
+               return;
+       }
+
+       /* different nodes have different setting, disable them all at first*/
+       for (num = 24; num < 32; num++) {
+               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
+                       continue;
+
+               ctl = read_pci_config(0, num, 3, 0x90);
+               ctl &= ~1;
+               write_pci_config(0, num, 3, 0x90, ctl);
+       }
+
+}
+
 void __init gart_iommu_hole_init(void)
 {
        u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
        u64 aper_base, last_aper_base = 0;
        int fix, num, valid_agp = 0;
+       int node;
 
        if (gart_iommu_aperture_disabled || !fix_aperture ||
            !early_pci_allowed())
@@ -228,6 +324,7 @@ void __init gart_iommu_hole_init(void)
        printk(KERN_INFO  "Checking aperture...\n");
 
        fix = 0;
+       node = 0;
        for (num = 24; num < 32; num++) {
                if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
                        continue;
@@ -240,8 +337,9 @@ void __init gart_iommu_hole_init(void)
                aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
                aper_base <<= 25;
 
-               printk("CPU %d: aperture @ %Lx size %u MB\n", num-24,
-                      aper_base, aper_size>>20);
+               printk(KERN_INFO "Node %d: aperture @ %Lx size %u MB\n",
+                               node, aper_base, aper_size >> 20);
+               node++;
 
                if (!aperture_valid(aper_base, aper_size)) {
                        fix = 1;
@@ -277,10 +375,13 @@ void __init gart_iommu_hole_init(void)
                   force_iommu ||
                   valid_agp ||
                   fallback_aper_force) {
-               printk("Your BIOS doesn't leave a aperture memory hole\n");
-               printk("Please enable the IOMMU option in the BIOS setup\n");
-               printk("This costs you %d MB of RAM\n",
-                      32 << fallback_aper_order);
+               printk(KERN_ERR
+                       "Your BIOS doesn't leave a aperture memory hole\n");
+               printk(KERN_ERR
+                       "Please enable the IOMMU option in the BIOS setup\n");
+               printk(KERN_ERR
+                       "This costs you %d MB of RAM\n",
+                               32 << fallback_aper_order);
 
                aper_order = fallback_aper_order;
                aper_alloc = allocate_aperture();