x86_64: prepare shared kernel/pmtimer.c
[safe/jmp/linux-2.6] / arch / x86_64 / kernel / pci-gart.c
index ea8f404..4918c57 100644 (file)
@@ -10,7 +10,6 @@
  * Copyright 2002 Andi Kleen, SuSE Labs.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/ctype.h>
 #include <linux/agp_backend.h>
 #include <linux/topology.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <linux/kdebug.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
 #include <asm/pgtable.h>
 #include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/cacheflush.h>
-#include <asm/kdebug.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
+#include <asm/k8.h>
 
 unsigned long iommu_bus_base;  /* GART remapping area (physical) */
 static unsigned long iommu_size;       /* size of remapping area bytes */
@@ -46,8 +47,6 @@ u32 *iommu_gatt_base;                 /* Remapping table */
    also seen with Qlogic at least). */
 int iommu_fullflush = 1;
 
-#define MAX_NB 8
-
 /* Allocation bitmap for the remapping area */ 
 static DEFINE_SPINLOCK(iommu_bitmap_lock);
 static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
@@ -63,13 +62,6 @@ static u32 gart_unmapped_entry;
 #define to_pages(addr,size) \
        (round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT)
 
-#define for_all_nb(dev) \
-       dev = NULL;     \
-       while ((dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, dev))!=NULL)
-
-static struct pci_dev *northbridges[MAX_NB];
-static u32 northbridge_flush_word[MAX_NB];
-
 #define EMERGENCY_PAGES 32 /* = 128KB */ 
 
 #ifdef CONFIG_AGP
@@ -120,44 +112,17 @@ static void free_iommu(unsigned long offset, int size)
 /* 
  * Use global flush state to avoid races with multiple flushers.
  */
