Merge branch 'linus' into x86/gart
authorIngo Molnar <mingo@elte.hu>
Thu, 12 Jun 2008 09:27:22 +0000 (11:27 +0200)
committerIngo Molnar <mingo@elte.hu>
Thu, 12 Jun 2008 09:27:22 +0000 (11:27 +0200)
arch/x86/kernel/aperture_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-gart_64.c
drivers/char/agp/amd64-agp.c
include/asm-x86/gart.h

index 479926d9e0048d242023def47b3f596550a13344..eb20f168c0fdb9052ad37919415cecd70a2a9f89 100644 (file)
@@ -35,6 +35,18 @@ int fallback_aper_force __initdata;
 
 int fix_aperture __initdata = 1;
 
+struct bus_dev_range {
+       int bus;
+       int dev_base;
+       int dev_limit;
+};
+
+static struct bus_dev_range bus_dev_ranges[] __initdata = {
+       { 0x00, 0x18, 0x20},
+       { 0xff, 0x00, 0x20},
+       { 0xfe, 0x00, 0x20}
+};
+
 static struct resource gart_resource = {
        .name   = "GART",
        .flags  = IORESOURCE_MEM,
@@ -55,8 +67,9 @@ static u32 __init allocate_aperture(void)
        u32 aper_size;
        void *p;
 
-       if (fallback_aper_order > 7)
-               fallback_aper_order = 7;
+       /* aper_size should <= 1G */
+       if (fallback_aper_order > 5)
+               fallback_aper_order = 5;
        aper_size = (32 * 1024 * 1024) << fallback_aper_order;
 
        /*
@@ -65,7 +78,20 @@ static u32 __init allocate_aperture(void)
         * memory. Unfortunately we cannot move it up because that would
         * make the IOMMU useless.
         */
-       p = __alloc_bootmem_nopanic(aper_size, aper_size, 0);
+       /*
+        * using 512M as goal, in case kexec will load kernel_big
+        * that will do the on position decompress, and  could overlap with
+        * that positon with gart that is used.
+        * sequende:
+        * kernel_small
+        * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
+        * ==> kernel_small(gart area become e820_reserved)
+        * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
+        * ==> kerne_big (uncompressed size will be big than 64M or 128M)
+        * so don't use 512M below as gart iommu, leave the space for kernel
+        * code for safe
+        */
+       p = __alloc_bootmem_nopanic(aper_size, aper_size, 512ULL<<20);
        if (!p || __pa(p)+aper_size > 0xffffffff) {
                printk(KERN_ERR
                        "Cannot allocate aperture memory hole (%p,%uK)\n",
@@ -83,69 +109,53 @@ static u32 __init allocate_aperture(void)
        return (u32)__pa(p);
 }
 
-static int __init aperture_valid(u64 aper_base, u32 aper_size)
-{
-       if (!aper_base)
-               return 0;
-
-       if (aper_base + aper_size > 0x100000000UL) {
-               printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n");
-               return 0;
-       }
-       if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
-               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;
-}
 
 /* Find a PCI capability */
-static __u32 __init find_cap(int num, int slot, int func, int cap)
+static u32 __init find_cap(int bus, int slot, int func, int cap)
 {
        int bytes;
        u8 pos;
 
-       if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
+       if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) &
                                                PCI_STATUS_CAP_LIST))
                return 0;
 
-       pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
+       pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST);
        for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
                u8 id;
 
                pos &= ~3;
-               id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
+               id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID);
                if (id == 0xff)
                        break;
                if (id == cap)
                        return pos;
-               pos = read_pci_config_byte(num, slot, func,
+               pos = read_pci_config_byte(bus, slot, func,
                                                pos+PCI_CAP_LIST_NEXT);
        }
        return 0;
 }
 
 /* Read a standard AGPv3 bridge header */
