Hi, Here is a patch to fix cache coherency when doing I/O on the O2. It simply adds writeback and invalidate when unmapping DMA memory. This fixes coherency when reading from a device. It also adds support for mapping/unmapping pages for both the IP27 and the O2. Vivien Chappelier.
diff -Naur linux/arch/mips64/sgi-ip27/ip27-pci-dma.c linux.patch/arch/mips64/sgi-ip27/ip27-pci-dma.c --- linux/arch/mips64/sgi-ip27/ip27-pci-dma.c Sun Dec 9 15:47:15 2001 +++ linux.patch/arch/mips64/sgi-ip27/ip27-pci-dma.c Fri Dec 21 11:08:22 2001 @@ -112,7 +112,11 @@ /* Make sure that gcc doesn't leave the empty loop body. */ for (i = 0; i < nents; i++, sg++) { - sg->address = (char *)(bus_to_baddr[hwdev->bus->number] | __pa(sg->address)); + if(sg->address) + address = sg->address; + else + address = page_address(sg->page) + sg->offset; + sg->dvma_address = (char *)(bus_to_baddr[hwdev->bus->number] | __pa(address)); } return nents; diff -Naur linux/arch/mips64/sgi-ip32/ip32-pci-dma.c linux.patch/arch/mips64/sgi-ip32/ip32-pci-dma.c --- linux/arch/mips64/sgi-ip32/ip32-pci-dma.c Sun Dec 9 15:47:15 2001 +++ linux.patch/arch/mips64/sgi-ip32/ip32-pci-dma.c Fri Dec 21 11:07:33 2001 @@ -99,7 +99,10 @@ if (direction == PCI_DMA_NONE) BUG(); DPRINTK("pci_unmap_single\n"); - /* Nothing to do */ + if (direction != PCI_DMA_TODEVICE) { + mips_wbflush(); + dma_cache_wback_inv((unsigned long)__va(dma_addr), size); + } } /* @@ -122,6 +125,7 @@ int nents, int direction) { int i; + unsigned long address; if (direction == PCI_DMA_NONE) BUG(); @@ -131,9 +135,13 @@ DPRINTK("pci_map_sg\n"); /* Make sure that gcc doesn't leave the empty loop body. */ for (i = 0; i < nents; i++, sg++) { + if(sg->address) + address = sg->address; + else + address = page_address(sg->page) + sg->offset; mips_wbflush(); - dma_cache_wback_inv((unsigned long)sg->address, sg->length); - sg->address = (char *)(__pa(sg->address)); + dma_cache_wback_inv(address, sg->length); + sg->dvma_address = __pa(address); } return nents; @@ -147,10 +155,22 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { + int i; + unsigned long address; + if (direction == PCI_DMA_NONE) BUG(); DPRINTK("pci_unmap_sg\n"); - /* Nothing to do */ + for (i = 0; i < nents; i++, sg++) { + if (direction != PCI_DMA_TODEVICE) { + if(sg->address) + address = sg->address; + else + address = page_address(sg->page) + sg->offset; + mips_wbflush(); + dma_cache_wback_inv(address, sg->length); + } + } } /* @@ -188,13 +208,19 @@ int nelems, int direction) { int i; + unsigned long address; + if (direction == PCI_DMA_NONE) BUG(); DPRINTK("pci_dma_sync_sg\n"); /* Make sure that gcc doesn't leave the empty loop body. */ for (i = 0; i < nelems; i++, sg++){ + if(sg->address) + address = sg->address; + else + address = page_address(sg->page) + sg->offset; mips_wbflush(); - dma_cache_wback_inv((unsigned long)__va(sg->address), sg->length); + dma_cache_wback_inv(address, sg->length); } /* if(direction==PCI_DMA_TODEVICE) mace_inv_read_buffers();*/ diff -Naur linux/include/asm-mips64/mipsregs.h linux.patch/include/asm-mips64/mipsregs.h --- linux/include/asm-mips64/mipsregs.h Sun Dec 9 15:52:27 2001 +++ linux.patch/include/asm-mips64/mipsregs.h Fri Dec 21 11:28:06 2001 @@ -367,6 +367,7 @@ #define CONF_CM_CMASK 7 #define CONF_DB (1 << 4) #define CONF_IB (1 << 5) +#define CONF_SE (1 << 12) #define CONF_SC (1 << 17) #define CONF_AC (1 << 23) #define CONF_HALT (1 << 25) diff -Naur linux/include/asm-mips64/pci.h linux.patch/include/asm-mips64/pci.h --- linux/include/asm-mips64/pci.h Thu Dec 20 18:32:18 2001 +++ linux.patch/include/asm-mips64/pci.h Fri Dec 21 11:10:08 2001 @@ -319,7 +319,7 @@ * returns, or alternatively stop on the first sg_dma_len(sg) which * is 0. */ -#define sg_dma_address(sg) ((unsigned long)((sg)->address)) +#define sg_dma_address(sg) ((sg)->dvma_address) #define sg_dma_len(sg) ((sg)->length) #endif /* __KERNEL__ */ diff -Naur linux/include/asm-mips64/pgtable.h linux.patch/include/asm-mips64/pgtable.h --- linux/include/asm-mips64/pgtable.h Thu Dec 20 18:32:18 2001 +++ linux.patch/include/asm-mips64/pgtable.h Thu Dec 20 20:03:07 2001 @@ -180,11 +180,11 @@ #ifdef CONFIG_MIPS_UNCACHED #define PAGE_CACHABLE_DEFAULT _CACHE_UNCACHED #else /* ! UNCACHED */ -#ifdef CONFIG_SGI_IP22 +#if defined(CONFIG_SGI_IP22) || defined(CONFIG_SGI_IP32) #define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_NONCOHERENT -#else /* ! IP22 */ +#else /* ! (IP22 || IP32)*/ #define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_COW -#endif /* IP22 */ +#endif /* (IP22 || IP32) */ #endif /* UNCACHED */ #define PAGE_NONE __pgprot(_PAGE_PRESENT | PAGE_CACHABLE_DEFAULT) diff -Naur linux/include/asm-mips64/scatterlist.h linux.patch/include/asm-mips64/scatterlist.h --- linux/include/asm-mips64/scatterlist.h Thu Dec 20 18:32:18 2001 +++ linux.patch/include/asm-mips64/scatterlist.h Fri Dec 21 11:09:40 2001 @@ -7,7 +7,7 @@ unsigned int offset; unsigned int length; - __u32 dvma_address; + dma_addr_t dvma_address; }; struct mmu_sglist {