Merge tag 'mips_4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Aug 2018 02:24:32 +0000 (19:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Aug 2018 02:24:32 +0000 (19:24 -0700)
Pull MIPS updates from Paul Burton:
 "Here are the main MIPS changes for 4.19.

  An overview of the general architecture changes:

   - Massive DMA ops refactoring from Christoph Hellwig (huzzah for
     deleting crufty code!).

   - We introduce NT_MIPS_DSP & NT_MIPS_FP_MODE ELF notes &
     corresponding regsets to expose DSP ASE & floating point mode state
     respectively, both for live debugging & core dumps.

   - We better optimize our code by hard-coding cpu_has_* macros at
     compile time where their values are known due to the ISA revision
     that the kernel build is targeting.

   - The EJTAG exception handler now better handles SMP systems, where
     it was previously possible for CPUs to clobber a register value
     saved by another CPU.

   - Our implementation of memset() gained a couple of fixes for MIPSr6
     systems to return correct values in some cases where stores fault.

   - We now implement ioremap_wc() using the uncached-accelerated cache
     coherency attribute where supported, which is detected during boot,
     and fall back to plain uncached access where necessary. The
     MIPS-specific (and unused in tree) ioremap_uncached_accelerated() &
     ioremap_cacheable_cow() are removed.

   - The prctl(PR_SET_FP_MODE, ...) syscall is better supported for SMP
     systems by reworking the way we ensure remote CPUs that may be
     running threads within the affected process switch mode.

   - Systems using the MIPS Coherence Manager will now set the
     MIPS_IC_SNOOPS_REMOTE flag to avoid some unnecessary cache
     maintenance overhead when flushing the icache.

   - A few fixes were made for building with clang/LLVM, which now
     sucessfully builds kernels for many of our platforms.

   - Miscellaneous cleanups all over.

  And some platform-specific changes:

   - ar7 gained stubs for a few clock API functions to fix build
     failures for some drivers.

   - ath79 gained support for a few new SoCs, a few fixes & better
     gpio-keys support.

   - Ci20 now exposes its SPI bus using the spi-gpio driver.

   - The generic platform can now auto-detect a suitable value for
     PHYS_OFFSET based upon the memory map described by the device tree,
     allowing us to avoid wasting memory on page book-keeping for
     systems where RAM starts at a non-zero physical address.

   - Ingenic systems using the jz4740 platform code now link their
     vmlinuz higher to allow for kernels of a realistic size.

   - Loongson32 now builds the kernel targeting MIPSr1 rather than
     MIPSr2 to avoid CPU errata.

   - Loongson64 gains a couple of fixes, a workaround for a write
     buffering issue & support for the Loongson 3A R3.1 CPU.

   - Malta now uses the piix4-poweroff driver to handle powering down.

   - Microsemi Ocelot gained support for its SPI bus & NOR flash, its
     second MDIO bus and can now be supported by a FIT/.itb image.

   - Octeon saw a bunch of header cleanups which remove a lot of
     duplicate or unused code"

* tag 'mips_4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux: (123 commits)
  MIPS: Remove remnants of UASM_ISA
  MIPS: netlogic: xlr: Remove erroneous check in nlm_fmn_send()
  MIPS: VDSO: Force link endianness
  MIPS: Always specify -EB or -EL when using clang
  MIPS: Use dins to simplify __write_64bit_c0_split()
  MIPS: Use read-write output operand in __write_64bit_c0_split()
  MIPS: Avoid using array as parameter to write_c0_kpgd()
  MIPS: vdso: Allow clang's --target flag in VDSO cflags
  MIPS: genvdso: Remove GOT checks
  MIPS: Remove obsolete MIPS checks for DST node "chosen@0"
  MIPS: generic: Remove input symbols from defconfig
  MIPS: Delete unused code in linux32.c
  MIPS: Remove unused sys_32_mmap2
  MIPS: Remove nabi_no_regargs
  mips: dts: mscc: enable spi and NOR flash support on ocelot PCB123
  mips: dts: mscc: Add spi on Ocelot
  MIPS: Loongson: Merge load addresses
  MIPS: Loongson: Set Loongson32 to MIPS32R1
  MIPS: mscc: ocelot: add interrupt controller properties to GPIO controller
  MIPS: generic: Select MIPS_AUTO_PFN_OFFSET
  ...