-static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
+static u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order)
 {
        u32 apsize;
        u32 apsizereg;
        int nbits;
        u32 aper_low, aper_hi;
        u64 aper;
+       u32 old_order;
 
-       printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", num, slot, func);
-       apsizereg = read_pci_config_16(num, slot, func, cap + 0x14);
+       printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", bus, slot, func);
+       apsizereg = read_pci_config_16(bus, slot, func, cap + 0x14);
        if (apsizereg == 0xffffffff) {
                printk(KERN_ERR "APSIZE in AGP bridge unreadable\n");
                return 0;
        }
 
+       /* old_order could be the value from NB gart setting */
+       old_order = *order;
+
        apsize = apsizereg & 0xfff;
        /* Some BIOS use weird encodings not in the AGPv3 table. */
        if (apsize & 0xff)
@@ -155,14 +165,26 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
        if ((int)*order < 0) /* < 32MB */
                *order = 0;
 
-       aper_low = read_pci_config(num, slot, func, 0x10);
-       aper_hi = read_pci_config(num, slot, func, 0x14);
+       aper_low = read_pci_config(bus, slot, func, 0x10);
+       aper_hi = read_pci_config(bus, slot, func, 0x14);
        aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
 
+       /*
+        * On some sick chips, APSIZE is 0. It means it wants 4G
+        * so let double check that order, and lets trust AMD NB settings:
+        */
+       printk(KERN_INFO "Aperture from AGP @ %Lx old size %u MB\n",
+                       aper, 32 << old_order);
+       if (aper + (32ULL<<(20 + *order)) > 0x100000000ULL) {
+               printk(KERN_INFO "Aperture size %u MB (APSIZE %x) is not right, using settings from NB\n",
+                               32 << *order, apsizereg);
+               *order = old_order;
+       }
+
        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))
+       if (!aperture_valid(aper, (32*1024*1024) << *order, 32<<20))
                return 0;
        return (u32)aper;
 }
@@ -180,17 +202,17 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
  * the AGP bridges should be always an own bus on the HT hierarchy,
  * but do it here for future safety.
  */
