Re: [PATCH v3] powerpc/watchpoint: Workaround P10 DD1 issue with VSX-32 byte instructions

2020-12-15 Thread Michael Ellerman
On Fri, 6 Nov 2020 10:26:50 +0530, Ravi Bangoria wrote:
> 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)
> 
> [...]

Applied to powerpc/next.

[1/1] powerpc/watchpoint: Workaround P10 DD1 issue with VSX-32 byte instructions
  https://git.kernel.org/powerpc/c/3d2ffcdd2a982e8bbe65fa0f94fb21bf304c281e

cheers


[PATCH v3] powerpc/watchpoint: Workaround P10 DD1 issue with VSX-32 byte instructions

2020-11-05 Thread Ravi Bangoria
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.

Signed-off-by: Ravi Bangoria 
[Fixed build warning reported by kernel test robot]
Reported-by: kernel test robot 
---
v2->v3:
 - v2: 
https://lore.kernel.org/r/20201022034039.330365-1-ravi.bango...@linux.ibm.com
 - Drop first patch which introduced CPU_FTRS_POWER10_DD1. Instead use
   P1 DD1 PVR direclty in if condition. We can't set CPU_FTRS_POWER10_DD1
   inside guest as guest can be migrated to futur version of cpu.

Dependency: VSX-32 byte emulation support patches
  https://lore.kernel.org/r/20201011050908.72173-1-ravi.bango...@linux.ibm.com

 arch/powerpc/kernel/hw_breakpoint.c | 68 -
 1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/hw_breakpoint.c 
b/arch/powerpc/kernel/hw_breakpoint.c
index 1f4a1efa0074..67297aea5d94 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -644,6 +644,11 @@ static bool is_larx_stcx_instr(int type)
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
  * it and throw a warning message to let the user know about it.
@@ -694,6 +699,58 @@ static bool stepping_handler(struct pt_regs *regs, struct 
perf_event **bp,
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)
 {
bool err = false;
@@ -752,8 +809,15 @@ int hw_breakpoint_handler(struct die_args *args)
goto reset;
 
if (!nr_hit) {
-   rc = NOTIFY_DONE;
-   goto out;
+   /* Workaround for Power10 DD1 */
+   if (mfspr(SPRN_PVR) == 0x800100 &&
+   !IS_ENABLED(CONFIG_PPC_8xx) &&
+   is_octword_vsx_instr(type, size)) {
+   handle_p10dd1_spurious_exception(info, hit, ea);
+   } else {
+   rc = NOTIFY_DONE;
+   goto out;
+   }
}
 
/*
-- 
2.25.1