X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=arch%2Fsparc%2Fmm%2Fiommu.c;h=489bf68d5f05d49786b4f52de6356a951c9be4ad;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=b661ca03ae814d85d98ba1ffea1ca4b46481f6db;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index b661ca03a..489bf68d5 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -71,14 +71,16 @@ iommu_init(int iommund, struct sbus_bus *sbus) prom_printf("Unable to allocate iommu structure\n"); prom_halt(); } - prom_getproperty(iommund, "reg", (void *) iommu_promregs, - sizeof(iommu_promregs)); - memset(&r, 0, sizeof(r)); - r.flags = iommu_promregs[0].which_io; - r.start = iommu_promregs[0].phys_addr; - iommu->regs = (struct iommu_regs *) - sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs"); - if(!iommu->regs) { + iommu->regs = NULL; + if (prom_getproperty(iommund, "reg", (void *) iommu_promregs, + sizeof(iommu_promregs)) != -1) { + memset(&r, 0, sizeof(r)); + r.flags = iommu_promregs[0].which_io; + r.start = iommu_promregs[0].phys_addr; + iommu->regs = (struct iommu_regs *) + sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs"); + } + if (!iommu->regs) { prom_printf("Cannot map IOMMU registers\n"); prom_halt(); } @@ -119,6 +121,13 @@ iommu_init(int iommund, struct sbus_bus *sbus) prom_halt(); } bit_map_init(&iommu->usemap, bitmap, IOMMU_NPTES); + /* To be coherent on HyperSparc, the page color of DVMA + * and physical addresses must match. + */ + if (srmmu_modtype == HyperSparc) + iommu->usemap.num_colors = vac_cache_size >> PAGE_SHIFT; + else + iommu->usemap.num_colors = 1; printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n", impl, vers, iommu->page_table, @@ -128,7 +137,9 @@ iommu_init(int iommund, struct sbus_bus *sbus) } /* This begs to be btfixup-ed by srmmu. */ -static void iommu_viking_flush_iotlb(iopte_t *iopte, unsigned int niopte) +/* Flush the iotlb entries to ram. */ +/* This could be better if we didn't have to flush whole pages. */ +static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) { unsigned long start; unsigned long end; @@ -145,6 +156,11 @@ static void iommu_viking_flush_iotlb(iopte_t *iopte, unsigned int niopte) viking_flush_page(start); start += PAGE_SIZE; } + } else { + while(start < end) { + __flush_page_to_ram(start); + start += PAGE_SIZE; + } } } @@ -156,7 +172,8 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) unsigned int busa, busa0; int i; - ioptex = bit_map_string_get(&iommu->usemap, npages, 1); + /* page color = pfn of page */ + ioptex = bit_map_string_get(&iommu->usemap, npages, page_to_pfn(page)); if (ioptex < 0) panic("iommu out"); busa0 = iommu->start + (ioptex << PAGE_SHIFT); @@ -172,7 +189,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) page++; } - iommu_viking_flush_iotlb(iopte0, npages); + iommu_flush_iotlb(iopte0, npages); return busa0; } @@ -327,7 +344,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va, if ((addr & ~PAGE_MASK) != 0) BUG(); if ((len & ~PAGE_MASK) != 0) BUG(); - ioptex = bit_map_string_get(&iommu->usemap, len >> PAGE_SHIFT, 1); + /* page color = physical address */ + ioptex = bit_map_string_get(&iommu->usemap, len >> PAGE_SHIFT, + addr >> PAGE_SHIFT); if (ioptex < 0) panic("iommu out"); @@ -371,7 +390,7 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va, * to handle the latter case as well. */ flush_cache_all(); - iommu_viking_flush_iotlb(first, len >> PAGE_SHIFT); + iommu_flush_iotlb(first, len >> PAGE_SHIFT); flush_tlb_all(); iommu_invalidate(iommu->regs);