105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter/*
205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * spu_restore.c
305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * (C) Copyright IBM Corp. 2005
505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * SPU-side context restore sequence outlined in
705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * Synergistic Processor Element Book IV
805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * Author: Mark Nutter <mnutter@us.ibm.com>
1005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
1105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * This program is free software; you can redistribute it and/or modify
1205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * it under the terms of the GNU General Public License as published by
1305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * the Free Software Foundation; either version 2, or (at your option)
1405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * any later version.
1505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
1605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * This program is distributed in the hope that it will be useful,
1705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * but WITHOUT ANY WARRANTY; without even the implied warranty of
1805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * GNU General Public License for more details.
2005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
2105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * You should have received a copy of the GNU General Public License
2205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * along with this program; if not, write to the Free Software
2305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
2505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter */
2605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
2705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
2805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#ifndef LS_SIZE
2905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#define LS_SIZE                 0x40000	/* 256K (in bytes) */
3005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#endif
3105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
3205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nuttertypedef unsigned int u32;
3305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nuttertypedef unsigned long long u64;
3405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
3505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#include <spu_intrinsics.h>
3605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#include <asm/spu_csa.h>
3705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#include "spu_utils.h"
3805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
3905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#define BR_INSTR		0x327fff80	/* br -4         */
4005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#define NOP_INSTR		0x40200000	/* nop           */
4105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#define HEQ_INSTR		0x7b000000	/* heq $0, $0    */
4205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#define STOP_INSTR		0x00000000	/* stop 0x0      */
4305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#define ILLEGAL_INSTR		0x00800000	/* illegal instr */
4405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter#define RESTORE_COMPLETE	0x00003ffc	/* stop 0x3ffc   */
4505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
4605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void fetch_regs_from_mem(addr64 lscsa_ea)
4705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
4805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int ls = (unsigned int)&regs_spill[0];
4905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int size = sizeof(regs_spill);
5005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int tag_id = 0;
5105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int cmd = 0x40;	/* GET */
5205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
5305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_LSA, ls);
5405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
5505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_EAL, lscsa_ea.ui[1]);
5605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_Size, size);
5705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_TagID, tag_id);
5805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_Cmd, cmd);
5905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
6005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
6105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void restore_upper_240kb(addr64 lscsa_ea)
6205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
6305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int ls = 16384;
6405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int list = (unsigned int)&dma_list[0];
6505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int size = sizeof(dma_list);
6605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int tag_id = 0;
6705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int cmd = 0x44;	/* GETL */
6805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
6905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 4:
7005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Enqueue the GETL command (tag 0) to the MFC SPU command
7105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    queue to transfer the upper 240 kb of LS from CSA.
7205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
7305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_LSA, ls);
7405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_EAH, lscsa_ea.ui[0]);
7505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_EAL, list);
7605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_Size, size);
7705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_TagID, tag_id);
7805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_Cmd, cmd);
7905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
8005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
8105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void restore_decr(void)
8205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
8305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
8405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int decr_running;
8505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int decr;
8605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
87ca53da3abb1d49748931ff2acb66d5a6eeeba2a1Masato Noguchi	/* Restore, Step 6(moved):
8805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    If the LSCSA "decrementer running" flag is set
8905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    then write the SPU_WrDec channel with the
9005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    decrementer value from LSCSA.
9105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
9205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(decr_status);
931cfc0f86eb0348dd04ace8c2171642ebe9cd87bbMasato Noguchi	decr_running = regs_spill[offset].slot[0] & SPU_DECR_STATUS_RUNNING;
9405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	if (decr_running) {
9505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		offset = LSCSA_QW_OFFSET(decr);
9605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		decr = regs_spill[offset].slot[0];
9705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		spu_writech(SPU_WrDec, decr);
9805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	}
9905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
10005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
10105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void write_ppu_mb(void)
10205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
10305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
10405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int data;
10505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
10605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 11:
10705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Write the MFC_WrOut_MB channel with the PPU_MB
10805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    data from LSCSA.
10905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
11005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(ppu_mb);
11105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	data = regs_spill[offset].slot[0];
11205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(SPU_WrOutMbox, data);
11305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
11405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
11505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void write_ppuint_mb(void)
11605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
11705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
11805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int data;
11905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
12005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 12:
12105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Write the MFC_WrInt_MB channel with the PPUINT_MB
12205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    data from LSCSA.
12305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
12405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(ppuint_mb);
12505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	data = regs_spill[offset].slot[0];
12605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(SPU_WrOutIntrMbox, data);
12705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
12805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
12905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void restore_fpcr(void)
13005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
13105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
13205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	vector unsigned int fpcr;
13305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
13405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 13:
13505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Restore the floating-point status and control
13605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    register from the LSCSA.
13705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
13805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(fpcr);
13905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	fpcr = regs_spill[offset].v;
14005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_mtfpscr(fpcr);
14105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
14205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
14305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void restore_srr0(void)
14405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
14505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
14605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int srr0;
14705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
14805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 14:
14905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Restore the SPU SRR0 data from the LSCSA.
15005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
15105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(srr0);
15205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	srr0 = regs_spill[offset].slot[0];
15305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(SPU_WrSRR0, srr0);
15405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
15505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
15605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void restore_event_mask(void)
15705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
15805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
15905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int event_mask;
16005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
16105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 15:
16205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Restore the SPU_RdEventMsk data from the LSCSA.
16305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
16405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(event_mask);
16505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	event_mask = regs_spill[offset].slot[0];
16605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(SPU_WrEventMask, event_mask);
16705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
16805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
16905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void restore_tag_mask(void)
17005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
17105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
17205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int tag_mask;
17305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
17405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 16:
17505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Restore the SPU_RdTagMsk data from the LSCSA.
17605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
17705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(tag_mask);
17805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	tag_mask = regs_spill[offset].slot[0];
17905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_writech(MFC_WrTagMask, tag_mask);
18005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
18105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
18205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterstatic inline void restore_complete(void)
18305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
18405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	extern void exit_fini(void);
18505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int *exit_instrs = (unsigned int *)exit_fini;
18605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int offset;
18705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int stopped_status;
18805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	unsigned int stopped_code;
18905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
19005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	/* Restore, Step 18:
19105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Issue a stop-and-signal instruction with
19205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    "good context restore" signal value.
19305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *
19405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 * Restore, Step 19:
19505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    There may be additional instructions placed
19605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    here by the PPE Sequence for SPU Context
19705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    Restore in order to restore the correct
19805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    "stopped state".
19905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *
20005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    This step is handled here by analyzing the
20105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    LSCSA.stopped_status and then modifying the
20205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 *    exit() function to behave appropriately.
20305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	 */
20405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
20505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	offset = LSCSA_QW_OFFSET(stopped_status);
20605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	stopped_status = regs_spill[offset].slot[0];
20705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	stopped_code = regs_spill[offset].slot[1];
20805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
20905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	switch (stopped_status) {
21005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_P_I:
21105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[P,I]=1.  Add illegal instruction
21205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * followed by stop-and-signal instruction after
21305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * end of restore code.
21405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 */
21505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
21605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = ILLEGAL_INSTR;
21705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = STOP_INSTR | stopped_code;
21805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
21905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_P_H:
22005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[P,H]=1.  Add 'heq $0, $0' followed
22105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * by stop-and-signal instruction after end of
22205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * restore code.
22305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 */
22405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
22505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = HEQ_INSTR;
22605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = STOP_INSTR | stopped_code;
22705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
22805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_S_P:
22905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[S,P]=1.  Add nop instruction
23005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * followed by 'br -4' after end of restore
23105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * code.
23205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 */
23305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
23405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = STOP_INSTR | stopped_code;
23505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = NOP_INSTR;
23605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[3] = BR_INSTR;
23705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
23805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_S_I:
23905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[S,I]=1.  Add  illegal instruction
24005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * followed by 'br -4' after end of restore code.
24105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 */
24205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
24305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = ILLEGAL_INSTR;
24405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = NOP_INSTR;
24505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[3] = BR_INSTR;
24605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
24705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_I:
24805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[I]=1. Add illegal instruction followed
24905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * by infinite loop after end of restore sequence.
25005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 */
25105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
25205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = ILLEGAL_INSTR;
25305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = NOP_INSTR;
25405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[3] = BR_INSTR;
25505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
25605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_S:
25705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[S]=1. Add two 'nop' instructions. */
25805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
25905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = NOP_INSTR;
26005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = NOP_INSTR;
26105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[3] = BR_INSTR;
26205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
26305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_H:
26405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[H]=1. Add 'heq $0, $0' instruction
26505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * after end of restore code.
26605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 */
26705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
26805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = HEQ_INSTR;
26905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = NOP_INSTR;
27005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[3] = BR_INSTR;
27105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
27205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_P:
27305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[P]=1. Add stop-and-signal instruction
27405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 * after end of restore code.
27505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		 */
27605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
27705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = STOP_INSTR | stopped_code;
27805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
27905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	case SPU_STOPPED_STATUS_R:
28005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		/* SPU_Status[I,S,H,P,R]=0. Add infinite loop. */
28105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[0] = RESTORE_COMPLETE;
28205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[1] = NOP_INSTR;
28305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[2] = NOP_INSTR;
28405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		exit_instrs[3] = BR_INSTR;
28505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
28605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	default:
28725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* SPU_Status[R]=1. No additional instructions. */
28805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter		break;
28905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	}
29005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	spu_sync();
29105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
29205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
29305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter/**
29405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * main - entry point for SPU-side context restore.
29505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
29605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * This code deviates from the documented sequence in the
29705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter * following aspects:
29805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *
2997022543ee404880aab5c641e4983e237815edc35Jeremy Kerr *	1. The EA for LSCSA is passed from PPE in the
30005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *	   signal notification channels.
30105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *	2. The register spill area is pulled by SPU
30205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *	   into LS, rather than pushed by PPE.
30305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *	3. All 128 registers are restored by exit().
30405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *	4. The exit() function is modified at run
30505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *	   time in order to properly restore the
30605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter *	   SPU_Status register.
30705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter */
30805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutterint main()
30905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter{
31005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	addr64 lscsa_ea;
31105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
31205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1);
31305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2);
31405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	fetch_regs_from_mem(lscsa_ea);
31505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
31605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	set_event_mask();		/* Step 1.  */
31705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	set_tag_mask();			/* Step 2.  */
31805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	build_dma_list(lscsa_ea);	/* Step 3.  */
31905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	restore_upper_240kb(lscsa_ea);	/* Step 4.  */
32005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter					/* Step 5: done by 'exit'. */
32105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	enqueue_putllc(lscsa_ea);	/* Step 7. */
32205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	set_tag_update();		/* Step 8. */
32305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	read_tag_status();		/* Step 9. */
324ca53da3abb1d49748931ff2acb66d5a6eeeba2a1Masato Noguchi	restore_decr();			/* moved Step 6. */
32505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	read_llar_status();		/* Step 10. */
32605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	write_ppu_mb();			/* Step 11. */
32705b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	write_ppuint_mb();		/* Step 12. */
32805b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	restore_fpcr();			/* Step 13. */
32905b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	restore_srr0();			/* Step 14. */
33005b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	restore_event_mask();		/* Step 15. */
33105b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	restore_tag_mask();		/* Step 16. */
33205b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter					/* Step 17. done by 'exit'. */
33305b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	restore_complete();		/* Step 18. */
33405b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter
33505b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter	return 0;
33605b841174c289ca62a6b42d883b8791d9ac3a4bdMark Nutter}
337