Commit 3d2ffcdd authored by Ravi Bangoria's avatar Ravi Bangoria Committed by Michael Ellerman

powerpc/watchpoint: Workaround P10 DD1 issue with VSX-32 byte instructions

POWER10 DD1 has an issue where it generates watchpoint exceptions when
it shouldn't. The conditions where this occur are:

 - octword op
 - ending address of DAWR range is less than starting address of op
 - those addresses need to be in the same or in two consecutive 512B
   blocks
 - 'op address + 64B' generates an address that has a carry into bit
   52 (crosses 2K boundary)

Handle such spurious exception by considering them as extraneous and
emulating/single-steeping instruction without generating an event.

[ravi: Fixed build warning reported by lkp@intel.com]
Signed-off-by: default avatarRavi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20201106045650.278987-1-ravi.bangoria@linux.ibm.com
parent 35785b29
...@@ -499,6 +499,11 @@ static bool is_larx_stcx_instr(int type) ...@@ -499,6 +499,11 @@ static bool is_larx_stcx_instr(int type)
return type == LARX || type == STCX; return type == LARX || type == STCX;
} }
static bool is_octword_vsx_instr(int type, int size)
{
return ((type == LOAD_VSX || type == STORE_VSX) && size == 32);
}
/* /*
* We've failed in reliably handling the hw-breakpoint. Unregister * We've failed in reliably handling the hw-breakpoint. Unregister
* it and throw a warning message to let the user know about it. * it and throw a warning message to let the user know about it.
...@@ -549,6 +554,58 @@ static bool stepping_handler(struct pt_regs *regs, struct perf_event **bp, ...@@ -549,6 +554,58 @@ static bool stepping_handler(struct pt_regs *regs, struct perf_event **bp,
return true; return true;
} }
static void handle_p10dd1_spurious_exception(struct arch_hw_breakpoint **info,
int *hit, unsigned long ea)
{
int i;
unsigned long hw_end_addr;
/*
* Handle spurious exception only when any bp_per_reg is set.
* Otherwise this might be created by xmon and not actually a
* spurious exception.
*/
for (i = 0; i < nr_wp_slots(); i++) {
if (!info[i])
continue;
hw_end_addr = ALIGN(info[i]->address + info[i]->len, HW_BREAKPOINT_SIZE);
/*
* Ending address of DAWR range is less than starting
* address of op.
*/
if ((hw_end_addr - 1) >= ea)
continue;
/*
* Those addresses need to be in the same or in two
* consecutive 512B blocks;
*/
if (((hw_end_addr - 1) >> 10) != (ea >> 10))
continue;
/*
* 'op address + 64B' generates an address that has a
* carry into bit 52 (crosses 2K boundary).
*/
if ((ea & 0x800) == ((ea + 64) & 0x800))
continue;
break;
}
if (i == nr_wp_slots())
return;
for (i = 0; i < nr_wp_slots(); i++) {
if (info[i]) {
hit[i] = 1;
info[i]->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
}
}
}
int hw_breakpoint_handler(struct die_args *args) int hw_breakpoint_handler(struct die_args *args)
{ {
bool err = false; bool err = false;
...@@ -607,9 +664,15 @@ int hw_breakpoint_handler(struct die_args *args) ...@@ -607,9 +664,15 @@ int hw_breakpoint_handler(struct die_args *args)
goto reset; goto reset;
if (!nr_hit) { if (!nr_hit) {
/* Workaround for Power10 DD1 */
if (!IS_ENABLED(CONFIG_PPC_8xx) && mfspr(SPRN_PVR) == 0x800100 &&
is_octword_vsx_instr(type, size)) {
handle_p10dd1_spurious_exception(info, hit, ea);
} else {
rc = NOTIFY_DONE; rc = NOTIFY_DONE;
goto out; goto out;
} }
}
/* /*
* Return early after invoking user-callback function without restoring * Return early after invoking user-callback function without restoring
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment