Commit 08eeb44b authored by Paul Burton's avatar Paul Burton

MIPS: Use read-write output operand in __write_64bit_c0_split()

Commit c22c8043 ("MIPS: Fix input modify in
__write_64bit_c0_split()") modified __write_64bit_c0_split() constraints
such that we have both an input & an output which we hope to assign to
the same registers, and modify the output rather than incorrectly
clobbering an input.

The way in which we use both an output & an input parameter with the
input constrained to share the output registers is a little convoluted &
also problematic for clang, which complains if the input & output values
have different widths. For example:

  In file included from kernel/fork.c:98:
  ./arch/mips/include/asm/mmu_context.h:149:19: error: unsupported
    inline asm: input with type 'unsigned long' matching output with
    type 'unsigned long long'
          write_c0_entryhi(cpu_asid(cpu, next));
          ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
  ./arch/mips/include/asm/mmu_context.h:93:2: note: expanded from macro
    'cpu_asid'
          (cpu_context((cpu), (mm)) & cpu_asid_mask(&cpu_data[cpu]))
          ^
  ./arch/mips/include/asm/mipsregs.h:1617:65: note: expanded from macro
    'write_c0_entryhi'
  #define write_c0_entryhi(val)   __write_ulong_c0_register($10, 0, val)
                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
  ./arch/mips/include/asm/mipsregs.h:1430:39: note: expanded from macro
    '__write_ulong_c0_register'
                  __write_64bit_c0_register(reg, sel, val);               \
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
  ./arch/mips/include/asm/mipsregs.h:1400:41: note: expanded from macro
    '__write_64bit_c0_register'
                  __write_64bit_c0_split(register, sel, value);           \
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
  ./arch/mips/include/asm/mipsregs.h:1498:13: note: expanded from macro
    '__write_64bit_c0_split'
                          : "r,0" (val));                                 \
                                   ^~~

We can both fix this build failure & simplify the code somewhat by
assigning the __tmp variable with the input value in C prior to our
inline assembly, and then using a single read-write output operand (ie.
a constraint beginning with +) to provide this value to our assembly.
Signed-off-by: default avatarPaul Burton <paul.burton@mips.com>
parent b023a939
...@@ -1485,32 +1485,30 @@ do { \ ...@@ -1485,32 +1485,30 @@ do { \
#define __write_64bit_c0_split(source, sel, val) \ #define __write_64bit_c0_split(source, sel, val) \
do { \ do { \
unsigned long long __tmp; \ unsigned long long __tmp = (val); \
unsigned long __flags; \ unsigned long __flags; \
\ \
local_irq_save(__flags); \ local_irq_save(__flags); \
if (sel == 0) \ if (sel == 0) \
__asm__ __volatile__( \ __asm__ __volatile__( \
".set\tmips64\n\t" \ ".set\tmips64\n\t" \
"dsll\t%L0, %L1, 32\n\t" \ "dsll\t%L0, %L0, 32\n\t" \
"dsrl\t%L0, %L0, 32\n\t" \ "dsrl\t%L0, %L0, 32\n\t" \
"dsll\t%M0, %M1, 32\n\t" \ "dsll\t%M0, %M0, 32\n\t" \
"or\t%L0, %L0, %M0\n\t" \ "or\t%L0, %L0, %M0\n\t" \
"dmtc0\t%L0, " #source "\n\t" \ "dmtc0\t%L0, " #source "\n\t" \
".set\tmips0" \ ".set\tmips0" \
: "=&r,r" (__tmp) \ : "+r" (__tmp)); \
: "r,0" (val)); \
else \ else \
__asm__ __volatile__( \ __asm__ __volatile__( \
".set\tmips64\n\t" \ ".set\tmips64\n\t" \
"dsll\t%L0, %L1, 32\n\t" \ "dsll\t%L0, %L0, 32\n\t" \
"dsrl\t%L0, %L0, 32\n\t" \ "dsrl\t%L0, %L0, 32\n\t" \
"dsll\t%M0, %M1, 32\n\t" \ "dsll\t%M0, %M0, 32\n\t" \
"or\t%L0, %L0, %M0\n\t" \ "or\t%L0, %L0, %M0\n\t" \
"dmtc0\t%L0, " #source ", " #sel "\n\t" \ "dmtc0\t%L0, " #source ", " #sel "\n\t" \
".set\tmips0" \ ".set\tmips0" \
: "=&r,r" (__tmp) \ : "+r" (__tmp)); \
: "r,0" (val)); \
local_irq_restore(__flags); \ local_irq_restore(__flags); \
} while (0) } while (0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment