Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1e2ec2e authored by Max Filippov's avatar Max Filippov Committed by Greg Kroah-Hartman
Browse files

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: f7c34874 ("xtensa: add exclusive atomics support")
Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5efb3f91
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -55,6 +55,10 @@ struct thread_info {
	mm_segment_t		addr_limit;	/* thread address space */
	mm_segment_t		addr_limit;	/* thread address space */


	unsigned long		cpenable;
	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. */
	/* Allocate storage for extra user states and coprocessor states. */
#if XTENSA_HAVE_COPROCESSORS
#if XTENSA_HAVE_COPROCESSORS
+3 −0
Original line number Original line Diff line number Diff line
@@ -93,6 +93,9 @@ int main(void)
	DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
	DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
	DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
	DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
	DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable));
	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
#if XTENSA_HAVE_COPROCESSORS
	DEFINE(THREAD_XTREGS_CP0, offsetof(struct thread_info, xtregs_cp.cp0));
	DEFINE(THREAD_XTREGS_CP0, offsetof(struct thread_info, xtregs_cp.cp0));
	DEFINE(THREAD_XTREGS_CP1, offsetof(struct thread_info, xtregs_cp.cp1));
	DEFINE(THREAD_XTREGS_CP1, offsetof(struct thread_info, xtregs_cp.cp1));
+11 −0
Original line number Original line Diff line number Diff line
@@ -374,6 +374,11 @@ common_exception:
	s32i	a2, a1, PT_LCOUNT
	s32i	a2, a1, PT_LCOUNT
#endif
#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. */
	/* It is now save to restore the EXC_TABLE_FIXUP variable. */


	rsr	a2, exccause
	rsr	a2, exccause
@@ -2024,6 +2029,12 @@ ENTRY(_switch_to)
	s32i	a3, a4, THREAD_CPENABLE
	s32i	a3, a4, THREAD_CPENABLE
#endif
#endif


#if XCHAL_HAVE_EXCLUSIVE
	l32i	a3, a5, THREAD_ATOMCTL8
	getex	a3
	s32i	a3, a4, THREAD_ATOMCTL8
#endif

	/* Flush register file. */
	/* Flush register file. */


	spill_registers_kernel
	spill_registers_kernel