ARM: 7882/1: mm: fix __phys_to_virt to work with 64 bit phys_addr_t in BE case
authorVictor Kamensky <victor.kamensky@linaro.org>
Thu, 7 Nov 2013 07:42:41 +0000 (08:42 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 14 Nov 2013 11:13:08 +0000 (11:13 +0000)
commit139cc2ba7400dab80228a2bfa683e2f49cf5d3ff
tree8bad5c8854e7283175e6b978cea6c3d33e542a99
parent10593b2e49327f7cd193fc2ba30fa3da322bda6a
ARM: 7882/1: mm: fix __phys_to_virt to work with 64 bit phys_addr_t in BE case

Make sure that inline assembler that expects 'r' operand
receives 32 bit value.

Before this fix in case of CONFIG_ARCH_PHYS_ADDR_T_64BIT and
CONFIG_ARM_PATCH_PHYS_VIRT __phys_to_virt function passed 64 bit
value to __pv_stub inline assembler where 'r' operand is
expected. Compiler behavior in such case is not well specified.
It worked in little endian case, but in big endian case
incorrect code was generated, where compiler confused which
part of 64 bit value it needed to modify. For example BE
snippet looked like this:

N:0x80904E08 : MOV      r2,#0
N:0x80904E0C : SUB      r2,r2,#0x81000000

when LE similar code looked like this

N:0x808FCE2C : MOV      r2,r0
N:0x808FCE30 : SUB      r2,r2,#0xc0, 8 ; #0xc0000000

Note 'r0' register is va that have to be translated into phys

To avoid this situation use explicit cast to 'unsigned long',
which explicitly discard upper part of phys address and convert
value to 32 bit. Also add comment so such cast will not be
removed in the future.

Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/include/asm/memory.h