-static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
+static u32 __init search_agp_bridge(u32 *order, int *valid_agp)
 {
-       int num, slot, func;
+       int bus, slot, func;
 
        /* Poor man's PCI discovery */
-       for (num = 0; num < 256; num++) {
+       for (bus = 0; bus < 256; bus++) {
                for (slot = 0; slot < 32; slot++) {
                        for (func = 0; func < 8; func++) {
                                u32 class, cap;
                                u8 type;
-                               class = read_pci_config(num, slot, func,
+                               class = read_pci_config(bus, slot, func,
                                                        PCI_CLASS_REVISION);
                                if (class == 0xffffffff)
                                        break;
@@ -199,17 +221,17 @@ static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
                                case PCI_CLASS_BRIDGE_HOST:
                                case PCI_CLASS_BRIDGE_OTHER: /* needed? */
                                        /* AGP bridge? */
-                                       cap = find_cap(num, slot, func,
+                                       cap = find_cap(bus, slot, func,
                                                        PCI_CAP_ID_AGP);
                                        if (!cap)
                                                break;
                                        *valid_agp = 1;
-                                       return read_agp(num, slot, func, cap,
+                                       return read_agp(bus, slot, func, cap,
                                                        order);
                                }
 
                                /* No multi-function device? */
-                               type = read_pci_config_byte(num, slot, func,
+                               type = read_pci_config_byte(bus, slot, func,
                                                               PCI_HEADER_TYPE);
                                if (!(type & 0x80))
                                        break;
@@ -249,36 +271,50 @@ void __init early_gart_iommu_check(void)
         * or BIOS forget to put that in reserved.
         * try to update e820 to make that region as reserved.
         */
-       int fix, num;
+       int i, fix, slot;
        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;
+       int aper_enabled = 0, last_aper_enabled = 0, last_valid = 0;
 
        if (!early_pci_allowed())
                return;
 
+       /* This is mostly duplicate of iommu_hole_init */
        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;
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
+
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
+
+                       ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
+                       aper_enabled = ctl & AMD64_GARTEN;
+                       aper_order = (ctl >> 1) & 7;
+                       aper_size = (32 * 1024 * 1024) << aper_order;
+                       aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
+                       aper_base <<= 25;
+
+                       if (last_valid) {
+                               if ((aper_order != last_aper_order) ||
+                                   (aper_base != last_aper_base) ||
+                                   (aper_enabled != last_aper_enabled)) {
+                                       fix = 1;
+                                       break;
+                               }
+                       }
+
+                       last_aper_order = aper_order;
+                       last_aper_base = aper_base;
+                       last_aper_enabled = aper_enabled;
+                       last_valid = 1;
                }
-               last_aper_order = aper_order;
-               last_aper_base = aper_base;
-               last_aper_enabled = aper_enabled;
        }
 
        if (!fix && !aper_enabled)
@@ -288,34 +324,48 @@ void __init early_gart_iommu_check(void)
                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 */
+               if (!e820_all_mapped(aper_base, aper_base + aper_size,
+                                   E820_RESERVED)) {
+                       /* reserve it, so we can reuse it in second kernel */
                        printk(KERN_INFO "update e820 for GART\n");
                        add_memory_region(aper_base, aper_size, E820_RESERVED);
                        update_e820();
                }
-               return;
        }
 
+       if (!fix)
+               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;
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
 
-               ctl = read_pci_config(0, num, 3, 0x90);
-               ctl &= ~1;
-               write_pci_config(0, num, 3, 0x90, ctl);
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
+
+                       ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
+                       ctl &= ~AMD64_GARTEN;
+                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
+               }
        }
 
 }
 
+static int __initdata printed_gart_size_msg;
+
 void __init gart_iommu_hole_init(void)
 {
+       u32 agp_aper_base = 0, agp_aper_order = 0;
        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;
+       int fix, slot, valid_agp = 0;
+       int i, node;
 
        if (gart_iommu_aperture_disabled || !fix_aperture ||
            !early_pci_allowed())
@@ -323,38 +373,63 @@ void __init gart_iommu_hole_init(void)
 
        printk(KERN_INFO  "Checking aperture...\n");
 
+       if (!fallback_aper_force)
+               agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp);
+
        fix = 0;
        node = 0;
-       for (num = 24; num < 32; num++) {
-               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
-                       continue;
-
-               iommu_detected = 1;
-               gart_iommu_aperture = 1;
-
-               aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7;
-               aper_size = (32 * 1024 * 1024) << aper_order;
-               aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
-               aper_base <<= 25;
-
-               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;
-                       break;
-               }
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
+
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
+
+                       iommu_detected = 1;
+                       gart_iommu_aperture = 1;
+
+                       aper_order = (read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL) >> 1) & 7;
+                       aper_size = (32 * 1024 * 1024) << aper_order;
+                       aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
+                       aper_base <<= 25;
+
+                       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, 64<<20)) {
+                               if (valid_agp && agp_aper_base &&
+                                   agp_aper_base == aper_base &&
+                                   agp_aper_order == aper_order) {
+                                       /* the same between two setting from NB and agp */
+                                       if (!no_iommu && end_pfn > MAX_DMA32_PFN && !printed_gart_size_msg) {
+                                               printk(KERN_ERR "you are using iommu with agp, but GART size is less than 64M\n");
+                                               printk(KERN_ERR "please increase GART size in your BIOS setup\n");
+                                               printk(KERN_ERR "if BIOS doesn't have that option, contact your HW vendor!\n");
+                                               printed_gart_size_msg = 1;
+                                       }
+                               } else {
+                                       fix = 1;
+                                       goto out;
+                               }
+                       }
 
-               if ((last_aper_order && aper_order != last_aper_order) ||
-                   (last_aper_base && aper_base != last_aper_base)) {
-                       fix = 1;
-                       break;
+                       if ((last_aper_order && aper_order != last_aper_order) ||
+                           (last_aper_base && aper_base != last_aper_base)) {
+                               fix = 1;
+                               goto out;
+                       }
+                       last_aper_order = aper_order;
+                       last_aper_base = aper_base;
                }
-               last_aper_order = aper_order;
-               last_aper_base = aper_base;
        }
 
