xref: /openbmc/linux/arch/powerpc/platforms/cell/spufs/spu_save.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
205b84117SMark Nutter /*
305b84117SMark Nutter  * spu_save.c
405b84117SMark Nutter  *
505b84117SMark Nutter  * (C) Copyright IBM Corp. 2005
605b84117SMark Nutter  *
705b84117SMark Nutter  * SPU-side context save sequence outlined in
805b84117SMark Nutter  * Synergistic Processor Element Book IV
905b84117SMark Nutter  *
1005b84117SMark Nutter  * Author: Mark Nutter <mnutter@us.ibm.com>
1105b84117SMark Nutter  */
1205b84117SMark Nutter 
1305b84117SMark Nutter 
1405b84117SMark Nutter #ifndef LS_SIZE
1505b84117SMark Nutter #define LS_SIZE                 0x40000	/* 256K (in bytes) */
1605b84117SMark Nutter #endif
1705b84117SMark Nutter 
1805b84117SMark Nutter typedef unsigned int u32;
1905b84117SMark Nutter typedef unsigned long long u64;
2005b84117SMark Nutter 
2105b84117SMark Nutter #include <spu_intrinsics.h>
2205b84117SMark Nutter #include <asm/spu_csa.h>
2305b84117SMark Nutter #include "spu_utils.h"
2405b84117SMark Nutter 
save_event_mask(void)2505b84117SMark Nutter static inline void save_event_mask(void)
2605b84117SMark Nutter {
2705b84117SMark Nutter 	unsigned int offset;
2805b84117SMark Nutter 
2905b84117SMark Nutter 	/* Save, Step 2:
3005b84117SMark Nutter 	 *    Read the SPU_RdEventMsk channel and save to the LSCSA.
3105b84117SMark Nutter 	 */
3205b84117SMark Nutter 	offset = LSCSA_QW_OFFSET(event_mask);
337a896dc5SSebastian Siewior 	regs_spill[offset].slot[0] = spu_readch(SPU_RdEventMask);
3405b84117SMark Nutter }
3505b84117SMark Nutter 
save_tag_mask(void)3605b84117SMark Nutter static inline void save_tag_mask(void)
3705b84117SMark Nutter {
3805b84117SMark Nutter 	unsigned int offset;
3905b84117SMark Nutter 
4005b84117SMark Nutter 	/* Save, Step 3:
4105b84117SMark Nutter 	 *    Read the SPU_RdTagMsk channel and save to the LSCSA.
4205b84117SMark Nutter 	 */
4305b84117SMark Nutter 	offset = LSCSA_QW_OFFSET(tag_mask);
4405b84117SMark Nutter 	regs_spill[offset].slot[0] = spu_readch(MFC_RdTagMask);
4505b84117SMark Nutter }
4605b84117SMark Nutter 
save_upper_240kb(addr64 lscsa_ea)4705b84117SMark Nutter static inline void save_upper_240kb(addr64 lscsa_ea)
4805b84117SMark Nutter {
4905b84117SMark Nutter 	unsigned int ls = 16384;
5005b84117SMark Nutter 	unsigned int list = (unsigned int)&dma_list[0];
5105b84117SMark Nutter 	unsigned int size = sizeof(dma_list);
5205b84117SMark Nutter 	unsigned int tag_id = 0;
5305b84117SMark Nutter 	unsigned int cmd = 0x24;	/* PUTL */
5405b84117SMark Nutter 
5505b84117SMark Nutter 	/* Save, Step 7:
5605b84117SMark Nutter 	 *    Enqueue the PUTL command (tag 0) to the MFC SPU command
5705b84117SMark Nutter 	 *    queue to transfer the remaining 240 kb of LS to CSA.
5805b84117SMark Nutter 	 */
5905b84117SMark Nutter 	spu_writech(MFC_LSA, ls);
6005b84117SMark Nutter 	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
6105b84117SMark Nutter 	spu_writech(MFC_EAL, list);
6205b84117SMark Nutter 	spu_writech(MFC_Size, size);
6305b84117SMark Nutter 	spu_writech(MFC_TagID, tag_id);
6405b84117SMark Nutter 	spu_writech(MFC_Cmd, cmd);
6505b84117SMark Nutter }
6605b84117SMark Nutter 
save_fpcr(void)6705b84117SMark Nutter static inline void save_fpcr(void)
6805b84117SMark Nutter {
6905b84117SMark Nutter 	// vector unsigned int fpcr;
7005b84117SMark Nutter 	unsigned int offset;
7105b84117SMark Nutter 
7205b84117SMark Nutter 	/* Save, Step 9:
7305b84117SMark Nutter 	 *    Issue the floating-point status and control register
7405b84117SMark Nutter 	 *    read instruction, and save to the LSCSA.
7505b84117SMark Nutter 	 */
7605b84117SMark Nutter 	offset = LSCSA_QW_OFFSET(fpcr);
7705b84117SMark Nutter 	regs_spill[offset].v = spu_mffpscr();
7805b84117SMark Nutter }
7905b84117SMark Nutter 
save_decr(void)8005b84117SMark Nutter static inline void save_decr(void)
8105b84117SMark Nutter {
8205b84117SMark Nutter 	unsigned int offset;
8305b84117SMark Nutter 
8405b84117SMark Nutter 	/* Save, Step 10:
8505b84117SMark Nutter 	 *    Read and save the SPU_RdDec channel data to
8605b84117SMark Nutter 	 *    the LSCSA.
8705b84117SMark Nutter 	 */
8805b84117SMark Nutter 	offset = LSCSA_QW_OFFSET(decr);
8905b84117SMark Nutter 	regs_spill[offset].slot[0] = spu_readch(SPU_RdDec);
9005b84117SMark Nutter }
9105b84117SMark Nutter 
save_srr0(void)9205b84117SMark Nutter static inline void save_srr0(void)
9305b84117SMark Nutter {
9405b84117SMark Nutter 	unsigned int offset;
9505b84117SMark Nutter 
9605b84117SMark Nutter 	/* Save, Step 11:
9705b84117SMark Nutter 	 *    Read and save the SPU_WSRR0 channel data to
9805b84117SMark Nutter 	 *    the LSCSA.
9905b84117SMark Nutter 	 */
10005b84117SMark Nutter 	offset = LSCSA_QW_OFFSET(srr0);
10105b84117SMark Nutter 	regs_spill[offset].slot[0] = spu_readch(SPU_RdSRR0);
10205b84117SMark Nutter }
10305b84117SMark Nutter 
spill_regs_to_mem(addr64 lscsa_ea)10405b84117SMark Nutter static inline void spill_regs_to_mem(addr64 lscsa_ea)
10505b84117SMark Nutter {
10605b84117SMark Nutter 	unsigned int ls = (unsigned int)&regs_spill[0];
10705b84117SMark Nutter 	unsigned int size = sizeof(regs_spill);
10805b84117SMark Nutter 	unsigned int tag_id = 0;
10905b84117SMark Nutter 	unsigned int cmd = 0x20;	/* PUT */
11005b84117SMark Nutter 
11105b84117SMark Nutter 	/* Save, Step 13:
11205b84117SMark Nutter 	 *    Enqueue a PUT command (tag 0) to send the LSCSA
11305b84117SMark Nutter 	 *    to the CSA.
11405b84117SMark Nutter 	 */
11505b84117SMark Nutter 	spu_writech(MFC_LSA, ls);
11605b84117SMark Nutter 	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
11705b84117SMark Nutter 	spu_writech(MFC_EAL, lscsa_ea.ui[1]);
11805b84117SMark Nutter 	spu_writech(MFC_Size, size);
11905b84117SMark Nutter 	spu_writech(MFC_TagID, tag_id);
12005b84117SMark Nutter 	spu_writech(MFC_Cmd, cmd);
12105b84117SMark Nutter }
12205b84117SMark Nutter 
enqueue_sync(addr64 lscsa_ea)12305b84117SMark Nutter static inline void enqueue_sync(addr64 lscsa_ea)
12405b84117SMark Nutter {
12505b84117SMark Nutter 	unsigned int tag_id = 0;
12605b84117SMark Nutter 	unsigned int cmd = 0xCC;
12705b84117SMark Nutter 
12805b84117SMark Nutter 	/* Save, Step 14:
12905b84117SMark Nutter 	 *    Enqueue an MFC_SYNC command (tag 0).
13005b84117SMark Nutter 	 */
13105b84117SMark Nutter 	spu_writech(MFC_TagID, tag_id);
13205b84117SMark Nutter 	spu_writech(MFC_Cmd, cmd);
13305b84117SMark Nutter }
13405b84117SMark Nutter 
save_complete(void)13505b84117SMark Nutter static inline void save_complete(void)
13605b84117SMark Nutter {
13705b84117SMark Nutter 	/* Save, Step 18:
13805b84117SMark Nutter 	 *    Issue a stop-and-signal instruction indicating
13905b84117SMark Nutter 	 *    "save complete".  Note: This function will not
14005b84117SMark Nutter 	 *    return!!
14105b84117SMark Nutter 	 */
14205b84117SMark Nutter 	spu_stop(SPU_SAVE_COMPLETE);
14305b84117SMark Nutter }
14405b84117SMark Nutter 
14505b84117SMark Nutter /**
14605b84117SMark Nutter  * main - entry point for SPU-side context save.
14705b84117SMark Nutter  *
14805b84117SMark Nutter  * This code deviates from the documented sequence as follows:
14905b84117SMark Nutter  *
15005b84117SMark Nutter  *      1. The EA for LSCSA is passed from PPE in the
15105b84117SMark Nutter  *         signal notification channels.
15205b84117SMark Nutter  *      2. All 128 registers are saved by crt0.o.
15305b84117SMark Nutter  */
main()15405b84117SMark Nutter int main()
15505b84117SMark Nutter {
15605b84117SMark Nutter 	addr64 lscsa_ea;
15705b84117SMark Nutter 
15805b84117SMark Nutter 	lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
15905b84117SMark Nutter 	lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
16005b84117SMark Nutter 
16105b84117SMark Nutter 	/* Step 1: done by exit(). */
16205b84117SMark Nutter 	save_event_mask();	/* Step 2.  */
16305b84117SMark Nutter 	save_tag_mask();	/* Step 3.  */
16405b84117SMark Nutter 	set_event_mask();	/* Step 4.  */
16505b84117SMark Nutter 	set_tag_mask();		/* Step 5.  */
16605b84117SMark Nutter 	build_dma_list(lscsa_ea);	/* Step 6.  */
16705b84117SMark Nutter 	save_upper_240kb(lscsa_ea);	/* Step 7.  */
16805b84117SMark Nutter 	/* Step 8: done by exit(). */
16905b84117SMark Nutter 	save_fpcr();		/* Step 9.  */
17005b84117SMark Nutter 	save_decr();		/* Step 10. */
17105b84117SMark Nutter 	save_srr0();		/* Step 11. */
17205b84117SMark Nutter 	enqueue_putllc(lscsa_ea);	/* Step 12. */
17305b84117SMark Nutter 	spill_regs_to_mem(lscsa_ea);	/* Step 13. */
17405b84117SMark Nutter 	enqueue_sync(lscsa_ea);	/* Step 14. */
17505b84117SMark Nutter 	set_tag_update();	/* Step 15. */
17605b84117SMark Nutter 	read_tag_status();	/* Step 16. */
17705b84117SMark Nutter 	read_llar_status();	/* Step 17. */
17805b84117SMark Nutter 	save_complete();	/* Step 18. */
17905b84117SMark Nutter 
18005b84117SMark Nutter 	return 0;
18105b84117SMark Nutter }
182