162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * spu_switch.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2005
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Mark Nutter <mnutter@us.ibm.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Host-side part of SPU context switch sequence outlined in
1062306a36Sopenharmony_ci * Synergistic Processor Element, Book IV.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * A fully premptive switch of an SPE is very expensive in terms
1362306a36Sopenharmony_ci * of time and system resources.  SPE Book IV indicates that SPE
1462306a36Sopenharmony_ci * allocation should follow a "serially reusable device" model,
1562306a36Sopenharmony_ci * in which the SPE is assigned a task until it completes.  When
1662306a36Sopenharmony_ci * this is not possible, this sequence may be used to premptively
1762306a36Sopenharmony_ci * save, and then later (optionally) restore the context of a
1862306a36Sopenharmony_ci * program executing on an SPE.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/export.h>
2262306a36Sopenharmony_ci#include <linux/errno.h>
2362306a36Sopenharmony_ci#include <linux/hardirq.h>
2462306a36Sopenharmony_ci#include <linux/sched.h>
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/mm.h>
2762306a36Sopenharmony_ci#include <linux/vmalloc.h>
2862306a36Sopenharmony_ci#include <linux/smp.h>
2962306a36Sopenharmony_ci#include <linux/stddef.h>
3062306a36Sopenharmony_ci#include <linux/unistd.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <asm/io.h>
3362306a36Sopenharmony_ci#include <asm/spu.h>
3462306a36Sopenharmony_ci#include <asm/spu_priv1.h>
3562306a36Sopenharmony_ci#include <asm/spu_csa.h>
3662306a36Sopenharmony_ci#include <asm/mmu_context.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include "spufs.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "spu_save_dump.h"
4162306a36Sopenharmony_ci#include "spu_restore_dump.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#if 0
4462306a36Sopenharmony_ci#define POLL_WHILE_TRUE(_c) {				\
4562306a36Sopenharmony_ci    do {						\
4662306a36Sopenharmony_ci    } while (_c);					\
4762306a36Sopenharmony_ci  }
4862306a36Sopenharmony_ci#else
4962306a36Sopenharmony_ci#define RELAX_SPIN_COUNT				1000
5062306a36Sopenharmony_ci#define POLL_WHILE_TRUE(_c) {				\
5162306a36Sopenharmony_ci    do {						\
5262306a36Sopenharmony_ci	int _i;						\
5362306a36Sopenharmony_ci	for (_i=0; _i<RELAX_SPIN_COUNT && (_c); _i++) { \
5462306a36Sopenharmony_ci	    cpu_relax();				\
5562306a36Sopenharmony_ci	}						\
5662306a36Sopenharmony_ci	if (unlikely(_c)) yield();			\
5762306a36Sopenharmony_ci	else break;					\
5862306a36Sopenharmony_ci    } while (_c);					\
5962306a36Sopenharmony_ci  }
6062306a36Sopenharmony_ci#endif				/* debug */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define POLL_WHILE_FALSE(_c)	POLL_WHILE_TRUE(!(_c))
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline void acquire_spu_lock(struct spu *spu)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	/* Save, Step 1:
6762306a36Sopenharmony_ci	 * Restore, Step 1:
6862306a36Sopenharmony_ci	 *    Acquire SPU-specific mutual exclusion lock.
6962306a36Sopenharmony_ci	 *    TBD.
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic inline void release_spu_lock(struct spu *spu)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	/* Restore, Step 76:
7662306a36Sopenharmony_ci	 *    Release SPU-specific mutual exclusion lock.
7762306a36Sopenharmony_ci	 *    TBD.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic inline int check_spu_isolate(struct spu_state *csa, struct spu *spu)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
8462306a36Sopenharmony_ci	u32 isolate_state;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Save, Step 2:
8762306a36Sopenharmony_ci	 * Save, Step 6:
8862306a36Sopenharmony_ci	 *     If SPU_Status[E,L,IS] any field is '1', this
8962306a36Sopenharmony_ci	 *     SPU is in isolate state and cannot be context
9062306a36Sopenharmony_ci	 *     saved at this time.
9162306a36Sopenharmony_ci	 */
9262306a36Sopenharmony_ci	isolate_state = SPU_STATUS_ISOLATED_STATE |
9362306a36Sopenharmony_ci	    SPU_STATUS_ISOLATED_LOAD_STATUS | SPU_STATUS_ISOLATED_EXIT_STATUS;
9462306a36Sopenharmony_ci	return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	/* Save, Step 3:
10062306a36Sopenharmony_ci	 * Restore, Step 2:
10162306a36Sopenharmony_ci	 *     Save INT_Mask_class0 in CSA.
10262306a36Sopenharmony_ci	 *     Write INT_MASK_class0 with value of 0.
10362306a36Sopenharmony_ci	 *     Save INT_Mask_class1 in CSA.
10462306a36Sopenharmony_ci	 *     Write INT_MASK_class1 with value of 0.
10562306a36Sopenharmony_ci	 *     Save INT_Mask_class2 in CSA.
10662306a36Sopenharmony_ci	 *     Write INT_MASK_class2 with value of 0.
10762306a36Sopenharmony_ci	 *     Synchronize all three interrupts to be sure
10862306a36Sopenharmony_ci	 *     we no longer execute a handler on another CPU.
10962306a36Sopenharmony_ci	 */
11062306a36Sopenharmony_ci	spin_lock_irq(&spu->register_lock);
11162306a36Sopenharmony_ci	if (csa) {
11262306a36Sopenharmony_ci		csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0);
11362306a36Sopenharmony_ci		csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1);
11462306a36Sopenharmony_ci		csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci	spu_int_mask_set(spu, 0, 0ul);
11762306a36Sopenharmony_ci	spu_int_mask_set(spu, 1, 0ul);
11862306a36Sopenharmony_ci	spu_int_mask_set(spu, 2, 0ul);
11962306a36Sopenharmony_ci	eieio();
12062306a36Sopenharmony_ci	spin_unlock_irq(&spu->register_lock);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/*
12362306a36Sopenharmony_ci	 * This flag needs to be set before calling synchronize_irq so
12462306a36Sopenharmony_ci	 * that the update will be visible to the relevant handlers
12562306a36Sopenharmony_ci	 * via a simple load.
12662306a36Sopenharmony_ci	 */
12762306a36Sopenharmony_ci	set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
12862306a36Sopenharmony_ci	clear_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags);
12962306a36Sopenharmony_ci	synchronize_irq(spu->irqs[0]);
13062306a36Sopenharmony_ci	synchronize_irq(spu->irqs[1]);
13162306a36Sopenharmony_ci	synchronize_irq(spu->irqs[2]);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	/* Save, Step 4:
13762306a36Sopenharmony_ci	 * Restore, Step 25.
13862306a36Sopenharmony_ci	 *    Set a software watchdog timer, which specifies the
13962306a36Sopenharmony_ci	 *    maximum allowable time for a context save sequence.
14062306a36Sopenharmony_ci	 *
14162306a36Sopenharmony_ci	 *    For present, this implementation will not set a global
14262306a36Sopenharmony_ci	 *    watchdog timer, as virtualization & variable system load
14362306a36Sopenharmony_ci	 *    may cause unpredictable execution times.
14462306a36Sopenharmony_ci	 */
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic inline void inhibit_user_access(struct spu_state *csa, struct spu *spu)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	/* Save, Step 5:
15062306a36Sopenharmony_ci	 * Restore, Step 3:
15162306a36Sopenharmony_ci	 *     Inhibit user-space access (if provided) to this
15262306a36Sopenharmony_ci	 *     SPU by unmapping the virtual pages assigned to
15362306a36Sopenharmony_ci	 *     the SPU memory-mapped I/O (MMIO) for problem
15462306a36Sopenharmony_ci	 *     state. TBD.
15562306a36Sopenharmony_ci	 */
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic inline void set_switch_pending(struct spu_state *csa, struct spu *spu)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	/* Save, Step 7:
16162306a36Sopenharmony_ci	 * Restore, Step 5:
16262306a36Sopenharmony_ci	 *     Set a software context switch pending flag.
16362306a36Sopenharmony_ci	 *     Done above in Step 3 - disable_interrupts().
16462306a36Sopenharmony_ci	 */
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Save, Step 8:
17262306a36Sopenharmony_ci	 *     Suspend DMA and save MFC_CNTL.
17362306a36Sopenharmony_ci	 */
17462306a36Sopenharmony_ci	switch (in_be64(&priv2->mfc_control_RW) &
17562306a36Sopenharmony_ci	       MFC_CNTL_SUSPEND_DMA_STATUS_MASK) {
17662306a36Sopenharmony_ci	case MFC_CNTL_SUSPEND_IN_PROGRESS:
17762306a36Sopenharmony_ci		POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
17862306a36Sopenharmony_ci				  MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
17962306a36Sopenharmony_ci				 MFC_CNTL_SUSPEND_COMPLETE);
18062306a36Sopenharmony_ci		fallthrough;
18162306a36Sopenharmony_ci	case MFC_CNTL_SUSPEND_COMPLETE:
18262306a36Sopenharmony_ci		if (csa)
18362306a36Sopenharmony_ci			csa->priv2.mfc_control_RW =
18462306a36Sopenharmony_ci				in_be64(&priv2->mfc_control_RW) |
18562306a36Sopenharmony_ci				MFC_CNTL_SUSPEND_DMA_QUEUE;
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	case MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION:
18862306a36Sopenharmony_ci		out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE);
18962306a36Sopenharmony_ci		POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
19062306a36Sopenharmony_ci				  MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
19162306a36Sopenharmony_ci				 MFC_CNTL_SUSPEND_COMPLETE);
19262306a36Sopenharmony_ci		if (csa)
19362306a36Sopenharmony_ci			csa->priv2.mfc_control_RW =
19462306a36Sopenharmony_ci				in_be64(&priv2->mfc_control_RW) &
19562306a36Sopenharmony_ci				~MFC_CNTL_SUSPEND_DMA_QUEUE &
19662306a36Sopenharmony_ci				~MFC_CNTL_SUSPEND_MASK;
19762306a36Sopenharmony_ci		break;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic inline void save_spu_runcntl(struct spu_state *csa, struct spu *spu)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* Save, Step 9:
20662306a36Sopenharmony_ci	 *     Save SPU_Runcntl in the CSA.  This value contains
20762306a36Sopenharmony_ci	 *     the "Application Desired State".
20862306a36Sopenharmony_ci	 */
20962306a36Sopenharmony_ci	csa->prob.spu_runcntl_RW = in_be32(&prob->spu_runcntl_RW);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	/* Save, Step 10:
21562306a36Sopenharmony_ci	 *     Save MFC_SR1 in the CSA.
21662306a36Sopenharmony_ci	 */
21762306a36Sopenharmony_ci	csa->priv1.mfc_sr1_RW = spu_mfc_sr1_get(spu);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic inline void save_spu_status(struct spu_state *csa, struct spu *spu)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* Save, Step 11:
22562306a36Sopenharmony_ci	 *     Read SPU_Status[R], and save to CSA.
22662306a36Sopenharmony_ci	 */
22762306a36Sopenharmony_ci	if ((in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) == 0) {
22862306a36Sopenharmony_ci		csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
22962306a36Sopenharmony_ci	} else {
23062306a36Sopenharmony_ci		u32 stopped;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
23362306a36Sopenharmony_ci		eieio();
23462306a36Sopenharmony_ci		POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
23562306a36Sopenharmony_ci				SPU_STATUS_RUNNING);
23662306a36Sopenharmony_ci		stopped =
23762306a36Sopenharmony_ci		    SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP |
23862306a36Sopenharmony_ci		    SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
23962306a36Sopenharmony_ci		if ((in_be32(&prob->spu_status_R) & stopped) == 0)
24062306a36Sopenharmony_ci			csa->prob.spu_status_R = SPU_STATUS_RUNNING;
24162306a36Sopenharmony_ci		else
24262306a36Sopenharmony_ci			csa->prob.spu_status_R = in_be32(&prob->spu_status_R);
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic inline void save_mfc_stopped_status(struct spu_state *csa,
24762306a36Sopenharmony_ci		struct spu *spu)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
25062306a36Sopenharmony_ci	const u64 mask = MFC_CNTL_DECREMENTER_RUNNING |
25162306a36Sopenharmony_ci			MFC_CNTL_DMA_QUEUES_EMPTY;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Save, Step 12:
25462306a36Sopenharmony_ci	 *     Read MFC_CNTL[Ds].  Update saved copy of
25562306a36Sopenharmony_ci	 *     CSA.MFC_CNTL[Ds].
25662306a36Sopenharmony_ci	 *
25762306a36Sopenharmony_ci	 * update: do the same with MFC_CNTL[Q].
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci	csa->priv2.mfc_control_RW &= ~mask;
26062306a36Sopenharmony_ci	csa->priv2.mfc_control_RW |= in_be64(&priv2->mfc_control_RW) & mask;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/* Save, Step 13:
26862306a36Sopenharmony_ci	 *     Write MFC_CNTL[Dh] set to a '1' to halt
26962306a36Sopenharmony_ci	 *     the decrementer.
27062306a36Sopenharmony_ci	 */
27162306a36Sopenharmony_ci	out_be64(&priv2->mfc_control_RW,
27262306a36Sopenharmony_ci		 MFC_CNTL_DECREMENTER_HALTED | MFC_CNTL_SUSPEND_MASK);
27362306a36Sopenharmony_ci	eieio();
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic inline void save_timebase(struct spu_state *csa, struct spu *spu)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	/* Save, Step 14:
27962306a36Sopenharmony_ci	 *    Read PPE Timebase High and Timebase low registers
28062306a36Sopenharmony_ci	 *    and save in CSA.  TBD.
28162306a36Sopenharmony_ci	 */
28262306a36Sopenharmony_ci	csa->suspend_time = get_cycles();
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic inline void remove_other_spu_access(struct spu_state *csa,
28662306a36Sopenharmony_ci					   struct spu *spu)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	/* Save, Step 15:
28962306a36Sopenharmony_ci	 *     Remove other SPU access to this SPU by unmapping
29062306a36Sopenharmony_ci	 *     this SPU's pages from their address space.  TBD.
29162306a36Sopenharmony_ci	 */
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic inline void do_mfc_mssync(struct spu_state *csa, struct spu *spu)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Save, Step 16:
29962306a36Sopenharmony_ci	 * Restore, Step 11.
30062306a36Sopenharmony_ci	 *     Write SPU_MSSync register. Poll SPU_MSSync[P]
30162306a36Sopenharmony_ci	 *     for a value of 0.
30262306a36Sopenharmony_ci	 */
30362306a36Sopenharmony_ci	out_be64(&prob->spc_mssync_RW, 1UL);
30462306a36Sopenharmony_ci	POLL_WHILE_TRUE(in_be64(&prob->spc_mssync_RW) & MS_SYNC_PENDING);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	/* Save, Step 17:
31062306a36Sopenharmony_ci	 * Restore, Step 12.
31162306a36Sopenharmony_ci	 * Restore, Step 48.
31262306a36Sopenharmony_ci	 *     Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register.
31362306a36Sopenharmony_ci	 *     Then issue a PPE sync instruction.
31462306a36Sopenharmony_ci	 */
31562306a36Sopenharmony_ci	spu_tlb_invalidate(spu);
31662306a36Sopenharmony_ci	mb();
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic inline void handle_pending_interrupts(struct spu_state *csa,
32062306a36Sopenharmony_ci					     struct spu *spu)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	/* Save, Step 18:
32362306a36Sopenharmony_ci	 *     Handle any pending interrupts from this SPU
32462306a36Sopenharmony_ci	 *     here.  This is OS or hypervisor specific.  One
32562306a36Sopenharmony_ci	 *     option is to re-enable interrupts to handle any
32662306a36Sopenharmony_ci	 *     pending interrupts, with the interrupt handlers
32762306a36Sopenharmony_ci	 *     recognizing the software Context Switch Pending
32862306a36Sopenharmony_ci	 *     flag, to ensure the SPU execution or MFC command
32962306a36Sopenharmony_ci	 *     queue is not restarted.  TBD.
33062306a36Sopenharmony_ci	 */
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic inline void save_mfc_queues(struct spu_state *csa, struct spu *spu)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
33662306a36Sopenharmony_ci	int i;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* Save, Step 19:
33962306a36Sopenharmony_ci	 *     If MFC_Cntl[Se]=0 then save
34062306a36Sopenharmony_ci	 *     MFC command queues.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if ((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DMA_QUEUES_EMPTY) == 0) {
34362306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
34462306a36Sopenharmony_ci			csa->priv2.puq[i].mfc_cq_data0_RW =
34562306a36Sopenharmony_ci			    in_be64(&priv2->puq[i].mfc_cq_data0_RW);
34662306a36Sopenharmony_ci			csa->priv2.puq[i].mfc_cq_data1_RW =
34762306a36Sopenharmony_ci			    in_be64(&priv2->puq[i].mfc_cq_data1_RW);
34862306a36Sopenharmony_ci			csa->priv2.puq[i].mfc_cq_data2_RW =
34962306a36Sopenharmony_ci			    in_be64(&priv2->puq[i].mfc_cq_data2_RW);
35062306a36Sopenharmony_ci			csa->priv2.puq[i].mfc_cq_data3_RW =
35162306a36Sopenharmony_ci			    in_be64(&priv2->puq[i].mfc_cq_data3_RW);
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci		for (i = 0; i < 16; i++) {
35462306a36Sopenharmony_ci			csa->priv2.spuq[i].mfc_cq_data0_RW =
35562306a36Sopenharmony_ci			    in_be64(&priv2->spuq[i].mfc_cq_data0_RW);
35662306a36Sopenharmony_ci			csa->priv2.spuq[i].mfc_cq_data1_RW =
35762306a36Sopenharmony_ci			    in_be64(&priv2->spuq[i].mfc_cq_data1_RW);
35862306a36Sopenharmony_ci			csa->priv2.spuq[i].mfc_cq_data2_RW =
35962306a36Sopenharmony_ci			    in_be64(&priv2->spuq[i].mfc_cq_data2_RW);
36062306a36Sopenharmony_ci			csa->priv2.spuq[i].mfc_cq_data3_RW =
36162306a36Sopenharmony_ci			    in_be64(&priv2->spuq[i].mfc_cq_data3_RW);
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic inline void save_ppu_querymask(struct spu_state *csa, struct spu *spu)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Save, Step 20:
37162306a36Sopenharmony_ci	 *     Save the PPU_QueryMask register
37262306a36Sopenharmony_ci	 *     in the CSA.
37362306a36Sopenharmony_ci	 */
37462306a36Sopenharmony_ci	csa->prob.dma_querymask_RW = in_be32(&prob->dma_querymask_RW);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* Save, Step 21:
38262306a36Sopenharmony_ci	 *     Save the PPU_QueryType register
38362306a36Sopenharmony_ci	 *     in the CSA.
38462306a36Sopenharmony_ci	 */
38562306a36Sopenharmony_ci	csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic inline void save_ppu_tagstatus(struct spu_state *csa, struct spu *spu)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* Save the Prxy_TagStatus register in the CSA.
39362306a36Sopenharmony_ci	 *
39462306a36Sopenharmony_ci	 * It is unnecessary to restore dma_tagstatus_R, however,
39562306a36Sopenharmony_ci	 * dma_tagstatus_R in the CSA is accessed via backing_ops, so
39662306a36Sopenharmony_ci	 * we must save it.
39762306a36Sopenharmony_ci	 */
39862306a36Sopenharmony_ci	csa->prob.dma_tagstatus_R = in_be32(&prob->dma_tagstatus_R);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* Save, Step 22:
40662306a36Sopenharmony_ci	 *     Save the MFC_CSR_TSQ register
40762306a36Sopenharmony_ci	 *     in the LSCSA.
40862306a36Sopenharmony_ci	 */
40962306a36Sopenharmony_ci	csa->priv2.spu_tag_status_query_RW =
41062306a36Sopenharmony_ci	    in_be64(&priv2->spu_tag_status_query_RW);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic inline void save_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Save, Step 23:
41862306a36Sopenharmony_ci	 *     Save the MFC_CSR_CMD1 and MFC_CSR_CMD2
41962306a36Sopenharmony_ci	 *     registers in the CSA.
42062306a36Sopenharmony_ci	 */
42162306a36Sopenharmony_ci	csa->priv2.spu_cmd_buf1_RW = in_be64(&priv2->spu_cmd_buf1_RW);
42262306a36Sopenharmony_ci	csa->priv2.spu_cmd_buf2_RW = in_be64(&priv2->spu_cmd_buf2_RW);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic inline void save_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* Save, Step 24:
43062306a36Sopenharmony_ci	 *     Save the MFC_CSR_ATO register in
43162306a36Sopenharmony_ci	 *     the CSA.
43262306a36Sopenharmony_ci	 */
43362306a36Sopenharmony_ci	csa->priv2.spu_atomic_status_RW = in_be64(&priv2->spu_atomic_status_RW);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	/* Save, Step 25:
43962306a36Sopenharmony_ci	 *     Save the MFC_TCLASS_ID register in
44062306a36Sopenharmony_ci	 *     the CSA.
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	csa->priv1.mfc_tclass_id_RW = spu_mfc_tclass_id_get(spu);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	/* Save, Step 26:
44862306a36Sopenharmony_ci	 * Restore, Step 23.
44962306a36Sopenharmony_ci	 *     Write the MFC_TCLASS_ID register with
45062306a36Sopenharmony_ci	 *     the value 0x10000000.
45162306a36Sopenharmony_ci	 */
45262306a36Sopenharmony_ci	spu_mfc_tclass_id_set(spu, 0x10000000);
45362306a36Sopenharmony_ci	eieio();
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic inline void purge_mfc_queue(struct spu_state *csa, struct spu *spu)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* Save, Step 27:
46162306a36Sopenharmony_ci	 * Restore, Step 14.
46262306a36Sopenharmony_ci	 *     Write MFC_CNTL[Pc]=1 (purge queue).
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci	out_be64(&priv2->mfc_control_RW,
46562306a36Sopenharmony_ci			MFC_CNTL_PURGE_DMA_REQUEST |
46662306a36Sopenharmony_ci			MFC_CNTL_SUSPEND_MASK);
46762306a36Sopenharmony_ci	eieio();
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic inline void wait_purge_complete(struct spu_state *csa, struct spu *spu)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/* Save, Step 28:
47562306a36Sopenharmony_ci	 *     Poll MFC_CNTL[Ps] until value '11' is read
47662306a36Sopenharmony_ci	 *     (purge complete).
47762306a36Sopenharmony_ci	 */
47862306a36Sopenharmony_ci	POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
47962306a36Sopenharmony_ci			 MFC_CNTL_PURGE_DMA_STATUS_MASK) ==
48062306a36Sopenharmony_ci			 MFC_CNTL_PURGE_DMA_COMPLETE);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	/* Save, Step 30:
48662306a36Sopenharmony_ci	 * Restore, Step 18:
48762306a36Sopenharmony_ci	 *     Write MFC_SR1 with MFC_SR1[D=0,S=1] and
48862306a36Sopenharmony_ci	 *     MFC_SR1[TL,R,Pr,T] set correctly for the
48962306a36Sopenharmony_ci	 *     OS specific environment.
49062306a36Sopenharmony_ci	 *
49162306a36Sopenharmony_ci	 *     Implementation note: The SPU-side code
49262306a36Sopenharmony_ci	 *     for save/restore is privileged, so the
49362306a36Sopenharmony_ci	 *     MFC_SR1[Pr] bit is not set.
49462306a36Sopenharmony_ci	 *
49562306a36Sopenharmony_ci	 */
49662306a36Sopenharmony_ci	spu_mfc_sr1_set(spu, (MFC_STATE1_MASTER_RUN_CONTROL_MASK |
49762306a36Sopenharmony_ci			      MFC_STATE1_RELOCATE_MASK |
49862306a36Sopenharmony_ci			      MFC_STATE1_BUS_TLBIE_MASK));
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic inline void save_spu_npc(struct spu_state *csa, struct spu *spu)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* Save, Step 31:
50662306a36Sopenharmony_ci	 *     Save SPU_NPC in the CSA.
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	csa->prob.spu_npc_RW = in_be32(&prob->spu_npc_RW);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic inline void save_spu_privcntl(struct spu_state *csa, struct spu *spu)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* Save, Step 32:
51662306a36Sopenharmony_ci	 *     Save SPU_PrivCntl in the CSA.
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	csa->priv2.spu_privcntl_RW = in_be64(&priv2->spu_privcntl_RW);
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic inline void reset_spu_privcntl(struct spu_state *csa, struct spu *spu)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* Save, Step 33:
52662306a36Sopenharmony_ci	 * Restore, Step 16:
52762306a36Sopenharmony_ci	 *     Write SPU_PrivCntl[S,Le,A] fields reset to 0.
52862306a36Sopenharmony_ci	 */
52962306a36Sopenharmony_ci	out_be64(&priv2->spu_privcntl_RW, 0UL);
53062306a36Sopenharmony_ci	eieio();
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic inline void save_spu_lslr(struct spu_state *csa, struct spu *spu)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* Save, Step 34:
53862306a36Sopenharmony_ci	 *     Save SPU_LSLR in the CSA.
53962306a36Sopenharmony_ci	 */
54062306a36Sopenharmony_ci	csa->priv2.spu_lslr_RW = in_be64(&priv2->spu_lslr_RW);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic inline void reset_spu_lslr(struct spu_state *csa, struct spu *spu)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* Save, Step 35:
54862306a36Sopenharmony_ci	 * Restore, Step 17.
54962306a36Sopenharmony_ci	 *     Reset SPU_LSLR.
55062306a36Sopenharmony_ci	 */
55162306a36Sopenharmony_ci	out_be64(&priv2->spu_lslr_RW, LS_ADDR_MASK);
55262306a36Sopenharmony_ci	eieio();
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic inline void save_spu_cfg(struct spu_state *csa, struct spu *spu)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* Save, Step 36:
56062306a36Sopenharmony_ci	 *     Save SPU_Cfg in the CSA.
56162306a36Sopenharmony_ci	 */
56262306a36Sopenharmony_ci	csa->priv2.spu_cfg_RW = in_be64(&priv2->spu_cfg_RW);
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic inline void save_pm_trace(struct spu_state *csa, struct spu *spu)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	/* Save, Step 37:
56862306a36Sopenharmony_ci	 *     Save PM_Trace_Tag_Wait_Mask in the CSA.
56962306a36Sopenharmony_ci	 *     Not performed by this implementation.
57062306a36Sopenharmony_ci	 */
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic inline void save_mfc_rag(struct spu_state *csa, struct spu *spu)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	/* Save, Step 38:
57662306a36Sopenharmony_ci	 *     Save RA_GROUP_ID register and the
57762306a36Sopenharmony_ci	 *     RA_ENABLE reigster in the CSA.
57862306a36Sopenharmony_ci	 */
57962306a36Sopenharmony_ci	csa->priv1.resource_allocation_groupID_RW =
58062306a36Sopenharmony_ci		spu_resource_allocation_groupID_get(spu);
58162306a36Sopenharmony_ci	csa->priv1.resource_allocation_enable_RW =
58262306a36Sopenharmony_ci		spu_resource_allocation_enable_get(spu);
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/* Save, Step 39:
59062306a36Sopenharmony_ci	 *     Save MB_Stat register in the CSA.
59162306a36Sopenharmony_ci	 */
59262306a36Sopenharmony_ci	csa->prob.mb_stat_R = in_be32(&prob->mb_stat_R);
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic inline void save_ppu_mb(struct spu_state *csa, struct spu *spu)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* Save, Step 40:
60062306a36Sopenharmony_ci	 *     Save the PPU_MB register in the CSA.
60162306a36Sopenharmony_ci	 */
60262306a36Sopenharmony_ci	csa->prob.pu_mb_R = in_be32(&prob->pu_mb_R);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Save, Step 41:
61062306a36Sopenharmony_ci	 *     Save the PPUINT_MB register in the CSA.
61162306a36Sopenharmony_ci	 */
61262306a36Sopenharmony_ci	csa->priv2.puint_mb_R = in_be64(&priv2->puint_mb_R);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
61862306a36Sopenharmony_ci	u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
61962306a36Sopenharmony_ci	int i;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* Save, Step 42:
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	/* Save CH 1, without channel count */
62562306a36Sopenharmony_ci	out_be64(&priv2->spu_chnlcntptr_RW, 1);
62662306a36Sopenharmony_ci	csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Save the following CH: [0,3,4,24,25,27] */
62962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
63062306a36Sopenharmony_ci		idx = ch_indices[i];
63162306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcntptr_RW, idx);
63262306a36Sopenharmony_ci		eieio();
63362306a36Sopenharmony_ci		csa->spu_chnldata_RW[idx] = in_be64(&priv2->spu_chnldata_RW);
63462306a36Sopenharmony_ci		csa->spu_chnlcnt_RW[idx] = in_be64(&priv2->spu_chnlcnt_RW);
63562306a36Sopenharmony_ci		out_be64(&priv2->spu_chnldata_RW, 0UL);
63662306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcnt_RW, 0UL);
63762306a36Sopenharmony_ci		eieio();
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic inline void save_spu_mb(struct spu_state *csa, struct spu *spu)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
64462306a36Sopenharmony_ci	int i;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* Save, Step 43:
64762306a36Sopenharmony_ci	 *     Save SPU Read Mailbox Channel.
64862306a36Sopenharmony_ci	 */
64962306a36Sopenharmony_ci	out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
65062306a36Sopenharmony_ci	eieio();
65162306a36Sopenharmony_ci	csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW);
65262306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
65362306a36Sopenharmony_ci		csa->spu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW);
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci	out_be64(&priv2->spu_chnlcnt_RW, 0UL);
65662306a36Sopenharmony_ci	eieio();
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic inline void save_mfc_cmd(struct spu_state *csa, struct spu *spu)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* Save, Step 44:
66462306a36Sopenharmony_ci	 *     Save MFC_CMD Channel.
66562306a36Sopenharmony_ci	 */
66662306a36Sopenharmony_ci	out_be64(&priv2->spu_chnlcntptr_RW, 21UL);
66762306a36Sopenharmony_ci	eieio();
66862306a36Sopenharmony_ci	csa->spu_chnlcnt_RW[21] = in_be64(&priv2->spu_chnlcnt_RW);
66962306a36Sopenharmony_ci	eieio();
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic inline void reset_ch(struct spu_state *csa, struct spu *spu)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
67562306a36Sopenharmony_ci	u64 ch_indices[4] = { 21UL, 23UL, 28UL, 30UL };
67662306a36Sopenharmony_ci	u64 ch_counts[4] = { 16UL, 1UL, 1UL, 1UL };
67762306a36Sopenharmony_ci	u64 idx;
67862306a36Sopenharmony_ci	int i;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* Save, Step 45:
68162306a36Sopenharmony_ci	 *     Reset the following CH: [21, 23, 28, 30]
68262306a36Sopenharmony_ci	 */
68362306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
68462306a36Sopenharmony_ci		idx = ch_indices[i];
68562306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcntptr_RW, idx);
68662306a36Sopenharmony_ci		eieio();
68762306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
68862306a36Sopenharmony_ci		eieio();
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* Save, Step 46:
69762306a36Sopenharmony_ci	 * Restore, Step 25.
69862306a36Sopenharmony_ci	 *     Write MFC_CNTL[Sc]=0 (resume queue processing).
69962306a36Sopenharmony_ci	 */
70062306a36Sopenharmony_ci	out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE);
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu,
70462306a36Sopenharmony_ci		unsigned int *code, int code_size)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	/* Save, Step 47:
70762306a36Sopenharmony_ci	 * Restore, Step 30.
70862306a36Sopenharmony_ci	 *     If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All
70962306a36Sopenharmony_ci	 *     register, then initialize SLB_VSID and SLB_ESID
71062306a36Sopenharmony_ci	 *     to provide access to SPU context save code and
71162306a36Sopenharmony_ci	 *     LSCSA.
71262306a36Sopenharmony_ci	 *
71362306a36Sopenharmony_ci	 *     This implementation places both the context
71462306a36Sopenharmony_ci	 *     switch code and LSCSA in kernel address space.
71562306a36Sopenharmony_ci	 *
71662306a36Sopenharmony_ci	 *     Further this implementation assumes that the
71762306a36Sopenharmony_ci	 *     MFC_SR1[R]=1 (in other words, assume that
71862306a36Sopenharmony_ci	 *     translation is desired by OS environment).
71962306a36Sopenharmony_ci	 */
72062306a36Sopenharmony_ci	spu_invalidate_slbs(spu);
72162306a36Sopenharmony_ci	spu_setup_kernel_slbs(spu, csa->lscsa, code, code_size);
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic inline void set_switch_active(struct spu_state *csa, struct spu *spu)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	/* Save, Step 48:
72762306a36Sopenharmony_ci	 * Restore, Step 23.
72862306a36Sopenharmony_ci	 *     Change the software context switch pending flag
72962306a36Sopenharmony_ci	 *     to context switch active.  This implementation does
73062306a36Sopenharmony_ci	 *     not uses a switch active flag.
73162306a36Sopenharmony_ci	 *
73262306a36Sopenharmony_ci	 * Now that we have saved the mfc in the csa, we can add in the
73362306a36Sopenharmony_ci	 * restart command if an exception occurred.
73462306a36Sopenharmony_ci	 */
73562306a36Sopenharmony_ci	if (test_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags))
73662306a36Sopenharmony_ci		csa->priv2.mfc_control_RW |= MFC_CNTL_RESTART_DMA_COMMAND;
73762306a36Sopenharmony_ci	clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
73862306a36Sopenharmony_ci	mb();
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic inline void enable_interrupts(struct spu_state *csa, struct spu *spu)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
74462306a36Sopenharmony_ci	    CLASS1_ENABLE_STORAGE_FAULT_INTR;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* Save, Step 49:
74762306a36Sopenharmony_ci	 * Restore, Step 22:
74862306a36Sopenharmony_ci	 *     Reset and then enable interrupts, as
74962306a36Sopenharmony_ci	 *     needed by OS.
75062306a36Sopenharmony_ci	 *
75162306a36Sopenharmony_ci	 *     This implementation enables only class1
75262306a36Sopenharmony_ci	 *     (translation) interrupts.
75362306a36Sopenharmony_ci	 */
75462306a36Sopenharmony_ci	spin_lock_irq(&spu->register_lock);
75562306a36Sopenharmony_ci	spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
75662306a36Sopenharmony_ci	spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK);
75762306a36Sopenharmony_ci	spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
75862306a36Sopenharmony_ci	spu_int_mask_set(spu, 0, 0ul);
75962306a36Sopenharmony_ci	spu_int_mask_set(spu, 1, class1_mask);
76062306a36Sopenharmony_ci	spu_int_mask_set(spu, 2, 0ul);
76162306a36Sopenharmony_ci	spin_unlock_irq(&spu->register_lock);
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic inline int send_mfc_dma(struct spu *spu, unsigned long ea,
76562306a36Sopenharmony_ci			       unsigned int ls_offset, unsigned int size,
76662306a36Sopenharmony_ci			       unsigned int tag, unsigned int rclass,
76762306a36Sopenharmony_ci			       unsigned int cmd)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
77062306a36Sopenharmony_ci	union mfc_tag_size_class_cmd command;
77162306a36Sopenharmony_ci	unsigned int transfer_size;
77262306a36Sopenharmony_ci	volatile unsigned int status = 0x0;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	while (size > 0) {
77562306a36Sopenharmony_ci		transfer_size =
77662306a36Sopenharmony_ci		    (size > MFC_MAX_DMA_SIZE) ? MFC_MAX_DMA_SIZE : size;
77762306a36Sopenharmony_ci		command.u.mfc_size = transfer_size;
77862306a36Sopenharmony_ci		command.u.mfc_tag = tag;
77962306a36Sopenharmony_ci		command.u.mfc_rclassid = rclass;
78062306a36Sopenharmony_ci		command.u.mfc_cmd = cmd;
78162306a36Sopenharmony_ci		do {
78262306a36Sopenharmony_ci			out_be32(&prob->mfc_lsa_W, ls_offset);
78362306a36Sopenharmony_ci			out_be64(&prob->mfc_ea_W, ea);
78462306a36Sopenharmony_ci			out_be64(&prob->mfc_union_W.all64, command.all64);
78562306a36Sopenharmony_ci			status =
78662306a36Sopenharmony_ci			    in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
78762306a36Sopenharmony_ci			if (unlikely(status & 0x2)) {
78862306a36Sopenharmony_ci				cpu_relax();
78962306a36Sopenharmony_ci			}
79062306a36Sopenharmony_ci		} while (status & 0x3);
79162306a36Sopenharmony_ci		size -= transfer_size;
79262306a36Sopenharmony_ci		ea += transfer_size;
79362306a36Sopenharmony_ci		ls_offset += transfer_size;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci	return 0;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic inline void save_ls_16kb(struct spu_state *csa, struct spu *spu)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
80162306a36Sopenharmony_ci	unsigned int ls_offset = 0x0;
80262306a36Sopenharmony_ci	unsigned int size = 16384;
80362306a36Sopenharmony_ci	unsigned int tag = 0;
80462306a36Sopenharmony_ci	unsigned int rclass = 0;
80562306a36Sopenharmony_ci	unsigned int cmd = MFC_PUT_CMD;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* Save, Step 50:
80862306a36Sopenharmony_ci	 *     Issue a DMA command to copy the first 16K bytes
80962306a36Sopenharmony_ci	 *     of local storage to the CSA.
81062306a36Sopenharmony_ci	 */
81162306a36Sopenharmony_ci	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic inline void set_spu_npc(struct spu_state *csa, struct spu *spu)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	/* Save, Step 51:
81962306a36Sopenharmony_ci	 * Restore, Step 31.
82062306a36Sopenharmony_ci	 *     Write SPU_NPC[IE]=0 and SPU_NPC[LSA] to entry
82162306a36Sopenharmony_ci	 *     point address of context save code in local
82262306a36Sopenharmony_ci	 *     storage.
82362306a36Sopenharmony_ci	 *
82462306a36Sopenharmony_ci	 *     This implementation uses SPU-side save/restore
82562306a36Sopenharmony_ci	 *     programs with entry points at LSA of 0.
82662306a36Sopenharmony_ci	 */
82762306a36Sopenharmony_ci	out_be32(&prob->spu_npc_RW, 0);
82862306a36Sopenharmony_ci	eieio();
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_cistatic inline void set_signot1(struct spu_state *csa, struct spu *spu)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
83462306a36Sopenharmony_ci	union {
83562306a36Sopenharmony_ci		u64 ull;
83662306a36Sopenharmony_ci		u32 ui[2];
83762306a36Sopenharmony_ci	} addr64;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/* Save, Step 52:
84062306a36Sopenharmony_ci	 * Restore, Step 32:
84162306a36Sopenharmony_ci	 *    Write SPU_Sig_Notify_1 register with upper 32-bits
84262306a36Sopenharmony_ci	 *    of the CSA.LSCSA effective address.
84362306a36Sopenharmony_ci	 */
84462306a36Sopenharmony_ci	addr64.ull = (u64) csa->lscsa;
84562306a36Sopenharmony_ci	out_be32(&prob->signal_notify1, addr64.ui[0]);
84662306a36Sopenharmony_ci	eieio();
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cistatic inline void set_signot2(struct spu_state *csa, struct spu *spu)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
85262306a36Sopenharmony_ci	union {
85362306a36Sopenharmony_ci		u64 ull;
85462306a36Sopenharmony_ci		u32 ui[2];
85562306a36Sopenharmony_ci	} addr64;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	/* Save, Step 53:
85862306a36Sopenharmony_ci	 * Restore, Step 33:
85962306a36Sopenharmony_ci	 *    Write SPU_Sig_Notify_2 register with lower 32-bits
86062306a36Sopenharmony_ci	 *    of the CSA.LSCSA effective address.
86162306a36Sopenharmony_ci	 */
86262306a36Sopenharmony_ci	addr64.ull = (u64) csa->lscsa;
86362306a36Sopenharmony_ci	out_be32(&prob->signal_notify2, addr64.ui[1]);
86462306a36Sopenharmony_ci	eieio();
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic inline void send_save_code(struct spu_state *csa, struct spu *spu)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	unsigned long addr = (unsigned long)&spu_save_code[0];
87062306a36Sopenharmony_ci	unsigned int ls_offset = 0x0;
87162306a36Sopenharmony_ci	unsigned int size = sizeof(spu_save_code);
87262306a36Sopenharmony_ci	unsigned int tag = 0;
87362306a36Sopenharmony_ci	unsigned int rclass = 0;
87462306a36Sopenharmony_ci	unsigned int cmd = MFC_GETFS_CMD;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* Save, Step 54:
87762306a36Sopenharmony_ci	 *     Issue a DMA command to copy context save code
87862306a36Sopenharmony_ci	 *     to local storage and start SPU.
87962306a36Sopenharmony_ci	 */
88062306a36Sopenharmony_ci	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Save, Step 55:
88862306a36Sopenharmony_ci	 * Restore, Step 38.
88962306a36Sopenharmony_ci	 *     Write PPU_QueryMask=1 (enable Tag Group 0)
89062306a36Sopenharmony_ci	 *     and issue eieio instruction.
89162306a36Sopenharmony_ci	 */
89262306a36Sopenharmony_ci	out_be32(&prob->dma_querymask_RW, MFC_TAGID_TO_TAGMASK(0));
89362306a36Sopenharmony_ci	eieio();
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic inline void wait_tag_complete(struct spu_state *csa, struct spu *spu)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
89962306a36Sopenharmony_ci	u32 mask = MFC_TAGID_TO_TAGMASK(0);
90062306a36Sopenharmony_ci	unsigned long flags;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	/* Save, Step 56:
90362306a36Sopenharmony_ci	 * Restore, Step 39.
90462306a36Sopenharmony_ci	 * Restore, Step 39.
90562306a36Sopenharmony_ci	 * Restore, Step 46.
90662306a36Sopenharmony_ci	 *     Poll PPU_TagStatus[gn] until 01 (Tag group 0 complete)
90762306a36Sopenharmony_ci	 *     or write PPU_QueryType[TS]=01 and wait for Tag Group
90862306a36Sopenharmony_ci	 *     Complete Interrupt.  Write INT_Stat_Class0 or
90962306a36Sopenharmony_ci	 *     INT_Stat_Class2 with value of 'handled'.
91062306a36Sopenharmony_ci	 */
91162306a36Sopenharmony_ci	POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	local_irq_save(flags);
91462306a36Sopenharmony_ci	spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
91562306a36Sopenharmony_ci	spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
91662306a36Sopenharmony_ci	local_irq_restore(flags);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
92262306a36Sopenharmony_ci	unsigned long flags;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	/* Save, Step 57:
92562306a36Sopenharmony_ci	 * Restore, Step 40.
92662306a36Sopenharmony_ci	 *     Poll until SPU_Status[R]=0 or wait for SPU Class 0
92762306a36Sopenharmony_ci	 *     or SPU Class 2 interrupt.  Write INT_Stat_class0
92862306a36Sopenharmony_ci	 *     or INT_Stat_class2 with value of handled.
92962306a36Sopenharmony_ci	 */
93062306a36Sopenharmony_ci	POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	local_irq_save(flags);
93362306a36Sopenharmony_ci	spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
93462306a36Sopenharmony_ci	spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
93562306a36Sopenharmony_ci	local_irq_restore(flags);
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic inline int check_save_status(struct spu_state *csa, struct spu *spu)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
94162306a36Sopenharmony_ci	u32 complete;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	/* Save, Step 54:
94462306a36Sopenharmony_ci	 *     If SPU_Status[P]=1 and SPU_Status[SC] = "success",
94562306a36Sopenharmony_ci	 *     context save succeeded, otherwise context save
94662306a36Sopenharmony_ci	 *     failed.
94762306a36Sopenharmony_ci	 */
94862306a36Sopenharmony_ci	complete = ((SPU_SAVE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
94962306a36Sopenharmony_ci		    SPU_STATUS_STOPPED_BY_STOP);
95062306a36Sopenharmony_ci	return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic inline void terminate_spu_app(struct spu_state *csa, struct spu *spu)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	/* Restore, Step 4:
95662306a36Sopenharmony_ci	 *    If required, notify the "using application" that
95762306a36Sopenharmony_ci	 *    the SPU task has been terminated.  TBD.
95862306a36Sopenharmony_ci	 */
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic inline void suspend_mfc_and_halt_decr(struct spu_state *csa,
96262306a36Sopenharmony_ci		struct spu *spu)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/* Restore, Step 7:
96762306a36Sopenharmony_ci	 *     Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend
96862306a36Sopenharmony_ci	 *     the queue and halt the decrementer.
96962306a36Sopenharmony_ci	 */
97062306a36Sopenharmony_ci	out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
97162306a36Sopenharmony_ci		 MFC_CNTL_DECREMENTER_HALTED);
97262306a36Sopenharmony_ci	eieio();
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic inline void wait_suspend_mfc_complete(struct spu_state *csa,
97662306a36Sopenharmony_ci					     struct spu *spu)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/* Restore, Step 8:
98162306a36Sopenharmony_ci	 * Restore, Step 47.
98262306a36Sopenharmony_ci	 *     Poll MFC_CNTL[Ss] until 11 is returned.
98362306a36Sopenharmony_ci	 */
98462306a36Sopenharmony_ci	POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
98562306a36Sopenharmony_ci			 MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
98662306a36Sopenharmony_ci			 MFC_CNTL_SUSPEND_COMPLETE);
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic inline int suspend_spe(struct spu_state *csa, struct spu *spu)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/* Restore, Step 9:
99462306a36Sopenharmony_ci	 *    If SPU_Status[R]=1, stop SPU execution
99562306a36Sopenharmony_ci	 *    and wait for stop to complete.
99662306a36Sopenharmony_ci	 *
99762306a36Sopenharmony_ci	 *    Returns       1 if SPU_Status[R]=1 on entry.
99862306a36Sopenharmony_ci	 *                  0 otherwise
99962306a36Sopenharmony_ci	 */
100062306a36Sopenharmony_ci	if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) {
100162306a36Sopenharmony_ci		if (in_be32(&prob->spu_status_R) &
100262306a36Sopenharmony_ci		    SPU_STATUS_ISOLATED_EXIT_STATUS) {
100362306a36Sopenharmony_ci			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
100462306a36Sopenharmony_ci					SPU_STATUS_RUNNING);
100562306a36Sopenharmony_ci		}
100662306a36Sopenharmony_ci		if ((in_be32(&prob->spu_status_R) &
100762306a36Sopenharmony_ci		     SPU_STATUS_ISOLATED_LOAD_STATUS)
100862306a36Sopenharmony_ci		    || (in_be32(&prob->spu_status_R) &
100962306a36Sopenharmony_ci			SPU_STATUS_ISOLATED_STATE)) {
101062306a36Sopenharmony_ci			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
101162306a36Sopenharmony_ci			eieio();
101262306a36Sopenharmony_ci			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
101362306a36Sopenharmony_ci					SPU_STATUS_RUNNING);
101462306a36Sopenharmony_ci			out_be32(&prob->spu_runcntl_RW, 0x2);
101562306a36Sopenharmony_ci			eieio();
101662306a36Sopenharmony_ci			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
101762306a36Sopenharmony_ci					SPU_STATUS_RUNNING);
101862306a36Sopenharmony_ci		}
101962306a36Sopenharmony_ci		if (in_be32(&prob->spu_status_R) &
102062306a36Sopenharmony_ci		    SPU_STATUS_WAITING_FOR_CHANNEL) {
102162306a36Sopenharmony_ci			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
102262306a36Sopenharmony_ci			eieio();
102362306a36Sopenharmony_ci			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
102462306a36Sopenharmony_ci					SPU_STATUS_RUNNING);
102562306a36Sopenharmony_ci		}
102662306a36Sopenharmony_ci		return 1;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci	return 0;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* Restore, Step 10:
103662306a36Sopenharmony_ci	 *    If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1,
103762306a36Sopenharmony_ci	 *    release SPU from isolate state.
103862306a36Sopenharmony_ci	 */
103962306a36Sopenharmony_ci	if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) {
104062306a36Sopenharmony_ci		if (in_be32(&prob->spu_status_R) &
104162306a36Sopenharmony_ci		    SPU_STATUS_ISOLATED_EXIT_STATUS) {
104262306a36Sopenharmony_ci			spu_mfc_sr1_set(spu,
104362306a36Sopenharmony_ci					MFC_STATE1_MASTER_RUN_CONTROL_MASK);
104462306a36Sopenharmony_ci			eieio();
104562306a36Sopenharmony_ci			out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
104662306a36Sopenharmony_ci			eieio();
104762306a36Sopenharmony_ci			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
104862306a36Sopenharmony_ci					SPU_STATUS_RUNNING);
104962306a36Sopenharmony_ci		}
105062306a36Sopenharmony_ci		if ((in_be32(&prob->spu_status_R) &
105162306a36Sopenharmony_ci		     SPU_STATUS_ISOLATED_LOAD_STATUS)
105262306a36Sopenharmony_ci		    || (in_be32(&prob->spu_status_R) &
105362306a36Sopenharmony_ci			SPU_STATUS_ISOLATED_STATE)) {
105462306a36Sopenharmony_ci			spu_mfc_sr1_set(spu,
105562306a36Sopenharmony_ci					MFC_STATE1_MASTER_RUN_CONTROL_MASK);
105662306a36Sopenharmony_ci			eieio();
105762306a36Sopenharmony_ci			out_be32(&prob->spu_runcntl_RW, 0x2);
105862306a36Sopenharmony_ci			eieio();
105962306a36Sopenharmony_ci			POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
106062306a36Sopenharmony_ci					SPU_STATUS_RUNNING);
106162306a36Sopenharmony_ci		}
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
106862306a36Sopenharmony_ci	u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
106962306a36Sopenharmony_ci	u64 idx;
107062306a36Sopenharmony_ci	int i;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/* Restore, Step 20:
107362306a36Sopenharmony_ci	 */
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* Reset CH 1 */
107662306a36Sopenharmony_ci	out_be64(&priv2->spu_chnlcntptr_RW, 1);
107762306a36Sopenharmony_ci	out_be64(&priv2->spu_chnldata_RW, 0UL);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	/* Reset the following CH: [0,3,4,24,25,27] */
108062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
108162306a36Sopenharmony_ci		idx = ch_indices[i];
108262306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcntptr_RW, idx);
108362306a36Sopenharmony_ci		eieio();
108462306a36Sopenharmony_ci		out_be64(&priv2->spu_chnldata_RW, 0UL);
108562306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcnt_RW, 0UL);
108662306a36Sopenharmony_ci		eieio();
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_cistatic inline void reset_ch_part2(struct spu_state *csa, struct spu *spu)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
109362306a36Sopenharmony_ci	u64 ch_indices[5] = { 21UL, 23UL, 28UL, 29UL, 30UL };
109462306a36Sopenharmony_ci	u64 ch_counts[5] = { 16UL, 1UL, 1UL, 0UL, 1UL };
109562306a36Sopenharmony_ci	u64 idx;
109662306a36Sopenharmony_ci	int i;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	/* Restore, Step 21:
109962306a36Sopenharmony_ci	 *     Reset the following CH: [21, 23, 28, 29, 30]
110062306a36Sopenharmony_ci	 */
110162306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
110262306a36Sopenharmony_ci		idx = ch_indices[i];
110362306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcntptr_RW, idx);
110462306a36Sopenharmony_ci		eieio();
110562306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
110662306a36Sopenharmony_ci		eieio();
110762306a36Sopenharmony_ci	}
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic inline void setup_spu_status_part1(struct spu_state *csa,
111162306a36Sopenharmony_ci					  struct spu *spu)
111262306a36Sopenharmony_ci{
111362306a36Sopenharmony_ci	u32 status_P = SPU_STATUS_STOPPED_BY_STOP;
111462306a36Sopenharmony_ci	u32 status_I = SPU_STATUS_INVALID_INSTR;
111562306a36Sopenharmony_ci	u32 status_H = SPU_STATUS_STOPPED_BY_HALT;
111662306a36Sopenharmony_ci	u32 status_S = SPU_STATUS_SINGLE_STEP;
111762306a36Sopenharmony_ci	u32 status_S_I = SPU_STATUS_SINGLE_STEP | SPU_STATUS_INVALID_INSTR;
111862306a36Sopenharmony_ci	u32 status_S_P = SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_STOP;
111962306a36Sopenharmony_ci	u32 status_P_H = SPU_STATUS_STOPPED_BY_HALT |SPU_STATUS_STOPPED_BY_STOP;
112062306a36Sopenharmony_ci	u32 status_P_I = SPU_STATUS_STOPPED_BY_STOP |SPU_STATUS_INVALID_INSTR;
112162306a36Sopenharmony_ci	u32 status_code;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	/* Restore, Step 27:
112462306a36Sopenharmony_ci	 *     If the CSA.SPU_Status[I,S,H,P]=1 then add the correct
112562306a36Sopenharmony_ci	 *     instruction sequence to the end of the SPU based restore
112662306a36Sopenharmony_ci	 *     code (after the "context restored" stop and signal) to
112762306a36Sopenharmony_ci	 *     restore the correct SPU status.
112862306a36Sopenharmony_ci	 *
112962306a36Sopenharmony_ci	 *     NOTE: Rather than modifying the SPU executable, we
113062306a36Sopenharmony_ci	 *     instead add a new 'stopped_status' field to the
113162306a36Sopenharmony_ci	 *     LSCSA.  The SPU-side restore reads this field and
113262306a36Sopenharmony_ci	 *     takes the appropriate action when exiting.
113362306a36Sopenharmony_ci	 */
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	status_code =
113662306a36Sopenharmony_ci	    (csa->prob.spu_status_R >> SPU_STOP_STATUS_SHIFT) & 0xFFFF;
113762306a36Sopenharmony_ci	if ((csa->prob.spu_status_R & status_P_I) == status_P_I) {
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		/* SPU_Status[P,I]=1 - Illegal Instruction followed
114062306a36Sopenharmony_ci		 * by Stop and Signal instruction, followed by 'br -4'.
114162306a36Sopenharmony_ci		 *
114262306a36Sopenharmony_ci		 */
114362306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_I;
114462306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[1] = status_code;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	} else if ((csa->prob.spu_status_R & status_P_H) == status_P_H) {
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci		/* SPU_Status[P,H]=1 - Halt Conditional, followed
114962306a36Sopenharmony_ci		 * by Stop and Signal instruction, followed by
115062306a36Sopenharmony_ci		 * 'br -4'.
115162306a36Sopenharmony_ci		 */
115262306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_H;
115362306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[1] = status_code;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	} else if ((csa->prob.spu_status_R & status_S_P) == status_S_P) {
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		/* SPU_Status[S,P]=1 - Stop and Signal instruction
115862306a36Sopenharmony_ci		 * followed by 'br -4'.
115962306a36Sopenharmony_ci		 */
116062306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_P;
116162306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[1] = status_code;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	} else if ((csa->prob.spu_status_R & status_S_I) == status_S_I) {
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		/* SPU_Status[S,I]=1 - Illegal instruction followed
116662306a36Sopenharmony_ci		 * by 'br -4'.
116762306a36Sopenharmony_ci		 */
116862306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_I;
116962306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[1] = status_code;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	} else if ((csa->prob.spu_status_R & status_P) == status_P) {
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci		/* SPU_Status[P]=1 - Stop and Signal instruction
117462306a36Sopenharmony_ci		 * followed by 'br -4'.
117562306a36Sopenharmony_ci		 */
117662306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P;
117762306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[1] = status_code;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	} else if ((csa->prob.spu_status_R & status_H) == status_H) {
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci		/* SPU_Status[H]=1 - Halt Conditional, followed
118262306a36Sopenharmony_ci		 * by 'br -4'.
118362306a36Sopenharmony_ci		 */
118462306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_H;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	} else if ((csa->prob.spu_status_R & status_S) == status_S) {
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci		/* SPU_Status[S]=1 - Two nop instructions.
118962306a36Sopenharmony_ci		 */
119062306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	} else if ((csa->prob.spu_status_R & status_I) == status_I) {
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		/* SPU_Status[I]=1 - Illegal instruction followed
119562306a36Sopenharmony_ci		 * by 'br -4'.
119662306a36Sopenharmony_ci		 */
119762306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_I;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic inline void setup_spu_status_part2(struct spu_state *csa,
120362306a36Sopenharmony_ci					  struct spu *spu)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	u32 mask;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	/* Restore, Step 28:
120862306a36Sopenharmony_ci	 *     If the CSA.SPU_Status[I,S,H,P,R]=0 then
120962306a36Sopenharmony_ci	 *     add a 'br *' instruction to the end of
121062306a36Sopenharmony_ci	 *     the SPU based restore code.
121162306a36Sopenharmony_ci	 *
121262306a36Sopenharmony_ci	 *     NOTE: Rather than modifying the SPU executable, we
121362306a36Sopenharmony_ci	 *     instead add a new 'stopped_status' field to the
121462306a36Sopenharmony_ci	 *     LSCSA.  The SPU-side restore reads this field and
121562306a36Sopenharmony_ci	 *     takes the appropriate action when exiting.
121662306a36Sopenharmony_ci	 */
121762306a36Sopenharmony_ci	mask = SPU_STATUS_INVALID_INSTR |
121862306a36Sopenharmony_ci	    SPU_STATUS_SINGLE_STEP |
121962306a36Sopenharmony_ci	    SPU_STATUS_STOPPED_BY_HALT |
122062306a36Sopenharmony_ci	    SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
122162306a36Sopenharmony_ci	if (!(csa->prob.spu_status_R & mask)) {
122262306a36Sopenharmony_ci		csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_R;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_cistatic inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	/* Restore, Step 29:
122962306a36Sopenharmony_ci	 *     Restore RA_GROUP_ID register and the
123062306a36Sopenharmony_ci	 *     RA_ENABLE reigster from the CSA.
123162306a36Sopenharmony_ci	 */
123262306a36Sopenharmony_ci	spu_resource_allocation_groupID_set(spu,
123362306a36Sopenharmony_ci			csa->priv1.resource_allocation_groupID_RW);
123462306a36Sopenharmony_ci	spu_resource_allocation_enable_set(spu,
123562306a36Sopenharmony_ci			csa->priv1.resource_allocation_enable_RW);
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic inline void send_restore_code(struct spu_state *csa, struct spu *spu)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	unsigned long addr = (unsigned long)&spu_restore_code[0];
124162306a36Sopenharmony_ci	unsigned int ls_offset = 0x0;
124262306a36Sopenharmony_ci	unsigned int size = sizeof(spu_restore_code);
124362306a36Sopenharmony_ci	unsigned int tag = 0;
124462306a36Sopenharmony_ci	unsigned int rclass = 0;
124562306a36Sopenharmony_ci	unsigned int cmd = MFC_GETFS_CMD;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	/* Restore, Step 37:
124862306a36Sopenharmony_ci	 *     Issue MFC DMA command to copy context
124962306a36Sopenharmony_ci	 *     restore code to local storage.
125062306a36Sopenharmony_ci	 */
125162306a36Sopenharmony_ci	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic inline void setup_decr(struct spu_state *csa, struct spu *spu)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	/* Restore, Step 34:
125762306a36Sopenharmony_ci	 *     If CSA.MFC_CNTL[Ds]=1 (decrementer was
125862306a36Sopenharmony_ci	 *     running) then adjust decrementer, set
125962306a36Sopenharmony_ci	 *     decrementer running status in LSCSA,
126062306a36Sopenharmony_ci	 *     and set decrementer "wrapped" status
126162306a36Sopenharmony_ci	 *     in LSCSA.
126262306a36Sopenharmony_ci	 */
126362306a36Sopenharmony_ci	if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
126462306a36Sopenharmony_ci		cycles_t resume_time = get_cycles();
126562306a36Sopenharmony_ci		cycles_t delta_time = resume_time - csa->suspend_time;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci		csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
126862306a36Sopenharmony_ci		if (csa->lscsa->decr.slot[0] < delta_time) {
126962306a36Sopenharmony_ci			csa->lscsa->decr_status.slot[0] |=
127062306a36Sopenharmony_ci				 SPU_DECR_STATUS_WRAPPED;
127162306a36Sopenharmony_ci		}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci		csa->lscsa->decr.slot[0] -= delta_time;
127462306a36Sopenharmony_ci	} else {
127562306a36Sopenharmony_ci		csa->lscsa->decr_status.slot[0] = 0;
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic inline void setup_ppu_mb(struct spu_state *csa, struct spu *spu)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	/* Restore, Step 35:
128262306a36Sopenharmony_ci	 *     Copy the CSA.PU_MB data into the LSCSA.
128362306a36Sopenharmony_ci	 */
128462306a36Sopenharmony_ci	csa->lscsa->ppu_mb.slot[0] = csa->prob.pu_mb_R;
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cistatic inline void setup_ppuint_mb(struct spu_state *csa, struct spu *spu)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	/* Restore, Step 36:
129062306a36Sopenharmony_ci	 *     Copy the CSA.PUINT_MB data into the LSCSA.
129162306a36Sopenharmony_ci	 */
129262306a36Sopenharmony_ci	csa->lscsa->ppuint_mb.slot[0] = csa->priv2.puint_mb_R;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic inline int check_restore_status(struct spu_state *csa, struct spu *spu)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
129862306a36Sopenharmony_ci	u32 complete;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	/* Restore, Step 40:
130162306a36Sopenharmony_ci	 *     If SPU_Status[P]=1 and SPU_Status[SC] = "success",
130262306a36Sopenharmony_ci	 *     context restore succeeded, otherwise context restore
130362306a36Sopenharmony_ci	 *     failed.
130462306a36Sopenharmony_ci	 */
130562306a36Sopenharmony_ci	complete = ((SPU_RESTORE_COMPLETE << SPU_STOP_STATUS_SHIFT) |
130662306a36Sopenharmony_ci		    SPU_STATUS_STOPPED_BY_STOP);
130762306a36Sopenharmony_ci	return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0;
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_cistatic inline void restore_spu_privcntl(struct spu_state *csa, struct spu *spu)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	/* Restore, Step 41:
131562306a36Sopenharmony_ci	 *     Restore SPU_PrivCntl from the CSA.
131662306a36Sopenharmony_ci	 */
131762306a36Sopenharmony_ci	out_be64(&priv2->spu_privcntl_RW, csa->priv2.spu_privcntl_RW);
131862306a36Sopenharmony_ci	eieio();
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic inline void restore_status_part1(struct spu_state *csa, struct spu *spu)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
132462306a36Sopenharmony_ci	u32 mask;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	/* Restore, Step 42:
132762306a36Sopenharmony_ci	 *     If any CSA.SPU_Status[I,S,H,P]=1, then
132862306a36Sopenharmony_ci	 *     restore the error or single step state.
132962306a36Sopenharmony_ci	 */
133062306a36Sopenharmony_ci	mask = SPU_STATUS_INVALID_INSTR |
133162306a36Sopenharmony_ci	    SPU_STATUS_SINGLE_STEP |
133262306a36Sopenharmony_ci	    SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP;
133362306a36Sopenharmony_ci	if (csa->prob.spu_status_R & mask) {
133462306a36Sopenharmony_ci		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
133562306a36Sopenharmony_ci		eieio();
133662306a36Sopenharmony_ci		POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
133762306a36Sopenharmony_ci				SPU_STATUS_RUNNING);
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic inline void restore_status_part2(struct spu_state *csa, struct spu *spu)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
134462306a36Sopenharmony_ci	u32 mask;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	/* Restore, Step 43:
134762306a36Sopenharmony_ci	 *     If all CSA.SPU_Status[I,S,H,P,R]=0 then write
134862306a36Sopenharmony_ci	 *     SPU_RunCntl[R0R1]='01', wait for SPU_Status[R]=1,
134962306a36Sopenharmony_ci	 *     then write '00' to SPU_RunCntl[R0R1] and wait
135062306a36Sopenharmony_ci	 *     for SPU_Status[R]=0.
135162306a36Sopenharmony_ci	 */
135262306a36Sopenharmony_ci	mask = SPU_STATUS_INVALID_INSTR |
135362306a36Sopenharmony_ci	    SPU_STATUS_SINGLE_STEP |
135462306a36Sopenharmony_ci	    SPU_STATUS_STOPPED_BY_HALT |
135562306a36Sopenharmony_ci	    SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING;
135662306a36Sopenharmony_ci	if (!(csa->prob.spu_status_R & mask)) {
135762306a36Sopenharmony_ci		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
135862306a36Sopenharmony_ci		eieio();
135962306a36Sopenharmony_ci		POLL_WHILE_FALSE(in_be32(&prob->spu_status_R) &
136062306a36Sopenharmony_ci				 SPU_STATUS_RUNNING);
136162306a36Sopenharmony_ci		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
136262306a36Sopenharmony_ci		eieio();
136362306a36Sopenharmony_ci		POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
136462306a36Sopenharmony_ci				SPU_STATUS_RUNNING);
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	unsigned long addr = (unsigned long)&csa->lscsa->ls[0];
137162306a36Sopenharmony_ci	unsigned int ls_offset = 0x0;
137262306a36Sopenharmony_ci	unsigned int size = 16384;
137362306a36Sopenharmony_ci	unsigned int tag = 0;
137462306a36Sopenharmony_ci	unsigned int rclass = 0;
137562306a36Sopenharmony_ci	unsigned int cmd = MFC_GET_CMD;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	/* Restore, Step 44:
137862306a36Sopenharmony_ci	 *     Issue a DMA command to restore the first
137962306a36Sopenharmony_ci	 *     16kb of local storage from CSA.
138062306a36Sopenharmony_ci	 */
138162306a36Sopenharmony_ci	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	/* Restore, Step 47.
138962306a36Sopenharmony_ci	 *     Write MFC_Cntl[Sc,Sm]='1','0' to suspend
139062306a36Sopenharmony_ci	 *     the queue.
139162306a36Sopenharmony_ci	 */
139262306a36Sopenharmony_ci	out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE);
139362306a36Sopenharmony_ci	eieio();
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	/* Restore, Step 49:
139962306a36Sopenharmony_ci	 *     Write INT_MASK_class0 with value of 0.
140062306a36Sopenharmony_ci	 *     Write INT_MASK_class1 with value of 0.
140162306a36Sopenharmony_ci	 *     Write INT_MASK_class2 with value of 0.
140262306a36Sopenharmony_ci	 *     Write INT_STAT_class0 with value of -1.
140362306a36Sopenharmony_ci	 *     Write INT_STAT_class1 with value of -1.
140462306a36Sopenharmony_ci	 *     Write INT_STAT_class2 with value of -1.
140562306a36Sopenharmony_ci	 */
140662306a36Sopenharmony_ci	spin_lock_irq(&spu->register_lock);
140762306a36Sopenharmony_ci	spu_int_mask_set(spu, 0, 0ul);
140862306a36Sopenharmony_ci	spu_int_mask_set(spu, 1, 0ul);
140962306a36Sopenharmony_ci	spu_int_mask_set(spu, 2, 0ul);
141062306a36Sopenharmony_ci	spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK);
141162306a36Sopenharmony_ci	spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK);
141262306a36Sopenharmony_ci	spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK);
141362306a36Sopenharmony_ci	spin_unlock_irq(&spu->register_lock);
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic inline void restore_mfc_queues(struct spu_state *csa, struct spu *spu)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
141962306a36Sopenharmony_ci	int i;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	/* Restore, Step 50:
142262306a36Sopenharmony_ci	 *     If MFC_Cntl[Se]!=0 then restore
142362306a36Sopenharmony_ci	 *     MFC command queues.
142462306a36Sopenharmony_ci	 */
142562306a36Sopenharmony_ci	if ((csa->priv2.mfc_control_RW & MFC_CNTL_DMA_QUEUES_EMPTY_MASK) == 0) {
142662306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
142762306a36Sopenharmony_ci			out_be64(&priv2->puq[i].mfc_cq_data0_RW,
142862306a36Sopenharmony_ci				 csa->priv2.puq[i].mfc_cq_data0_RW);
142962306a36Sopenharmony_ci			out_be64(&priv2->puq[i].mfc_cq_data1_RW,
143062306a36Sopenharmony_ci				 csa->priv2.puq[i].mfc_cq_data1_RW);
143162306a36Sopenharmony_ci			out_be64(&priv2->puq[i].mfc_cq_data2_RW,
143262306a36Sopenharmony_ci				 csa->priv2.puq[i].mfc_cq_data2_RW);
143362306a36Sopenharmony_ci			out_be64(&priv2->puq[i].mfc_cq_data3_RW,
143462306a36Sopenharmony_ci				 csa->priv2.puq[i].mfc_cq_data3_RW);
143562306a36Sopenharmony_ci		}
143662306a36Sopenharmony_ci		for (i = 0; i < 16; i++) {
143762306a36Sopenharmony_ci			out_be64(&priv2->spuq[i].mfc_cq_data0_RW,
143862306a36Sopenharmony_ci				 csa->priv2.spuq[i].mfc_cq_data0_RW);
143962306a36Sopenharmony_ci			out_be64(&priv2->spuq[i].mfc_cq_data1_RW,
144062306a36Sopenharmony_ci				 csa->priv2.spuq[i].mfc_cq_data1_RW);
144162306a36Sopenharmony_ci			out_be64(&priv2->spuq[i].mfc_cq_data2_RW,
144262306a36Sopenharmony_ci				 csa->priv2.spuq[i].mfc_cq_data2_RW);
144362306a36Sopenharmony_ci			out_be64(&priv2->spuq[i].mfc_cq_data3_RW,
144462306a36Sopenharmony_ci				 csa->priv2.spuq[i].mfc_cq_data3_RW);
144562306a36Sopenharmony_ci		}
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci	eieio();
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_cistatic inline void restore_ppu_querymask(struct spu_state *csa, struct spu *spu)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	/* Restore, Step 51:
145562306a36Sopenharmony_ci	 *     Restore the PPU_QueryMask register from CSA.
145662306a36Sopenharmony_ci	 */
145762306a36Sopenharmony_ci	out_be32(&prob->dma_querymask_RW, csa->prob.dma_querymask_RW);
145862306a36Sopenharmony_ci	eieio();
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_cistatic inline void restore_ppu_querytype(struct spu_state *csa, struct spu *spu)
146262306a36Sopenharmony_ci{
146362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/* Restore, Step 52:
146662306a36Sopenharmony_ci	 *     Restore the PPU_QueryType register from CSA.
146762306a36Sopenharmony_ci	 */
146862306a36Sopenharmony_ci	out_be32(&prob->dma_querytype_RW, csa->prob.dma_querytype_RW);
146962306a36Sopenharmony_ci	eieio();
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_cistatic inline void restore_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	/* Restore, Step 53:
147762306a36Sopenharmony_ci	 *     Restore the MFC_CSR_TSQ register from CSA.
147862306a36Sopenharmony_ci	 */
147962306a36Sopenharmony_ci	out_be64(&priv2->spu_tag_status_query_RW,
148062306a36Sopenharmony_ci		 csa->priv2.spu_tag_status_query_RW);
148162306a36Sopenharmony_ci	eieio();
148262306a36Sopenharmony_ci}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_cistatic inline void restore_mfc_csr_cmd(struct spu_state *csa, struct spu *spu)
148562306a36Sopenharmony_ci{
148662306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	/* Restore, Step 54:
148962306a36Sopenharmony_ci	 *     Restore the MFC_CSR_CMD1 and MFC_CSR_CMD2
149062306a36Sopenharmony_ci	 *     registers from CSA.
149162306a36Sopenharmony_ci	 */
149262306a36Sopenharmony_ci	out_be64(&priv2->spu_cmd_buf1_RW, csa->priv2.spu_cmd_buf1_RW);
149362306a36Sopenharmony_ci	out_be64(&priv2->spu_cmd_buf2_RW, csa->priv2.spu_cmd_buf2_RW);
149462306a36Sopenharmony_ci	eieio();
149562306a36Sopenharmony_ci}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic inline void restore_mfc_csr_ato(struct spu_state *csa, struct spu *spu)
149862306a36Sopenharmony_ci{
149962306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	/* Restore, Step 55:
150262306a36Sopenharmony_ci	 *     Restore the MFC_CSR_ATO register from CSA.
150362306a36Sopenharmony_ci	 */
150462306a36Sopenharmony_ci	out_be64(&priv2->spu_atomic_status_RW, csa->priv2.spu_atomic_status_RW);
150562306a36Sopenharmony_ci}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_cistatic inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	/* Restore, Step 56:
151062306a36Sopenharmony_ci	 *     Restore the MFC_TCLASS_ID register from CSA.
151162306a36Sopenharmony_ci	 */
151262306a36Sopenharmony_ci	spu_mfc_tclass_id_set(spu, csa->priv1.mfc_tclass_id_RW);
151362306a36Sopenharmony_ci	eieio();
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cistatic inline void set_llr_event(struct spu_state *csa, struct spu *spu)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	u64 ch0_cnt, ch0_data;
151962306a36Sopenharmony_ci	u64 ch1_data;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/* Restore, Step 57:
152262306a36Sopenharmony_ci	 *    Set the Lock Line Reservation Lost Event by:
152362306a36Sopenharmony_ci	 *      1. OR CSA.SPU_Event_Status with bit 21 (Lr) set to 1.
152462306a36Sopenharmony_ci	 *      2. If CSA.SPU_Channel_0_Count=0 and
152562306a36Sopenharmony_ci	 *         CSA.SPU_Wr_Event_Mask[Lr]=1 and
152662306a36Sopenharmony_ci	 *         CSA.SPU_Event_Status[Lr]=0 then set
152762306a36Sopenharmony_ci	 *         CSA.SPU_Event_Status_Count=1.
152862306a36Sopenharmony_ci	 */
152962306a36Sopenharmony_ci	ch0_cnt = csa->spu_chnlcnt_RW[0];
153062306a36Sopenharmony_ci	ch0_data = csa->spu_chnldata_RW[0];
153162306a36Sopenharmony_ci	ch1_data = csa->spu_chnldata_RW[1];
153262306a36Sopenharmony_ci	csa->spu_chnldata_RW[0] |= MFC_LLR_LOST_EVENT;
153362306a36Sopenharmony_ci	if ((ch0_cnt == 0) && !(ch0_data & MFC_LLR_LOST_EVENT) &&
153462306a36Sopenharmony_ci	    (ch1_data & MFC_LLR_LOST_EVENT)) {
153562306a36Sopenharmony_ci		csa->spu_chnlcnt_RW[0] = 1;
153662306a36Sopenharmony_ci	}
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cistatic inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	/* Restore, Step 58:
154262306a36Sopenharmony_ci	 *     If the status of the CSA software decrementer
154362306a36Sopenharmony_ci	 *     "wrapped" flag is set, OR in a '1' to
154462306a36Sopenharmony_ci	 *     CSA.SPU_Event_Status[Tm].
154562306a36Sopenharmony_ci	 */
154662306a36Sopenharmony_ci	if (!(csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED))
154762306a36Sopenharmony_ci		return;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if ((csa->spu_chnlcnt_RW[0] == 0) &&
155062306a36Sopenharmony_ci	    (csa->spu_chnldata_RW[1] & 0x20) &&
155162306a36Sopenharmony_ci	    !(csa->spu_chnldata_RW[0] & 0x20))
155262306a36Sopenharmony_ci		csa->spu_chnlcnt_RW[0] = 1;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	csa->spu_chnldata_RW[0] |= 0x20;
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_cistatic inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
155862306a36Sopenharmony_ci{
155962306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
156062306a36Sopenharmony_ci	u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
156162306a36Sopenharmony_ci	int i;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	/* Restore, Step 59:
156462306a36Sopenharmony_ci	 *	Restore the following CH: [0,3,4,24,25,27]
156562306a36Sopenharmony_ci	 */
156662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
156762306a36Sopenharmony_ci		idx = ch_indices[i];
156862306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcntptr_RW, idx);
156962306a36Sopenharmony_ci		eieio();
157062306a36Sopenharmony_ci		out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[idx]);
157162306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[idx]);
157262306a36Sopenharmony_ci		eieio();
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic inline void restore_ch_part2(struct spu_state *csa, struct spu *spu)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
157962306a36Sopenharmony_ci	u64 ch_indices[3] = { 9UL, 21UL, 23UL };
158062306a36Sopenharmony_ci	u64 ch_counts[3] = { 1UL, 16UL, 1UL };
158162306a36Sopenharmony_ci	u64 idx;
158262306a36Sopenharmony_ci	int i;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	/* Restore, Step 60:
158562306a36Sopenharmony_ci	 *     Restore the following CH: [9,21,23].
158662306a36Sopenharmony_ci	 */
158762306a36Sopenharmony_ci	ch_counts[0] = 1UL;
158862306a36Sopenharmony_ci	ch_counts[1] = csa->spu_chnlcnt_RW[21];
158962306a36Sopenharmony_ci	ch_counts[2] = 1UL;
159062306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
159162306a36Sopenharmony_ci		idx = ch_indices[i];
159262306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcntptr_RW, idx);
159362306a36Sopenharmony_ci		eieio();
159462306a36Sopenharmony_ci		out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]);
159562306a36Sopenharmony_ci		eieio();
159662306a36Sopenharmony_ci	}
159762306a36Sopenharmony_ci}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_cistatic inline void restore_spu_lslr(struct spu_state *csa, struct spu *spu)
160062306a36Sopenharmony_ci{
160162306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	/* Restore, Step 61:
160462306a36Sopenharmony_ci	 *     Restore the SPU_LSLR register from CSA.
160562306a36Sopenharmony_ci	 */
160662306a36Sopenharmony_ci	out_be64(&priv2->spu_lslr_RW, csa->priv2.spu_lslr_RW);
160762306a36Sopenharmony_ci	eieio();
160862306a36Sopenharmony_ci}
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_cistatic inline void restore_spu_cfg(struct spu_state *csa, struct spu *spu)
161162306a36Sopenharmony_ci{
161262306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	/* Restore, Step 62:
161562306a36Sopenharmony_ci	 *     Restore the SPU_Cfg register from CSA.
161662306a36Sopenharmony_ci	 */
161762306a36Sopenharmony_ci	out_be64(&priv2->spu_cfg_RW, csa->priv2.spu_cfg_RW);
161862306a36Sopenharmony_ci	eieio();
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_cistatic inline void restore_pm_trace(struct spu_state *csa, struct spu *spu)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	/* Restore, Step 63:
162462306a36Sopenharmony_ci	 *     Restore PM_Trace_Tag_Wait_Mask from CSA.
162562306a36Sopenharmony_ci	 *     Not performed by this implementation.
162662306a36Sopenharmony_ci	 */
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_cistatic inline void restore_spu_npc(struct spu_state *csa, struct spu *spu)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	/* Restore, Step 64:
163462306a36Sopenharmony_ci	 *     Restore SPU_NPC from CSA.
163562306a36Sopenharmony_ci	 */
163662306a36Sopenharmony_ci	out_be32(&prob->spu_npc_RW, csa->prob.spu_npc_RW);
163762306a36Sopenharmony_ci	eieio();
163862306a36Sopenharmony_ci}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_cistatic inline void restore_spu_mb(struct spu_state *csa, struct spu *spu)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
164362306a36Sopenharmony_ci	int i;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	/* Restore, Step 65:
164662306a36Sopenharmony_ci	 *     Restore MFC_RdSPU_MB from CSA.
164762306a36Sopenharmony_ci	 */
164862306a36Sopenharmony_ci	out_be64(&priv2->spu_chnlcntptr_RW, 29UL);
164962306a36Sopenharmony_ci	eieio();
165062306a36Sopenharmony_ci	out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]);
165162306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
165262306a36Sopenharmony_ci		out_be64(&priv2->spu_chnldata_RW, csa->spu_mailbox_data[i]);
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci	eieio();
165562306a36Sopenharmony_ci}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cistatic inline void check_ppu_mb_stat(struct spu_state *csa, struct spu *spu)
165862306a36Sopenharmony_ci{
165962306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	/* Restore, Step 66:
166262306a36Sopenharmony_ci	 *     If CSA.MB_Stat[P]=0 (mailbox empty) then
166362306a36Sopenharmony_ci	 *     read from the PPU_MB register.
166462306a36Sopenharmony_ci	 */
166562306a36Sopenharmony_ci	if ((csa->prob.mb_stat_R & 0xFF) == 0) {
166662306a36Sopenharmony_ci		in_be32(&prob->pu_mb_R);
166762306a36Sopenharmony_ci		eieio();
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu)
167262306a36Sopenharmony_ci{
167362306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	/* Restore, Step 66:
167662306a36Sopenharmony_ci	 *     If CSA.MB_Stat[I]=0 (mailbox empty) then
167762306a36Sopenharmony_ci	 *     read from the PPUINT_MB register.
167862306a36Sopenharmony_ci	 */
167962306a36Sopenharmony_ci	if ((csa->prob.mb_stat_R & 0xFF0000) == 0) {
168062306a36Sopenharmony_ci		in_be64(&priv2->puint_mb_R);
168162306a36Sopenharmony_ci		eieio();
168262306a36Sopenharmony_ci		spu_int_stat_clear(spu, 2, CLASS2_ENABLE_MAILBOX_INTR);
168362306a36Sopenharmony_ci		eieio();
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_cistatic inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu)
168862306a36Sopenharmony_ci{
168962306a36Sopenharmony_ci	/* Restore, Step 69:
169062306a36Sopenharmony_ci	 *     Restore the MFC_SR1 register from CSA.
169162306a36Sopenharmony_ci	 */
169262306a36Sopenharmony_ci	spu_mfc_sr1_set(spu, csa->priv1.mfc_sr1_RW);
169362306a36Sopenharmony_ci	eieio();
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_cistatic inline void set_int_route(struct spu_state *csa, struct spu *spu)
169762306a36Sopenharmony_ci{
169862306a36Sopenharmony_ci	struct spu_context *ctx = spu->ctx;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	spu_cpu_affinity_set(spu, ctx->last_ran);
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cistatic inline void restore_other_spu_access(struct spu_state *csa,
170462306a36Sopenharmony_ci					    struct spu *spu)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	/* Restore, Step 70:
170762306a36Sopenharmony_ci	 *     Restore other SPU mappings to this SPU. TBD.
170862306a36Sopenharmony_ci	 */
170962306a36Sopenharmony_ci}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic inline void restore_spu_runcntl(struct spu_state *csa, struct spu *spu)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	/* Restore, Step 71:
171662306a36Sopenharmony_ci	 *     If CSA.SPU_Status[R]=1 then write
171762306a36Sopenharmony_ci	 *     SPU_RunCntl[R0R1]='01'.
171862306a36Sopenharmony_ci	 */
171962306a36Sopenharmony_ci	if (csa->prob.spu_status_R & SPU_STATUS_RUNNING) {
172062306a36Sopenharmony_ci		out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
172162306a36Sopenharmony_ci		eieio();
172262306a36Sopenharmony_ci	}
172362306a36Sopenharmony_ci}
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_cistatic inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu)
172662306a36Sopenharmony_ci{
172762306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	/* Restore, Step 72:
173062306a36Sopenharmony_ci	 *    Restore the MFC_CNTL register for the CSA.
173162306a36Sopenharmony_ci	 */
173262306a36Sopenharmony_ci	out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW);
173362306a36Sopenharmony_ci	eieio();
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	/*
173662306a36Sopenharmony_ci	 * The queue is put back into the same state that was evident prior to
173762306a36Sopenharmony_ci	 * the context switch. The suspend flag is added to the saved state in
173862306a36Sopenharmony_ci	 * the csa, if the operational state was suspending or suspended. In
173962306a36Sopenharmony_ci	 * this case, the code that suspended the mfc is responsible for
174062306a36Sopenharmony_ci	 * continuing it. Note that SPE faults do not change the operational
174162306a36Sopenharmony_ci	 * state of the spu.
174262306a36Sopenharmony_ci	 */
174362306a36Sopenharmony_ci}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_cistatic inline void enable_user_access(struct spu_state *csa, struct spu *spu)
174662306a36Sopenharmony_ci{
174762306a36Sopenharmony_ci	/* Restore, Step 73:
174862306a36Sopenharmony_ci	 *     Enable user-space access (if provided) to this
174962306a36Sopenharmony_ci	 *     SPU by mapping the virtual pages assigned to
175062306a36Sopenharmony_ci	 *     the SPU memory-mapped I/O (MMIO) for problem
175162306a36Sopenharmony_ci	 *     state. TBD.
175262306a36Sopenharmony_ci	 */
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistatic inline void reset_switch_active(struct spu_state *csa, struct spu *spu)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	/* Restore, Step 74:
175862306a36Sopenharmony_ci	 *     Reset the "context switch active" flag.
175962306a36Sopenharmony_ci	 *     Not performed by this implementation.
176062306a36Sopenharmony_ci	 */
176162306a36Sopenharmony_ci}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_cistatic inline void reenable_interrupts(struct spu_state *csa, struct spu *spu)
176462306a36Sopenharmony_ci{
176562306a36Sopenharmony_ci	/* Restore, Step 75:
176662306a36Sopenharmony_ci	 *     Re-enable SPU interrupts.
176762306a36Sopenharmony_ci	 */
176862306a36Sopenharmony_ci	spin_lock_irq(&spu->register_lock);
176962306a36Sopenharmony_ci	spu_int_mask_set(spu, 0, csa->priv1.int_mask_class0_RW);
177062306a36Sopenharmony_ci	spu_int_mask_set(spu, 1, csa->priv1.int_mask_class1_RW);
177162306a36Sopenharmony_ci	spu_int_mask_set(spu, 2, csa->priv1.int_mask_class2_RW);
177262306a36Sopenharmony_ci	spin_unlock_irq(&spu->register_lock);
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_cistatic int quiece_spu(struct spu_state *prev, struct spu *spu)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	/*
177862306a36Sopenharmony_ci	 * Combined steps 2-18 of SPU context save sequence, which
177962306a36Sopenharmony_ci	 * quiesce the SPU state (disable SPU execution, MFC command
178062306a36Sopenharmony_ci	 * queues, decrementer, SPU interrupts, etc.).
178162306a36Sopenharmony_ci	 *
178262306a36Sopenharmony_ci	 * Returns      0 on success.
178362306a36Sopenharmony_ci	 *              2 if failed step 2.
178462306a36Sopenharmony_ci	 *              6 if failed step 6.
178562306a36Sopenharmony_ci	 */
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	if (check_spu_isolate(prev, spu)) {	/* Step 2. */
178862306a36Sopenharmony_ci		return 2;
178962306a36Sopenharmony_ci	}
179062306a36Sopenharmony_ci	disable_interrupts(prev, spu);	        /* Step 3. */
179162306a36Sopenharmony_ci	set_watchdog_timer(prev, spu);	        /* Step 4. */
179262306a36Sopenharmony_ci	inhibit_user_access(prev, spu);	        /* Step 5. */
179362306a36Sopenharmony_ci	if (check_spu_isolate(prev, spu)) {	/* Step 6. */
179462306a36Sopenharmony_ci		return 6;
179562306a36Sopenharmony_ci	}
179662306a36Sopenharmony_ci	set_switch_pending(prev, spu);	        /* Step 7. */
179762306a36Sopenharmony_ci	save_mfc_cntl(prev, spu);		/* Step 8. */
179862306a36Sopenharmony_ci	save_spu_runcntl(prev, spu);	        /* Step 9. */
179962306a36Sopenharmony_ci	save_mfc_sr1(prev, spu);	        /* Step 10. */
180062306a36Sopenharmony_ci	save_spu_status(prev, spu);	        /* Step 11. */
180162306a36Sopenharmony_ci	save_mfc_stopped_status(prev, spu);     /* Step 12. */
180262306a36Sopenharmony_ci	halt_mfc_decr(prev, spu);	        /* Step 13. */
180362306a36Sopenharmony_ci	save_timebase(prev, spu);		/* Step 14. */
180462306a36Sopenharmony_ci	remove_other_spu_access(prev, spu);	/* Step 15. */
180562306a36Sopenharmony_ci	do_mfc_mssync(prev, spu);	        /* Step 16. */
180662306a36Sopenharmony_ci	issue_mfc_tlbie(prev, spu);	        /* Step 17. */
180762306a36Sopenharmony_ci	handle_pending_interrupts(prev, spu);	/* Step 18. */
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	return 0;
181062306a36Sopenharmony_ci}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_cistatic void save_csa(struct spu_state *prev, struct spu *spu)
181362306a36Sopenharmony_ci{
181462306a36Sopenharmony_ci	/*
181562306a36Sopenharmony_ci	 * Combine steps 19-44 of SPU context save sequence, which
181662306a36Sopenharmony_ci	 * save regions of the privileged & problem state areas.
181762306a36Sopenharmony_ci	 */
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	save_mfc_queues(prev, spu);	/* Step 19. */
182062306a36Sopenharmony_ci	save_ppu_querymask(prev, spu);	/* Step 20. */
182162306a36Sopenharmony_ci	save_ppu_querytype(prev, spu);	/* Step 21. */
182262306a36Sopenharmony_ci	save_ppu_tagstatus(prev, spu);  /* NEW.     */
182362306a36Sopenharmony_ci	save_mfc_csr_tsq(prev, spu);	/* Step 22. */
182462306a36Sopenharmony_ci	save_mfc_csr_cmd(prev, spu);	/* Step 23. */
182562306a36Sopenharmony_ci	save_mfc_csr_ato(prev, spu);	/* Step 24. */
182662306a36Sopenharmony_ci	save_mfc_tclass_id(prev, spu);	/* Step 25. */
182762306a36Sopenharmony_ci	set_mfc_tclass_id(prev, spu);	/* Step 26. */
182862306a36Sopenharmony_ci	save_mfc_cmd(prev, spu);	/* Step 26a - moved from 44. */
182962306a36Sopenharmony_ci	purge_mfc_queue(prev, spu);	/* Step 27. */
183062306a36Sopenharmony_ci	wait_purge_complete(prev, spu);	/* Step 28. */
183162306a36Sopenharmony_ci	setup_mfc_sr1(prev, spu);	/* Step 30. */
183262306a36Sopenharmony_ci	save_spu_npc(prev, spu);	/* Step 31. */
183362306a36Sopenharmony_ci	save_spu_privcntl(prev, spu);	/* Step 32. */
183462306a36Sopenharmony_ci	reset_spu_privcntl(prev, spu);	/* Step 33. */
183562306a36Sopenharmony_ci	save_spu_lslr(prev, spu);	/* Step 34. */
183662306a36Sopenharmony_ci	reset_spu_lslr(prev, spu);	/* Step 35. */
183762306a36Sopenharmony_ci	save_spu_cfg(prev, spu);	/* Step 36. */
183862306a36Sopenharmony_ci	save_pm_trace(prev, spu);	/* Step 37. */
183962306a36Sopenharmony_ci	save_mfc_rag(prev, spu);	/* Step 38. */
184062306a36Sopenharmony_ci	save_ppu_mb_stat(prev, spu);	/* Step 39. */
184162306a36Sopenharmony_ci	save_ppu_mb(prev, spu);	        /* Step 40. */
184262306a36Sopenharmony_ci	save_ppuint_mb(prev, spu);	/* Step 41. */
184362306a36Sopenharmony_ci	save_ch_part1(prev, spu);	/* Step 42. */
184462306a36Sopenharmony_ci	save_spu_mb(prev, spu);	        /* Step 43. */
184562306a36Sopenharmony_ci	reset_ch(prev, spu);	        /* Step 45. */
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic void save_lscsa(struct spu_state *prev, struct spu *spu)
184962306a36Sopenharmony_ci{
185062306a36Sopenharmony_ci	/*
185162306a36Sopenharmony_ci	 * Perform steps 46-57 of SPU context save sequence,
185262306a36Sopenharmony_ci	 * which save regions of the local store and register
185362306a36Sopenharmony_ci	 * file.
185462306a36Sopenharmony_ci	 */
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	resume_mfc_queue(prev, spu);	/* Step 46. */
185762306a36Sopenharmony_ci	/* Step 47. */
185862306a36Sopenharmony_ci	setup_mfc_slbs(prev, spu, spu_save_code, sizeof(spu_save_code));
185962306a36Sopenharmony_ci	set_switch_active(prev, spu);	/* Step 48. */
186062306a36Sopenharmony_ci	enable_interrupts(prev, spu);	/* Step 49. */
186162306a36Sopenharmony_ci	save_ls_16kb(prev, spu);	/* Step 50. */
186262306a36Sopenharmony_ci	set_spu_npc(prev, spu);	        /* Step 51. */
186362306a36Sopenharmony_ci	set_signot1(prev, spu);		/* Step 52. */
186462306a36Sopenharmony_ci	set_signot2(prev, spu);		/* Step 53. */
186562306a36Sopenharmony_ci	send_save_code(prev, spu);	/* Step 54. */
186662306a36Sopenharmony_ci	set_ppu_querymask(prev, spu);	/* Step 55. */
186762306a36Sopenharmony_ci	wait_tag_complete(prev, spu);	/* Step 56. */
186862306a36Sopenharmony_ci	wait_spu_stopped(prev, spu);	/* Step 57. */
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_cistatic void force_spu_isolate_exit(struct spu *spu)
187262306a36Sopenharmony_ci{
187362306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
187462306a36Sopenharmony_ci	struct spu_priv2 __iomem *priv2 = spu->priv2;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	/* Stop SPE execution and wait for completion. */
187762306a36Sopenharmony_ci	out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
187862306a36Sopenharmony_ci	iobarrier_rw();
187962306a36Sopenharmony_ci	POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	/* Restart SPE master runcntl. */
188262306a36Sopenharmony_ci	spu_mfc_sr1_set(spu, MFC_STATE1_MASTER_RUN_CONTROL_MASK);
188362306a36Sopenharmony_ci	iobarrier_w();
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	/* Initiate isolate exit request and wait for completion. */
188662306a36Sopenharmony_ci	out_be64(&priv2->spu_privcntl_RW, 4LL);
188762306a36Sopenharmony_ci	iobarrier_w();
188862306a36Sopenharmony_ci	out_be32(&prob->spu_runcntl_RW, 2);
188962306a36Sopenharmony_ci	iobarrier_rw();
189062306a36Sopenharmony_ci	POLL_WHILE_FALSE((in_be32(&prob->spu_status_R)
189162306a36Sopenharmony_ci				& SPU_STATUS_STOPPED_BY_STOP));
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	/* Reset load request to normal. */
189462306a36Sopenharmony_ci	out_be64(&priv2->spu_privcntl_RW, SPU_PRIVCNT_LOAD_REQUEST_NORMAL);
189562306a36Sopenharmony_ci	iobarrier_w();
189662306a36Sopenharmony_ci}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci/**
189962306a36Sopenharmony_ci * stop_spu_isolate
190062306a36Sopenharmony_ci *	Check SPU run-control state and force isolated
190162306a36Sopenharmony_ci *	exit function as necessary.
190262306a36Sopenharmony_ci */
190362306a36Sopenharmony_cistatic void stop_spu_isolate(struct spu *spu)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	struct spu_problem __iomem *prob = spu->problem;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	if (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_STATE) {
190862306a36Sopenharmony_ci		/* The SPU is in isolated state; the only way
190962306a36Sopenharmony_ci		 * to get it out is to perform an isolated
191062306a36Sopenharmony_ci		 * exit (clean) operation.
191162306a36Sopenharmony_ci		 */
191262306a36Sopenharmony_ci		force_spu_isolate_exit(spu);
191362306a36Sopenharmony_ci	}
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_cistatic void harvest(struct spu_state *prev, struct spu *spu)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	/*
191962306a36Sopenharmony_ci	 * Perform steps 2-25 of SPU context restore sequence,
192062306a36Sopenharmony_ci	 * which resets an SPU either after a failed save, or
192162306a36Sopenharmony_ci	 * when using SPU for first time.
192262306a36Sopenharmony_ci	 */
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	disable_interrupts(prev, spu);	        /* Step 2.  */
192562306a36Sopenharmony_ci	inhibit_user_access(prev, spu);	        /* Step 3.  */
192662306a36Sopenharmony_ci	terminate_spu_app(prev, spu);	        /* Step 4.  */
192762306a36Sopenharmony_ci	set_switch_pending(prev, spu);	        /* Step 5.  */
192862306a36Sopenharmony_ci	stop_spu_isolate(spu);			/* NEW.     */
192962306a36Sopenharmony_ci	remove_other_spu_access(prev, spu);	/* Step 6.  */
193062306a36Sopenharmony_ci	suspend_mfc_and_halt_decr(prev, spu);	/* Step 7.  */
193162306a36Sopenharmony_ci	wait_suspend_mfc_complete(prev, spu);	/* Step 8.  */
193262306a36Sopenharmony_ci	if (!suspend_spe(prev, spu))	        /* Step 9.  */
193362306a36Sopenharmony_ci		clear_spu_status(prev, spu);	/* Step 10. */
193462306a36Sopenharmony_ci	do_mfc_mssync(prev, spu);	        /* Step 11. */
193562306a36Sopenharmony_ci	issue_mfc_tlbie(prev, spu);	        /* Step 12. */
193662306a36Sopenharmony_ci	handle_pending_interrupts(prev, spu);	/* Step 13. */
193762306a36Sopenharmony_ci	purge_mfc_queue(prev, spu);	        /* Step 14. */
193862306a36Sopenharmony_ci	wait_purge_complete(prev, spu);	        /* Step 15. */
193962306a36Sopenharmony_ci	reset_spu_privcntl(prev, spu);	        /* Step 16. */
194062306a36Sopenharmony_ci	reset_spu_lslr(prev, spu);              /* Step 17. */
194162306a36Sopenharmony_ci	setup_mfc_sr1(prev, spu);	        /* Step 18. */
194262306a36Sopenharmony_ci	spu_invalidate_slbs(spu);		/* Step 19. */
194362306a36Sopenharmony_ci	reset_ch_part1(prev, spu);	        /* Step 20. */
194462306a36Sopenharmony_ci	reset_ch_part2(prev, spu);	        /* Step 21. */
194562306a36Sopenharmony_ci	enable_interrupts(prev, spu);	        /* Step 22. */
194662306a36Sopenharmony_ci	set_switch_active(prev, spu);	        /* Step 23. */
194762306a36Sopenharmony_ci	set_mfc_tclass_id(prev, spu);	        /* Step 24. */
194862306a36Sopenharmony_ci	resume_mfc_queue(prev, spu);	        /* Step 25. */
194962306a36Sopenharmony_ci}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_cistatic void restore_lscsa(struct spu_state *next, struct spu *spu)
195262306a36Sopenharmony_ci{
195362306a36Sopenharmony_ci	/*
195462306a36Sopenharmony_ci	 * Perform steps 26-40 of SPU context restore sequence,
195562306a36Sopenharmony_ci	 * which restores regions of the local store and register
195662306a36Sopenharmony_ci	 * file.
195762306a36Sopenharmony_ci	 */
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	set_watchdog_timer(next, spu);	        /* Step 26. */
196062306a36Sopenharmony_ci	setup_spu_status_part1(next, spu);	/* Step 27. */
196162306a36Sopenharmony_ci	setup_spu_status_part2(next, spu);	/* Step 28. */
196262306a36Sopenharmony_ci	restore_mfc_rag(next, spu);	        /* Step 29. */
196362306a36Sopenharmony_ci	/* Step 30. */
196462306a36Sopenharmony_ci	setup_mfc_slbs(next, spu, spu_restore_code, sizeof(spu_restore_code));
196562306a36Sopenharmony_ci	set_spu_npc(next, spu);	                /* Step 31. */
196662306a36Sopenharmony_ci	set_signot1(next, spu);	                /* Step 32. */
196762306a36Sopenharmony_ci	set_signot2(next, spu);	                /* Step 33. */
196862306a36Sopenharmony_ci	setup_decr(next, spu);	                /* Step 34. */
196962306a36Sopenharmony_ci	setup_ppu_mb(next, spu);	        /* Step 35. */
197062306a36Sopenharmony_ci	setup_ppuint_mb(next, spu);	        /* Step 36. */
197162306a36Sopenharmony_ci	send_restore_code(next, spu);	        /* Step 37. */
197262306a36Sopenharmony_ci	set_ppu_querymask(next, spu);	        /* Step 38. */
197362306a36Sopenharmony_ci	wait_tag_complete(next, spu);	        /* Step 39. */
197462306a36Sopenharmony_ci	wait_spu_stopped(next, spu);	        /* Step 40. */
197562306a36Sopenharmony_ci}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_cistatic void restore_csa(struct spu_state *next, struct spu *spu)
197862306a36Sopenharmony_ci{
197962306a36Sopenharmony_ci	/*
198062306a36Sopenharmony_ci	 * Combine steps 41-76 of SPU context restore sequence, which
198162306a36Sopenharmony_ci	 * restore regions of the privileged & problem state areas.
198262306a36Sopenharmony_ci	 */
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	restore_spu_privcntl(next, spu);	/* Step 41. */
198562306a36Sopenharmony_ci	restore_status_part1(next, spu);	/* Step 42. */
198662306a36Sopenharmony_ci	restore_status_part2(next, spu);	/* Step 43. */
198762306a36Sopenharmony_ci	restore_ls_16kb(next, spu);	        /* Step 44. */
198862306a36Sopenharmony_ci	wait_tag_complete(next, spu);	        /* Step 45. */
198962306a36Sopenharmony_ci	suspend_mfc(next, spu);	                /* Step 46. */
199062306a36Sopenharmony_ci	wait_suspend_mfc_complete(next, spu);	/* Step 47. */
199162306a36Sopenharmony_ci	issue_mfc_tlbie(next, spu);	        /* Step 48. */
199262306a36Sopenharmony_ci	clear_interrupts(next, spu);	        /* Step 49. */
199362306a36Sopenharmony_ci	restore_mfc_queues(next, spu);	        /* Step 50. */
199462306a36Sopenharmony_ci	restore_ppu_querymask(next, spu);	/* Step 51. */
199562306a36Sopenharmony_ci	restore_ppu_querytype(next, spu);	/* Step 52. */
199662306a36Sopenharmony_ci	restore_mfc_csr_tsq(next, spu);	        /* Step 53. */
199762306a36Sopenharmony_ci	restore_mfc_csr_cmd(next, spu);	        /* Step 54. */
199862306a36Sopenharmony_ci	restore_mfc_csr_ato(next, spu);	        /* Step 55. */
199962306a36Sopenharmony_ci	restore_mfc_tclass_id(next, spu);	/* Step 56. */
200062306a36Sopenharmony_ci	set_llr_event(next, spu);	        /* Step 57. */
200162306a36Sopenharmony_ci	restore_decr_wrapped(next, spu);	/* Step 58. */
200262306a36Sopenharmony_ci	restore_ch_part1(next, spu);	        /* Step 59. */
200362306a36Sopenharmony_ci	restore_ch_part2(next, spu);	        /* Step 60. */
200462306a36Sopenharmony_ci	restore_spu_lslr(next, spu);	        /* Step 61. */
200562306a36Sopenharmony_ci	restore_spu_cfg(next, spu);	        /* Step 62. */
200662306a36Sopenharmony_ci	restore_pm_trace(next, spu);	        /* Step 63. */
200762306a36Sopenharmony_ci	restore_spu_npc(next, spu);	        /* Step 64. */
200862306a36Sopenharmony_ci	restore_spu_mb(next, spu);	        /* Step 65. */
200962306a36Sopenharmony_ci	check_ppu_mb_stat(next, spu);	        /* Step 66. */
201062306a36Sopenharmony_ci	check_ppuint_mb_stat(next, spu);	/* Step 67. */
201162306a36Sopenharmony_ci	spu_invalidate_slbs(spu);		/* Modified Step 68. */
201262306a36Sopenharmony_ci	restore_mfc_sr1(next, spu);	        /* Step 69. */
201362306a36Sopenharmony_ci	set_int_route(next, spu);		/* NEW      */
201462306a36Sopenharmony_ci	restore_other_spu_access(next, spu);	/* Step 70. */
201562306a36Sopenharmony_ci	restore_spu_runcntl(next, spu);	        /* Step 71. */
201662306a36Sopenharmony_ci	restore_mfc_cntl(next, spu);	        /* Step 72. */
201762306a36Sopenharmony_ci	enable_user_access(next, spu);	        /* Step 73. */
201862306a36Sopenharmony_ci	reset_switch_active(next, spu);	        /* Step 74. */
201962306a36Sopenharmony_ci	reenable_interrupts(next, spu);	        /* Step 75. */
202062306a36Sopenharmony_ci}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_cistatic int __do_spu_save(struct spu_state *prev, struct spu *spu)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	int rc;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	/*
202762306a36Sopenharmony_ci	 * SPU context save can be broken into three phases:
202862306a36Sopenharmony_ci	 *
202962306a36Sopenharmony_ci	 *     (a) quiesce [steps 2-16].
203062306a36Sopenharmony_ci	 *     (b) save of CSA, performed by PPE [steps 17-42]
203162306a36Sopenharmony_ci	 *     (c) save of LSCSA, mostly performed by SPU [steps 43-52].
203262306a36Sopenharmony_ci	 *
203362306a36Sopenharmony_ci	 * Returns      0 on success.
203462306a36Sopenharmony_ci	 *              2,6 if failed to quiece SPU
203562306a36Sopenharmony_ci	 *              53 if SPU-side of save failed.
203662306a36Sopenharmony_ci	 */
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	rc = quiece_spu(prev, spu);	        /* Steps 2-16. */
203962306a36Sopenharmony_ci	switch (rc) {
204062306a36Sopenharmony_ci	default:
204162306a36Sopenharmony_ci	case 2:
204262306a36Sopenharmony_ci	case 6:
204362306a36Sopenharmony_ci		harvest(prev, spu);
204462306a36Sopenharmony_ci		return rc;
204562306a36Sopenharmony_ci		break;
204662306a36Sopenharmony_ci	case 0:
204762306a36Sopenharmony_ci		break;
204862306a36Sopenharmony_ci	}
204962306a36Sopenharmony_ci	save_csa(prev, spu);	                /* Steps 17-43. */
205062306a36Sopenharmony_ci	save_lscsa(prev, spu);	                /* Steps 44-53. */
205162306a36Sopenharmony_ci	return check_save_status(prev, spu);	/* Step 54.     */
205262306a36Sopenharmony_ci}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_cistatic int __do_spu_restore(struct spu_state *next, struct spu *spu)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	int rc;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	/*
205962306a36Sopenharmony_ci	 * SPU context restore can be broken into three phases:
206062306a36Sopenharmony_ci	 *
206162306a36Sopenharmony_ci	 *    (a) harvest (or reset) SPU [steps 2-24].
206262306a36Sopenharmony_ci	 *    (b) restore LSCSA [steps 25-40], mostly performed by SPU.
206362306a36Sopenharmony_ci	 *    (c) restore CSA [steps 41-76], performed by PPE.
206462306a36Sopenharmony_ci	 *
206562306a36Sopenharmony_ci	 * The 'harvest' step is not performed here, but rather
206662306a36Sopenharmony_ci	 * as needed below.
206762306a36Sopenharmony_ci	 */
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	restore_lscsa(next, spu);	        /* Steps 24-39. */
207062306a36Sopenharmony_ci	rc = check_restore_status(next, spu);	/* Step 40.     */
207162306a36Sopenharmony_ci	switch (rc) {
207262306a36Sopenharmony_ci	default:
207362306a36Sopenharmony_ci		/* Failed. Return now. */
207462306a36Sopenharmony_ci		return rc;
207562306a36Sopenharmony_ci		break;
207662306a36Sopenharmony_ci	case 0:
207762306a36Sopenharmony_ci		/* Fall through to next step. */
207862306a36Sopenharmony_ci		break;
207962306a36Sopenharmony_ci	}
208062306a36Sopenharmony_ci	restore_csa(next, spu);
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	return 0;
208362306a36Sopenharmony_ci}
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci/**
208662306a36Sopenharmony_ci * spu_save - SPU context save, with locking.
208762306a36Sopenharmony_ci * @prev: pointer to SPU context save area, to be saved.
208862306a36Sopenharmony_ci * @spu: pointer to SPU iomem structure.
208962306a36Sopenharmony_ci *
209062306a36Sopenharmony_ci * Acquire locks, perform the save operation then return.
209162306a36Sopenharmony_ci */
209262306a36Sopenharmony_ciint spu_save(struct spu_state *prev, struct spu *spu)
209362306a36Sopenharmony_ci{
209462306a36Sopenharmony_ci	int rc;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	acquire_spu_lock(spu);	        /* Step 1.     */
209762306a36Sopenharmony_ci	rc = __do_spu_save(prev, spu);	/* Steps 2-53. */
209862306a36Sopenharmony_ci	release_spu_lock(spu);
209962306a36Sopenharmony_ci	if (rc != 0 && rc != 2 && rc != 6) {
210062306a36Sopenharmony_ci		panic("%s failed on SPU[%d], rc=%d.\n",
210162306a36Sopenharmony_ci		      __func__, spu->number, rc);
210262306a36Sopenharmony_ci	}
210362306a36Sopenharmony_ci	return 0;
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(spu_save);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci/**
210862306a36Sopenharmony_ci * spu_restore - SPU context restore, with harvest and locking.
210962306a36Sopenharmony_ci * @new: pointer to SPU context save area, to be restored.
211062306a36Sopenharmony_ci * @spu: pointer to SPU iomem structure.
211162306a36Sopenharmony_ci *
211262306a36Sopenharmony_ci * Perform harvest + restore, as we may not be coming
211362306a36Sopenharmony_ci * from a previous successful save operation, and the
211462306a36Sopenharmony_ci * hardware state is unknown.
211562306a36Sopenharmony_ci */
211662306a36Sopenharmony_ciint spu_restore(struct spu_state *new, struct spu *spu)
211762306a36Sopenharmony_ci{
211862306a36Sopenharmony_ci	int rc;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	acquire_spu_lock(spu);
212162306a36Sopenharmony_ci	harvest(NULL, spu);
212262306a36Sopenharmony_ci	spu->slb_replace = 0;
212362306a36Sopenharmony_ci	rc = __do_spu_restore(new, spu);
212462306a36Sopenharmony_ci	release_spu_lock(spu);
212562306a36Sopenharmony_ci	if (rc) {
212662306a36Sopenharmony_ci		panic("%s failed on SPU[%d] rc=%d.\n",
212762306a36Sopenharmony_ci		       __func__, spu->number, rc);
212862306a36Sopenharmony_ci	}
212962306a36Sopenharmony_ci	return rc;
213062306a36Sopenharmony_ci}
213162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(spu_restore);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic void init_prob(struct spu_state *csa)
213462306a36Sopenharmony_ci{
213562306a36Sopenharmony_ci	csa->spu_chnlcnt_RW[9] = 1;
213662306a36Sopenharmony_ci	csa->spu_chnlcnt_RW[21] = 16;
213762306a36Sopenharmony_ci	csa->spu_chnlcnt_RW[23] = 1;
213862306a36Sopenharmony_ci	csa->spu_chnlcnt_RW[28] = 1;
213962306a36Sopenharmony_ci	csa->spu_chnlcnt_RW[30] = 1;
214062306a36Sopenharmony_ci	csa->prob.spu_runcntl_RW = SPU_RUNCNTL_STOP;
214162306a36Sopenharmony_ci	csa->prob.mb_stat_R = 0x000400;
214262306a36Sopenharmony_ci}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_cistatic void init_priv1(struct spu_state *csa)
214562306a36Sopenharmony_ci{
214662306a36Sopenharmony_ci	/* Enable decode, relocate, tlbie response, master runcntl. */
214762306a36Sopenharmony_ci	csa->priv1.mfc_sr1_RW = MFC_STATE1_LOCAL_STORAGE_DECODE_MASK |
214862306a36Sopenharmony_ci	    MFC_STATE1_MASTER_RUN_CONTROL_MASK |
214962306a36Sopenharmony_ci	    MFC_STATE1_PROBLEM_STATE_MASK |
215062306a36Sopenharmony_ci	    MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	/* Enable OS-specific set of interrupts. */
215362306a36Sopenharmony_ci	csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR |
215462306a36Sopenharmony_ci	    CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR |
215562306a36Sopenharmony_ci	    CLASS0_ENABLE_SPU_ERROR_INTR;
215662306a36Sopenharmony_ci	csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
215762306a36Sopenharmony_ci	    CLASS1_ENABLE_STORAGE_FAULT_INTR;
215862306a36Sopenharmony_ci	csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR |
215962306a36Sopenharmony_ci	    CLASS2_ENABLE_SPU_HALT_INTR |
216062306a36Sopenharmony_ci	    CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR;
216162306a36Sopenharmony_ci}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic void init_priv2(struct spu_state *csa)
216462306a36Sopenharmony_ci{
216562306a36Sopenharmony_ci	csa->priv2.spu_lslr_RW = LS_ADDR_MASK;
216662306a36Sopenharmony_ci	csa->priv2.mfc_control_RW = MFC_CNTL_RESUME_DMA_QUEUE |
216762306a36Sopenharmony_ci	    MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION |
216862306a36Sopenharmony_ci	    MFC_CNTL_DMA_QUEUES_EMPTY_MASK;
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci/**
217262306a36Sopenharmony_ci * spu_alloc_csa - allocate and initialize an SPU context save area.
217362306a36Sopenharmony_ci *
217462306a36Sopenharmony_ci * Allocate and initialize the contents of an SPU context save area.
217562306a36Sopenharmony_ci * This includes enabling address translation, interrupt masks, etc.,
217662306a36Sopenharmony_ci * as appropriate for the given OS environment.
217762306a36Sopenharmony_ci *
217862306a36Sopenharmony_ci * Note that storage for the 'lscsa' is allocated separately,
217962306a36Sopenharmony_ci * as it is by far the largest of the context save regions,
218062306a36Sopenharmony_ci * and may need to be pinned or otherwise specially aligned.
218162306a36Sopenharmony_ci */
218262306a36Sopenharmony_ciint spu_init_csa(struct spu_state *csa)
218362306a36Sopenharmony_ci{
218462306a36Sopenharmony_ci	int rc;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	if (!csa)
218762306a36Sopenharmony_ci		return -EINVAL;
218862306a36Sopenharmony_ci	memset(csa, 0, sizeof(struct spu_state));
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	rc = spu_alloc_lscsa(csa);
219162306a36Sopenharmony_ci	if (rc)
219262306a36Sopenharmony_ci		return rc;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	spin_lock_init(&csa->register_lock);
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	init_prob(csa);
219762306a36Sopenharmony_ci	init_priv1(csa);
219862306a36Sopenharmony_ci	init_priv2(csa);
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	return 0;
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_civoid spu_fini_csa(struct spu_state *csa)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	spu_free_lscsa(csa);
220662306a36Sopenharmony_ci}
2207