-static void flush_gart(struct device *dev)
+static void flush_gart(void)
 { 
        unsigned long flags;
-       int flushed = 0;
-       int i, max;
-
        spin_lock_irqsave(&iommu_bitmap_lock, flags);
-       if (need_flush) { 
-               max = 0;
-               for (i = 0; i < MAX_NB; i++) {
-                       if (!northbridges[i]) 
-                               continue;
-                       pci_write_config_dword(northbridges[i], 0x9c, 
-                                              northbridge_flush_word[i] | 1); 
-                       flushed++;
-                       max = i;
-               }
-               for (i = 0; i <= max; i++) {
-                       u32 w;
-                       if (!northbridges[i])
-                               continue;
-                       /* Make sure the hardware actually executed the flush. */
-                       for (;;) { 
-                               pci_read_config_dword(northbridges[i], 0x9c, &w);
-                               if (!(w & 1))
-                                       break;
-                               cpu_relax();
-                       }
-               } 
-               if (!flushed) 
-                       printk("nothing to flush?\n");
+       if (need_flush) {
+               k8_flush_garts();
                need_flush = 0;
        } 
        spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
 } 
 
-
-
 #ifdef CONFIG_IOMMU_LEAK
 
 #define SET_LEAK(x) if (iommu_leak_tab) \
@@ -221,7 +186,7 @@ static void iommu_full(struct device *dev, size_t size, int dir)
 static inline int need_iommu(struct device *dev, unsigned long addr, size_t size)
 { 
        u64 mask = *dev->dma_mask;
-       int high = addr + size >= mask;
+       int high = addr + size > mask;
        int mmu = high;
        if (force_iommu) 
                mmu = 1; 
@@ -231,7 +196,7 @@ static inline int need_iommu(struct device *dev, unsigned long addr, size_t size
 static inline int nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
 { 
        u64 mask = *dev->dma_mask;
-       int high = addr + size >= mask;
+       int high = addr + size > mask;
        int mmu = high;
        return mmu; 
 }
@@ -266,17 +231,15 @@ static dma_addr_t gart_map_simple(struct device *dev, char *buf,
                                 size_t size, int dir)
 {
        dma_addr_t map = dma_map_area(dev, virt_to_bus(buf), size, dir);
-       flush_gart(dev);
+       flush_gart();
        return map;
 }
 
 /* Map a single area into the IOMMU */
-dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
+static dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
 {
        unsigned long phys_mem, bus;
 
-       BUG_ON(dir == DMA_NONE);
-
        if (!dev)
                dev = &fallback_dev;
 
@@ -291,7 +254,7 @@ dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
 /*
  * Free a DMA mapping.
  */
-void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
+static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
                      size_t size, int direction)
 {
        unsigned long iommu_page;
@@ -313,7 +276,7 @@ void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
 /*
  * Wrapper for pci_unmap_single working with scatterlists.
  */
-void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
+static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
 {
        int i;
 
@@ -351,7 +314,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
                s->dma_address = addr;
                s->dma_length = s->length;
        }
-       flush_gart(dev);
+       flush_gart();
        return nents;
 }
 
@@ -419,7 +382,6 @@ int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
        unsigned long pages = 0;
        int need = 0, nextneed;
 
-       BUG_ON(dir == DMA_NONE);
        if (nents == 0) 
                return 0;
 
@@ -458,13 +420,13 @@ int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
        if (dma_map_cont(sg, start, i, sg+out, pages, need) < 0)
                goto error;
        out++;
-       flush_gart(dev);
+       flush_gart();
        if (out < nents) 
                sg[out].dma_length = 0; 
        return out;
 
 error:
-       flush_gart(NULL);
+       flush_gart();
        gart_unmap_sg(dev, sg, nents, dir);
        /* When it was forced or merged try again in a dumb way */
        if (force_iommu || iommu_merge) {
@@ -515,7 +477,7 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size)
        aper_base <<= 25;
 
        aper_size = (32 * 1024 * 1024) << aper_order; 
-       if (aper_base + aper_size >= 0xffffffff || !aper_size)
+       if (aper_base + aper_size > 0x100000000UL || !aper_size)
                aper_base = 0;
 
        *size = aper_size;
@@ -532,10 +494,13 @@ 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;
+
        printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
        aper_size = aper_base = info->aper_size = 0;
-       for_all_nb(dev) { 
+       dev = NULL;
+       for (i = 0; i < num_k8_northbridges; i++) {
+               dev = k8_northbridges[i];
                new_aper_base = read_aperture(dev, &new_aper_size); 
                if (!new_aper_base) 
                        goto nommu; 
@@ -555,14 +520,19 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
        gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); 
        gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size)); 
        if (!gatt) 
-               panic("Cannot allocate GATT table"); 
+               panic("Cannot allocate GATT table");
+       if (change_page_attr_addr((unsigned long)gatt, gatt_size >> PAGE_SHIFT, PAGE_KERNEL_NOCACHE))
+               panic("Could not set GART PTEs to uncacheable pages");
+       global_flush_tlb();
+
        memset(gatt, 0, gatt_size); 
        agp_gatt_table = gatt;
-       
-       for_all_nb(dev) { 
+
+       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);
@@ -573,7 +543,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
 
                pci_write_config_dword(dev, 0x90, ctl); 
        }
-       flush_gart(NULL); 
+       flush_gart();
        
        printk("PCI-DMA: aperture base @ %x size %u KB\n",aper_base, aper_size>>10); 
        return 0;
@@ -587,7 +557,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
 
 extern int agp_amd64_init(void);
 
-static struct dma_mapping_ops gart_dma_ops = {
+static const struct dma_mapping_ops gart_dma_ops = {
        .mapping_error = NULL,
        .map_single = gart_map_single,
        .map_simple = gart_map_simple,
@@ -602,15 +572,39 @@ static struct dma_mapping_ops gart_dma_ops = {
        .unmap_sg = gart_unmap_sg,
 };
 
-static int __init pci_iommu_init(void)
+void gart_iommu_shutdown(void)
+{
+       struct pci_dev *dev;
+       int i;
+
+       if (no_agp && (dma_ops != &gart_dma_ops))
+               return;
+
+        for (i = 0; i < num_k8_northbridges; i++) {
+                u32 ctl;
+
+                dev = k8_northbridges[i];
+                pci_read_config_dword(dev, 0x90, &ctl);
+
+                ctl &= ~1;
+
+                pci_write_config_dword(dev, 0x90, ctl);
+        }
+}
+
+void __init gart_iommu_init(void)
 { 
        struct agp_kern_info info;
        unsigned long aper_size;
        unsigned long iommu_start;
-       struct pci_dev *dev;
        unsigned long scratch;
        long i;
 
+       if (cache_k8_northbridges() < 0 || num_k8_northbridges == 0) {
+               printk(KERN_INFO "PCI-GART: No AMD northbridge found.\n");
+               return;
+       }
+
 #ifndef CONFIG_AGP_AMD64
        no_agp = 1; 
 #else
@@ -622,27 +616,22 @@ static int __init pci_iommu_init(void)
 #endif 
 
        if (swiotlb)
-               return -1; 
+               return;
+
+       /* Did we detect a different HW IOMMU? */
+       if (iommu_detected && !iommu_aperture)
+               return;
 
        if (no_iommu ||
            (!force_iommu && end_pfn <= MAX_DMA32_PFN) ||
            !iommu_aperture ||
            (no_agp && init_k8_gatt(&info) < 0)) {
-               printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n");
                if (end_pfn > MAX_DMA32_PFN) {
                        printk(KERN_ERR "WARNING more than 4GB of memory "
-                                       "but IOMMU not available.\n"
+                                       "but GART IOMMU not available.\n"
                               KERN_ERR "WARNING 32bit PCI may malfunction.\n");
                }
-               return -1;
-       }
-
-       i = 0;
-       for_all_nb(dev)
-               i++;
-       if (i > MAX_NB) {
-               printk(KERN_ERR "PCI-GART: Too many northbridges (%ld). Disabled\n", i);
-               return -1;
+               return;
        }
 
        printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n");
@@ -707,27 +696,11 @@ static int __init pci_iommu_init(void)
        for (i = EMERGENCY_PAGES; i < iommu_pages; i++) 
                iommu_gatt_base[i] = gart_unmapped_entry;
 
-       for_all_nb(dev) {
-               u32 flag; 
-               int cpu = PCI_SLOT(dev->devfn) - 24;
-               if (cpu >= MAX_NB)
-                       continue;
-               northbridges[cpu] = dev;
-               pci_read_config_dword(dev, 0x9c, &flag); /* cache flush word */
-               northbridge_flush_word[cpu] = flag; 
-       }
-                    
-       flush_gart(NULL);
-
+       flush_gart();
        dma_ops = &gart_dma_ops;
-
-       return 0;
 } 
 
-/* Must execute after PCI subsystem */
-fs_initcall(pci_iommu_init);
-
-void gart_parse_options(char *p)
+void __init gart_parse_options(char *p)
 {
        int arg;