summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2012-09-06 23:24:57 +0200
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-09-10 01:59:13 +0200
commitcd14457304c9d232267a3a76a2a43f1f791e545d (patch)
treedefabdab4b813faf7bcd083f8670020cf799003c /arch
parentpowerpc: Rework set_dabr so it can take a DABRX value as well (diff)
downloadlinux-cd14457304c9d232267a3a76a2a43f1f791e545d.tar.xz
linux-cd14457304c9d232267a3a76a2a43f1f791e545d.zip
powerpc: Dynamically calculate the dabrx based on kernel/user/hypervisor
Currently we mark the DABRX to interrupt on all matches (hypervisor/kernel/user and then filter in software. We can be a lot smarter now that we can set the DABRX dynamically. This sets the DABRX based on the flags passed by the user. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/hw_breakpoint.h1
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c15
-rw-r--r--arch/powerpc/platforms/pseries/setup.c2
3 files changed, 13 insertions, 5 deletions
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index c6f48eb5299c..423424599dad 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -28,6 +28,7 @@
struct arch_hw_breakpoint {
unsigned long address;
+ unsigned long dabrx;
int type;
u8 len; /* length of the target data symbol */
bool extraneous_interrupt;
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 6891d79ecef6..a89cae481b04 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
* If so, DABR will be populated in single_step_dabr_instruction().
*/
if (current->thread.last_hit_ubp != bp)
- set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
+ set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
return 0;
}
@@ -170,6 +170,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
info->address = bp->attr.bp_addr;
info->len = bp->attr.bp_len;
+ info->dabrx = DABRX_ALL;
+ if (bp->attr.exclude_user)
+ info->dabrx &= ~DABRX_USER;
+ if (bp->attr.exclude_kernel)
+ info->dabrx &= ~DABRX_KERNEL;
+ if (bp->attr.exclude_hv)
+ info->dabrx &= ~DABRX_HYP;
/*
* Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
@@ -197,7 +204,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
info = counter_arch_bp(tsk->thread.last_hit_ubp);
regs->msr &= ~MSR_SE;
- set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
+ set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
tsk->thread.last_hit_ubp = NULL;
}
@@ -281,7 +288,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
if (!info->extraneous_interrupt)
perf_bp_event(bp, regs);
- set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
+ set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
out:
rcu_read_unlock();
return rc;
@@ -313,7 +320,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args)
if (!info->extraneous_interrupt)
perf_bp_event(bp, regs);
- set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL);
+ set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
current->thread.last_hit_ubp = NULL;
/*
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index a3a69658a6ec..e3cb7ae61658 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -425,7 +425,7 @@ static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx)
if (dabrx == 0 && dabr == 0)
dabrx = DABRX_USER;
/* PAPR says we can only set kernel and user bits */
- dabrx &= H_DABRX_KERNEL | H_DABRX_USER;
+ dabrx &= DABRX_KERNEL | DABRX_USER;
return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx);
}