| From a0fc1436f1f4f84e93144480bf30e0c958d135b6 Mon Sep 17 00:00:00 2001 |
| From: Max Filippov <jcmvbkbc@gmail.com> |
| Date: Fri, 31 Jul 2020 12:38:05 -0700 |
| Subject: [PATCH] xtensa: add missing exclusive access state management |
| |
| commit a0fc1436f1f4f84e93144480bf30e0c958d135b6 upstream. |
| |
| The result of the s32ex opcode is recorded in the ATOMCTL special |
| register and must be retrieved with the getex opcode. Context switch |
| between s32ex and getex may trash the ATOMCTL register and result in |
| duplicate update or missing update of the atomic variable. |
| Add atomctl8 field to the struct thread_info and use getex to swap |
| ATOMCTL bit 8 as a part of context switch. |
| Clear exclusive access monitor on kernel entry. |
| |
| Cc: stable@vger.kernel.org |
| Fixes: f7c34874f04a ("xtensa: add exclusive atomics support") |
| Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> |
| |
| diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h |
| index 8918f0f20c53..6acbbe0d87d3 100644 |
| --- a/arch/xtensa/include/asm/thread_info.h |
| +++ b/arch/xtensa/include/asm/thread_info.h |
| @@ -55,6 +55,10 @@ struct thread_info { |
| mm_segment_t addr_limit; /* thread address space */ |
| |
| unsigned long cpenable; |
| +#if XCHAL_HAVE_EXCLUSIVE |
| + /* result of the most recent exclusive store */ |
| + unsigned long atomctl8; |
| +#endif |
| |
| /* Allocate storage for extra user states and coprocessor states. */ |
| #if XTENSA_HAVE_COPROCESSORS |
| diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c |
| index 33a257b33723..dc5c83cad9be 100644 |
| --- a/arch/xtensa/kernel/asm-offsets.c |
| +++ b/arch/xtensa/kernel/asm-offsets.c |
| @@ -93,6 +93,9 @@ int main(void) |
| DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra)); |
| DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp)); |
| DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable)); |
| +#if XCHAL_HAVE_EXCLUSIVE |
| + DEFINE(THREAD_ATOMCTL8, offsetof (struct thread_info, atomctl8)); |
| +#endif |
| #if XTENSA_HAVE_COPROCESSORS |
| DEFINE(THREAD_XTREGS_CP0, offsetof(struct thread_info, xtregs_cp.cp0)); |
| DEFINE(THREAD_XTREGS_CP1, offsetof(struct thread_info, xtregs_cp.cp1)); |
| diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S |
| index 98515c24d9b2..703cf6205efe 100644 |
| --- a/arch/xtensa/kernel/entry.S |
| +++ b/arch/xtensa/kernel/entry.S |
| @@ -374,6 +374,11 @@ common_exception: |
| s32i a2, a1, PT_LCOUNT |
| #endif |
| |
| +#if XCHAL_HAVE_EXCLUSIVE |
| + /* Clear exclusive access monitor set by interrupted code */ |
| + clrex |
| +#endif |
| + |
| /* It is now save to restore the EXC_TABLE_FIXUP variable. */ |
| |
| rsr a2, exccause |
| @@ -2020,6 +2025,12 @@ ENTRY(_switch_to) |
| s32i a3, a4, THREAD_CPENABLE |
| #endif |
| |
| +#if XCHAL_HAVE_EXCLUSIVE |
| + l32i a3, a5, THREAD_ATOMCTL8 |
| + getex a3 |
| + s32i a3, a4, THREAD_ATOMCTL8 |
| +#endif |
| + |
| /* Flush register file. */ |
| |
| spill_registers_kernel |
| -- |
| 2.27.0 |
| |