~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/cell/spufs/spu_restore.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * spu_restore.c
  4  *
  5  * (C) Copyright IBM Corp. 2005
  6  *
  7  * SPU-side context restore sequence outlined in
  8  * Synergistic Processor Element Book IV
  9  *
 10  * Author: Mark Nutter <mnutter@us.ibm.com>
 11  */
 12 
 13 
 14 #ifndef LS_SIZE
 15 #define LS_SIZE                 0x40000 /* 256K (in bytes) */
 16 #endif
 17 
 18 typedef unsigned int u32;
 19 typedef unsigned long long u64;
 20 
 21 #include <spu_intrinsics.h>
 22 #include <asm/spu_csa.h>
 23 #include "spu_utils.h"
 24 
 25 #define BR_INSTR                0x327fff80      /* br -4         */
 26 #define NOP_INSTR               0x40200000      /* nop           */
 27 #define HEQ_INSTR               0x7b000000      /* heq $0, $0    */
 28 #define STOP_INSTR              0x00000000      /* stop 0x0      */
 29 #define ILLEGAL_INSTR           0x00800000      /* illegal instr */
 30 #define RESTORE_COMPLETE        0x00003ffc      /* stop 0x3ffc   */
 31 
 32 static inline void fetch_regs_from_mem(addr64 lscsa_ea)
 33 {
 34         unsigned int ls = (unsigned int)&regs_spill[0];
 35         unsigned int size = sizeof(regs_spill);
 36         unsigned int tag_id = 0;
 37         unsigned int cmd = 0x40;        /* GET */
 38 
 39         spu_writech(MFC_LSA, ls);
 40         spu_writech(MFC_EAH, lscsa_ea.ui[0]);
 41         spu_writech(MFC_EAL, lscsa_ea.ui[1]);
 42         spu_writech(MFC_Size, size);
 43         spu_writech(MFC_TagID, tag_id);
 44         spu_writech(MFC_Cmd, cmd);
 45 }
 46 
 47 static inline void restore_upper_240kb(addr64 lscsa_ea)
 48 {
 49         unsigned int ls = 16384;
 50         unsigned int list = (unsigned int)&dma_list[0];
 51         unsigned int size = sizeof(dma_list);
 52         unsigned int tag_id = 0;
 53         unsigned int cmd = 0x44;        /* GETL */
 54 
 55         /* Restore, Step 4:
 56          *    Enqueue the GETL command (tag 0) to the MFC SPU command
 57          *    queue to transfer the upper 240 kb of LS from CSA.
 58          */
 59         spu_writech(MFC_LSA, ls);
 60         spu_writech(MFC_EAH, lscsa_ea.ui[0]);
 61         spu_writech(MFC_EAL, list);
 62         spu_writech(MFC_Size, size);
 63         spu_writech(MFC_TagID, tag_id);
 64         spu_writech(MFC_Cmd, cmd);
 65 }
 66 
 67 static inline void restore_decr(void)
 68 {
 69         unsigned int offset;
 70         unsigned int decr_running;
 71         unsigned int decr;
 72 
 73         /* Restore, Step 6(moved):
 74          *    If the LSCSA "decrementer running" flag is set
 75          *    then write the SPU_WrDec channel with the
 76          *    decrementer value from LSCSA.
 77          */
 78         offset = LSCSA_QW_OFFSET(decr_status);
 79         decr_running = regs_spill[offset].slot[0] & SPU_DECR_STATUS_RUNNING;
 80         if (decr_running) {
 81                 offset = LSCSA_QW_OFFSET(decr);
 82                 decr = regs_spill[offset].slot[0];
 83                 spu_writech(SPU_WrDec, decr);
 84         }
 85 }
 86 
 87 static inline void write_ppu_mb(void)
 88 {
 89         unsigned int offset;
 90         unsigned int data;
 91 
 92         /* Restore, Step 11:
 93          *    Write the MFC_WrOut_MB channel with the PPU_MB
 94          *    data from LSCSA.
 95          */
 96         offset = LSCSA_QW_OFFSET(ppu_mb);
 97         data = regs_spill[offset].slot[0];
 98         spu_writech(SPU_WrOutMbox, data);
 99 }
