X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;ds=sidebyside;f=arch%2Fx86_64%2Fkernel%2Fpci-calgary.c;h=5bd20b542c1efc47a0d93da505135bb08a35f346;hb=e65845045588806fa5c8df8a4f4253516515a5e3;hp=3215675ab128b35ce7c793cd234b62f5a8ac795a;hpb=1709775828de83b099554176b6d4971ebc772962;p=powerpc.git diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index 3215675ab1..5bd20b542c 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -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;