aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2006-10-24 12:31:27 -0400
committerPaul Mackerras <paulus@samba.org>2006-10-25 00:20:22 -0400
commitff8a8f25976aa58bbae7883405b00dcbaf4cc823 (patch)
tree7add339fe063a30b23e52d523ecb310e796966cf
parent302eca184fb844670fb128c69e22a8a28bbce48a (diff)
[POWERPC] add support for stopping spus from xmon
This patch adds support for stopping, and restarting, spus from xmon. We use the spu master runcntl bit to stop execution, this is apparently the "right" way to control spu execution and spufs will be changed in the future to use this bit. Testing has shown that to restart execution we have to turn the master runcntl bit on and also rewrite the spu runcntl bit, even if it is already set to 1 (running). Stopping spus is triggered by the xmon command 'ss' - "spus stop" perhaps. Restarting them is triggered via 'sr'. Restart doesn't start execution on spus unless they were running prior to being stopped by xmon. Walking the spu->full_list in xmon after a panic, would mean corruption of any spu struct would make all the others inaccessible. To avoid this, and also to make the next patch easier, we cache pointers to all spus during boot. We attempt to catch and recover from errors while stopping and restarting the spus, but as with most xmon functionality there are no guarantees that performing these operations won't crash xmon itself. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c4
-rw-r--r--arch/powerpc/xmon/xmon.c142
-rw-r--r--include/asm-powerpc/xmon.h2
3 files changed, 146 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index b75b091098ef..032bc923342a 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -38,6 +38,7 @@
38#include <asm/spu.h> 38#include <asm/spu.h>
39#include <asm/spu_priv1.h> 39#include <asm/spu_priv1.h>
40#include <asm/mmu_context.h> 40#include <asm/mmu_context.h>
41#include <asm/xmon.h>
41 42
42#include "interrupt.h" 43#include "interrupt.h"
43 44
@@ -943,6 +944,9 @@ static int __init init_spu_base(void)
943 break; 944 break;
944 } 945 }
945 } 946 }
947
948 xmon_register_spus(&spu_full_list);
949
946 return ret; 950 return ret;
947} 951}
948module_init(init_spu_base); 952module_init(init_spu_base);
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index f56ffef4defa..6a2ed8b319f0 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -37,6 +37,8 @@
37#include <asm/sstep.h> 37#include <asm/sstep.h>
38#include <asm/bug.h> 38#include <asm/bug.h>
39#include <asm/irq_regs.h> 39#include <asm/irq_regs.h>
40#include <asm/spu.h>
41#include <asm/spu_priv1.h>
40 42
41#ifdef CONFIG_PPC64 43#ifdef CONFIG_PPC64
42#include <asm/hvcall.h> 44#include <asm/hvcall.h>
@@ -147,6 +149,8 @@ static void xmon_print_symbol(unsigned long address, const char *mid,
147 const char *after); 149 const char *after);
148static const char *getvecname(unsigned long vec); 150static const char *getvecname(unsigned long vec);
149 151
152static int do_spu_cmd(void);
153
150int xmon_no_auto_backtrace; 154int xmon_no_auto_backtrace;
151 155
152extern int print_insn_powerpc(unsigned long, unsigned long, int); 156extern int print_insn_powerpc(unsigned long, unsigned long, int);
@@ -209,8 +213,12 @@ Commands:\n\
209 mi show information about memory allocation\n\ 213 mi show information about memory allocation\n\
210 p call a procedure\n\ 214 p call a procedure\n\
211 r print registers\n\ 215 r print registers\n\
212 s single step\n\ 216 s single step\n"
213 S print special registers\n\ 217#ifdef CONFIG_PPC_CELL
218" ss stop execution on all spus\n\
219 sr restore execution on stopped spus\n"
220#endif
221" S print special registers\n\
214 t print backtrace\n\ 222 t print backtrace\n\
215 x exit monitor and recover\n\ 223 x exit monitor and recover\n\
216 X exit monitor and dont recover\n" 224 X exit monitor and dont recover\n"
@@ -518,6 +526,7 @@ int xmon(struct pt_regs *excp)
518 xmon_save_regs(&regs); 526 xmon_save_regs(&regs);
519 excp = &regs; 527 excp = &regs;
520 } 528 }
529
521 return xmon_core(excp, 0); 530 return xmon_core(excp, 0);
522} 531}
523EXPORT_SYMBOL(xmon); 532EXPORT_SYMBOL(xmon);
@@ -809,6 +818,8 @@ cmds(struct pt_regs *excp)
809 cacheflush(); 818 cacheflush();
810 break; 819 break;
811 case 's': 820 case 's':
821 if (do_spu_cmd() == 0)
822 break;
812 if (do_step(excp)) 823 if (do_step(excp))
813 return cmd; 824 return cmd;
814 break; 825 break;
@@ -2630,3 +2641,130 @@ void __init xmon_setup(void)
2630 if (xmon_early) 2641 if (xmon_early)
2631 debugger(NULL); 2642 debugger(NULL);
2632} 2643}
2644
2645#ifdef CONFIG_PPC_CELL
2646
2647struct spu_info {
2648 struct spu *spu;
2649 u64 saved_mfc_sr1_RW;
2650 u32 saved_spu_runcntl_RW;
2651 u8 stopped_ok;
2652};
2653
2654#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2655
2656static struct spu_info spu_info[XMON_NUM_SPUS];
2657
2658void xmon_register_spus(struct list_head *list)
2659{
2660 struct spu *spu;
2661
2662 list_for_each_entry(spu, list, full_list) {
2663 if (spu->number >= XMON_NUM_SPUS) {
2664 WARN_ON(1);
2665 continue;
2666 }
2667
2668 spu_info[spu->number].spu = spu;
2669 spu_info[spu->number].stopped_ok = 0;
2670 }
2671}
2672
2673static void stop_spus(void)
2674{
2675 struct spu *spu;
2676 int i;
2677 u64 tmp;
2678
2679 for (i = 0; i < XMON_NUM_SPUS; i++) {
2680 if (!spu_info[i].spu)
2681 continue;
2682
2683 if (setjmp(bus_error_jmp) == 0) {
2684 catch_memory_errors = 1;
2685 sync();
2686
2687 spu = spu_info[i].spu;
2688
2689 spu_info[i].saved_spu_runcntl_RW =
2690 in_be32(&spu->problem->spu_runcntl_RW);
2691
2692 tmp = spu_mfc_sr1_get(spu);
2693 spu_info[i].saved_mfc_sr1_RW = tmp;
2694
2695 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2696 spu_mfc_sr1_set(spu, tmp);
2697
2698 sync();
2699 __delay(200);
2700
2701 spu_info[i].stopped_ok = 1;
2702 printf("Stopped spu %.2d\n", i);
2703 } else {
2704 catch_memory_errors = 0;
2705 printf("*** Error stopping spu %.2d\n", i);
2706 }
2707 catch_memory_errors = 0;
2708 }
2709}
2710
2711static void restart_spus(void)
2712{
2713 struct spu *spu;
2714 int i;
2715
2716 for (i = 0; i < XMON_NUM_SPUS; i++) {
2717 if (!spu_info[i].spu)
2718 continue;
2719
2720 if (!spu_info[i].stopped_ok) {
2721 printf("*** Error, spu %d was not successfully stopped"
2722 ", not restarting\n", i);
2723 continue;
2724 }
2725
2726 if (setjmp(bus_error_jmp) == 0) {
2727 catch_memory_errors = 1;
2728 sync();
2729
2730 spu = spu_info[i].spu;
2731 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2732 out_be32(&spu->problem->spu_runcntl_RW,
2733 spu_info[i].saved_spu_runcntl_RW);
2734
2735 sync();
2736 __delay(200);
2737
2738 printf("Restarted spu %.2d\n", i);
2739 } else {
2740 catch_memory_errors = 0;
2741 printf("*** Error restarting spu %.2d\n", i);
2742 }
2743 catch_memory_errors = 0;
2744 }
2745}
2746
2747static int do_spu_cmd(void)
2748{
2749 int cmd;
2750
2751 cmd = inchar();
2752 switch (cmd) {
2753 case 's':
2754 stop_spus();
2755 break;
2756 case 'r':
2757 restart_spus();
2758 break;
2759 default:
2760 return -1;
2761 }
2762
2763 return 0;
2764}
2765#else /* ! CONFIG_PPC_CELL */
2766static int do_spu_cmd(void)
2767{
2768 return -1;
2769}
2770#endif
diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h
index f1d337ed68d5..88320a05f0a8 100644
--- a/include/asm-powerpc/xmon.h
+++ b/include/asm-powerpc/xmon.h
@@ -14,8 +14,10 @@
14 14
15#ifdef CONFIG_XMON 15#ifdef CONFIG_XMON
16extern void xmon_setup(void); 16extern void xmon_setup(void);
17extern void xmon_register_spus(struct list_head *list);
17#else 18#else
18static inline void xmon_setup(void) { }; 19static inline void xmon_setup(void) { };
20static inline void xmon_register_spus(struct list_head *list) { };
19#endif 21#endif
20 22
21#endif /* __KERNEL __ */ 23#endif /* __KERNEL __ */