1 /*
2 * spu_save.c
3 *
4 * (C) Copyright IBM Corp. 2005
5 *
6 * SPU-side context save sequence outlined in
7 * Synergistic Processor Element Book IV
8 *
9 * Author: Mark Nutter <mnutter@us.ibm.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28 #ifndef LS_SIZE
29 #define LS_SIZE 0x40000 /* 256K (in bytes) */
30 #endif
31
32 typedef unsigned int u32;
33 typedef unsigned long long u64;
34
35 #include <spu_intrinsics.h>
36 #include <asm/spu_csa.h>
37 #include "spu_utils.h"
38
save_event_mask(void)39 static inline void save_event_mask(void)
40 {
41 unsigned int offset;
42
43 /* Save, Step 2:
44 * Read the SPU_RdEventMsk channel and save to the LSCSA.
45 */
46 offset = LSCSA_QW_OFFSET(event_mask);
47 regs_spill[offset].slot[0] = spu_readch(SPU_RdEventMask);
48 }
49
save_tag_mask(void)50 static inline void save_tag_mask(void)
51 {
52 unsigned int offset;
53
54 /* Save, Step 3:
55 * Read the SPU_RdTagMsk channel and save to the LSCSA.
56 */
57 offset = LSCSA_QW_OFFSET(tag_mask);
58 regs_spill[offset].slot[0] = spu_readch(MFC_RdTagMask);
59 }
60
save_upper_240kb(addr64 lscsa_ea)61 static inline void save_upper_240kb(addr64 lscsa_ea)
62 {
63 unsigned int ls = 16384;
64 unsigned int list = (unsigned int)&dma_list[0];
65 unsigned int size = sizeof(dma_list);
66 unsigned int tag_id = 0;
67 unsigned int cmd = 0x24; /* PUTL */
68
69 /* Save, Step 7:
70 * Enqueue the PUTL command (tag 0) to the MFC SPU command
71 * queue to transfer the remaining 240 kb of LS to CSA.
72 */
73 spu_writech(MFC_LSA, ls);
74 spu_writech(MFC_EAH, lscsa_ea.ui[0]);
75 spu_writech(MFC_EAL, list);
76 spu_writech(MFC_Size, size);
77 spu_writech(MFC_TagID, tag_id);
78 spu_writech(MFC_Cmd, cmd);
79 }
80
save_fpcr(void)81 static inline void save_fpcr(void)
82 {
83 // vector unsigned int fpcr;
84 unsigned int offset;
85
86 /* Save, Step 9:
87 * Issue the floating-point status and control register
88 * read instruction, and save to the LSCSA.
89 */
90 offset = LSCSA_QW_OFFSET(fpcr);
91 regs_spill[offset].v = spu_mffpscr();
92 }
93
save_decr(void)94 static inline void save_decr(void)
95 {
96 unsigned int offset;
97
98 /* Save, Step 10:
99 * Read and save the SPU_RdDec channel data to
100 * the LSCSA.
101 */
102 offset = LSCSA_QW_OFFSET(decr);
103 regs_spill[offset].slot[0] = spu_readch(SPU_RdDec);
104 }
105
save_srr0(void)106 static inline void save_srr0(void)
107 {
108 unsigned int offset;
109
110 /* Save, Step 11:
111 * Read and save the SPU_WSRR0 channel data to
112 * the LSCSA.
113 */
114 offset = LSCSA_QW_OFFSET(srr0);
115 regs_spill[offset].slot[0] = spu_readch(SPU_RdSRR0);
116 }
117
spill_regs_to_mem(addr64 lscsa_ea)118 static inline void spill_regs_to_mem(addr64 lscsa_ea)
119 {
120 unsigned int ls = (unsigned int)®s_spill[0];
121 unsigned int size = sizeof(regs_spill);
122 unsigned int tag_id = 0;
123 unsigned int cmd = 0x20; /* PUT */
124
125 /* Save, Step 13:
126 * Enqueue a PUT command (tag 0) to send the LSCSA
127 * to the CSA.
128 */
129 spu_writech(MFC_LSA, ls);
130 spu_writech(MFC_EAH, lscsa_ea.ui[0]);
131 spu_writech(MFC_EAL, lscsa_ea.ui[1]);
132 spu_writech(MFC_Size, size);
133 spu_writech(MFC_TagID, tag_id);
134 spu_writech(MFC_Cmd, cmd);
135 }
136
enqueue_sync(addr64 lscsa_ea)137 static inline void enqueue_sync(addr64 lscsa_ea)
138 {
139 unsigned int tag_id = 0;
140 unsigned int cmd = 0xCC;
141
142 /* Save, Step 14:
143 * Enqueue an MFC_SYNC command (tag 0).
144 */
145 spu_writech(MFC_TagID, tag_id);
146 spu_writech(MFC_Cmd, cmd);
147 }
148
save_complete(void)149 static inline void save_complete(void)
150 {
151 /* Save, Step 18:
152 * Issue a stop-and-signal instruction indicating
153 * "save complete". Note: This function will not
154 * return!!
155 */
156 spu_stop(SPU_SAVE_COMPLETE);
157 }
158
159 /**
160 * main - entry point for SPU-side context save.
161 *
162 * This code deviates from the documented sequence as follows:
163 *
164 * 1. The EA for LSCSA is passed from PPE in the
165 * signal notification channels.
166 * 2. All 128 registers are saved by crt0.o.
167 */
main()168 int main()
169 {
170 addr64 lscsa_ea;
171
172 lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
173 lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
174
175 /* Step 1: done by exit(). */
176 save_event_mask(); /* Step 2. */
177 save_tag_mask(); /* Step 3. */
178 set_event_mask(); /* Step 4. */
179 set_tag_mask(); /* Step 5. */
180 build_dma_list(lscsa_ea); /* Step 6. */
181 save_upper_240kb(lscsa_ea); /* Step 7. */
182 /* Step 8: done by exit(). */
183 save_fpcr(); /* Step 9. */
184 save_decr(); /* Step 10. */
185 save_srr0(); /* Step 11. */
186 enqueue_putllc(lscsa_ea); /* Step 12. */
187 spill_regs_to_mem(lscsa_ea); /* Step 13. */
188 enqueue_sync(lscsa_ea); /* Step 14. */
189 set_tag_update(); /* Step 15. */
190 read_tag_status(); /* Step 16. */
191 read_llar_status(); /* Step 17. */
192 save_complete(); /* Step 18. */
193
194 return 0;
195 }
196