+out:
        if (!fix && !fallback_aper_force) {
                if (last_aper_base) {
                        unsigned long n = (32 * 1024 * 1024) << last_aper_order;
@@ -364,8 +439,10 @@ void __init gart_iommu_hole_init(void)
                return;
        }
 
-       if (!fallback_aper_force)
-               aper_alloc = search_agp_bridge(&aper_order, &valid_agp);
+       if (!fallback_aper_force) {
+               aper_alloc = agp_aper_base;
+               aper_order = agp_aper_order;
+       }
 
        if (aper_alloc) {
                /* Got the aperture from the AGP bridge */
@@ -401,16 +478,22 @@ void __init gart_iommu_hole_init(void)
        }
 
        /* Fix up the north bridges */
-       for (num = 24; num < 32; num++) {
-               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
-                       continue;
-
-               /*
-                * Don't enable translation yet. That is done later.
-                * Assume this BIOS didn't initialise the GART so
-                * just overwrite all previous bits
-                */
-               write_pci_config(0, num, 3, 0x90, aper_order<<1);
-               write_pci_config(0, num, 3, 0x94, aper_alloc>>25);
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
+
+                       /* Don't enable translation yet. That is done later.
+                          Assume this BIOS didn't initialise the GART so
+                          just overwrite all previous bits */
+                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, aper_order << 1);
+                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25);
+               }
        }
 }
index c5ef1af8e79de6883b005cfa99d59bb9164e978c..7747bc82b11d7d8c5d9f88109d544c17233d315f 100644 (file)
@@ -77,10 +77,14 @@ void __init dma32_reserve_bootmem(void)
        if (end_pfn <= MAX_DMA32_PFN)
                return;
 
+       /*
+        * check aperture_64.c allocate_aperture() for reason about
+        * using 512M as goal
+        */
        align = 64ULL<<20;
        size = round_up(dma32_bootmem_size, align);
        dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align,
-                                __pa(MAX_DMA_ADDRESS));
+                                512ULL<<20);
        if (dma32_bootmem_ptr)
                dma32_bootmem_size = size;
        else
@@ -88,7 +92,6 @@ void __init dma32_reserve_bootmem(void)
 }
 static void __init dma32_free_bootmem(void)
 {
-       int node;
 
        if (end_pfn <= MAX_DMA32_PFN)
                return;
@@ -96,9 +99,7 @@ static void __init dma32_free_bootmem(void)
        if (!dma32_bootmem_ptr)
                return;
 
-       for_each_online_node(node)
-               free_bootmem_node(NODE_DATA(node), __pa(dma32_bootmem_ptr),
-                                 dma32_bootmem_size);
+       free_bootmem(__pa(dma32_bootmem_ptr), dma32_bootmem_size);
 
        dma32_bootmem_ptr = NULL;
        dma32_bootmem_size = 0;
index aa8ec928caa85ff43d4da3a0fe3e7d570b57f08a..3710097f02ebbaeefc009235cdc05b5a271c5584 100644 (file)
@@ -534,8 +534,8 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size)
        unsigned aper_size = 0, aper_base_32, aper_order;
        u64 aper_base;
 
-       pci_read_config_dword(dev, 0x94, &aper_base_32);
-       pci_read_config_dword(dev, 0x90, &aper_order);
+       pci_read_config_dword(dev, AMD64_GARTAPERTUREBASE, &aper_base_32);
+       pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &aper_order);
        aper_order = (aper_order >> 1) & 7;
 
        aper_base = aper_base_32 & 0x7fff;
@@ -615,19 +615,8 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
        agp_gatt_table = gatt;
 
        for (i = 0; i < num_k8_northbridges; i++) {
-               u32 gatt_reg;
-               u32 ctl;
-
                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);
-
-               ctl |= 1;
-               ctl &= ~((1<<4) | (1<<5));
-
-               pci_write_config_dword(dev, 0x90, ctl);
+               enable_gart_translation(dev, __pa(gatt));
        }
 
        error = sysdev_class_register(&gart_sysdev_class);
@@ -677,11 +666,11 @@ void gart_iommu_shutdown(void)
                u32 ctl;
 
                dev = k8_northbridges[i];
-               pci_read_config_dword(dev, 0x90, &ctl);
+               pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
 
-               ctl &= ~1;
+               ctl &= ~GARTEN;
 
-               pci_write_config_dword(dev, 0x90, ctl);
+               pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
        }
 }
 
