Commit b76bc6c8 authored by Andy Ross's avatar Andy Ross Committed by Anas Nashif
Browse files

arch/xtensa: Fix outgoing stack flush for dummy threads



On CPU startup, When we reach the cache flush code in arch_switch(),
the outgoing thread is a dummy.  The behavior of the existing code was
to leave the existing value in the SR unchanged (probably NULL at
startup).  Then the context switch would walk from that address up to
the top of the outgoing stack, flushing everything in between.  That's
wrong, because the outgoing stack is a real pointer (generally the
interrupt stack of the current CPU), and we're flushing everything in
memory underneath it.

This also reverts commit 29abc8ad ("xtensa: fix booting secondary
cores on the dummy thread"), which appears to have been an early
attempt to address this issue.  It worked (modulo all the extra and
potentially incorrect flushing) on cavs v1.5/1.8 because of the way
the entry code worked there.  But on 2.5 we now hit the first context
switch in a case where those extra lines are in address space already
marked unwritable by the CPU, so the flush explodes.

Signed-off-by: default avatarAndy Ross <andrew.j.ross@intel.com>
parent a71336ca
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -248,14 +248,17 @@ xtensa_switch:

#ifdef CONFIG_KERNEL_COHERENCE
	/* Flush the stack.  The top of stack was stored for us in
	 * EXCSAVE3 (FIXME: shouldn't be hardcoded!) by arch_cohere_stacks().
	 * EXCSAVE3 (FIXME: shouldn't be hardcoded!) by
	 * arch_cohere_stacks().  It can be NULL for a dummy thread.
	 */
	rsr.EXCSAVE3 a0
	beqz a0, noflush
	mov a3, a1
flushloop:
	dhwb a3, 0
	addi a3, a3, XCHAL_DCACHE_LINESIZE
	blt a3, a0, flushloop
noflush:
#endif

	/* Restore the A3 argument we spilled earlier (via the base
+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ static ALWAYS_INLINE void arch_cohere_stacks(struct k_thread *old_thread,
	/* Dummy threads appear at system initialization, but don't
	 * have stack_info data and will never be saved.  Ignore.
	 */
	if (!osz) {
	if (old_thread->base.thread_state & _THREAD_DUMMY) {
		return;
	}