| From a7e89326b415b5d81c4b1016fd4a40db861eb58d Mon Sep 17 00:00:00 2001 |
| From: James Hogan <james.hogan@imgtec.com> |
| Date: Tue, 1 Mar 2016 22:19:36 +0000 |
| Subject: MIPS: Fix watchpoint restoration |
| |
| From: James Hogan <james.hogan@imgtec.com> |
| |
| commit a7e89326b415b5d81c4b1016fd4a40db861eb58d upstream. |
| |
| Commit f51246efee2b ("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: f51246efee2b ("MIPS: Get rid of finish_arch_switch().") |
| Signed-off-by: James Hogan <james.hogan@imgtec.com> |
| Cc: Paul Burton <paul.burton@imgtec.com> |
| Cc: linux-mips@linux-mips.org |
| Patchwork: https://patchwork.linux-mips.org/patch/12726/ |
| Signed-off-by: Ralf Baechle <ralf@linux-mips.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/mips/include/asm/switch_to.h | 2 +- |
| arch/mips/include/asm/watch.h | 10 +++++----- |
| arch/mips/kernel/pm.c | 2 +- |
| arch/mips/kernel/watch.c | 5 ++--- |
| 4 files changed, 9 insertions(+), 10 deletions(-) |
| |
| --- a/arch/mips/include/asm/switch_to.h |
| +++ b/arch/mips/include/asm/switch_to.h |
| @@ -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) |
| |
| --- a/arch/mips/include/asm/watch.h |
| +++ b/arch/mips/include/asm/watch.h |
| @@ -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, \ |
| - ¤t_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 */ |
| --- a/arch/mips/kernel/pm.c |
| +++ b/arch/mips/kernel/pm.c |
| @@ -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); |
| } |
| |
| /** |
| --- a/arch/mips/kernel/watch.c |
| +++ b/arch/mips/kernel/watch.c |
| @@ -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 = |
| - ¤t->thread.watch.mips3264; |
| + struct mips3264_watch_reg_state *watches = &t->thread.watch.mips3264; |
| switch (current_cpu_data.watch_reg_use_cnt) { |
| default: |
| BUG(); |