// SPDX-License-Identifier: GPL-2.0-or-later
/*
* spu_restore . c
*
* ( C ) Copyright IBM Corp . 2005
*
* SPU - side context restore sequence outlined in
* Synergistic Processor Element Book IV
*
* Author : Mark Nutter < mnutter @ us . ibm . com >
*/
#ifndef LS_SIZE
#define LS_SIZE 0 x40000 /* 256K (in bytes) */
#endif
typedef unsigned int u32;
typedef unsigned long long u64;
#include <spu_intrinsics.h>
#include <asm /spu_csa.h>
#include "spu_utils.h"
#define BR_INSTR 0 x327fff80 /* br -4 */
#define NOP_INSTR 0 x40200000 /* nop */
#define HEQ_INSTR 0 x7b000000 /* heq $0, $0 */
#define STOP_INSTR 0 x00000000 /* stop 0x0 */
#define ILLEGAL_INSTR 0 x00800000 /* illegal instr */
#define RESTORE_COMPLETE 0 x00003ffc /* stop 0x3ffc */
static inline void fetch_regs_from_mem(addr64 lscsa_ea)
{
unsigned int ls = (unsigned int )®s_spill[0 ];
unsigned int size = sizeof (regs_spill);
unsigned int tag_id = 0 ;
unsigned int cmd = 0 x40; /* GET */
spu_writech(MFC_LSA, ls);
spu_writech(MFC_EAH, lscsa_ea.ui[0 ]);
spu_writech(MFC_EAL, lscsa_ea.ui[1 ]);
spu_writech(MFC_Size, size);
spu_writech(MFC_TagID, tag_id);
spu_writech(MFC_Cmd, cmd);
}
static inline void restore_upper_240kb(addr64 lscsa_ea)
{
unsigned int ls = 16384 ;
unsigned int list = (unsigned int )&dma_list[0 ];
unsigned int size = sizeof (dma_list);
unsigned int tag_id = 0 ;
unsigned int cmd = 0 x44; /* GETL */
/* Restore, Step 4:
* Enqueue the GETL command ( tag 0 ) to the MFC SPU command
* queue to transfer the upper 240 kb of LS from CSA .
*/
spu_writech(MFC_LSA, ls);
spu_writech(MFC_EAH, lscsa_ea.ui[0 ]);
spu_writech(MFC_EAL, list);
spu_writech(MFC_Size, size);
spu_writech(MFC_TagID, tag_id);
spu_writech(MFC_Cmd, cmd);
}
static inline void restore_decr(void )
{
unsigned int offset;
unsigned int decr_running;
unsigned int decr;
/* Restore, Step 6(moved):
* If the LSCSA " decrementer running " flag is set
* then write the SPU_WrDec channel with the
* decrementer value from LSCSA .
*/
offset = LSCSA_QW_OFFSET(decr_status);
decr_running = regs_spill[offset].slot[0 ] & SPU_DECR_STATUS_RUNNING;
if (decr_running) {
offset = LSCSA_QW_OFFSET(decr);
decr = regs_spill[offset].slot[0 ];
spu_writech(SPU_WrDec, decr);
}
}
static inline void write_ppu_mb(void )
{
unsigned int offset;
unsigned int data;
/* Restore, Step 11:
* Write the MFC_WrOut_MB channel with the PPU_MB
* data from LSCSA .
*/
offset = LSCSA_QW_OFFSET(ppu_mb);
data = regs_spill[offset].slot[0 ];
spu_writech(SPU_WrOutMbox, data);
}
static inline void write_ppuint_mb(void )
{
unsigned int offset;
unsigned int data;
/* Restore, Step 12:
* Write the MFC_WrInt_MB channel with the PPUINT_MB
* data from LSCSA .
*/
offset = LSCSA_QW_OFFSET(ppuint_mb);
data = regs_spill[offset].slot[0 ];
spu_writech(SPU_WrOutIntrMbox, data);
}
static inline void restore_fpcr(void )
{
unsigned int offset;
vector unsigned int fpcr;
/* Restore, Step 13:
* Restore the floating - point status and control
* register from the LSCSA .
*/
offset = LSCSA_QW_OFFSET(fpcr);
fpcr = regs_spill[offset].v;
spu_mtfpscr(fpcr);
}
static inline void restore_srr0(void )
{
unsigned int offset;
unsigned int srr0;
/* Restore, Step 14:
* Restore the SPU SRR0 data from the LSCSA .
*/
offset = LSCSA_QW_OFFSET(srr0);
srr0 = regs_spill[offset].slot[0 ];
spu_writech(SPU_WrSRR0, srr0);
}
static inline void restore_event_mask(void )
{
unsigned int offset;
unsigned int event_mask;
/* Restore, Step 15:
* Restore the SPU_RdEventMsk data from the LSCSA .
*/
offset = LSCSA_QW_OFFSET(event_mask);
event_mask = regs_spill[offset].slot[0 ];
spu_writech(SPU_WrEventMask, event_mask);
}
static inline void restore_tag_mask(void )
{
unsigned int offset;
unsigned int tag_mask;
/* Restore, Step 16:
* Restore the SPU_RdTagMsk data from the LSCSA .
*/
offset = LSCSA_QW_OFFSET(tag_mask);
tag_mask = regs_spill[offset].slot[0 ];
spu_writech(MFC_WrTagMask, tag_mask);
}
static inline void restore_complete(void )
{
extern void exit_fini(void );
unsigned int *exit_instrs = (unsigned int *)exit_fini;
unsigned int offset;
unsigned int stopped_status;
unsigned int stopped_code;
/* Restore, Step 18:
* Issue a stop - and - signal instruction with
* " good context restore " signal value .
*
* Restore , Step 19 :
* There may be additional instructions placed
* here by the PPE Sequence for SPU Context
* Restore in order to restore the correct
* " stopped state " .
*
* This step is handled here by analyzing the
* LSCSA . stopped_status and then modifying the
* exit ( ) function to behave appropriately .
*/
offset = LSCSA_QW_OFFSET(stopped_status);
stopped_status = regs_spill[offset].slot[0 ];
stopped_code = regs_spill[offset].slot[1 ];
switch (stopped_status) {
case SPU_STOPPED_STATUS_P_I:
/* SPU_Status[P,I]=1. Add illegal instruction
* followed by stop - and - signal instruction after
* end of restore code .
*/
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = ILLEGAL_INSTR;
exit_instrs[2 ] = STOP_INSTR | stopped_code;
break ;
case SPU_STOPPED_STATUS_P_H:
/* SPU_Status[P,H]=1. Add 'heq $0, $0' followed
* by stop - and - signal instruction after end of
* restore code .
*/
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = HEQ_INSTR;
exit_instrs[2 ] = STOP_INSTR | stopped_code;
break ;
case SPU_STOPPED_STATUS_S_P:
/* SPU_Status[S,P]=1. Add nop instruction
* followed by ' br - 4 ' after end of restore
* code .
*/
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = STOP_INSTR | stopped_code;
exit_instrs[2 ] = NOP_INSTR;
exit_instrs[3 ] = BR_INSTR;
break ;
case SPU_STOPPED_STATUS_S_I:
/* SPU_Status[S,I]=1. Add illegal instruction
* followed by ' br - 4 ' after end of restore code .
*/
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = ILLEGAL_INSTR;
exit_instrs[2 ] = NOP_INSTR;
exit_instrs[3 ] = BR_INSTR;
break ;
case SPU_STOPPED_STATUS_I:
/* SPU_Status[I]=1. Add illegal instruction followed
* by infinite loop after end of restore sequence .
*/
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = ILLEGAL_INSTR;
exit_instrs[2 ] = NOP_INSTR;
exit_instrs[3 ] = BR_INSTR;
break ;
case SPU_STOPPED_STATUS_S:
/* SPU_Status[S]=1. Add two 'nop' instructions. */
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = NOP_INSTR;
exit_instrs[2 ] = NOP_INSTR;
exit_instrs[3 ] = BR_INSTR;
break ;
case SPU_STOPPED_STATUS_H:
/* SPU_Status[H]=1. Add 'heq $0, $0' instruction
* after end of restore code .
*/
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = HEQ_INSTR;
exit_instrs[2 ] = NOP_INSTR;
exit_instrs[3 ] = BR_INSTR;
break ;
case SPU_STOPPED_STATUS_P:
/* SPU_Status[P]=1. Add stop-and-signal instruction
* after end of restore code .
*/
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = STOP_INSTR | stopped_code;
break ;
case SPU_STOPPED_STATUS_R:
/* SPU_Status[I,S,H,P,R]=0. Add infinite loop. */
exit_instrs[0 ] = RESTORE_COMPLETE;
exit_instrs[1 ] = NOP_INSTR;
exit_instrs[2 ] = NOP_INSTR;
exit_instrs[3 ] = BR_INSTR;
break ;
default :
/* SPU_Status[R]=1. No additional instructions. */
break ;
}
spu_sync();
}
/**
* main - entry point for SPU - side context restore .
*
* This code deviates from the documented sequence in the
* following aspects :
*
* 1 . The EA for LSCSA is passed from PPE in the
* signal notification channels .
* 2 . The register spill area is pulled by SPU
* into LS , rather than pushed by PPE .
* 3 . All 128 registers are restored by exit ( ) .
* 4 . The exit ( ) function is modified at run
* time in order to properly restore the
* SPU_Status register .
*/
int main()
{
addr64 lscsa_ea;
lscsa_ea.ui[0 ] = spu_readch(SPU_RdSigNotify1);
lscsa_ea.ui[1 ] = spu_readch(SPU_RdSigNotify2);
fetch_regs_from_mem(lscsa_ea);
set_event_mask(); /* Step 1. */
set_tag_mask(); /* Step 2. */
build_dma_list(lscsa_ea); /* Step 3. */
restore_upper_240kb(lscsa_ea); /* Step 4. */
/* Step 5: done by 'exit'. */
enqueue_putllc(lscsa_ea); /* Step 7. */
set_tag_update(); /* Step 8. */
read_tag_status(); /* Step 9. */
restore_decr(); /* moved Step 6. */
read_llar_status(); /* Step 10. */
write_ppu_mb(); /* Step 11. */
write_ppuint_mb(); /* Step 12. */
restore_fpcr(); /* Step 13. */
restore_srr0(); /* Step 14. */
restore_event_mask(); /* Step 15. */
restore_tag_mask(); /* Step 16. */
/* Step 17. done by 'exit'. */
restore_complete(); /* Step 18. */
return 0 ;
}
Messung V0.5 in Prozent C=86 H=99 G=92
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland