📄 switch.c
字号:
/* Save, Step 54: * Issue a DMA command to copy context save code * to local storage and start SPU. */ send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);}static inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu){ struct spu_problem __iomem *prob = spu->problem; /* Save, Step 55: * Restore, Step 38. * Write PPU_QueryMask=1 (enable Tag Group 0) * and issue eieio instruction. */ out_be32(&prob->dma_querymask_RW, MFC_TAGID_TO_TAGMASK(0)); eieio();}static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu){ struct spu_problem __iomem *prob = spu->problem; u32 mask = MFC_TAGID_TO_TAGMASK(0); unsigned long flags; /* Save, Step 56: * Restore, Step 39. * Restore, Step 39. * Restore, Step 46. * Poll PPU_TagStatus[gn] until 01 (Tag group 0 complete) * or write PPU_QueryType[TS]=01 and wait for Tag Group * Complete Interrupt. Write INT_Stat_Class0 or * INT_Stat_Class2 with value of 'handled'. */ POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask); local_irq_save(flags); spu_int_stat_clear(spu, 0, ~(0ul)); spu_int_stat_clear(spu, 2, ~(0ul)); local_irq_restore(flags);}static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu){ struct spu_problem __iomem *prob = spu->problem; unsigned long flags; /* Save, Step 57: * Restore, Step 40. * Poll until SPU_Status[R]=0 or wait for SPU Class 0 * or SPU Class 2 interrupt. Write INT_Stat_class0 * or INT_Stat_class2 with value of handled. */ POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); local_irq_save(flags); spu_int_stat_clear(spu, 0, ~(0ul)); spu_int_stat_clear(spu, 2, ~(0ul)); local_irq_restore(flags);}static inline int check_save_status(struct spu_state *csa, struct spu *spu){ struct spu_problem __iomem *prob = spu->problem; u32 complete; /* Save, Step 54: * If SPU_Status[P]=1 and SPU_Status[SC] = "success", * context save succeeded, otherwise context save * failed. */ complete = ((SPU_SAVE_COMPLETE << SPU_STOP_STATUS_SHIFT) | SPU_STATUS_STOPPED_BY_STOP); return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;}static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu){ /* Restore, Step 4: * If required, notify the "using application" that * the SPU task has been terminated. TBD. */}static inline void suspend_mfc_and_halt_decr(struct spu_state *csa, struct spu *spu){ struct spu_priv2 __iomem *priv2 = spu->priv2; /* Restore, Step 7: * Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend * the queue and halt the decrementer. */ out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE | MFC_CNTL_DECREMENTER_HALTED); eieio();}static inline void wait_suspend_mfc_complete(struct spu_state *csa, struct spu *spu){ struct spu_priv2 __iomem *priv2 = spu->priv2; /* Restore, Step 8: * Restore, Step 47. * Poll MFC_CNTL[Ss] until 11 is returned. */ POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_SUSPEND_DMA_STATUS_MASK) == MFC_CNTL_SUSPEND_COMPLETE);}static inline int suspend_spe(struct spu_state *csa, struct spu *spu){ struct spu_problem __iomem *prob = spu->problem; /* Restore, Step 9: * If SPU_Status[R]=1, stop SPU execution * and wait for stop to complete. * * Returns 1 if SPU_Status[R]=1 on entry. * 0 otherwise */ if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) { if (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_EXIT_STATUS) { POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); } if ((in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_LOAD_STATUS) || (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_STATE)) { out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); eieio(); POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); out_be32(&prob->spu_runcntl_RW, 0x2); eieio(); POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); } if (in_be32(&prob->spu_status_R) & SPU_STATUS_WAITING_FOR_CHANNEL) { out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); eieio(); POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); } return 1; } return 0;}static inline void clear_spu_status(struct spu_state *csa, struct spu *spu){ struct spu_problem __iomem *prob = spu->problem; /* Restore, Step 10: * If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1, * release SPU from isolate state. */ if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) { if (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_EXIT_STATUS) { spu_mfc_sr1_set(spu, MFC_STATE1_MASTER_RUN_CONTROL_MASK); eieio(); out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); eieio(); POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); } if ((in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_LOAD_STATUS) || (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_STATE)) { spu_mfc_sr1_set(spu, MFC_STATE1_MASTER_RUN_CONTROL_MASK); eieio(); out_be32(&prob->spu_runcntl_RW, 0x2); eieio(); POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); } }}static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu){ struct spu_priv2 __iomem *priv2 = spu->priv2; u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; u64 idx; int i; /* Restore, Step 20: */ /* Reset CH 1 */ out_be64(&priv2->spu_chnlcntptr_RW, 1); out_be64(&priv2->spu_chnldata_RW, 0UL); /* Reset the following CH: [0,3,4,24,25,27] */ for (i = 0; i < ARRAY_SIZE(ch_indices); i++) { idx = ch_indices[i]; out_be64(&priv2->spu_chnlcntptr_RW, idx); eieio(); out_be64(&priv2->spu_chnldata_RW, 0UL); out_be64(&priv2->spu_chnlcnt_RW, 0UL); eieio(); }}static inline void reset_ch_part2(struct spu_state *csa, struct spu *spu){ struct spu_priv2 __iomem *priv2 = spu->priv2; u64 ch_indices[5] = { 21UL, 23UL, 28UL, 29UL, 30UL }; u64 ch_counts[5] = { 16UL, 1UL, 1UL, 0UL, 1UL }; u64 idx; int i; /* Restore, Step 21: * Reset the following CH: [21, 23, 28, 29, 30] */ for (i = 0; i < 5; i++) { idx = ch_indices[i]; out_be64(&priv2->spu_chnlcntptr_RW, idx); eieio(); out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]); eieio(); }}static inline void setup_spu_status_part1(struct spu_state *csa, struct spu *spu){ u32 status_P = SPU_STATUS_STOPPED_BY_STOP; u32 status_I = SPU_STATUS_INVALID_INSTR; u32 status_H = SPU_STATUS_STOPPED_BY_HALT; u32 status_S = SPU_STATUS_SINGLE_STEP; u32 status_S_I = SPU_STATUS_SINGLE_STEP | SPU_STATUS_INVALID_INSTR; u32 status_S_P = SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_STOP; u32 status_P_H = SPU_STATUS_STOPPED_BY_HALT |SPU_STATUS_STOPPED_BY_STOP; u32 status_P_I = SPU_STATUS_STOPPED_BY_STOP |SPU_STATUS_INVALID_INSTR; u32 status_code; /* Restore, Step 27: * If the CSA.SPU_Status[I,S,H,P]=1 then add the correct * instruction sequence to the end of the SPU based restore * code (after the "context restored" stop and signal) to * restore the correct SPU status. * * NOTE: Rather than modifying the SPU executable, we * instead add a new 'stopped_status' field to the * LSCSA. The SPU-side restore reads this field and * takes the appropriate action when exiting. */ status_code = (csa->prob.spu_status_R >> SPU_STOP_STATUS_SHIFT) & 0xFFFF; if ((csa->prob.spu_status_R & status_P_I) == status_P_I) { /* SPU_Status[P,I]=1 - Illegal Instruction followed * by Stop and Signal instruction, followed by 'br -4'. * */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_I; csa->lscsa->stopped_status.slot[1] = status_code; } else if ((csa->prob.spu_status_R & status_P_H) == status_P_H) { /* SPU_Status[P,H]=1 - Halt Conditional, followed * by Stop and Signal instruction, followed by * 'br -4'. */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_H; csa->lscsa->stopped_status.slot[1] = status_code; } else if ((csa->prob.spu_status_R & status_S_P) == status_S_P) { /* SPU_Status[S,P]=1 - Stop and Signal instruction * followed by 'br -4'. */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_P; csa->lscsa->stopped_status.slot[1] = status_code; } else if ((csa->prob.spu_status_R & status_S_I) == status_S_I) { /* SPU_Status[S,I]=1 - Illegal instruction followed * by 'br -4'. */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_I; csa->lscsa->stopped_status.slot[1] = status_code; } else if ((csa->prob.spu_status_R & status_P) == status_P) { /* SPU_Status[P]=1 - Stop and Signal instruction * followed by 'br -4'. */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P; csa->lscsa->stopped_status.slot[1] = status_code; } else if ((csa->prob.spu_status_R & status_H) == status_H) { /* SPU_Status[H]=1 - Halt Conditional, followed * by 'br -4'. */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_H; } else if ((csa->prob.spu_status_R & status_S) == status_S) { /* SPU_Status[S]=1 - Two nop instructions. */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S; } else if ((csa->prob.spu_status_R & status_I) == status_I) { /* SPU_Status[I]=1 - Illegal instruction followed * by 'br -4'. */ csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_I; }}static inline void setup_spu_status_part2(struct spu_state *csa, struct spu *spu){ u32 mask; /* Restore, Step 28: * If the CSA.SPU_Status[I,S,H,P,R]=0 then * add a 'br *' instruction to the end of * the SPU based restore code. * * NOTE: Rather than modifying the SPU executable, we * instead add a new 'stopped_status' field to the * LSCSA. The SPU-side restore reads this field and * takes the appropriate action when exiting. */ mask = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING; if (!(csa->prob.spu_status_R & mask)) { csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_R; }}static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu){ /* Restore, Step 29: * Restore RA_GROUP_ID register and the * RA_ENABLE reigster from the CSA. */ spu_resource_allocation_groupID_set(spu, csa->priv1.resource_allocation_groupID_RW); spu_resource_allocation_enable_set(spu, csa->priv1.resource_allocation_enable_RW);}static inline void send_restore_code(struct spu_state *csa, struct spu *spu){ unsigned long addr = (unsigned long)&spu_restore_code[0]; unsigned int ls_offset = 0x0; unsigned int size = sizeof(spu_restore_code); unsigned int tag = 0; unsigned int rclass = 0; unsigned int cmd = MFC_GETFS_CMD; /* Restore, Step 37: * Issue MFC DMA command to copy context * restore code to local storage. */ send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);}static inline void setup_decr(struct spu_state *csa, struct spu *spu){ /* Restore, Step 34: * If CSA.MFC_CNTL[Ds]=1 (decrementer was * running) then adjust decrementer, set * decrementer running status in LSCSA, * and set decrementer "wrapped" status * in LSCSA. */ if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) { cycles_t resume_time = get_cycles(); cycles_t delta_time = resume_time - csa->suspend_time; csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING; if (csa->lscsa->decr.slot[0] < delta_time) { csa->lscsa->decr_status.slot[0] |= SPU_DECR_STATUS_WRAPPED; } csa->lscsa->decr.slot[0] -= delta_time; } else { csa->lscsa->decr_status.slot[0] = 0; }}static inline void setup_ppu_mb(struct spu_state *csa, struct spu *spu){ /* Restore, Step 35: * Copy the CSA.PU_MB data into the LSCSA. */ csa->lscsa->ppu_mb.slot[0] = csa->prob.pu_mb_R;}static inline void setup_ppuint_mb(struct spu_state *csa, struct spu *spu){ /* Restore, Step 36: * Copy the CSA.PUINT_MB data into the LSCSA. */ csa->lscsa->ppuint_mb.slot[0] = csa->priv2.puint_mb_R;}static inline int check_restore_status(struct spu_state *csa, struct spu *spu){ struct spu_problem __iomem *prob = spu->problem; u32 complete; /* Restore, Step 40: * If SPU_Status[P]=1 and SPU_Status[SC] = "success", * context restore succeeded, otherwise context restore * failed. */ complete = ((SPU_RESTORE_COMPLETE << SPU_STOP_STATUS_SHIFT) | SPU_STATUS_STOPPED_BY_STOP); return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;}static inline void restore_spu_privcntl(struct spu_state *csa, struct spu *spu){ struct spu_priv2 __iomem *priv2 = spu->priv2; /* Restore, Step 41: * Restore SPU_PrivCntl from the CSA. */ out_be64(&priv2->spu_privcntl_RW, csa->priv2.spu_privcntl_RW); eieio();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -