Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Michael Ellerman and committed by
Paul Mackerras
ff8a8f25 302eca18

+146 -2
+4
arch/powerpc/platforms/cell/spu_base.c
··· 38 38 #include <asm/spu.h> 39 39 #include <asm/spu_priv1.h> 40 40 #include <asm/mmu_context.h> 41 + #include <asm/xmon.h> 41 42 42 43 #include "interrupt.h" 43 44 ··· 944 943 break; 945 944 } 946 945 } 946 + 947 + xmon_register_spus(&spu_full_list); 948 + 947 949 return ret; 948 950 } 949 951 module_init(init_spu_base);
+140 -2
arch/powerpc/xmon/xmon.c
··· 37 37 #include <asm/sstep.h> 38 38 #include <asm/bug.h> 39 39 #include <asm/irq_regs.h> 40 + #include <asm/spu.h> 41 + #include <asm/spu_priv1.h> 40 42 41 43 #ifdef CONFIG_PPC64 42 44 #include <asm/hvcall.h> ··· 149 147 const char *after); 150 148 static const char *getvecname(unsigned long vec); 151 149 150 + static int do_spu_cmd(void); 151 + 152 152 int xmon_no_auto_backtrace; 153 153 154 154 extern int print_insn_powerpc(unsigned long, unsigned long, int); ··· 213 209 mi show information about memory allocation\n\ 214 210 p call a procedure\n\ 215 211 r print registers\n\ 216 - s single step\n\ 217 - S print special registers\n\ 212 + s single step\n" 213 + #ifdef CONFIG_PPC_CELL 214 + " ss stop execution on all spus\n\ 215 + sr restore execution on stopped spus\n" 216 + #endif 217 + " S print special registers\n\ 218 218 t print backtrace\n\ 219 219 x exit monitor and recover\n\ 220 220 X exit monitor and dont recover\n" ··· 526 518 xmon_save_regs(&regs); 527 519 excp = &regs; 528 520 } 521 + 529 522 return xmon_core(excp, 0); 530 523 } 531 524 EXPORT_SYMBOL(xmon); ··· 818 809 cacheflush(); 819 810 break; 820 811 case 's': 812 + if (do_spu_cmd() == 0) 813 + break; 821 814 if (do_step(excp)) 822 815 return cmd; 823 816 break; ··· 2641 2630 if (xmon_early) 2642 2631 debugger(NULL); 2643 2632 } 2633 + 2634 + #ifdef CONFIG_PPC_CELL 2635 + 2636 + struct spu_info { 2637 + struct spu *spu; 2638 + u64 saved_mfc_sr1_RW; 2639 + u32 saved_spu_runcntl_RW; 2640 + u8 stopped_ok; 2641 + }; 2642 + 2643 + #define XMON_NUM_SPUS 16 /* Enough for current hardware */ 2644 + 2645 + static struct spu_info spu_info[XMON_NUM_SPUS]; 2646 + 2647 + void xmon_register_spus(struct list_head *list) 2648 + { 2649 + struct spu *spu; 2650 + 2651 + list_for_each_entry(spu, list, full_list) { 2652 + if (spu->number >= XMON_NUM_SPUS) { 2653 + WARN_ON(1); 2654 + continue; 2655 + } 2656 + 2657 + spu_info[spu->number].spu = spu; 2658 + spu_info[spu->number].stopped_ok = 0; 2659 + } 2660 + } 2661 + 2662 + static void stop_spus(void) 2663 + { 2664 + struct spu *spu; 2665 + int i; 2666 + u64 tmp; 2667 + 2668 + for (i = 0; i < XMON_NUM_SPUS; i++) { 2669 + if (!spu_info[i].spu) 2670 + continue; 2671 + 2672 + if (setjmp(bus_error_jmp) == 0) { 2673 + catch_memory_errors = 1; 2674 + sync(); 2675 + 2676 + spu = spu_info[i].spu; 2677 + 2678 + spu_info[i].saved_spu_runcntl_RW = 2679 + in_be32(&spu->problem->spu_runcntl_RW); 2680 + 2681 + tmp = spu_mfc_sr1_get(spu); 2682 + spu_info[i].saved_mfc_sr1_RW = tmp; 2683 + 2684 + tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK; 2685 + spu_mfc_sr1_set(spu, tmp); 2686 + 2687 + sync(); 2688 + __delay(200); 2689 + 2690 + spu_info[i].stopped_ok = 1; 2691 + printf("Stopped spu %.2d\n", i); 2692 + } else { 2693 + catch_memory_errors = 0; 2694 + printf("*** Error stopping spu %.2d\n", i); 2695 + } 2696 + catch_memory_errors = 0; 2697 + } 2698 + } 2699 + 2700 + static void restart_spus(void) 2701 + { 2702 + struct spu *spu; 2703 + int i; 2704 + 2705 + for (i = 0; i < XMON_NUM_SPUS; i++) { 2706 + if (!spu_info[i].spu) 2707 + continue; 2708 + 2709 + if (!spu_info[i].stopped_ok) { 2710 + printf("*** Error, spu %d was not successfully stopped" 2711 + ", not restarting\n", i); 2712 + continue; 2713 + } 2714 + 2715 + if (setjmp(bus_error_jmp) == 0) { 2716 + catch_memory_errors = 1; 2717 + sync(); 2718 + 2719 + spu = spu_info[i].spu; 2720 + spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW); 2721 + out_be32(&spu->problem->spu_runcntl_RW, 2722 + spu_info[i].saved_spu_runcntl_RW); 2723 + 2724 + sync(); 2725 + __delay(200); 2726 + 2727 + printf("Restarted spu %.2d\n", i); 2728 + } else { 2729 + catch_memory_errors = 0; 2730 + printf("*** Error restarting spu %.2d\n", i); 2731 + } 2732 + catch_memory_errors = 0; 2733 + } 2734 + } 2735 + 2736 + static int do_spu_cmd(void) 2737 + { 2738 + int cmd; 2739 + 2740 + cmd = inchar(); 2741 + switch (cmd) { 2742 + case 's': 2743 + stop_spus(); 2744 + break; 2745 + case 'r': 2746 + restart_spus(); 2747 + break; 2748 + default: 2749 + return -1; 2750 + } 2751 + 2752 + return 0; 2753 + } 2754 + #else /* ! CONFIG_PPC_CELL */ 2755 + static int do_spu_cmd(void) 2756 + { 2757 + return -1; 2758 + } 2759 + #endif
+2
include/asm-powerpc/xmon.h
··· 14 14 15 15 #ifdef CONFIG_XMON 16 16 extern void xmon_setup(void); 17 + extern void xmon_register_spus(struct list_head *list); 17 18 #else 18 19 static inline void xmon_setup(void) { }; 20 + static inline void xmon_register_spus(struct list_head *list) { }; 19 21 #endif 20 22 21 23 #endif /* __KERNEL __ */