From 9178ba294b6839eeff1a91bed95515d783f3ee6c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 13 Oct 2014 16:01:09 +0200 Subject: powerpc: Convert power off logic to pm_power_off The generic Linux framework to power off the machine is a function pointer called pm_power_off. The trick about this pointer is that device drivers can potentially implement it rather than board files. Today on powerpc we set pm_power_off to invoke our generic full machine power off logic which then calls ppc_md.power_off to invoke machine specific power off. However, when we want to add a power off GPIO via the "gpio-poweroff" driver, this card house falls apart. That driver only registers itself if pm_power_off is NULL to ensure it doesn't override board specific logic. However, since we always set pm_power_off to the generic power off logic (which will just not power off the machine if no ppc_md.power_off call is implemented), we can't implement power off via the generic GPIO power off driver. To fix this up, let's get rid of the ppc_md.power_off logic and just always use pm_power_off as was intended. Then individual drivers such as the GPIO power off driver can implement power off logic via that function pointer. With this patch set applied and a few patches on top of QEMU that implement a power off GPIO on the virt e500 machine, I can successfully turn off my virtual machine after halt. Signed-off-by: Alexander Graf [mpe: Squash into one patch and update changelog based on cover letter] Signed-off-by: Michael Ellerman --- arch/powerpc/xmon/xmon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/xmon') diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index b988b5addf86..506d25681fe3 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -981,7 +981,8 @@ static void bootcmds(void) else if (cmd == 'h') ppc_md.halt(); else if (cmd == 'p') - ppc_md.power_off(); + if (pm_power_off) + pm_power_off(); } static int cpu_cmd(void) -- cgit v1.2.3-59-g8ed1b From d8ee6f34fdd28ade6b7b3a9be175bc5c0c3cfb38 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 12 Nov 2014 16:54:54 +1100 Subject: powerpc/xmon: Fix build when 4xx=y and 44x=n dump_tlb_44x() is only defined when 44x=y, but the ifdef in xmon.c checks for 4xx, leading to a build failure: arch/powerpc/xmon/xmon.c:912:4: error: implicit declaration of function 'dump_tlb_44x' Signed-off-by: Michael Ellerman --- arch/powerpc/xmon/xmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/xmon') diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 506d25681fe3..ef18021d52e1 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -907,7 +907,7 @@ cmds(struct pt_regs *excp) case 'u': dump_segments(); break; -#elif defined(CONFIG_4xx) +#elif defined(CONFIG_44x) case 'u': dump_tlb_44x(); break; -- cgit v1.2.3-59-g8ed1b From 1ad7d70562eeb14df8b6d3e1a0a56f1bdfb990f7 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Fri, 28 Nov 2014 10:06:42 +0530 Subject: powerpc/xmon: Enable HW instruction breakpoint on POWER8 This patch enables support for hardware instruction breakpoint in xmon on POWER8 platform with the help of a new register called the CIABR (Completed Instruction Address Breakpoint Register). With this patch, a single hardware instruction breakpoint can be added and cleared during any active xmon debug session. The hardware based instruction breakpoint mechanism works correctly with the existing TRAP based instruction breakpoint available on xmon. There are no powerpc CPU with CPU_FTR_IABR feature any more. This patch has re-purposed all the existing IABR related code to work with CIABR register based HW instruction breakpoint. This has one odd feature, which is that when we hit a breakpoint xmon doesn't tell us we have hit the breakpoint. This is because xmon is expecting bp->address == regs->nip. Because CIABR fires on completition regs->nip points to the instruction after the breakpoint. We could fix that, but it would then confuse other parts of the xmon code which think we need to emulate the instruction. [mpe] Signed-off-by: Michael Ellerman Signed-off-by: Anshuman Khandual --- arch/powerpc/xmon/xmon.c | 58 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/xmon') diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index ef18021d52e1..820dc135f040 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -51,6 +51,12 @@ #include #endif +#if defined(CONFIG_PPC_SPLPAR) +#include +#else +static inline long plapr_set_ciabr(unsigned long ciabr) {return 0; }; +#endif + #include "nonstdio.h" #include "dis-asm.h" @@ -270,6 +276,45 @@ static inline void cinval(void *p) asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); } +/** + * write_ciabr() - write the CIABR SPR + * @ciabr: The value to write. + * + * This function writes a value to the CIARB register either directly + * through mtspr instruction if the kernel is in HV privilege mode or + * call a hypervisor function to achieve the same in case the kernel + * is in supervisor privilege mode. + */ +static void write_ciabr(unsigned long ciabr) +{ + if (!cpu_has_feature(CPU_FTR_ARCH_207S)) + return; + + if (cpu_has_feature(CPU_FTR_HVMODE)) { + mtspr(SPRN_CIABR, ciabr); + return; + } + plapr_set_ciabr(ciabr); +} + +/** + * set_ciabr() - set the CIABR + * @addr: The value to set. + * + * This function sets the correct privilege value into the the HW + * breakpoint address before writing it up in the CIABR register. + */ +static void set_ciabr(unsigned long addr) +{ + addr &= ~CIABR_PRIV; + + if (cpu_has_feature(CPU_FTR_HVMODE)) + addr |= CIABR_PRIV_HYPER; + else + addr |= CIABR_PRIV_SUPER; + write_ciabr(addr); +} + /* * Disable surveillance (the service processor watchdog function) * while we are in xmon. @@ -764,9 +809,9 @@ static void insert_cpu_bpts(void) brk.len = 8; __set_breakpoint(&brk); } - if (iabr && cpu_has_feature(CPU_FTR_IABR)) - mtspr(SPRN_IABR, iabr->address - | (iabr->enabled & (BP_IABR|BP_IABR_TE))); + + if (iabr) + set_ciabr(iabr->address); } static void remove_bpts(void) @@ -792,8 +837,7 @@ static void remove_bpts(void) static void remove_cpu_bpts(void) { hw_breakpoint_disable(); - if (cpu_has_feature(CPU_FTR_IABR)) - mtspr(SPRN_IABR, 0); + write_ciabr(0); } /* Command interpreting routine */ @@ -1128,7 +1172,7 @@ static char *breakpoint_help_string = "b [cnt] set breakpoint at given instr addr\n" "bc clear all breakpoints\n" "bc clear breakpoint number n or at addr\n" - "bi [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n" + "bi [cnt] set hardware instr breakpoint (POWER8 only)\n" "bd [cnt] set hardware data breakpoint\n" ""; @@ -1167,7 +1211,7 @@ bpt_cmds(void) break; case 'i': /* bi - hardware instr breakpoint */ - if (!cpu_has_feature(CPU_FTR_IABR)) { + if (!cpu_has_feature(CPU_FTR_ARCH_207S)) { printf("Hardware instruction breakpoint " "not supported on this cpu\n"); break; -- cgit v1.2.3-59-g8ed1b From abb90ee7bca5af977b90a0c6be44f631fdacc932 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 1 Dec 2014 16:54:13 +1100 Subject: powerpc/xmon: Cleanup the breakpoint flags Drop BP_IABR_TE, which though used, does not do anything useful. Rename BP_IABR to BP_CIABR. Renumber the flags. Signed-off-by: Michael Ellerman --- arch/powerpc/xmon/xmon.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'arch/powerpc/xmon') diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 820dc135f040..dfe337238699 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -94,10 +94,9 @@ struct bpt { }; /* Bits in bpt.enabled */ -#define BP_IABR_TE 1 /* IABR translation enabled */ -#define BP_IABR 2 -#define BP_TRAP 8 -#define BP_DABR 0x10 +#define BP_CIABR 1 +#define BP_TRAP 2 +#define BP_DABR 4 #define NBPTS 256 static struct bpt bpts[NBPTS]; @@ -772,7 +771,7 @@ static void insert_bpts(void) bp = bpts; for (i = 0; i < NBPTS; ++i, ++bp) { - if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0) + if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0) continue; if (mread(bp->address, &bp->instr[0], 4) != 4) { printf("Couldn't read instruction at %lx, " @@ -787,7 +786,7 @@ static void insert_bpts(void) continue; } store_inst(&bp->instr[0]); - if (bp->enabled & BP_IABR) + if (bp->enabled & BP_CIABR) continue; if (mwrite(bp->address, &bpinstr, 4) != 4) { printf("Couldn't write instruction at %lx, " @@ -822,7 +821,7 @@ static void remove_bpts(void) bp = bpts; for (i = 0; i < NBPTS; ++i, ++bp) { - if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP) + if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP) continue; if (mread(bp->address, &instr, 4) == 4 && instr == bpinstr @@ -1217,7 +1216,7 @@ bpt_cmds(void) break; } if (iabr) { - iabr->enabled &= ~(BP_IABR | BP_IABR_TE); + iabr->enabled &= ~BP_CIABR; iabr = NULL; } if (!scanhex(&a)) @@ -1226,7 +1225,7 @@ bpt_cmds(void) break; bp = new_breakpoint(a); if (bp != NULL) { - bp->enabled |= BP_IABR | BP_IABR_TE; + bp->enabled |= BP_CIABR; iabr = bp; } break; @@ -1283,7 +1282,7 @@ bpt_cmds(void) if (!bp->enabled) continue; printf("%2x %s ", BP_NUM(bp), - (bp->enabled & BP_IABR)? "inst": "trap"); + (bp->enabled & BP_CIABR) ? "inst": "trap"); xmon_print_symbol(bp->address, " ", "\n"); } break; -- cgit v1.2.3-59-g8ed1b