index d8200ac8f8cbb8643355719aa78bd144eccee9ef..f5af65ac8c7830bcf93a104aa878b9a99859f5f0 100644 (file)
 #include <asm/page.h>          /* PAGE_SIZE */
 #include <asm/e820.h>
 #include <asm/k8.h>
+#include <asm/gart.h>
 #include "agp.h"
 
-/* PTE bits. */
-#define GPTE_VALID     1
-#define GPTE_COHERENT  2
-
-/* Aperture control register bits. */
-#define GARTEN         (1<<0)
-#define DISGARTCPU     (1<<4)
-#define DISGARTIO      (1<<5)
-
-/* GART cache control register bits. */
-#define INVGART                (1<<0)
-#define GARTPTEERR     (1<<1)
-
-/* K8 On-cpu GART registers */
-#define AMD64_GARTAPERTURECTL  0x90
-#define AMD64_GARTAPERTUREBASE 0x94
-#define AMD64_GARTTABLEBASE    0x98
-#define AMD64_GARTCACHECTL     0x9c
-#define AMD64_GARTEN           (1<<0)
-
 /* NVIDIA K8 registers */
 #define NVIDIA_X86_64_0_APBASE         0x10
 #define NVIDIA_X86_64_1_APBASE1                0x50
@@ -165,29 +146,18 @@ static int amd64_fetch_size(void)
  * In a multiprocessor x86-64 system, this function gets
  * called once for each CPU.
  */
-static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table)
+static u64 amd64_configure(struct pci_dev *hammer, u64 gatt_table)
 {
        u64 aperturebase;
        u32 tmp;
-       u64 addr, aper_base;
+       u64 aper_base;
 
        /* Address to map to */
-       pci_read_config_dword (hammer, AMD64_GARTAPERTUREBASE, &tmp);
+       pci_read_config_dword(hammer, AMD64_GARTAPERTUREBASE, &tmp);
        aperturebase = tmp << 25;
        aper_base = (aperturebase & PCI_BASE_ADDRESS_MEM_MASK);
 
-       /* address of the mappings table */
-       addr = (u64) gatt_table;
-       addr >>= 12;
-       tmp = (u32) addr<<4;
-       tmp &= ~0xf;
-       pci_write_config_dword (hammer, AMD64_GARTTABLEBASE, tmp);
-
-       /* Enable GART translation for this hammer. */
-       pci_read_config_dword(hammer, AMD64_GARTAPERTURECTL, &tmp);
-       tmp |= GARTEN;
-       tmp &= ~(DISGARTCPU | DISGARTIO);
-       pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp);
+       enable_gart_translation(hammer, gatt_table);
 
        return aper_base;
 }
@@ -226,9 +196,9 @@ static void amd64_cleanup(void)
         for (i = 0; i < num_k8_northbridges; i++) {
                struct pci_dev *dev = k8_northbridges[i];
                /* disable gart translation */
-               pci_read_config_dword (dev, AMD64_GARTAPERTURECTL, &tmp);
+               pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp);
                tmp &= ~AMD64_GARTEN;
-               pci_write_config_dword (dev, AMD64_GARTAPERTURECTL, tmp);
+               pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp);
        }
 }
 
@@ -258,24 +228,10 @@ static const struct agp_bridge_driver amd_8151_driver = {
 };
 
 /* Some basic sanity checks for the aperture. */
