root/arch/powerpc/platforms/cell/spufs/spu_restore.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fetch_regs_from_mem
  2. restore_upper_240kb
  3. restore_decr
  4. write_ppu_mb
  5. write_ppuint_mb
  6. restore_fpcr
  7. restore_srr0
  8. restore_event_mask
  9. restore_tag_mask
  10. restore_complete
  11. main

   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 }

/* [<][>][^][v][top][bottom][index][help] */