aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/process_32.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-11-09 02:27:40 -0500
committerPaul Mundt <lethal@linux-sh.org>2009-12-08 01:02:27 -0500
commit09a072947791088b88ae15111cf68fc5aaaf758d (patch)
tree510728ca3d3906a352cfc673e7f3e38e471165b4 /arch/sh/kernel/process_32.c
parent6ec22f9b037fc0c2e00ddb7023fad279c365324d (diff)
sh: hw-breakpoints: Add preliminary support for SH-4A UBC.
This adds preliminary support for the SH-4A UBC to the hw-breakpoints API. Presently only a single channel is implemented, and the ptrace interface still needs to be converted. This is the first step to cleaning up the long-standing UBC mess, making the UBC more generally accessible, and finally making it SMP safe. An additional abstraction will be layered on top of this as with the perf events code to permit the various CPU families to wire up support for their own specific UBCs, as many variations exist. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/process_32.c')
-rw-r--r--arch/sh/kernel/process_32.c94
1 files changed, 6 insertions, 88 deletions
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 0673c4746be3..4a2c866f9773 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -25,6 +25,7 @@
25#include <linux/fs.h> 25#include <linux/fs.h>
26#include <linux/ftrace.h> 26#include <linux/ftrace.h>
27#include <linux/preempt.h> 27#include <linux/preempt.h>
28#include <linux/hw_breakpoint.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
29#include <asm/mmu_context.h> 30#include <asm/mmu_context.h>
30#include <asm/pgalloc.h> 31#include <asm/pgalloc.h>
@@ -34,8 +35,6 @@
34#include <asm/syscalls.h> 35#include <asm/syscalls.h>
35#include <asm/watchdog.h> 36#include <asm/watchdog.h>
36 37
37int ubc_usercnt = 0;
38
39#ifdef CONFIG_32BIT 38#ifdef CONFIG_32BIT
40static void watchdog_trigger_immediate(void) 39static void watchdog_trigger_immediate(void)
41{ 40{
@@ -148,16 +147,15 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
148 */ 147 */
149void exit_thread(void) 148void exit_thread(void)
150{ 149{
151 if (current->thread.ubc_pc) {
152 current->thread.ubc_pc = 0;
153 ubc_usercnt -= 1;
154 }
155} 150}
156 151
157void flush_thread(void) 152void flush_thread(void)
158{ 153{
159#if defined(CONFIG_SH_FPU)
160 struct task_struct *tsk = current; 154 struct task_struct *tsk = current;
155
156 flush_ptrace_hw_breakpoint(tsk);
157
158#if defined(CONFIG_SH_FPU)
161 /* Forget lazy FPU state */ 159 /* Forget lazy FPU state */
162 clear_fpu(tsk, task_pt_regs(tsk)); 160 clear_fpu(tsk, task_pt_regs(tsk));
163 clear_used_math(); 161 clear_used_math();
@@ -195,9 +193,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
195{ 193{
196 struct thread_info *ti = task_thread_info(p); 194 struct thread_info *ti = task_thread_info(p);
197 struct pt_regs *childregs; 195 struct pt_regs *childregs;
198#if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP)
199 struct task_struct *tsk = current; 196 struct task_struct *tsk = current;
200#endif
201 197
202#if defined(CONFIG_SH_FPU) 198#if defined(CONFIG_SH_FPU)
203 unlazy_fpu(tsk, regs); 199 unlazy_fpu(tsk, regs);
@@ -234,53 +230,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
234 p->thread.sp = (unsigned long) childregs; 230 p->thread.sp = (unsigned long) childregs;
235 p->thread.pc = (unsigned long) ret_from_fork; 231 p->thread.pc = (unsigned long) ret_from_fork;
236 232
237 p->thread.ubc_pc = 0; 233 memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
238 234
239 return 0; 235 return 0;
240} 236}
241 237
242/* Tracing by user break controller. */
243static void ubc_set_tracing(int asid, unsigned long pc)
244{
245#if defined(CONFIG_CPU_SH4A)
246 unsigned long val;
247
248 val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE);
249 val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid));
250
251 ctrl_outl(val, UBC_CBR0);
252 ctrl_outl(pc, UBC_CAR0);
253 ctrl_outl(0x0, UBC_CAMR0);
254 ctrl_outl(0x0, UBC_CBCR);
255
256 val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
257 ctrl_outl(val, UBC_CRR0);
258
259 /* Read UBC register that we wrote last, for checking update */
260 val = ctrl_inl(UBC_CRR0);
261
262#else /* CONFIG_CPU_SH4A */
263 ctrl_outl(pc, UBC_BARA);
264
265#ifdef CONFIG_MMU
266 ctrl_outb(asid, UBC_BASRA);
267#endif
268
269 ctrl_outl(0, UBC_BAMRA);
270
271 if (current_cpu_data.type == CPU_SH7729 ||
272 current_cpu_data.type == CPU_SH7710 ||
273 current_cpu_data.type == CPU_SH7712 ||
274 current_cpu_data.type == CPU_SH7203){
275 ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
276 ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
277 } else {
278 ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
279 ctrl_outw(BRCR_PCBA, UBC_BRCR);
280 }
281#endif /* CONFIG_CPU_SH4A */
282}
283
284/* 238/*
285 * switch_to(x,y) should switch tasks from x to y. 239 * switch_to(x,y) should switch tasks from x to y.
286 * 240 *
@@ -302,25 +256,6 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
302 : "r" (task_thread_info(next))); 256 : "r" (task_thread_info(next)));
303#endif 257#endif
304 258
305 /* If no tasks are using the UBC, we're done */
306 if (ubc_usercnt == 0)
307 /* If no tasks are using the UBC, we're done */;
308 else if (next->thread.ubc_pc && next->mm) {
309 int asid = 0;
310#ifdef CONFIG_MMU
311 asid |= cpu_asid(smp_processor_id(), next->mm);
312#endif
313 ubc_set_tracing(asid, next->thread.ubc_pc);
314 } else {
315#if defined(CONFIG_CPU_SH4A)
316 ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
317 ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
318#else
319 ctrl_outw(0, UBC_BBRA);
320 ctrl_outw(0, UBC_BBRB);
321#endif
322 }
323
324 return prev; 259 return prev;
325} 260}
326 261
@@ -412,20 +347,3 @@ unsigned long get_wchan(struct task_struct *p)
412 347
413 return pc; 348 return pc;
414} 349}
415
416asmlinkage void break_point_trap(void)
417{
418 /* Clear tracing. */
419#if defined(CONFIG_CPU_SH4A)
420 ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
421 ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
422#else
423 ctrl_outw(0, UBC_BBRA);
424 ctrl_outw(0, UBC_BBRB);
425 ctrl_outl(0, UBC_BRCR);
426#endif
427 current->thread.ubc_pc = 0;
428 ubc_usercnt -= 1;
429
430 force_sig(SIGTRAP, current);
431}