xref: /linux/arch/sh/kernel/hw_breakpoint.c (revision 976e3645923bdd2fe7893aae33fd7a21098bfb28)
15933f6d2SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
209a07294SPaul Mundt /*
309a07294SPaul Mundt  * arch/sh/kernel/hw_breakpoint.c
409a07294SPaul Mundt  *
509a07294SPaul Mundt  * Unified kernel/user-space hardware breakpoint facility for the on-chip UBC.
609a07294SPaul Mundt  *
74352fc1bSPaul Mundt  * Copyright (C) 2009 - 2010  Paul Mundt
809a07294SPaul Mundt  */
909a07294SPaul Mundt #include <linux/init.h>
1009a07294SPaul Mundt #include <linux/perf_event.h>
113f07c014SIngo Molnar #include <linux/sched/signal.h>
1209a07294SPaul Mundt #include <linux/hw_breakpoint.h>
1309a07294SPaul Mundt #include <linux/percpu.h>
1409a07294SPaul Mundt #include <linux/kallsyms.h>
1509a07294SPaul Mundt #include <linux/notifier.h>
1609a07294SPaul Mundt #include <linux/kprobes.h>
1709a07294SPaul Mundt #include <linux/kdebug.h>
1809a07294SPaul Mundt #include <linux/io.h>
194352fc1bSPaul Mundt #include <linux/clk.h>
2009a07294SPaul Mundt #include <asm/hw_breakpoint.h>
2109a07294SPaul Mundt #include <asm/mmu_context.h>
2234d0b5afSPaul Mundt #include <asm/ptrace.h>
23e839ca52SDavid Howells #include <asm/traps.h>
2409a07294SPaul Mundt 
2509a07294SPaul Mundt /*
2609a07294SPaul Mundt  * Stores the breakpoints currently in use on each breakpoint address
2709a07294SPaul Mundt  * register for each cpus
2809a07294SPaul Mundt  */
2909a07294SPaul Mundt static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM]);
3009a07294SPaul Mundt 
314352fc1bSPaul Mundt /*
324352fc1bSPaul Mundt  * A dummy placeholder for early accesses until the CPUs get a chance to
334352fc1bSPaul Mundt  * register their UBCs later in the boot process.
344352fc1bSPaul Mundt  */
354352fc1bSPaul Mundt static struct sh_ubc ubc_dummy = { .num_events = 0 };
3609a07294SPaul Mundt 
374352fc1bSPaul Mundt static struct sh_ubc *sh_ubc __read_mostly = &ubc_dummy;
3809a07294SPaul Mundt 
3909a07294SPaul Mundt /*
4009a07294SPaul Mundt  * Install a perf counter breakpoint.
4109a07294SPaul Mundt  *
4209a07294SPaul Mundt  * We seek a free UBC channel and use it for this breakpoint.
4309a07294SPaul Mundt  *
4409a07294SPaul Mundt  * Atomic: we hold the counter->ctx->lock and we only handle variables
4509a07294SPaul Mundt  * and registers local to this cpu.
4609a07294SPaul Mundt  */
arch_install_hw_breakpoint(struct perf_event * bp)4709a07294SPaul Mundt int arch_install_hw_breakpoint(struct perf_event *bp)
4809a07294SPaul Mundt {
4909a07294SPaul Mundt 	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
5009a07294SPaul Mundt 	int i;
5109a07294SPaul Mundt 
524352fc1bSPaul Mundt 	for (i = 0; i < sh_ubc->num_events; i++) {
53c473b2c6SChristoph Lameter 		struct perf_event **slot = this_cpu_ptr(&bp_per_reg[i]);
5409a07294SPaul Mundt 
5509a07294SPaul Mundt 		if (!*slot) {
5609a07294SPaul Mundt 			*slot = bp;
5709a07294SPaul Mundt 			break;
5809a07294SPaul Mundt 		}
5909a07294SPaul Mundt 	}
6009a07294SPaul Mundt 
614352fc1bSPaul Mundt 	if (WARN_ONCE(i == sh_ubc->num_events, "Can't find any breakpoint slot"))
6209a07294SPaul Mundt 		return -EBUSY;
6309a07294SPaul Mundt 
644352fc1bSPaul Mundt 	clk_enable(sh_ubc->clk);
654352fc1bSPaul Mundt 	sh_ubc->enable(info, i);
6609a07294SPaul Mundt 
6709a07294SPaul Mundt 	return 0;
6809a07294SPaul Mundt }
6909a07294SPaul Mundt 
7009a07294SPaul Mundt /*
7109a07294SPaul Mundt  * Uninstall the breakpoint contained in the given counter.
7209a07294SPaul Mundt  *
7309a07294SPaul Mundt  * First we search the debug address register it uses and then we disable
7409a07294SPaul Mundt  * it.
7509a07294SPaul Mundt  *
7609a07294SPaul Mundt  * Atomic: we hold the counter->ctx->lock and we only handle variables
7709a07294SPaul Mundt  * and registers local to this cpu.
7809a07294SPaul Mundt  */
arch_uninstall_hw_breakpoint(struct perf_event * bp)7909a07294SPaul Mundt void arch_uninstall_hw_breakpoint(struct perf_event *bp)
8009a07294SPaul Mundt {
8109a07294SPaul Mundt 	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
8209a07294SPaul Mundt 	int i;
8309a07294SPaul Mundt 
844352fc1bSPaul Mundt 	for (i = 0; i < sh_ubc->num_events; i++) {
85c473b2c6SChristoph Lameter 		struct perf_event **slot = this_cpu_ptr(&bp_per_reg[i]);
8609a07294SPaul Mundt 
8709a07294SPaul Mundt 		if (*slot == bp) {
8809a07294SPaul Mundt 			*slot = NULL;
8909a07294SPaul Mundt 			break;
9009a07294SPaul Mundt 		}
9109a07294SPaul Mundt 	}
9209a07294SPaul Mundt 
934352fc1bSPaul Mundt 	if (WARN_ONCE(i == sh_ubc->num_events, "Can't find any breakpoint slot"))
9409a07294SPaul Mundt 		return;
9509a07294SPaul Mundt 
964352fc1bSPaul Mundt 	sh_ubc->disable(info, i);
974352fc1bSPaul Mundt 	clk_disable(sh_ubc->clk);
9809a07294SPaul Mundt }
9909a07294SPaul Mundt 
get_hbp_len(u16 hbp_len)10009a07294SPaul Mundt static int get_hbp_len(u16 hbp_len)
10109a07294SPaul Mundt {
10209a07294SPaul Mundt 	unsigned int len_in_bytes = 0;
10309a07294SPaul Mundt 
10409a07294SPaul Mundt 	switch (hbp_len) {
10509a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_1:
10609a07294SPaul Mundt 		len_in_bytes = 1;
10709a07294SPaul Mundt 		break;
10809a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_2:
10909a07294SPaul Mundt 		len_in_bytes = 2;
11009a07294SPaul Mundt 		break;
11109a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_4:
11209a07294SPaul Mundt 		len_in_bytes = 4;
11309a07294SPaul Mundt 		break;
11409a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_8:
11509a07294SPaul Mundt 		len_in_bytes = 8;
11609a07294SPaul Mundt 		break;
11709a07294SPaul Mundt 	}
11809a07294SPaul Mundt 	return len_in_bytes;
11909a07294SPaul Mundt }
12009a07294SPaul Mundt 
12109a07294SPaul Mundt /*
12209a07294SPaul Mundt  * Check for virtual address in kernel space.
12309a07294SPaul Mundt  */
arch_check_bp_in_kernelspace(struct arch_hw_breakpoint * hw)1248e983ff9SFrederic Weisbecker int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
12509a07294SPaul Mundt {
12609a07294SPaul Mundt 	unsigned int len;
127b2812d03SFrederic Weisbecker 	unsigned long va;
12809a07294SPaul Mundt 
1298e983ff9SFrederic Weisbecker 	va = hw->address;
1308e983ff9SFrederic Weisbecker 	len = get_hbp_len(hw->len);
13109a07294SPaul Mundt 
13209a07294SPaul Mundt 	return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
13309a07294SPaul Mundt }
13409a07294SPaul Mundt 
arch_bp_generic_fields(int sh_len,int sh_type,int * gen_len,int * gen_type)13509a07294SPaul Mundt int arch_bp_generic_fields(int sh_len, int sh_type,
13609a07294SPaul Mundt 			   int *gen_len, int *gen_type)
13709a07294SPaul Mundt {
13809a07294SPaul Mundt 	/* Len */
13909a07294SPaul Mundt 	switch (sh_len) {
14009a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_1:
14109a07294SPaul Mundt 		*gen_len = HW_BREAKPOINT_LEN_1;
14209a07294SPaul Mundt 		break;
14309a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_2:
14409a07294SPaul Mundt 		*gen_len = HW_BREAKPOINT_LEN_2;
14509a07294SPaul Mundt 		break;
14609a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_4:
14709a07294SPaul Mundt 		*gen_len = HW_BREAKPOINT_LEN_4;
14809a07294SPaul Mundt 		break;
14909a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_8:
15009a07294SPaul Mundt 		*gen_len = HW_BREAKPOINT_LEN_8;
15109a07294SPaul Mundt 		break;
15209a07294SPaul Mundt 	default:
15309a07294SPaul Mundt 		return -EINVAL;
15409a07294SPaul Mundt 	}
15509a07294SPaul Mundt 
15609a07294SPaul Mundt 	/* Type */
15709a07294SPaul Mundt 	switch (sh_type) {
15809a07294SPaul Mundt 	case SH_BREAKPOINT_READ:
15909a07294SPaul Mundt 		*gen_type = HW_BREAKPOINT_R;
160*1ee1119dSGustavo A. R. Silva 		break;
16109a07294SPaul Mundt 	case SH_BREAKPOINT_WRITE:
16209a07294SPaul Mundt 		*gen_type = HW_BREAKPOINT_W;
16309a07294SPaul Mundt 		break;
16409a07294SPaul Mundt 	case SH_BREAKPOINT_RW:
16509a07294SPaul Mundt 		*gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
16609a07294SPaul Mundt 		break;
16709a07294SPaul Mundt 	default:
16809a07294SPaul Mundt 		return -EINVAL;
16909a07294SPaul Mundt 	}
17009a07294SPaul Mundt 
17109a07294SPaul Mundt 	return 0;
17209a07294SPaul Mundt }
17309a07294SPaul Mundt 
arch_build_bp_info(struct perf_event * bp,const struct perf_event_attr * attr,struct arch_hw_breakpoint * hw)174551624d6SFrederic Weisbecker static int arch_build_bp_info(struct perf_event *bp,
175551624d6SFrederic Weisbecker 			      const struct perf_event_attr *attr,
176551624d6SFrederic Weisbecker 			      struct arch_hw_breakpoint *hw)
17709a07294SPaul Mundt {
178551624d6SFrederic Weisbecker 	hw->address = attr->bp_addr;
17909a07294SPaul Mundt 
18009a07294SPaul Mundt 	/* Len */
181551624d6SFrederic Weisbecker 	switch (attr->bp_len) {
18209a07294SPaul Mundt 	case HW_BREAKPOINT_LEN_1:
183551624d6SFrederic Weisbecker 		hw->len = SH_BREAKPOINT_LEN_1;
18409a07294SPaul Mundt 		break;
18509a07294SPaul Mundt 	case HW_BREAKPOINT_LEN_2:
186551624d6SFrederic Weisbecker 		hw->len = SH_BREAKPOINT_LEN_2;
18709a07294SPaul Mundt 		break;
18809a07294SPaul Mundt 	case HW_BREAKPOINT_LEN_4:
189551624d6SFrederic Weisbecker 		hw->len = SH_BREAKPOINT_LEN_4;
19009a07294SPaul Mundt 		break;
19109a07294SPaul Mundt 	case HW_BREAKPOINT_LEN_8:
192551624d6SFrederic Weisbecker 		hw->len = SH_BREAKPOINT_LEN_8;
19309a07294SPaul Mundt 		break;
19409a07294SPaul Mundt 	default:
19509a07294SPaul Mundt 		return -EINVAL;
19609a07294SPaul Mundt 	}
19709a07294SPaul Mundt 
19809a07294SPaul Mundt 	/* Type */
199551624d6SFrederic Weisbecker 	switch (attr->bp_type) {
20009a07294SPaul Mundt 	case HW_BREAKPOINT_R:
201551624d6SFrederic Weisbecker 		hw->type = SH_BREAKPOINT_READ;
20209a07294SPaul Mundt 		break;
20309a07294SPaul Mundt 	case HW_BREAKPOINT_W:
204551624d6SFrederic Weisbecker 		hw->type = SH_BREAKPOINT_WRITE;
20509a07294SPaul Mundt 		break;
20609a07294SPaul Mundt 	case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
207551624d6SFrederic Weisbecker 		hw->type = SH_BREAKPOINT_RW;
20809a07294SPaul Mundt 		break;
20909a07294SPaul Mundt 	default:
21009a07294SPaul Mundt 		return -EINVAL;
21109a07294SPaul Mundt 	}
21209a07294SPaul Mundt 
21309a07294SPaul Mundt 	return 0;
21409a07294SPaul Mundt }
21509a07294SPaul Mundt 
21609a07294SPaul Mundt /*
21709a07294SPaul Mundt  * Validate the arch-specific HW Breakpoint register settings
21809a07294SPaul Mundt  */
hw_breakpoint_arch_parse(struct perf_event * bp,const struct perf_event_attr * attr,struct arch_hw_breakpoint * hw)219551624d6SFrederic Weisbecker int hw_breakpoint_arch_parse(struct perf_event *bp,
220551624d6SFrederic Weisbecker 			     const struct perf_event_attr *attr,
221551624d6SFrederic Weisbecker 			     struct arch_hw_breakpoint *hw)
22209a07294SPaul Mundt {
22309a07294SPaul Mundt 	unsigned int align;
22409a07294SPaul Mundt 	int ret;
22509a07294SPaul Mundt 
226551624d6SFrederic Weisbecker 	ret = arch_build_bp_info(bp, attr, hw);
22709a07294SPaul Mundt 	if (ret)
22809a07294SPaul Mundt 		return ret;
22909a07294SPaul Mundt 
23009a07294SPaul Mundt 	ret = -EINVAL;
23109a07294SPaul Mundt 
232551624d6SFrederic Weisbecker 	switch (hw->len) {
23309a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_1:
23409a07294SPaul Mundt 		align = 0;
23509a07294SPaul Mundt 		break;
23609a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_2:
23709a07294SPaul Mundt 		align = 1;
23809a07294SPaul Mundt 		break;
23909a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_4:
24009a07294SPaul Mundt 		align = 3;
24109a07294SPaul Mundt 		break;
24209a07294SPaul Mundt 	case SH_BREAKPOINT_LEN_8:
24309a07294SPaul Mundt 		align = 7;
24409a07294SPaul Mundt 		break;
24509a07294SPaul Mundt 	default:
24609a07294SPaul Mundt 		return ret;
24709a07294SPaul Mundt 	}
24809a07294SPaul Mundt 
249105244ecSPaul Mundt 	/*
25009a07294SPaul Mundt 	 * Check that the low-order bits of the address are appropriate
25109a07294SPaul Mundt 	 * for the alignment implied by len.
25209a07294SPaul Mundt 	 */
253551624d6SFrederic Weisbecker 	if (hw->address & align)
25409a07294SPaul Mundt 		return -EINVAL;
25509a07294SPaul Mundt 
25609a07294SPaul Mundt 	return 0;
25709a07294SPaul Mundt }
25809a07294SPaul Mundt 
25909a07294SPaul Mundt /*
26009a07294SPaul Mundt  * Release the user breakpoints used by ptrace
26109a07294SPaul Mundt  */
flush_ptrace_hw_breakpoint(struct task_struct * tsk)26209a07294SPaul Mundt void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
26309a07294SPaul Mundt {
26409a07294SPaul Mundt 	int i;
26509a07294SPaul Mundt 	struct thread_struct *t = &tsk->thread;
26609a07294SPaul Mundt 
2674352fc1bSPaul Mundt 	for (i = 0; i < sh_ubc->num_events; i++) {
26809a07294SPaul Mundt 		unregister_hw_breakpoint(t->ptrace_bps[i]);
26909a07294SPaul Mundt 		t->ptrace_bps[i] = NULL;
27009a07294SPaul Mundt 	}
27109a07294SPaul Mundt }
27209a07294SPaul Mundt 
hw_breakpoint_handler(struct die_args * args)27309a07294SPaul Mundt static int __kprobes hw_breakpoint_handler(struct die_args *args)
27409a07294SPaul Mundt {
27509a07294SPaul Mundt 	int cpu, i, rc = NOTIFY_STOP;
27609a07294SPaul Mundt 	struct perf_event *bp;
2774352fc1bSPaul Mundt 	unsigned int cmf, resume_mask;
27809a07294SPaul Mundt 
2794352fc1bSPaul Mundt 	/*
2804352fc1bSPaul Mundt 	 * Do an early return if none of the channels triggered.
2814352fc1bSPaul Mundt 	 */
2824352fc1bSPaul Mundt 	cmf = sh_ubc->triggered_mask();
2834352fc1bSPaul Mundt 	if (unlikely(!cmf))
2844352fc1bSPaul Mundt 		return NOTIFY_DONE;
2854352fc1bSPaul Mundt 
2864352fc1bSPaul Mundt 	/*
2874352fc1bSPaul Mundt 	 * By default, resume all of the active channels.
2884352fc1bSPaul Mundt 	 */
2894352fc1bSPaul Mundt 	resume_mask = sh_ubc->active_mask();
2904352fc1bSPaul Mundt 
2914352fc1bSPaul Mundt 	/*
2924352fc1bSPaul Mundt 	 * Disable breakpoints during exception handling.
2934352fc1bSPaul Mundt 	 */
2944352fc1bSPaul Mundt 	sh_ubc->disable_all();
29509a07294SPaul Mundt 
29609a07294SPaul Mundt 	cpu = get_cpu();
2974352fc1bSPaul Mundt 	for (i = 0; i < sh_ubc->num_events; i++) {
2984352fc1bSPaul Mundt 		unsigned long event_mask = (1 << i);
2994352fc1bSPaul Mundt 
3004352fc1bSPaul Mundt 		if (likely(!(cmf & event_mask)))
3014352fc1bSPaul Mundt 			continue;
3024352fc1bSPaul Mundt 
30309a07294SPaul Mundt 		/*
30409a07294SPaul Mundt 		 * The counter may be concurrently released but that can only
30509a07294SPaul Mundt 		 * occur from a call_rcu() path. We can then safely fetch
30609a07294SPaul Mundt 		 * the breakpoint, use its callback, touch its counter
30709a07294SPaul Mundt 		 * while we are in an rcu_read_lock() path.
30809a07294SPaul Mundt 		 */
30909a07294SPaul Mundt 		rcu_read_lock();
31009a07294SPaul Mundt 
31109a07294SPaul Mundt 		bp = per_cpu(bp_per_reg[i], cpu);
3124352fc1bSPaul Mundt 		if (bp)
31309a07294SPaul Mundt 			rc = NOTIFY_DONE;
3144352fc1bSPaul Mundt 
3154352fc1bSPaul Mundt 		/*
3164352fc1bSPaul Mundt 		 * Reset the condition match flag to denote completion of
3174352fc1bSPaul Mundt 		 * exception handling.
3184352fc1bSPaul Mundt 		 */
3194352fc1bSPaul Mundt 		sh_ubc->clear_triggered_mask(event_mask);
3204352fc1bSPaul Mundt 
3214352fc1bSPaul Mundt 		/*
3224352fc1bSPaul Mundt 		 * bp can be NULL due to concurrent perf counter
3234352fc1bSPaul Mundt 		 * removing.
3244352fc1bSPaul Mundt 		 */
3254352fc1bSPaul Mundt 		if (!bp) {
32609a07294SPaul Mundt 			rcu_read_unlock();
32709a07294SPaul Mundt 			break;
32809a07294SPaul Mundt 		}
32909a07294SPaul Mundt 
3304352fc1bSPaul Mundt 		/*
3314352fc1bSPaul Mundt 		 * Don't restore the channel if the breakpoint is from
3324352fc1bSPaul Mundt 		 * ptrace, as it always operates in one-shot mode.
3334352fc1bSPaul Mundt 		 */
3344352fc1bSPaul Mundt 		if (bp->overflow_handler == ptrace_triggered)
3354352fc1bSPaul Mundt 			resume_mask &= ~(1 << i);
3364352fc1bSPaul Mundt 
337a28b460eSPaul Mundt 		perf_bp_event(bp, args->regs);
33809a07294SPaul Mundt 
3394352fc1bSPaul Mundt 		/* Deliver the signal to userspace */
3408e983ff9SFrederic Weisbecker 		if (!arch_check_bp_in_kernelspace(&bp->hw.info)) {
341195bce73SEric W. Biederman 			force_sig_fault(SIGTRAP, TRAP_HWBKPT,
3422e1661d2SEric W. Biederman 					(void __user *)NULL);
3434352fc1bSPaul Mundt 		}
3444352fc1bSPaul Mundt 
34509a07294SPaul Mundt 		rcu_read_unlock();
34609a07294SPaul Mundt 	}
34709a07294SPaul Mundt 
3484352fc1bSPaul Mundt 	if (cmf == 0)
3494352fc1bSPaul Mundt 		rc = NOTIFY_DONE;
35009a07294SPaul Mundt 
3514352fc1bSPaul Mundt 	sh_ubc->enable_all(resume_mask);
35209a07294SPaul Mundt 
35309a07294SPaul Mundt 	put_cpu();
35409a07294SPaul Mundt 
35509a07294SPaul Mundt 	return rc;
35609a07294SPaul Mundt }
35709a07294SPaul Mundt 
BUILD_TRAP_HANDLER(breakpoint)35809a07294SPaul Mundt BUILD_TRAP_HANDLER(breakpoint)
35909a07294SPaul Mundt {
36009a07294SPaul Mundt 	unsigned long ex = lookup_exception_vector();
36109a07294SPaul Mundt 	TRAP_HANDLER_DECL;
36209a07294SPaul Mundt 
3634352fc1bSPaul Mundt 	notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP);
36409a07294SPaul Mundt }
36509a07294SPaul Mundt 
36609a07294SPaul Mundt /*
36709a07294SPaul Mundt  * Handle debug exception notifications.
36809a07294SPaul Mundt  */
hw_breakpoint_exceptions_notify(struct notifier_block * unused,unsigned long val,void * data)36909a07294SPaul Mundt int __kprobes hw_breakpoint_exceptions_notify(struct notifier_block *unused,
37009a07294SPaul Mundt 				    unsigned long val, void *data)
37109a07294SPaul Mundt {
372b74ab703SPaul Mundt 	struct die_args *args = data;
373b74ab703SPaul Mundt 
37409a07294SPaul Mundt 	if (val != DIE_BREAKPOINT)
37509a07294SPaul Mundt 		return NOTIFY_DONE;
37609a07294SPaul Mundt 
377b74ab703SPaul Mundt 	/*
378b74ab703SPaul Mundt 	 * If the breakpoint hasn't been triggered by the UBC, it's
379b74ab703SPaul Mundt 	 * probably from a debugger, so don't do anything more here.
3804352fc1bSPaul Mundt 	 *
3814352fc1bSPaul Mundt 	 * This also permits the UBC interface clock to remain off for
3824352fc1bSPaul Mundt 	 * non-UBC breakpoints, as we don't need to check the triggered
3834352fc1bSPaul Mundt 	 * or active channel masks.
384b74ab703SPaul Mundt 	 */
3854352fc1bSPaul Mundt 	if (args->trapnr != sh_ubc->trap_nr)
386b74ab703SPaul Mundt 		return NOTIFY_DONE;
387b74ab703SPaul Mundt 
38809a07294SPaul Mundt 	return hw_breakpoint_handler(data);
38909a07294SPaul Mundt }
39009a07294SPaul Mundt 
hw_breakpoint_pmu_read(struct perf_event * bp)39109a07294SPaul Mundt void hw_breakpoint_pmu_read(struct perf_event *bp)
39209a07294SPaul Mundt {
39309a07294SPaul Mundt 	/* TODO */
39409a07294SPaul Mundt }
39509a07294SPaul Mundt 
register_sh_ubc(struct sh_ubc * ubc)3964352fc1bSPaul Mundt int register_sh_ubc(struct sh_ubc *ubc)
3974352fc1bSPaul Mundt {
3984352fc1bSPaul Mundt 	/* Bail if it's already assigned */
3994352fc1bSPaul Mundt 	if (sh_ubc != &ubc_dummy)
4004352fc1bSPaul Mundt 		return -EBUSY;
4014352fc1bSPaul Mundt 	sh_ubc = ubc;
4024352fc1bSPaul Mundt 
4034352fc1bSPaul Mundt 	pr_info("HW Breakpoints: %s UBC support registered\n", ubc->name);
4044352fc1bSPaul Mundt 
4054352fc1bSPaul Mundt 	WARN_ON(ubc->num_events > HBP_NUM);
4064352fc1bSPaul Mundt 
4074352fc1bSPaul Mundt 	return 0;
4084352fc1bSPaul Mundt }
409