1  2 
arch/mips/ath79/common.c
arch/mips/include/asm/atomic.h
arch/mips/include/asm/mipsregs.h
arch/mips/kernel/process.c
arch/mips/kernel/signal.c
arch/mips/kernel/traps.c
fs/binfmt_elf.c

diff --combined arch/mips/ath79/common.c
@@@ -58,7 -58,7 +58,7 @@@ EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init)
  
  void ath79_ddr_wb_flush(u32 reg)
  {
 -      void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg;
 +      void __iomem *flush_reg = ath79_ddr_wb_flush_base + (reg * 4);
  
        /* Flush the DDR write buffer. */
        __raw_writel(0x1, flush_reg);
@@@ -103,8 -103,12 +103,12 @@@ void ath79_device_reset_set(u32 mask
                reg = AR933X_RESET_REG_RESET_MODULE;
        else if (soc_is_ar934x())
                reg = AR934X_RESET_REG_RESET_MODULE;
+       else if (soc_is_qca953x())
+               reg = QCA953X_RESET_REG_RESET_MODULE;
        else if (soc_is_qca955x())
                reg = QCA955X_RESET_REG_RESET_MODULE;
+       else if (soc_is_qca956x() || soc_is_tp9343())
+               reg = QCA956X_RESET_REG_RESET_MODULE;
        else
                BUG();
  
@@@ -131,8 -135,12 +135,12 @@@ void ath79_device_reset_clear(u32 mask
                reg = AR933X_RESET_REG_RESET_MODULE;
        else if (soc_is_ar934x())
                reg = AR934X_RESET_REG_RESET_MODULE;
+       else if (soc_is_qca953x())
+               reg = QCA953X_RESET_REG_RESET_MODULE;
        else if (soc_is_qca955x())
                reg = QCA955X_RESET_REG_RESET_MODULE;
+       else if (soc_is_qca956x() || soc_is_tp9343())
+               reg = QCA956X_RESET_REG_RESET_MODULE;
        else
                BUG();
  
  #include <asm/cmpxchg.h>
  #include <asm/war.h>
  
+ /*
+  * Using a branch-likely instruction to check the result of an sc instruction
+  * works around a bug present in R10000 CPUs prior to revision 3.0 that could
+  * cause ll-sc sequences to execute non-atomically.
+  */
+ #if R10000_LLSC_WAR
+ # define __scbeqz "beqzl"
+ #else
+ # define __scbeqz "beqz"
+ #endif
  #define ATOMIC_INIT(i)          { (i) }
  
  /*
  #define ATOMIC_OP(op, c_op, asm_op)                                         \
  static __inline__ void atomic_##op(int i, atomic_t * v)                             \
  {                                                                           \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                int temp;                                                     \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     ll      %0, %1          # atomic_" #op "        \n"   \
                "       " #asm_op " %0, %2                              \n"   \
                "       sc      %0, %1                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)          \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               int temp;                                                     \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       ll      %0, %1          # atomic_" #op "\n"   \
-                       "       " #asm_op " %0, %2                      \n"   \
-                       "       sc      %0, %1                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)  \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!temp));                                    \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@@ -83,36 -81,20 +81,20 @@@ static __inline__ int atomic_##op##_ret
  {                                                                           \
        int result;                                                           \
                                                                              \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                int temp;                                                     \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     ll      %1, %2          # atomic_" #op "_return \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       sc      %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               int temp;                                                     \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       ll      %1, %2  # atomic_" #op "_return \n"   \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       sc      %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "+" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp; result c_op i;                                 \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@@ -131,36 -113,20 +113,20 @@@ static __inline__ int atomic_fetch_##op
  {                                                                           \
        int result;                                                           \
                                                                              \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                int temp;                                                     \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     ll      %1, %2          # atomic_fetch_" #op "  \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       sc      %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       move    %0, %1                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               int temp;                                                     \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       ll      %1, %2  # atomic_fetch_" #op "  \n"   \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       sc      %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "+" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp;                                                \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@@ -218,38 -184,17 +184,17 @@@ static __inline__ int atomic_sub_if_pos
  
        smp_mb__before_llsc();
  
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               int temp;
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     ll      %1, %2          # atomic_sub_if_positive\n"
-               "       subu    %0, %1, %3                              \n"
-               "       bltz    %0, 1f                                  \n"
-               "       sc      %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqzl   %0, 1b                                  \n"
-               "        subu   %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
-               "1:                                                     \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp),
-                 "+" GCC_OFF_SMALL_ASM() (v->counter)
-               : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)
-               : "memory");
-       } else if (kernel_uses_llsc) {
+       if (kernel_uses_llsc) {
                int temp;
  
                __asm__ __volatile__(
                "       .set    "MIPS_ISA_LEVEL"                        \n"
                "1:     ll      %1, %2          # atomic_sub_if_positive\n"
                "       subu    %0, %1, %3                              \n"
+               "       move    %1, %0                                  \n"
                "       bltz    %0, 1f                                  \n"
-               "       sc      %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqz    %0, 1b                                  \n"
-               "        subu   %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
+               "       sc      %1, %2                                  \n"
+               "\t" __scbeqz " %1, 1b                                  \n"
                "1:                                                     \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp),
  #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
  #define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
  
 -/**
 - * __atomic_add_unless - add unless the number is a given value
 - * @v: pointer of type atomic_t
 - * @a: the amount to add to v...
 - * @u: ...unless v is equal to u.
 - *
 - * Atomically adds @a to @v, so long as it was not @u.
 - * Returns the old value of @v.
 - */
 -static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 -{
 -      int c, old;
 -      c = atomic_read(v);
 -      for (;;) {
 -              if (unlikely(c == (u)))
 -                      break;
 -              old = atomic_cmpxchg((v), c, c + (a));
 -              if (likely(old == c))
 -                      break;
 -              c = old;
 -      }
 -      return c;
 -}
 -
 -#define atomic_dec_return(v) atomic_sub_return(1, (v))
 -#define atomic_inc_return(v) atomic_add_return(1, (v))
 -
 -/*
 - * atomic_sub_and_test - subtract value from variable and test result
 - * @i: integer value to subtract
 - * @v: pointer of type atomic_t
 - *
 - * Atomically subtracts @i from @v and returns
 - * true if the result is zero, or false for all
 - * other cases.
 - */
 -#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
 -
 -/*
 - * atomic_inc_and_test - increment and test
 - * @v: pointer of type atomic_t
 - *
 - * Atomically increments @v by 1
 - * and returns true if the result is zero, or false for all
 - * other cases.
 - */
 -#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
 -
 -/*
 - * atomic_dec_and_test - decrement by 1 and test
 - * @v: pointer of type atomic_t
 - *
 - * Atomically decrements @v by 1 and
 - * returns true if the result is 0, or false for all other
 - * cases.
 - */
 -#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
 -
  /*
   * atomic_dec_if_positive - decrement by 1 if old value positive
   * @v: pointer of type atomic_t
   */
  #define atomic_dec_if_positive(v)     atomic_sub_if_positive(1, v)
  
 -/*
 - * atomic_inc - increment atomic variable
 - * @v: pointer of type atomic_t
 - *
 - * Atomically increments @v by 1.
 - */
 -#define atomic_inc(v) atomic_add(1, (v))
 -
 -/*
 - * atomic_dec - decrement and test
 - * @v: pointer of type atomic_t
 - *
 - * Atomically decrements @v by 1.
 - */
 -#define atomic_dec(v) atomic_sub(1, (v))
 -
 -/*
 - * atomic_add_negative - add and test if negative
 - * @v: pointer of type atomic_t
 - * @i: integer value to add
 - *
 - * Atomically adds @i to @v and returns true
 - * if the result is negative, or false when
 - * result is greater than or equal to zero.
 - */
 -#define atomic_add_negative(i, v) (atomic_add_return(i, (v)) < 0)
 -
  #ifdef CONFIG_64BIT
  
  #define ATOMIC64_INIT(i)    { (i) }
  #define ATOMIC64_OP(op, c_op, asm_op)                                       \
  static __inline__ void atomic64_##op(long i, atomic64_t * v)                \
  {                                                                           \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                long temp;                                                    \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     lld     %0, %1          # atomic64_" #op "      \n"   \
                "       " #asm_op " %0, %2                              \n"   \
                "       scd     %0, %1                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)          \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               long temp;                                                    \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       lld     %0, %1          # atomic64_" #op "\n" \
-                       "       " #asm_op " %0, %2                      \n"   \
-                       "       scd     %0, %1                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)      \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!temp));                                    \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@@ -340,37 -357,20 +272,20 @@@ static __inline__ long atomic64_##op##_
  {                                                                           \
        long result;                                                          \
                                                                              \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                long temp;                                                    \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     lld     %1, %2          # atomic64_" #op "_return\n"  \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       scd     %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               long temp;                                                    \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       lld     %1, %2  # atomic64_" #op "_return\n"  \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       scd     %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "=" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)          \
-                       : "memory");                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp; result c_op i;                                 \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@@ -393,33 -393,16 +308,16 @@@ static __inline__ long atomic64_fetch_#
                long temp;                                                    \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     lld     %1, %2          # atomic64_fetch_" #op "\n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       scd     %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       move    %0, %1                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               long temp;                                                    \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       lld     %1, %2  # atomic64_fetch_" #op "\n"   \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       scd     %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "=" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)          \
-                       : "memory");                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp;                                                \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@@ -478,38 -461,17 +376,17 @@@ static __inline__ long atomic64_sub_if_
  
        smp_mb__before_llsc();
  
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               long temp;
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     lld     %1, %2          # atomic64_sub_if_positive\n"
-               "       dsubu   %0, %1, %3                              \n"
-               "       bltz    %0, 1f                                  \n"
-               "       scd     %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqzl   %0, 1b                                  \n"
-               "        dsubu  %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
-               "1:                                                     \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp),
-                 "=" GCC_OFF_SMALL_ASM() (v->counter)
-               : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)
-               : "memory");
-       } else if (kernel_uses_llsc) {
+       if (kernel_uses_llsc) {
                long temp;
  
                __asm__ __volatile__(
                "       .set    "MIPS_ISA_LEVEL"                        \n"
                "1:     lld     %1, %2          # atomic64_sub_if_positive\n"
                "       dsubu   %0, %1, %3                              \n"
+               "       move    %1, %0                                  \n"
                "       bltz    %0, 1f                                  \n"
-               "       scd     %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqz    %0, 1b                                  \n"
-               "        dsubu  %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
+               "       scd     %1, %2                                  \n"
+               "\t" __scbeqz " %1, 1b                                  \n"
                "1:                                                     \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp),
        ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
  #define atomic64_xchg(v, new) (xchg(&((v)->counter), (new)))
  
 -/**
 - * atomic64_add_unless - add unless the number is a given value
 - * @v: pointer of type atomic64_t
 - * @a: the amount to add to v...
 - * @u: ...unless v is equal to u.
 - *
 - * Atomically adds @a to @v, so long as it was not @u.
 - * Returns true iff @v was not @u.
 - */
 -static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 -{
 -      long c, old;
 -      c = atomic64_read(v);
 -      for (;;) {
 -              if (unlikely(c == (u)))
 -                      break;
 -              old = atomic64_cmpxchg((v), c, c + (a));
 -              if (likely(old == c))
 -                      break;
 -              c = old;
 -      }
 -      return c != (u);
 -}
 -
 -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 -
 -#define atomic64_dec_return(v) atomic64_sub_return(1, (v))
 -#define atomic64_inc_return(v) atomic64_add_return(1, (v))
 -
 -/*
 - * atomic64_sub_and_test - subtract value from variable and test result
 - * @i: integer value to subtract
 - * @v: pointer of type atomic64_t
 - *
 - * Atomically subtracts @i from @v and returns
 - * true if the result is zero, or false for all
 - * other cases.
 - */
 -#define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0)
 -
 -/*
 - * atomic64_inc_and_test - increment and test
 - * @v: pointer of type atomic64_t
 - *
 - * Atomically increments @v by 1
 - * and returns true if the result is zero, or false for all
 - * other cases.
 - */
 -#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
 -
 -/*
 - * atomic64_dec_and_test - decrement by 1 and test
 - * @v: pointer of type atomic64_t
 - *
 - * Atomically decrements @v by 1 and
 - * returns true if the result is 0, or false for all other
 - * cases.
 - */
 -#define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
 -
  /*
   * atomic64_dec_if_positive - decrement by 1 if old value positive
   * @v: pointer of type atomic64_t
   */
  #define atomic64_dec_if_positive(v)   atomic64_sub_if_positive(1, v)
  
 -/*
 - * atomic64_inc - increment atomic variable
 - * @v: pointer of type atomic64_t
 - *
 - * Atomically increments @v by 1.
 - */
 -#define atomic64_inc(v) atomic64_add(1, (v))
 -
 -/*
 - * atomic64_dec - decrement and test
 - * @v: pointer of type atomic64_t
 - *
 - * Atomically decrements @v by 1.
 - */
 -#define atomic64_dec(v) atomic64_sub(1, (v))
 -
 -/*
 - * atomic64_add_negative - add and test if negative
 - * @v: pointer of type atomic64_t
 - * @i: integer value to add
 - *
 - * Atomically adds @i to @v and returns true
 - * if the result is negative, or false when
 - * result is greater than or equal to zero.
 - */
 -#define atomic64_add_negative(i, v) (atomic64_add_return(i, (v)) < 0)
 -
  #endif /* CONFIG_64BIT */
  
  #endif /* _ASM_ATOMIC_H */
@@@ -16,6 -16,7 +16,7 @@@
  #include <linux/linkage.h>
  #include <linux/types.h>
  #include <asm/hazards.h>
+ #include <asm/isa-rev.h>
  #include <asm/war.h>
  
  /*
@@@ -51,6 -52,7 +52,7 @@@
  #define CP0_GLOBALNUMBER $3, 1
  #define CP0_CONTEXT $4
  #define CP0_PAGEMASK $5
+ #define CP0_PAGEGRAIN $5, 1
  #define CP0_SEGCTL0 $5, 2
  #define CP0_SEGCTL1 $5, 3
  #define CP0_SEGCTL2 $5, 4
@@@ -77,6 -79,7 +79,7 @@@
  #define CP0_CONFIG $16
  #define CP0_CONFIG3 $16, 3
  #define CP0_CONFIG5 $16, 5
+ #define CP0_CONFIG6 $16, 6
  #define CP0_LLADDR $17
  #define CP0_WATCHLO $18
  #define CP0_WATCHHI $19
  #define MIPS_CONF7_WII                (_ULCAST_(1) << 31)
  
  #define MIPS_CONF7_RPS                (_ULCAST_(1) << 2)
 -/* ExternalSync */
 -#define MIPS_CONF7_ES         (_ULCAST_(1) << 8)
  
  #define MIPS_CONF7_IAR                (_ULCAST_(1) << 10)
  #define MIPS_CONF7_AR         (_ULCAST_(1) << 16)
@@@ -1481,32 -1486,38 +1484,38 @@@ do {                                                                 
  
  #define __write_64bit_c0_split(source, sel, val)                      \
  do {                                                                  \
-       unsigned long long __tmp;                                       \
+       unsigned long long __tmp = (val);                               \
        unsigned long __flags;                                          \
                                                                        \
        local_irq_save(__flags);                                        \
-       if (sel == 0)                                                   \
+       if (MIPS_ISA_REV >= 2)                                          \
+               __asm__ __volatile__(                                   \
+                       ".set\tpush\n\t"                                \
+                       ".set\t" MIPS_ISA_LEVEL "\n\t"                  \
+                       "dins\t%L0, %M0, 32, 32\n\t"                    \
+                       "dmtc0\t%L0, " #source ", " #sel "\n\t"         \
+                       ".set\tpop"                                     \
+                       : "+r" (__tmp));                                \
+       else if (sel == 0)                                              \
                __asm__ __volatile__(                                   \
                        ".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"                        \
-                       "dsll\t%M0, %M1, 32\n\t"                        \
+                       "dsll\t%M0, %M0, 32\n\t"                        \
                        "or\t%L0, %L0, %M0\n\t"                         \
                        "dmtc0\t%L0, " #source "\n\t"                   \
                        ".set\tmips0"                                   \
-                       : "=&r,r" (__tmp)                               \
-                       : "r,0" (val));                                 \
+                       : "+r" (__tmp));                                \
        else                                                            \
                __asm__ __volatile__(                                   \
                        ".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"                        \
-                       "dsll\t%M0, %M1, 32\n\t"                        \
+                       "dsll\t%M0, %M0, 32\n\t"                        \
                        "or\t%L0, %L0, %M0\n\t"                         \
                        "dmtc0\t%L0, " #source ", " #sel "\n\t"         \
                        ".set\tmips0"                                   \
-                       : "=&r,r" (__tmp)                               \
-                       : "r,0" (val));                                 \
+                       : "+r" (__tmp));                                \
        local_irq_restore(__flags);                                     \
  } while (0)
  
@@@ -2765,6 -2776,7 +2774,6 @@@ __BUILD_SET_C0(status
  __BUILD_SET_C0(cause)
  __BUILD_SET_C0(config)
  __BUILD_SET_C0(config5)
 -__BUILD_SET_C0(config7)
  __BUILD_SET_C0(intcontrol)
  __BUILD_SET_C0(intctl)
  __BUILD_SET_C0(srsmap)
@@@ -29,7 -29,7 +29,8 @@@
  #include <linux/kallsyms.h>
  #include <linux/random.h>
  #include <linux/prctl.h>
 +#include <linux/nmi.h>
+ #include <linux/cpu.h>
  
  #include <asm/asm.h>
  #include <asm/bootinfo.h>
@@@ -656,42 -656,28 +657,42 @@@ unsigned long arch_align_stack(unsigne
        return sp & ALMASK;
  }
  
 -static void arch_dump_stack(void *info)
 +static DEFINE_PER_CPU(call_single_data_t, backtrace_csd);
 +static struct cpumask backtrace_csd_busy;
 +
 +static void handle_backtrace(void *info)
  {
 -      struct pt_regs *regs;
 +      nmi_cpu_backtrace(get_irq_regs());
 +      cpumask_clear_cpu(smp_processor_id(), &backtrace_csd_busy);
 +}
  
 -      regs = get_irq_regs();
 +static void raise_backtrace(cpumask_t *mask)
 +{
 +      call_single_data_t *csd;
 +      int cpu;
  
 -      if (regs)
 -              show_regs(regs);
 +      for_each_cpu(cpu, mask) {
 +              /*
 +               * If we previously sent an IPI to the target CPU & it hasn't
 +               * cleared its bit in the busy cpumask then it didn't handle
 +               * our previous IPI & it's not safe for us to reuse the
 +               * call_single_data_t.
 +               */
 +              if (cpumask_test_and_set_cpu(cpu, &backtrace_csd_busy)) {
 +                      pr_warn("Unable to send backtrace IPI to CPU%u - perhaps it hung?\n",
 +                              cpu);
 +                      continue;
 +              }
  
 -      dump_stack();
 +              csd = &per_cpu(backtrace_csd, cpu);
 +              csd->func = handle_backtrace;
 +              smp_call_function_single_async(cpu, csd);
 +      }
  }
  
  void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
  {
 -      long this_cpu = get_cpu();
 -
 -      if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
 -              dump_stack();
 -
 -      smp_call_function_many(mask, arch_dump_stack, NULL, 1);
 -
 -      put_cpu();
 +      nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace);
  }
  
  int mips_get_process_fp_mode(struct task_struct *task)
        return value;
  }
  
- static void prepare_for_fp_mode_switch(void *info)
+ static long prepare_for_fp_mode_switch(void *unused)
  {
-       struct mm_struct *mm = info;
-       if (current->mm == mm)
-               lose_fpu(1);
+       /*
+        * This is icky, but we use this to simply ensure that all CPUs have
+        * context switched, regardless of whether they were previously running
+        * kernel or user code. This ensures that no CPU currently has its FPU
+        * enabled, or is about to attempt to enable it through any path other
+        * than enable_restore_fp_context() which will wait appropriately for
+        * fp_mode_switching to be zero.
+        */
+       return 0;
  }
  
  int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
  {
        const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
        struct task_struct *t;
-       int max_users;
+       struct cpumask process_cpus;
+       int cpu;
  
        /* If nothing to change, return right away, successfully.  */
        if (value == mips_get_process_fp_mode(task))
        if (!(value & PR_FP_MODE_FR) && raw_cpu_has_fpu && cpu_has_mips_r6)
                return -EOPNOTSUPP;
  
-       /* Proceed with the mode switch */
-       preempt_disable();
-       /* Save FP & vector context, then disable FPU & MSA */
-       if (task->signal == current->signal)
-               lose_fpu(1);
-       /* Prevent any threads from obtaining live FP context */
-       atomic_set(&task->mm->context.fp_mode_switching, 1);
-       smp_mb__after_atomic();
-       /*
-        * If there are multiple online CPUs then force any which are running
-        * threads in this process to lose their FPU context, which they can't
-        * regain until fp_mode_switching is cleared later.
-        */
-       if (num_online_cpus() > 1) {
-               /* No need to send an IPI for the local CPU */
-               max_users = (task->mm == current->mm) ? 1 : 0;
-               if (atomic_read(&current->mm->mm_users) > max_users)
-                       smp_call_function(prepare_for_fp_mode_switch,
-                                         (void *)current->mm, 1);
-       }
-       /*
-        * There are now no threads of the process with live FP context, so it
-        * is safe to proceed with the FP mode switch.
-        */
+       /* Indicate the new FP mode in each thread */
        for_each_thread(task, t) {
                /* Update desired FP register width */
                if (value & PR_FP_MODE_FR) {
                        clear_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
        }
  
-       /* Allow threads to use FP again */
-       atomic_set(&task->mm->context.fp_mode_switching, 0);
-       preempt_enable();
+       /*
+        * We need to ensure that all threads in the process have switched mode
+        * before returning, in order to allow userland to not worry about
+        * races. We can do this by forcing all CPUs that any thread in the
+        * process may be running on to schedule something else - in this case
+        * prepare_for_fp_mode_switch().
+        *
+        * We begin by generating a mask of all CPUs that any thread in the
+        * process may be running on.
+        */
+       cpumask_clear(&process_cpus);
+       for_each_thread(task, t)
+               cpumask_set_cpu(task_cpu(t), &process_cpus);
+       /*
+        * Now we schedule prepare_for_fp_mode_switch() on each of those CPUs.
+        *
+        * The CPUs may have rescheduled already since we switched mode or
+        * generated the cpumask, but that doesn't matter. If the task in this
+        * process is scheduled out then our scheduling
+        * prepare_for_fp_mode_switch() will simply be redundant. If it's
+        * scheduled in then it will already have picked up the new FP mode
+        * whilst doing so.
+        */
+       get_online_cpus();
+       for_each_cpu_and(cpu, &process_cpus, cpu_online_mask)
+               work_on_cpu(cpu, prepare_for_fp_mode_switch, NULL);
+       put_online_cpus();
  
        wake_up_var(&task->mm->context.fp_mode_switching);
  
@@@ -592,13 -592,15 +592,15 @@@ SYSCALL_DEFINE3(sigaction, int, sig, co
  #endif
  
  #ifdef CONFIG_TRAD_SIGNALS
- asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
+ asmlinkage void sys_sigreturn(void)
  {
        struct sigframe __user *frame;
+       struct pt_regs *regs;
        sigset_t blocked;
        int sig;
  
-       frame = (struct sigframe __user *) regs.regs[29];
+       regs = current_pt_regs();
+       frame = (struct sigframe __user *)regs->regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
        if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
  
        set_current_blocked(&blocked);
  
-       sig = restore_sigcontext(&regs, &frame->sf_sc);
+       sig = restore_sigcontext(regs, &frame->sf_sc);
        if (sig < 0)
                goto badframe;
        else if (sig)
        __asm__ __volatile__(
                "move\t$29, %0\n\t"
                "j\tsyscall_exit"
-               :/* no outputs */
-               :"r" (&regs));
+               : /* no outputs */
+               : "r" (regs));
        /* Unreached */
  
  badframe:
  }
  #endif /* CONFIG_TRAD_SIGNALS */
  
- asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
+ asmlinkage void sys_rt_sigreturn(void)
  {
        struct rt_sigframe __user *frame;
+       struct pt_regs *regs;
        sigset_t set;
        int sig;
  
-       frame = (struct rt_sigframe __user *) regs.regs[29];
+       regs = current_pt_regs();
+       frame = (struct rt_sigframe __user *)regs->regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
        if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
  
        set_current_blocked(&set);
  
-       sig = restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext);
+       sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext);
        if (sig < 0)
                goto badframe;
        else if (sig)
        __asm__ __volatile__(
                "move\t$29, %0\n\t"
                "j\tsyscall_exit"
-               :/* no outputs */
-               :"r" (&regs));
+               : /* no outputs */
+               : "r" (regs));
        /* Unreached */
  
  badframe:
@@@ -801,7 -805,7 +805,7 @@@ static void handle_signal(struct ksigna
                regs->regs[0] = 0;              /* Don't deal with this again.  */
        }
  
 -      rseq_signal_deliver(regs);
 +      rseq_signal_deliver(ksig, regs);
  
        if (sig_uses_siginfo(&ksig->ka, abi))
                ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn,
@@@ -870,7 -874,7 +874,7 @@@ asmlinkage void do_notify_resume(struc
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
 -              rseq_handle_notify_resume(regs);
 +              rseq_handle_notify_resume(NULL, regs);
        }
  
        user_enter();
diff --combined arch/mips/kernel/traps.c
@@@ -351,7 -351,6 +351,7 @@@ static void __show_regs(const struct pt
  void show_regs(struct pt_regs *regs)
  {
        __show_regs((struct pt_regs *)regs);
 +      dump_stack();
  }
  
  void show_registers(struct pt_regs *regs)
@@@ -1221,13 -1220,6 +1221,6 @@@ static int enable_restore_fp_context(in
  {
        int err, was_fpu_owner, prior_msa;
  
-       /*
-        * If an FP mode switch is currently underway, wait for it to
-        * complete before proceeding.
-        */
-       wait_var_event(&current->mm->context.fp_mode_switching,
-                      !atomic_read(&current->mm->context.fp_mode_switching));
        if (!used_math()) {
                /* First time FP context user. */
                preempt_disable();
diff --combined fs/binfmt_elf.c
@@@ -1259,8 -1259,9 +1259,8 @@@ static int load_elf_library(struct fil
                goto out_free_ph;
        }
  
 -      len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr +
 -                          ELF_MIN_ALIGN - 1);
 -      bss = eppnt->p_memsz + eppnt->p_vaddr;
 +      len = ELF_PAGEALIGN(eppnt->p_filesz + eppnt->p_vaddr);
 +      bss = ELF_PAGEALIGN(eppnt->p_memsz + eppnt->p_vaddr);
        if (bss > len) {
                error = vm_brk(len, bss - len);
                if (error)
@@@ -1751,7 -1752,7 +1751,7 @@@ static int fill_thread_core_info(struc
                const struct user_regset *regset = &view->regsets[i];
                do_thread_regset_writeback(t->task, regset);
                if (regset->core_note_type && regset->get &&
-                   (!regset->active || regset->active(t->task, regset))) {
+                   (!regset->active || regset->active(t->task, regset) > 0)) {
                        int ret;
                        size_t size = regset_size(t->task, regset);
                        void *data = kmalloc(size, GFP_KERNEL);