Hi ! Watching the discussion about __pa(), CPHYSADDR and related stuff, with about a hundred e-mails last October, and rising again several times recently (see below), i wonder why we must cling so firmly to the "x - page_offset" algorithm, the least capable one. AFAIK this method is taken over unaltered from the i386 arch (yes, i know, the majority of archs did this), where we have a situation quite different from MIPS: A (preferably simple) mapping must be invented for kernel-memory with some, more or less deliberately chosen, "page-offset". There exist no addresses beside this mapping, no hardware "kernel-mappings" with (un)cached regions, cached-attributes, unmapped spaces, etc. and "x - page_offset" is necessary and sufficient to handle all addresses. On the MIPS-side there isn't really something like "the" page-offset, and the processor architecture already defines kernel spaces with respective address-syntax. In other words, the definitions in asm-mips/addrspace.h properly describe the virtual/physical conversions and masking, not some subtracting, is the natural way to go. Since __pa() and virt_to_phys() are currently "under construction" anyway, i think it's time to submit robust versions (with kernel_physaddr() stolen from the IP30 patch) for both, that handle any pitfall in one place and may be used without pain throughout the kernel. I don't know, which one to prefer, 29 drivers are using __pa(), 60 are using virt_to_phys(), the uses in arch/mips files are about equal. Having a robust __pa()/virt_to_phys() avoids the need for local fixes, like in sgiwd93.c and sgiseeq.c, which have to cope with at least one uncached (usu. 0x9000...) address-type and at least one cached type (usu. 0xa800...) in xkphys, and where virt_to_phys() blew up nicely. In some situation there may be need to handle a ckseg0/1 address additionaly. On Thu, 1 Mar 2007, Franck Bui-Huu wrote: > Date: Thu, 1 Mar 2007 10:39:08 +0100 > From: Franck Bui-Huu <vagabon.xyz@xxxxxxxxx> > To: Kumba <kumba@xxxxxxxxxx> > Cc: Linux MIPS List <linux-mips@xxxxxxxxxxxxxx> > Subject: Re: IP32 prom crashes due to __pa() funkiness > > Hi, > > Kumba wrote: > > > > Initially, booting a straight git checkout on an IP32 will cause it to > > prom crash, usually somewhere in between init_bootmem() and > > init_bootmem_core(). I bisected git to trace this back to one of the > > inital __pa() introduction patches from commit d4df6d4 (get ride of > > CPHYSADDR()). It actually appears that the actual commit that broke > > things was 620a480 (Make __pa() aware of XKPHYS/CKSEG0 address mix for > > 64 bit kernels). > > > > The [short-term] fix highlighted by Ilya is to make __pa() > > unconditionally be defined to "((unsigned long)(x) < CKSEG0 ? > > PAGE_OFFSET : CKSEG0)"; Discovered by building IP32 with > > CONFIG_BUILD_ELF64=n. > > > > Well, it means that you previously used CONFIG_BUILD_ELF64=y (this > implied that PAGE_OFFSET is in XKPHYS) whereas your kernel has CKSEG > load address (symbols need PAGE_OFFSET in CKSEG for address > translation). > > ... Signed-off-by: peter fuerst <post@xxxxxxxx> ======================================================================== --- c6275088cf65aaa1826e426e9e683b6c3e1f371c/include/asm-mips/addrspace.h Sat Mar 10 08:38:53 2007 +++ kernelphysaddr-version/include/asm-mips/addrspace.h Sat Mar 10 08:38:53 2007 @@ -54,6 +54,17 @@ #define XPHYSADDR(a) ((_ACAST64_(a)) & \ _CONST64_(0x000000ffffffffff)) +static inline unsigned long kernel_physaddr(unsigned long kva) +{ +#ifdef CONFIG_64BIT + if((kva & 0xffffffff80000000UL) == 0xffffffff80000000UL) + return CPHYSADDR(kva); + return XPHYSADDR(kva); +#else + return CPHYSADDR(kva); +#endif +} + #ifdef CONFIG_64BIT /* --- 92ec2618560c984355e653d33d5dc935e5e1488c/include/asm-mips/io.h Sat Mar 10 08:41:06 2007 +++ kernelphysaddr-version/include/asm-mips/io.h Sat Mar 10 08:41:06 2007 @@ -116,7 +116,7 @@ static inline void set_io_port_base(unsi */ static inline unsigned long virt_to_phys(volatile const void *address) { - return (unsigned long)address - PAGE_OFFSET + PHYS_OFFSET; + return kernel_physaddr((unsigned long)address); } /* --- d3fbd83ff545e49e2a0a5ca0f00dda4eedaf8be7/include/asm-mips/page.h Sat Mar 10 08:43:17 2007 +++ kernelphysaddr-version/include/asm-mips/page.h Sat Mar 10 08:43:17 2007 @@ -154,7 +154,7 @@ typedef struct { unsigned long pgprot; } #else #define __pa_page_offset(x) PAGE_OFFSET #endif -#define __pa(x) ((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET) +#define __pa(x) kernel_physaddr((unsigned long)(x)) #define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET)) #define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0)) ========================================================================