Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: Make (UN)CAC_ADDR() PHYS_OFFSET-agnostic

Converting an address between cached & uncached (typically addresses in
(c)kseg0 & (c)kseg1 or 2 xkphys regions) should not depend upon
PHYS_OFFSET in any way - we're converting from a virtual address in one
unmapped region to a virtual address in another unmapped region.

For some reason our CAC_ADDR() & UNCAC_ADDR() macros make use of
PAGE_OFFSET, which typically includes PHYS_OFFSET. This means that
platforms with a non-zero PHYS_OFFSET typically have to workaround
miscalculation by these 2 macros by also defining UNCAC_BASE to a value
that isn't really correct.

It appears that an attempt has previously been made to address this with
commit 3f4579252aa1 ("MIPS: make CAC_ADDR and UNCAC_ADDR account for
PHYS_OFFSET") which was later undone by commit ed3ce16c3d2b ("Revert
"MIPS: make CAC_ADDR and UNCAC_ADDR account for PHYS_OFFSET"") which
also introduced the ar7 workaround. That attempt at a fix was roughly
equivalent, but essentially caused the CAC_ADDR() & UNCAC_ADDR() macros
to cancel out PHYS_OFFSET by adding & then subtracting it again. In his
revert Leonid is correct that using PHYS_OFFSET makes no sense in the
context of these macros, but appears to have missed its inclusion via
PAGE_OFFSET which means PHYS_OFFSET actually had an effect after the
revert rather than before it.

Here we fix this by modifying CAC_ADDR() & UNCAC_ADDR() to stop using
PAGE_OFFSET (& thus PHYS_OFFSET), instead using __pa() & __va() along
with UNCAC_BASE.

For UNCAC_ADDR(), __pa() will convert a cached address to a physical
address which we can simply use as an offset from UNCAC_BASE to obtain
an address in the uncached region.

For CAC_ADDR() we can undo the effect of UNCAC_ADDR() by subtracting
UNCAC_BASE and using __va() on the result.

With this change made, remove definitions of UNCAC_BASE from the ar7 &
pic32 platforms which appear to have defined them only to workaround
this problem.

Signed-off-by: Paul Burton <paul.burton@mips.com>
References: 3f4579252aa1 ("MIPS: make CAC_ADDR and UNCAC_ADDR account for PHYS_OFFSET")
References: ed3ce16c3d2b ("Revert "MIPS: make CAC_ADDR and UNCAC_ADDR account for PHYS_OFFSET"")
Patchwork: https://patchwork.linux-mips.org/patch/20046/
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: James Hogan <jhogan@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: Vladimir Kondratiev <vladimir.kondratiev@intel.com>

+4 -8
-3
arch/mips/include/asm/mach-ar7/spaces.h
··· 17 17 #define PAGE_OFFSET _AC(0x94000000, UL) 18 18 #define PHYS_OFFSET _AC(0x14000000, UL) 19 19 20 - #define UNCAC_BASE _AC(0xb4000000, UL) /* 0xa0000000 + PHYS_OFFSET */ 21 - #define IO_BASE UNCAC_BASE 22 - 23 20 #include <asm/mach-generic/spaces.h> 24 21 25 22 #endif /* __ASM_AR7_SPACES_H */
-1
arch/mips/include/asm/mach-pic32/spaces.h
··· 16 16 17 17 #ifdef CONFIG_PIC32MZDA 18 18 #define PHYS_OFFSET _AC(0x08000000, UL) 19 - #define UNCAC_BASE _AC(0xa8000000, UL) 20 19 #endif 21 20 22 21 #include <asm/mach-generic/spaces.h>
+2 -2
arch/mips/include/asm/page.h
··· 252 252 ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ 253 253 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) 254 254 255 - #define UNCAC_ADDR(addr) ((addr) - PAGE_OFFSET + UNCAC_BASE) 256 - #define CAC_ADDR(addr) ((addr) - UNCAC_BASE + PAGE_OFFSET) 255 + #define UNCAC_ADDR(addr) (UNCAC_BASE + __pa(addr)) 256 + #define CAC_ADDR(addr) ((unsigned long)__va((addr) - UNCAC_BASE)) 257 257 258 258 #include <asm-generic/memory_model.h> 259 259 #include <asm-generic/getorder.h>
+1 -1
arch/mips/jazz/jazzdma.c
··· 576 576 577 577 if (!(attrs & DMA_ATTR_NON_CONSISTENT)) { 578 578 dma_cache_wback_inv((unsigned long)ret, size); 579 - ret = UNCAC_ADDR(ret); 579 + ret = (void *)UNCAC_ADDR(ret); 580 580 } 581 581 return ret; 582 582 }
+1 -1
arch/mips/mm/dma-noncoherent.c
··· 78 78 79 79 if (!dev_is_coherent(dev) && !(attrs & DMA_ATTR_NON_CONSISTENT)) { 80 80 dma_cache_wback_inv((unsigned long) ret, size); 81 - ret = UNCAC_ADDR(ret); 81 + ret = (void *)UNCAC_ADDR(ret); 82 82 } 83 83 84 84 return ret;