100 
101 static inline void write_ppuint_mb(void)
102 {
103         unsigned int offset;
104         unsigned int data;
105 
106         /* Restore, Step 12:
107          *    Write the MFC_WrInt_MB channel with the PPUINT_MB
108          *    data from LSCSA.
109          */
110         offset = LSCSA_QW_OFFSET(ppuint_mb);
111         data = regs_spill[offset].slot[0];
112         spu_writech(SPU_WrOutIntrMbox, data);
113 }
114 
115 static inline void restore_fpcr(void)
116 {
117         unsigned int offset;
118         vector unsigned int fpcr;
119 
120         /* Restore, Step 13:
121          *    Restore the floating-point status and control
122          *    register from the LSCSA.
123          */
124         offset = LSCSA_QW_OFFSET(fpcr);
125         fpcr = regs_spill[offset].v;
126         spu_mtfpscr(fpcr);
127 }
128 
129 static inline void restore_srr0(void)
130 {
131         unsigned int offset;
132         unsigned int srr0;
133 
134         /* Restore, Step 14:
135          *    Restore the SPU SRR0 data from the LSCSA.
136          */
137         offset = LSCSA_QW_OFFSET(srr0);
138         srr0 = regs_spill[offset].slot[0];
139         spu_writech(SPU_WrSRR0, srr0);
140 }
141 
142 static inline void restore_event_mask(void)
143 {
144         unsigned int offset;
145         unsigned int event_mask;
146 
147         /* Restore, Step 15:
148          *    Restore the SPU_RdEventMsk data from the LSCSA.
149          */
150         offset = LSCSA_QW_OFFSET(event_mask);
151         event_mask = regs_spill[offset].slot[0];
152         spu_writech(SPU_WrEventMask, event_mask);
153 }
154 
155 static inline void restore_tag_mask(void)
156 {
157         unsigned int offset;
158         unsigned int tag_mask;
159 
160         /* Restore, Step 16:
161          *    Restore the SPU_RdTagMsk data from the LSCSA.
162          */
163         offset = LSCSA_QW_OFFSET(tag_mask);
164         tag_mask = regs_spill[offset].slot[0];
165         spu_writech(MFC_WrTagMask, tag_mask);
166 }
167 
168 static inline void restore_complete(void)
169 {
170         extern void exit_fini(void);
171         unsigned int *exit_instrs = (unsigned int *)exit_fini;
172         unsigned int offset;
173         unsigned int stopped_status;
174         unsigned int stopped_code;
175 
176         /* Restore, Step 18:
177          *    Issue a stop-and-signal instruction with
178          *    "good context restore" signal value.
179          *
180          * Restore, Step 19:
181          *    There may be additional instructions placed
182          *    here by the PPE Sequence for SPU Context
183          *    Restore in order to restore the correct
184          *    "stopped state".
185          *
186          *    This step is handled here by analyzing the
187          *    LSCSA.stopped_status and then modifying the
188          *    exit() function to behave appropriately.
189          */
190 
191         offset = LSCSA_QW_OFFSET(stopped_status);
192         stopped_status = regs_spill[offset].slot[0];
193         stopped_code = regs_spill[offset].slot[1];
194 
195         switch (stopped_status) {
196         case SPU_STOPPED_STATUS_P_I:
197                 /* SPU_Status[P,I]=1.  Add illegal instruction
198                  * followed by stop-and-signal instruction after
199                  * end of restore code.
200                  */
201                 exit_instrs[0] = RESTORE_COMPLETE;
202                 exit_instrs[1] = ILLEGAL_INSTR;
203                 exit_instrs[2] = STOP_INSTR | stopped_code;
204                 break;
205         case SPU_STOPPED_STATUS_P_H:
206                 /* SPU_Status[P,H]=1.  Add 'heq $0, $0' followed
207                  * by stop-and-signal instruction after end of
208                  * restore code.
209                  */
210                 exit_instrs[0] = RESTORE_COMPLETE;
211                 exit_instrs[1] = HEQ_INSTR;
212                 exit_instrs[2] = STOP_INSTR | stopped_code;
213                 break;
214         case SPU_STOPPED_STATUS_S_P:
215                 /* SPU_Status[S,P]=1.  Add nop instruction
216                  * followed by 'br -4' after end of restore
217                  * code.
218                  */
219                 exit_instrs[0] = RESTORE_COMPLETE;
220                 exit_instrs[1] = STOP_INSTR | stopped_code;
221                 exit_instrs[2] = NOP_INSTR;
222                 exit_instrs[3] = BR_INSTR;
223                 break;
224         case SPU_STOPPED_STATUS_S_I:
225                 /* SPU_Status[S,I]=1.  Add  illegal instruction
226                  * followed by 'br -4' after end of restore code.
227                  */
228                 exit_instrs[0] = RESTORE_COMPLETE;
229                 exit_instrs[1] = ILLEGAL_INSTR;
230                 exit_instrs[2] = NOP_INSTR;
231                 exit_instrs[3] = BR_INSTR;
232                 break;
233         case SPU_STOPPED_STATUS_I:
234                 /* SPU_Status[I]=1. Add illegal instruction followed
235                  * by infinite loop after end of restore sequence.
236                  */
237                 exit_instrs[0] = RESTORE_COMPLETE;
238                 exit_instrs[1] = ILLEGAL_INSTR;
239                 exit_instrs[2] = NOP_INSTR;
240                 exit_instrs[3] = BR_INSTR;
241                 break;
242         case SPU_STOPPED_STATUS_S:
243                 /* SPU_Status[S]=1. Add two 'nop' instructions. */
244                 exit_instrs[0] = RESTORE_COMPLETE;
245                 exit_instrs[1] = NOP_INSTR;
246                 exit_instrs[2] = NOP_INSTR;
247                 exit_instrs[3] = BR_INSTR;
248                 break;
249         case SPU_STOPPED_STATUS_H:
250                 /* SPU_Status[H]=1. Add 'heq $0, $0' instruction
251                  * after end of restore code.
252                  */
253                 exit_instrs[0] = RESTORE_COMPLETE;
254                 exit_instrs[1] = HEQ_INSTR;
255                 exit_instrs[2] = NOP_INSTR;
256                 exit_instrs[3] = BR_INSTR;
257                 break;
258         case SPU_STOPPED_STATUS_P:
259                 /* SPU_Status[P]=1. Add stop-and-signal instruction
260                  * after end of restore code.
261                  */
262                 exit_instrs[0] = RESTORE_COMPLETE;
263                 exit_instrs[1] = STOP_INSTR | stopped_code;
264                 break;
265         case SPU_STOPPED_STATUS_R:
266                 /* SPU_Status[I,S,H,P,R]=0. Add infinite loop. */
267                 exit_instrs[0] = RESTORE_COMPLETE;
268                 exit_instrs[1] = NOP_INSTR;
269                 exit_instrs[2] = NOP_INSTR;
270                 exit_instrs[3] = BR_INSTR;
271                 break;
272         default:
273                 /* SPU_Status[R]=1. No additional instructions. */
274                 break;
275         }
276         spu_sync();
277 }
278 
279 /**
280  * main - entry point for SPU-side context restore.
281  *
282  * This code deviates from the documented sequence in the
283  * following aspects:
284  *
285  *      1. The EA for LSCSA is passed from PPE in the
286  *         signal notification channels.
287  *      2. The register spill area is pulled by SPU
288  *         into LS, rather than pushed by PPE.
289  *      3. All 128 registers are restored by exit().
290  *      4. The exit() function is modified at run
291  *         time in order to properly restore the
292  *         SPU_Status register.
293  */
294 int main()
295 {
296         addr64 lscsa_ea;
297 
298         lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
299         lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
300         fetch_regs_from_mem(lscsa_ea);
301 
302         set_event_mask();               /* Step 1.  */
303         set_tag_mask();                 /* Step 2.  */
304         build_dma_list(lscsa_ea);       /* Step 3.  */
305         restore_upper_240kb(lscsa_ea);  /* Step 4.  */
306                                         /* Step 5: done by 'exit'. */
307         enqueue_putllc(lscsa_ea);       /* Step 7. */
308         set_tag_update();               /* Step 8. */
309         read_tag_status();              /* Step 9. */
310         restore_decr();                 /* moved Step 6. */
311         read_llar_status();             /* Step 10. */
312         write_ppu_mb();                 /* Step 11. */
313         write_ppuint_mb();              /* Step 12. */
314         restore_fpcr();                 /* Step 13. */
315         restore_srr0();                 /* Step 14. */
316         restore_event_mask();           /* Step 15. */
317         restore_tag_mask();             /* Step 16. */
318                                         /* Step 17. done by 'exit'. */
319         restore_complete();             /* Step 18. */
320 
321         return 0;
322 }
323 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php