-static int __devinit aperture_valid(u64 aper, u32 size)
+static int __devinit agp_aperture_valid(u64 aper, u32 size)
 {
-       if (aper == 0) {
-               printk(KERN_ERR PFX "No aperture\n");
-               return 0;
-       }
-       if (size < 32*1024*1024) {
-               printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20);
-               return 0;
-       }
-       if ((u64)aper + size > 0x100000000ULL) {
-               printk(KERN_ERR PFX "Aperture out of bounds\n");
+       if (!aperture_valid(aper, size, 32*1024*1024))
                return 0;
-       }
-       if (e820_any_mapped(aper, aper + size, E820_RAM)) {
-               printk(KERN_ERR PFX "Aperture pointing to RAM\n");
-               return 0;
-       }
 
        /* Request the Aperture. This catches cases when someone else
           already put a mapping in there - happens with some very broken BIOS
@@ -308,11 +264,11 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
        u32 nb_order, nb_base;
        u16 apsize;
 
-       pci_read_config_dword(nb, 0x90, &nb_order);
+       pci_read_config_dword(nb, AMD64_GARTAPERTURECTL, &nb_order);
        nb_order = (nb_order >> 1) & 7;
-       pci_read_config_dword(nb, 0x94, &nb_base);
+       pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base);
        nb_aper = nb_base << 25;
-       if (aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) {
+       if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) {
                return 0;
        }
 
@@ -331,12 +287,23 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
        pci_read_config_dword(agp, 0x10, &aper_low);
        pci_read_config_dword(agp, 0x14, &aper_hi);
        aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
+
+       /*
+        * On some sick chips APSIZE is 0. This means it wants 4G
+        * so let double check that order, and lets trust the AMD NB settings
+        */
+       if (order >=0 && aper + (32ULL<<(20 + order)) > 0x100000000ULL) {
+               printk(KERN_INFO "Aperture size %u MB is not right, using settings from NB\n",
+                                 32 << order);
+               order = nb_order;
+       }
+
        printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order);
-       if (order < 0 || !aperture_valid(aper, (32*1024*1024)<<order))
+       if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order))
                return -1;
 
-       pci_write_config_dword(nb, 0x90, order << 1);
-       pci_write_config_dword(nb, 0x94, aper >> 25);
+       pci_write_config_dword(nb, AMD64_GARTAPERTURECTL, order << 1);
+       pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25);
 
        return 0;
 }
index 90958ed993faa3d140c495911bb77a1c57037ee9..c818b96f936b5190d8d025054f918657e6a609ac 100644 (file)
@@ -1,10 +1,13 @@
 #ifndef _ASM_X8664_IOMMU_H
 #define _ASM_X8664_IOMMU_H 1
 
+#include <asm/e820.h>
+
 extern void pci_iommu_shutdown(void);
 extern void no_iommu_init(void);
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
+extern int agp_amd64_init(void);
 #ifdef CONFIG_GART_IOMMU
 extern void gart_iommu_init(void);
 extern void gart_iommu_shutdown(void);
@@ -31,4 +34,63 @@ static inline void gart_iommu_shutdown(void)
 
 #endif
 
+/* PTE bits. */
+#define GPTE_VALID     1
+#define GPTE_COHERENT  2
+
+/* Aperture control register bits. */
+#define GARTEN         (1<<0)
+#define DISGARTCPU     (1<<4)
+#define DISGARTIO      (1<<5)
+
+/* GART cache control register bits. */
+#define INVGART                (1<<0)
+#define GARTPTEERR     (1<<1)
+
+/* K8 On-cpu GART registers */
+#define AMD64_GARTAPERTURECTL  0x90
+#define AMD64_GARTAPERTUREBASE 0x94
+#define AMD64_GARTTABLEBASE    0x98
+#define AMD64_GARTCACHECTL     0x9c
+#define AMD64_GARTEN           (1<<0)
+
+static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
+{
+       u32 tmp, ctl;
+
+        /* address of the mappings table */
+        addr >>= 12;
+        tmp = (u32) addr<<4;
+        tmp &= ~0xf;
+        pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp);
+
+        /* Enable GART translation for this hammer. */
+        pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
+        ctl |= GARTEN;
+        ctl &= ~(DISGARTCPU | DISGARTIO);
+        pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
+}
+
+static inline int aperture_valid(u64 aper_base, u32 aper_size, u32 min_size)
+{
+       if (!aper_base)
+               return 0;
+
+       if (aper_base + aper_size > 0x100000000ULL) {
+               printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n");
+               return 0;
+       }
+       if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
+               printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n");
+               return 0;
+       }
+       if (aper_size < min_size) {
+               printk(KERN_ERR "Aperture too small (%d MB) than (%d MB)\n",
+                                aper_size>>20, min_size>>20);
+               return 0;
+       }
+
+       return 1;
+}
+
 #endif