[PATCH] x86-64: dma_ops as const
[powerpc.git] / arch / x86_64 / kernel / pci-calgary.c
index 3215675..5bd20b5 100644 (file)
@@ -138,6 +138,8 @@ static const unsigned long phb_debug_offsets[] = {
 
 #define PHB_DEBUG_STUFF_OFFSET 0x0020
 
+#define EMERGENCY_PAGES 32 /* = 128KB */
+
 unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED;
 static int translate_empty_slots __read_mostly = 0;
 static int calgary_detected __read_mostly = 0;
@@ -296,6 +298,16 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 {
        unsigned long entry;
        unsigned long badbit;
+       unsigned long badend;
+
+       /* were we called with bad_dma_address? */
+       badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE);
+       if (unlikely((dma_addr >= bad_dma_address) && (dma_addr < badend))) {
+               printk(KERN_ERR "Calgary: driver tried unmapping bad DMA "
+                      "address 0x%Lx\n", dma_addr);
+               WARN_ON(1);
+               return;
+       }
 
        entry = dma_addr >> PAGE_SHIFT;
 
@@ -495,7 +507,7 @@ error:
        return ret;
 }
 
-static struct dma_mapping_ops calgary_dma_ops = {
+static const struct dma_mapping_ops calgary_dma_ops = {
        .alloc_coherent = calgary_alloc_coherent,
        .map_single = calgary_map_single,
        .unmap_single = calgary_unmap_single,
@@ -656,8 +668,8 @@ static void __init calgary_reserve_regions(struct pci_dev *dev)
        u64 start;
        struct iommu_table *tbl = dev->sysdata;
 
-       /* reserve bad_dma_address in case it's a legal address */
-       iommu_range_reserve(tbl, bad_dma_address, 1);
+       /* reserve EMERGENCY_PAGES from bad_dma_address and up */
+       iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES);
 
        /* avoid the BIOS/VGA first 640KB-1MB region */
        start = (640 * 1024);
@@ -1052,7 +1064,7 @@ void __init detect_calgary(void)
        void *tbl;
        int calgary_found = 0;
        unsigned long ptr;
-       int offset;
+       unsigned int offset, prev_offset;
        int ret;
 
        /*
@@ -1068,29 +1080,36 @@ void __init detect_calgary(void)
        if (!early_pci_allowed())
                return;
 
+       printk(KERN_DEBUG "Calgary: detecting Calgary via BIOS EBDA area\n");
+
        ptr = (unsigned long)phys_to_virt(get_bios_ebda());
 
        rio_table_hdr = NULL;
+       prev_offset = 0;
        offset = 0x180;
-       while (offset) {
+       /*
+        * The next offset is stored in the 1st word.
+        * Only parse up until the offset increases:
+        */
+       while (offset > prev_offset) {
                /* The block id is stored in the 2nd word */
                if (*((unsigned short *)(ptr + offset + 2)) == 0x4752){
                        /* set the pointer past the offset & block id */
                        rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4);
                        break;
                }
-               /* The next offset is stored in the 1st word. 0 means no more */
+               prev_offset = offset;
                offset = *((unsigned short *)(ptr + offset));
        }
        if (!rio_table_hdr) {
-               printk(KERN_ERR "Calgary: Unable to locate "
-                               "Rio Grande Table in EBDA - bailing!\n");
+               printk(KERN_DEBUG "Calgary: Unable to locate Rio Grande table "
+                      "in EBDA - bailing!\n");
                return;
        }
 
        ret = build_detail_arrays();
        if (ret) {
-               printk(KERN_ERR "Calgary: build_detail_arrays ret %d\n", ret);
+               printk(KERN_DEBUG "Calgary: build_detail_arrays ret %d\n", ret);
                return;
        }
 
@@ -1123,6 +1142,9 @@ void __init detect_calgary(void)
                }
        }
 
+       printk(KERN_DEBUG "Calgary: finished detection, Calgary %s\n",
+              calgary_found ? "found" : "not found");
+
        if (calgary_found) {
                iommu_detected = 1;
                calgary_detected = 1;
@@ -1166,6 +1188,7 @@ int __init calgary_iommu_init(void)
        }
 
        force_iommu = 1;
+       bad_dma_address = 0x0;
        dma_ops = &calgary_dma_ops;
 
        return 0;