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

Commit a7e89326 authored by James Hogan's avatar James Hogan Committed by Ralf Baechle
Browse files

MIPS: Fix watchpoint restoration



Commit f51246ef ("MIPS: Get rid of finish_arch_switch().") moved the
__restore_watch() call from finish_arch_switch() (i.e. after resume()
returns) to before the resume() call in switch_to(). This results in
watchpoints only being restored when a task is descheduled, preventing
the watchpoints from being effective most of the time, except due to
chance before the watchpoints are lazily removed.

Fix the call sequence from switch_to() through to
mips_install_watch_registers() to pass the task_struct pointer of the
next task, instead of using current. This allows the watchpoints for the
next (non-current) task to be restored without reintroducing
finish_arch_switch().

Fixes: f51246ef ("MIPS: Get rid of finish_arch_switch().")
Signed-off-by: default avatarJames Hogan <james.hogan@imgtec.com>
Cc: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: <stable@vger.kernel.org> # 4.3.x-
Patchwork: https://patchwork.linux-mips.org/patch/12726/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 81a76d71
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ do { \
	__clear_software_ll_bit();					\
	if (cpu_has_userlocal)						\
		write_c0_userlocal(task_thread_info(next)->tp_value);	\
	__restore_watch();						\
	__restore_watch(next);						\
	(last) = resume(prev, next, task_thread_info(next));		\
} while (0)

+5 −5
Original line number Diff line number Diff line
@@ -12,21 +12,21 @@

#include <asm/mipsregs.h>

void mips_install_watch_registers(void);
void mips_install_watch_registers(struct task_struct *t);
void mips_read_watch_registers(void);
void mips_clear_watch_registers(void);
void mips_probe_watch_registers(struct cpuinfo_mips *c);

#ifdef CONFIG_HARDWARE_WATCHPOINTS
#define __restore_watch() do {						\
#define __restore_watch(task) do {					\
	if (unlikely(test_bit(TIF_LOAD_WATCH,				\
			      &current_thread_info()->flags))) {	\
		mips_install_watch_registers();				\
			      &task_thread_info(task)->flags))) {	\
		mips_install_watch_registers(task);			\
	}								\
} while (0)

#else
#define __restore_watch() do {} while (0)
#define __restore_watch(task) do {} while (0)
#endif

#endif /* _ASM_WATCH_H */
+1 −1
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ static void mips_cpu_restore(void)
		write_c0_userlocal(current_thread_info()->tp_value);

	/* Restore watch registers */
	__restore_watch();
	__restore_watch(current);
}

/**
+2 −3
Original line number Diff line number Diff line
@@ -15,10 +15,9 @@
 * Install the watch registers for the current thread.	A maximum of
 * four registers are installed although the machine may have more.
 */
void mips_install_watch_registers(void)
void mips_install_watch_registers(struct task_struct *t)
{
	struct mips3264_watch_reg_state *watches =
		&current->thread.watch.mips3264;
	struct mips3264_watch_reg_state *watches = &t->thread.watch.mips3264;
	switch (current_cpu_data.watch_reg_use_cnt) {
	default:
		BUG();