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