18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * spu_switch.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright IBM Corp. 2005 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Mark Nutter <mnutter@us.ibm.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Host-side part of SPU context switch sequence outlined in 108c2ecf20Sopenharmony_ci * Synergistic Processor Element, Book IV. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * A fully premptive switch of an SPE is very expensive in terms 138c2ecf20Sopenharmony_ci * of time and system resources. SPE Book IV indicates that SPE 148c2ecf20Sopenharmony_ci * allocation should follow a "serially reusable device" model, 158c2ecf20Sopenharmony_ci * in which the SPE is assigned a task until it completes. When 168c2ecf20Sopenharmony_ci * this is not possible, this sequence may be used to premptively 178c2ecf20Sopenharmony_ci * save, and then later (optionally) restore the context of a 188c2ecf20Sopenharmony_ci * program executing on an SPE. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/export.h> 228c2ecf20Sopenharmony_ci#include <linux/errno.h> 238c2ecf20Sopenharmony_ci#include <linux/hardirq.h> 248c2ecf20Sopenharmony_ci#include <linux/sched.h> 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/mm.h> 278c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 288c2ecf20Sopenharmony_ci#include <linux/smp.h> 298c2ecf20Sopenharmony_ci#include <linux/stddef.h> 308c2ecf20Sopenharmony_ci#include <linux/unistd.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <asm/io.h> 338c2ecf20Sopenharmony_ci#include <asm/spu.h> 348c2ecf20Sopenharmony_ci#include <asm/spu_priv1.h> 358c2ecf20Sopenharmony_ci#include <asm/spu_csa.h> 368c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "spufs.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "spu_save_dump.h" 418c2ecf20Sopenharmony_ci#include "spu_restore_dump.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#if 0 448c2ecf20Sopenharmony_ci#define POLL_WHILE_TRUE(_c) { \ 458c2ecf20Sopenharmony_ci do { \ 468c2ecf20Sopenharmony_ci } while (_c); \ 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci#else 498c2ecf20Sopenharmony_ci#define RELAX_SPIN_COUNT 1000 508c2ecf20Sopenharmony_ci#define POLL_WHILE_TRUE(_c) { \ 518c2ecf20Sopenharmony_ci do { \ 528c2ecf20Sopenharmony_ci int _i; \ 538c2ecf20Sopenharmony_ci for (_i=0; _i<RELAX_SPIN_COUNT && (_c); _i++) { \ 548c2ecf20Sopenharmony_ci cpu_relax(); \ 558c2ecf20Sopenharmony_ci } \ 568c2ecf20Sopenharmony_ci if (unlikely(_c)) yield(); \ 578c2ecf20Sopenharmony_ci else break; \ 588c2ecf20Sopenharmony_ci } while (_c); \ 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci#endif /* debug */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c)) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic inline void acquire_spu_lock(struct spu *spu) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci /* Save, Step 1: 678c2ecf20Sopenharmony_ci * Restore, Step 1: 688c2ecf20Sopenharmony_ci * Acquire SPU-specific mutual exclusion lock. 698c2ecf20Sopenharmony_ci * TBD. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic inline void release_spu_lock(struct spu *spu) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci /* Restore, Step 76: 768c2ecf20Sopenharmony_ci * Release SPU-specific mutual exclusion lock. 778c2ecf20Sopenharmony_ci * TBD. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline int check_spu_isolate(struct spu_state *csa, struct spu *spu) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 848c2ecf20Sopenharmony_ci u32 isolate_state; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* Save, Step 2: 878c2ecf20Sopenharmony_ci * Save, Step 6: 888c2ecf20Sopenharmony_ci * If SPU_Status[E,L,IS] any field is '1', this 898c2ecf20Sopenharmony_ci * SPU is in isolate state and cannot be context 908c2ecf20Sopenharmony_ci * saved at this time. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci isolate_state = SPU_STATUS_ISOLATED_STATE | 938c2ecf20Sopenharmony_ci SPU_STATUS_ISOLATED_LOAD_STATUS | SPU_STATUS_ISOLATED_EXIT_STATUS; 948c2ecf20Sopenharmony_ci return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic inline void disable_interrupts(struct spu_state *csa, struct spu *spu) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci /* Save, Step 3: 1008c2ecf20Sopenharmony_ci * Restore, Step 2: 1018c2ecf20Sopenharmony_ci * Save INT_Mask_class0 in CSA. 1028c2ecf20Sopenharmony_ci * Write INT_MASK_class0 with value of 0. 1038c2ecf20Sopenharmony_ci * Save INT_Mask_class1 in CSA. 1048c2ecf20Sopenharmony_ci * Write INT_MASK_class1 with value of 0. 1058c2ecf20Sopenharmony_ci * Save INT_Mask_class2 in CSA. 1068c2ecf20Sopenharmony_ci * Write INT_MASK_class2 with value of 0. 1078c2ecf20Sopenharmony_ci * Synchronize all three interrupts to be sure 1088c2ecf20Sopenharmony_ci * we no longer execute a handler on another CPU. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci spin_lock_irq(&spu->register_lock); 1118c2ecf20Sopenharmony_ci if (csa) { 1128c2ecf20Sopenharmony_ci csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0); 1138c2ecf20Sopenharmony_ci csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1); 1148c2ecf20Sopenharmony_ci csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 0, 0ul); 1178c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 1, 0ul); 1188c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 2, 0ul); 1198c2ecf20Sopenharmony_ci eieio(); 1208c2ecf20Sopenharmony_ci spin_unlock_irq(&spu->register_lock); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * This flag needs to be set before calling synchronize_irq so 1248c2ecf20Sopenharmony_ci * that the update will be visible to the relevant handlers 1258c2ecf20Sopenharmony_ci * via a simple load. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags); 1288c2ecf20Sopenharmony_ci clear_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags); 1298c2ecf20Sopenharmony_ci synchronize_irq(spu->irqs[0]); 1308c2ecf20Sopenharmony_ci synchronize_irq(spu->irqs[1]); 1318c2ecf20Sopenharmony_ci synchronize_irq(spu->irqs[2]); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci /* Save, Step 4: 1378c2ecf20Sopenharmony_ci * Restore, Step 25. 1388c2ecf20Sopenharmony_ci * Set a software watchdog timer, which specifies the 1398c2ecf20Sopenharmony_ci * maximum allowable time for a context save sequence. 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * For present, this implementation will not set a global 1428c2ecf20Sopenharmony_ci * watchdog timer, as virtualization & variable system load 1438c2ecf20Sopenharmony_ci * may cause unpredictable execution times. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic inline void inhibit_user_access(struct spu_state *csa, struct spu *spu) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci /* Save, Step 5: 1508c2ecf20Sopenharmony_ci * Restore, Step 3: 1518c2ecf20Sopenharmony_ci * Inhibit user-space access (if provided) to this 1528c2ecf20Sopenharmony_ci * SPU by unmapping the virtual pages assigned to 1538c2ecf20Sopenharmony_ci * the SPU memory-mapped I/O (MMIO) for problem 1548c2ecf20Sopenharmony_ci * state. TBD. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic inline void set_switch_pending(struct spu_state *csa, struct spu *spu) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci /* Save, Step 7: 1618c2ecf20Sopenharmony_ci * Restore, Step 5: 1628c2ecf20Sopenharmony_ci * Set a software context switch pending flag. 1638c2ecf20Sopenharmony_ci * Done above in Step 3 - disable_interrupts(). 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Save, Step 8: 1728c2ecf20Sopenharmony_ci * Suspend DMA and save MFC_CNTL. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci switch (in_be64(&priv2->mfc_control_RW) & 1758c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_DMA_STATUS_MASK) { 1768c2ecf20Sopenharmony_ci case MFC_CNTL_SUSPEND_IN_PROGRESS: 1778c2ecf20Sopenharmony_ci POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) & 1788c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_DMA_STATUS_MASK) == 1798c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_COMPLETE); 1808c2ecf20Sopenharmony_ci fallthrough; 1818c2ecf20Sopenharmony_ci case MFC_CNTL_SUSPEND_COMPLETE: 1828c2ecf20Sopenharmony_ci if (csa) 1838c2ecf20Sopenharmony_ci csa->priv2.mfc_control_RW = 1848c2ecf20Sopenharmony_ci in_be64(&priv2->mfc_control_RW) | 1858c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_DMA_QUEUE; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION: 1888c2ecf20Sopenharmony_ci out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE); 1898c2ecf20Sopenharmony_ci POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) & 1908c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_DMA_STATUS_MASK) == 1918c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_COMPLETE); 1928c2ecf20Sopenharmony_ci if (csa) 1938c2ecf20Sopenharmony_ci csa->priv2.mfc_control_RW = 1948c2ecf20Sopenharmony_ci in_be64(&priv2->mfc_control_RW) & 1958c2ecf20Sopenharmony_ci ~MFC_CNTL_SUSPEND_DMA_QUEUE & 1968c2ecf20Sopenharmony_ci ~MFC_CNTL_SUSPEND_MASK; 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic inline void save_spu_runcntl(struct spu_state *csa, struct spu *spu) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* Save, Step 9: 2068c2ecf20Sopenharmony_ci * Save SPU_Runcntl in the CSA. This value contains 2078c2ecf20Sopenharmony_ci * the "Application Desired State". 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci csa->prob.spu_runcntl_RW = in_be32(&prob->spu_runcntl_RW); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci /* Save, Step 10: 2158c2ecf20Sopenharmony_ci * Save MFC_SR1 in the CSA. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci csa->priv1.mfc_sr1_RW = spu_mfc_sr1_get(spu); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic inline void save_spu_status(struct spu_state *csa, struct spu *spu) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* Save, Step 11: 2258c2ecf20Sopenharmony_ci * Read SPU_Status[R], and save to CSA. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci if ((in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) == 0) { 2288c2ecf20Sopenharmony_ci csa->prob.spu_status_R = in_be32(&prob->spu_status_R); 2298c2ecf20Sopenharmony_ci } else { 2308c2ecf20Sopenharmony_ci u32 stopped; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); 2338c2ecf20Sopenharmony_ci eieio(); 2348c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 2358c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 2368c2ecf20Sopenharmony_ci stopped = 2378c2ecf20Sopenharmony_ci SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | 2388c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; 2398c2ecf20Sopenharmony_ci if ((in_be32(&prob->spu_status_R) & stopped) == 0) 2408c2ecf20Sopenharmony_ci csa->prob.spu_status_R = SPU_STATUS_RUNNING; 2418c2ecf20Sopenharmony_ci else 2428c2ecf20Sopenharmony_ci csa->prob.spu_status_R = in_be32(&prob->spu_status_R); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic inline void save_mfc_stopped_status(struct spu_state *csa, 2478c2ecf20Sopenharmony_ci struct spu *spu) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 2508c2ecf20Sopenharmony_ci const u64 mask = MFC_CNTL_DECREMENTER_RUNNING | 2518c2ecf20Sopenharmony_ci MFC_CNTL_DMA_QUEUES_EMPTY; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Save, Step 12: 2548c2ecf20Sopenharmony_ci * Read MFC_CNTL[Ds]. Update saved copy of 2558c2ecf20Sopenharmony_ci * CSA.MFC_CNTL[Ds]. 2568c2ecf20Sopenharmony_ci * 2578c2ecf20Sopenharmony_ci * update: do the same with MFC_CNTL[Q]. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci csa->priv2.mfc_control_RW &= ~mask; 2608c2ecf20Sopenharmony_ci csa->priv2.mfc_control_RW |= in_be64(&priv2->mfc_control_RW) & mask; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Save, Step 13: 2688c2ecf20Sopenharmony_ci * Write MFC_CNTL[Dh] set to a '1' to halt 2698c2ecf20Sopenharmony_ci * the decrementer. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci out_be64(&priv2->mfc_control_RW, 2728c2ecf20Sopenharmony_ci MFC_CNTL_DECREMENTER_HALTED | MFC_CNTL_SUSPEND_MASK); 2738c2ecf20Sopenharmony_ci eieio(); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic inline void save_timebase(struct spu_state *csa, struct spu *spu) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci /* Save, Step 14: 2798c2ecf20Sopenharmony_ci * Read PPE Timebase High and Timebase low registers 2808c2ecf20Sopenharmony_ci * and save in CSA. TBD. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci csa->suspend_time = get_cycles(); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic inline void remove_other_spu_access(struct spu_state *csa, 2868c2ecf20Sopenharmony_ci struct spu *spu) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci /* Save, Step 15: 2898c2ecf20Sopenharmony_ci * Remove other SPU access to this SPU by unmapping 2908c2ecf20Sopenharmony_ci * this SPU's pages from their address space. TBD. 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic inline void do_mfc_mssync(struct spu_state *csa, struct spu *spu) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Save, Step 16: 2998c2ecf20Sopenharmony_ci * Restore, Step 11. 3008c2ecf20Sopenharmony_ci * Write SPU_MSSync register. Poll SPU_MSSync[P] 3018c2ecf20Sopenharmony_ci * for a value of 0. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci out_be64(&prob->spc_mssync_RW, 1UL); 3048c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be64(&prob->spc_mssync_RW) & MS_SYNC_PENDING); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci /* Save, Step 17: 3108c2ecf20Sopenharmony_ci * Restore, Step 12. 3118c2ecf20Sopenharmony_ci * Restore, Step 48. 3128c2ecf20Sopenharmony_ci * Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register. 3138c2ecf20Sopenharmony_ci * Then issue a PPE sync instruction. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci spu_tlb_invalidate(spu); 3168c2ecf20Sopenharmony_ci mb(); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic inline void handle_pending_interrupts(struct spu_state *csa, 3208c2ecf20Sopenharmony_ci struct spu *spu) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci /* Save, Step 18: 3238c2ecf20Sopenharmony_ci * Handle any pending interrupts from this SPU 3248c2ecf20Sopenharmony_ci * here. This is OS or hypervisor specific. One 3258c2ecf20Sopenharmony_ci * option is to re-enable interrupts to handle any 3268c2ecf20Sopenharmony_ci * pending interrupts, with the interrupt handlers 3278c2ecf20Sopenharmony_ci * recognizing the software Context Switch Pending 3288c2ecf20Sopenharmony_ci * flag, to ensure the SPU execution or MFC command 3298c2ecf20Sopenharmony_ci * queue is not restarted. TBD. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic inline void save_mfc_queues(struct spu_state *csa, struct spu *spu) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 3368c2ecf20Sopenharmony_ci int i; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Save, Step 19: 3398c2ecf20Sopenharmony_ci * If MFC_Cntl[Se]=0 then save 3408c2ecf20Sopenharmony_ci * MFC command queues. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci if ((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DMA_QUEUES_EMPTY) == 0) { 3438c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 3448c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data0_RW = 3458c2ecf20Sopenharmony_ci in_be64(&priv2->puq[i].mfc_cq_data0_RW); 3468c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data1_RW = 3478c2ecf20Sopenharmony_ci in_be64(&priv2->puq[i].mfc_cq_data1_RW); 3488c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data2_RW = 3498c2ecf20Sopenharmony_ci in_be64(&priv2->puq[i].mfc_cq_data2_RW); 3508c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data3_RW = 3518c2ecf20Sopenharmony_ci in_be64(&priv2->puq[i].mfc_cq_data3_RW); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 3548c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data0_RW = 3558c2ecf20Sopenharmony_ci in_be64(&priv2->spuq[i].mfc_cq_data0_RW); 3568c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data1_RW = 3578c2ecf20Sopenharmony_ci in_be64(&priv2->spuq[i].mfc_cq_data1_RW); 3588c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data2_RW = 3598c2ecf20Sopenharmony_ci in_be64(&priv2->spuq[i].mfc_cq_data2_RW); 3608c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data3_RW = 3618c2ecf20Sopenharmony_ci in_be64(&priv2->spuq[i].mfc_cq_data3_RW); 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic inline void save_ppu_querymask(struct spu_state *csa, struct spu *spu) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Save, Step 20: 3718c2ecf20Sopenharmony_ci * Save the PPU_QueryMask register 3728c2ecf20Sopenharmony_ci * in the CSA. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci csa->prob.dma_querymask_RW = in_be32(&prob->dma_querymask_RW); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Save, Step 21: 3828c2ecf20Sopenharmony_ci * Save the PPU_QueryType register 3838c2ecf20Sopenharmony_ci * in the CSA. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ci csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic inline void save_ppu_tagstatus(struct spu_state *csa, struct spu *spu) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* Save the Prxy_TagStatus register in the CSA. 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * It is unnecessary to restore dma_tagstatus_R, however, 3958c2ecf20Sopenharmony_ci * dma_tagstatus_R in the CSA is accessed via backing_ops, so 3968c2ecf20Sopenharmony_ci * we must save it. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci csa->prob.dma_tagstatus_R = in_be32(&prob->dma_tagstatus_R); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Save, Step 22: 4068c2ecf20Sopenharmony_ci * Save the MFC_CSR_TSQ register 4078c2ecf20Sopenharmony_ci * in the LSCSA. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci csa->priv2.spu_tag_status_query_RW = 4108c2ecf20Sopenharmony_ci in_be64(&priv2->spu_tag_status_query_RW); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic inline void save_mfc_csr_cmd(struct spu_state *csa, struct spu *spu) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Save, Step 23: 4188c2ecf20Sopenharmony_ci * Save the MFC_CSR_CMD1 and MFC_CSR_CMD2 4198c2ecf20Sopenharmony_ci * registers in the CSA. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci csa->priv2.spu_cmd_buf1_RW = in_be64(&priv2->spu_cmd_buf1_RW); 4228c2ecf20Sopenharmony_ci csa->priv2.spu_cmd_buf2_RW = in_be64(&priv2->spu_cmd_buf2_RW); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic inline void save_mfc_csr_ato(struct spu_state *csa, struct spu *spu) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Save, Step 24: 4308c2ecf20Sopenharmony_ci * Save the MFC_CSR_ATO register in 4318c2ecf20Sopenharmony_ci * the CSA. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci csa->priv2.spu_atomic_status_RW = in_be64(&priv2->spu_atomic_status_RW); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci /* Save, Step 25: 4398c2ecf20Sopenharmony_ci * Save the MFC_TCLASS_ID register in 4408c2ecf20Sopenharmony_ci * the CSA. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ci csa->priv1.mfc_tclass_id_RW = spu_mfc_tclass_id_get(spu); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci /* Save, Step 26: 4488c2ecf20Sopenharmony_ci * Restore, Step 23. 4498c2ecf20Sopenharmony_ci * Write the MFC_TCLASS_ID register with 4508c2ecf20Sopenharmony_ci * the value 0x10000000. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci spu_mfc_tclass_id_set(spu, 0x10000000); 4538c2ecf20Sopenharmony_ci eieio(); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic inline void purge_mfc_queue(struct spu_state *csa, struct spu *spu) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* Save, Step 27: 4618c2ecf20Sopenharmony_ci * Restore, Step 14. 4628c2ecf20Sopenharmony_ci * Write MFC_CNTL[Pc]=1 (purge queue). 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_ci out_be64(&priv2->mfc_control_RW, 4658c2ecf20Sopenharmony_ci MFC_CNTL_PURGE_DMA_REQUEST | 4668c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_MASK); 4678c2ecf20Sopenharmony_ci eieio(); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic inline void wait_purge_complete(struct spu_state *csa, struct spu *spu) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Save, Step 28: 4758c2ecf20Sopenharmony_ci * Poll MFC_CNTL[Ps] until value '11' is read 4768c2ecf20Sopenharmony_ci * (purge complete). 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_ci POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) & 4798c2ecf20Sopenharmony_ci MFC_CNTL_PURGE_DMA_STATUS_MASK) == 4808c2ecf20Sopenharmony_ci MFC_CNTL_PURGE_DMA_COMPLETE); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci /* Save, Step 30: 4868c2ecf20Sopenharmony_ci * Restore, Step 18: 4878c2ecf20Sopenharmony_ci * Write MFC_SR1 with MFC_SR1[D=0,S=1] and 4888c2ecf20Sopenharmony_ci * MFC_SR1[TL,R,Pr,T] set correctly for the 4898c2ecf20Sopenharmony_ci * OS specific environment. 4908c2ecf20Sopenharmony_ci * 4918c2ecf20Sopenharmony_ci * Implementation note: The SPU-side code 4928c2ecf20Sopenharmony_ci * for save/restore is privileged, so the 4938c2ecf20Sopenharmony_ci * MFC_SR1[Pr] bit is not set. 4948c2ecf20Sopenharmony_ci * 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci spu_mfc_sr1_set(spu, (MFC_STATE1_MASTER_RUN_CONTROL_MASK | 4978c2ecf20Sopenharmony_ci MFC_STATE1_RELOCATE_MASK | 4988c2ecf20Sopenharmony_ci MFC_STATE1_BUS_TLBIE_MASK)); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic inline void save_spu_npc(struct spu_state *csa, struct spu *spu) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Save, Step 31: 5068c2ecf20Sopenharmony_ci * Save SPU_NPC in the CSA. 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ci csa->prob.spu_npc_RW = in_be32(&prob->spu_npc_RW); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic inline void save_spu_privcntl(struct spu_state *csa, struct spu *spu) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* Save, Step 32: 5168c2ecf20Sopenharmony_ci * Save SPU_PrivCntl in the CSA. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ci csa->priv2.spu_privcntl_RW = in_be64(&priv2->spu_privcntl_RW); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic inline void reset_spu_privcntl(struct spu_state *csa, struct spu *spu) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Save, Step 33: 5268c2ecf20Sopenharmony_ci * Restore, Step 16: 5278c2ecf20Sopenharmony_ci * Write SPU_PrivCntl[S,Le,A] fields reset to 0. 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_ci out_be64(&priv2->spu_privcntl_RW, 0UL); 5308c2ecf20Sopenharmony_ci eieio(); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic inline void save_spu_lslr(struct spu_state *csa, struct spu *spu) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* Save, Step 34: 5388c2ecf20Sopenharmony_ci * Save SPU_LSLR in the CSA. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci csa->priv2.spu_lslr_RW = in_be64(&priv2->spu_lslr_RW); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic inline void reset_spu_lslr(struct spu_state *csa, struct spu *spu) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Save, Step 35: 5488c2ecf20Sopenharmony_ci * Restore, Step 17. 5498c2ecf20Sopenharmony_ci * Reset SPU_LSLR. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci out_be64(&priv2->spu_lslr_RW, LS_ADDR_MASK); 5528c2ecf20Sopenharmony_ci eieio(); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic inline void save_spu_cfg(struct spu_state *csa, struct spu *spu) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Save, Step 36: 5608c2ecf20Sopenharmony_ci * Save SPU_Cfg in the CSA. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci csa->priv2.spu_cfg_RW = in_be64(&priv2->spu_cfg_RW); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic inline void save_pm_trace(struct spu_state *csa, struct spu *spu) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci /* Save, Step 37: 5688c2ecf20Sopenharmony_ci * Save PM_Trace_Tag_Wait_Mask in the CSA. 5698c2ecf20Sopenharmony_ci * Not performed by this implementation. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic inline void save_mfc_rag(struct spu_state *csa, struct spu *spu) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci /* Save, Step 38: 5768c2ecf20Sopenharmony_ci * Save RA_GROUP_ID register and the 5778c2ecf20Sopenharmony_ci * RA_ENABLE reigster in the CSA. 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci csa->priv1.resource_allocation_groupID_RW = 5808c2ecf20Sopenharmony_ci spu_resource_allocation_groupID_get(spu); 5818c2ecf20Sopenharmony_ci csa->priv1.resource_allocation_enable_RW = 5828c2ecf20Sopenharmony_ci spu_resource_allocation_enable_get(spu); 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* Save, Step 39: 5908c2ecf20Sopenharmony_ci * Save MB_Stat register in the CSA. 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci csa->prob.mb_stat_R = in_be32(&prob->mb_stat_R); 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic inline void save_ppu_mb(struct spu_state *csa, struct spu *spu) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* Save, Step 40: 6008c2ecf20Sopenharmony_ci * Save the PPU_MB register in the CSA. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci csa->prob.pu_mb_R = in_be32(&prob->pu_mb_R); 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* Save, Step 41: 6108c2ecf20Sopenharmony_ci * Save the PPUINT_MB register in the CSA. 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_ci csa->priv2.puint_mb_R = in_be64(&priv2->puint_mb_R); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic inline void save_ch_part1(struct spu_state *csa, struct spu *spu) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 6188c2ecf20Sopenharmony_ci u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 6198c2ecf20Sopenharmony_ci int i; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Save, Step 42: 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Save CH 1, without channel count */ 6258c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, 1); 6268c2ecf20Sopenharmony_ci csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* Save the following CH: [0,3,4,24,25,27] */ 6298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ch_indices); i++) { 6308c2ecf20Sopenharmony_ci idx = ch_indices[i]; 6318c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, idx); 6328c2ecf20Sopenharmony_ci eieio(); 6338c2ecf20Sopenharmony_ci csa->spu_chnldata_RW[idx] = in_be64(&priv2->spu_chnldata_RW); 6348c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[idx] = in_be64(&priv2->spu_chnlcnt_RW); 6358c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnldata_RW, 0UL); 6368c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, 0UL); 6378c2ecf20Sopenharmony_ci eieio(); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic inline void save_spu_mb(struct spu_state *csa, struct spu *spu) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 6448c2ecf20Sopenharmony_ci int i; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* Save, Step 43: 6478c2ecf20Sopenharmony_ci * Save SPU Read Mailbox Channel. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, 29UL); 6508c2ecf20Sopenharmony_ci eieio(); 6518c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW); 6528c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 6538c2ecf20Sopenharmony_ci csa->spu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, 0UL); 6568c2ecf20Sopenharmony_ci eieio(); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic inline void save_mfc_cmd(struct spu_state *csa, struct spu *spu) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Save, Step 44: 6648c2ecf20Sopenharmony_ci * Save MFC_CMD Channel. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, 21UL); 6678c2ecf20Sopenharmony_ci eieio(); 6688c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[21] = in_be64(&priv2->spu_chnlcnt_RW); 6698c2ecf20Sopenharmony_ci eieio(); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic inline void reset_ch(struct spu_state *csa, struct spu *spu) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 6758c2ecf20Sopenharmony_ci u64 ch_indices[4] = { 21UL, 23UL, 28UL, 30UL }; 6768c2ecf20Sopenharmony_ci u64 ch_counts[4] = { 16UL, 1UL, 1UL, 1UL }; 6778c2ecf20Sopenharmony_ci u64 idx; 6788c2ecf20Sopenharmony_ci int i; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* Save, Step 45: 6818c2ecf20Sopenharmony_ci * Reset the following CH: [21, 23, 28, 30] 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 6848c2ecf20Sopenharmony_ci idx = ch_indices[i]; 6858c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, idx); 6868c2ecf20Sopenharmony_ci eieio(); 6878c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]); 6888c2ecf20Sopenharmony_ci eieio(); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Save, Step 46: 6978c2ecf20Sopenharmony_ci * Restore, Step 25. 6988c2ecf20Sopenharmony_ci * Write MFC_CNTL[Sc]=0 (resume queue processing). 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu, 7048c2ecf20Sopenharmony_ci unsigned int *code, int code_size) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci /* Save, Step 47: 7078c2ecf20Sopenharmony_ci * Restore, Step 30. 7088c2ecf20Sopenharmony_ci * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All 7098c2ecf20Sopenharmony_ci * register, then initialize SLB_VSID and SLB_ESID 7108c2ecf20Sopenharmony_ci * to provide access to SPU context save code and 7118c2ecf20Sopenharmony_ci * LSCSA. 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * This implementation places both the context 7148c2ecf20Sopenharmony_ci * switch code and LSCSA in kernel address space. 7158c2ecf20Sopenharmony_ci * 7168c2ecf20Sopenharmony_ci * Further this implementation assumes that the 7178c2ecf20Sopenharmony_ci * MFC_SR1[R]=1 (in other words, assume that 7188c2ecf20Sopenharmony_ci * translation is desired by OS environment). 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci spu_invalidate_slbs(spu); 7218c2ecf20Sopenharmony_ci spu_setup_kernel_slbs(spu, csa->lscsa, code, code_size); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic inline void set_switch_active(struct spu_state *csa, struct spu *spu) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci /* Save, Step 48: 7278c2ecf20Sopenharmony_ci * Restore, Step 23. 7288c2ecf20Sopenharmony_ci * Change the software context switch pending flag 7298c2ecf20Sopenharmony_ci * to context switch active. This implementation does 7308c2ecf20Sopenharmony_ci * not uses a switch active flag. 7318c2ecf20Sopenharmony_ci * 7328c2ecf20Sopenharmony_ci * Now that we have saved the mfc in the csa, we can add in the 7338c2ecf20Sopenharmony_ci * restart command if an exception occurred. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_ci if (test_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags)) 7368c2ecf20Sopenharmony_ci csa->priv2.mfc_control_RW |= MFC_CNTL_RESTART_DMA_COMMAND; 7378c2ecf20Sopenharmony_ci clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags); 7388c2ecf20Sopenharmony_ci mb(); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic inline void enable_interrupts(struct spu_state *csa, struct spu *spu) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR | 7448c2ecf20Sopenharmony_ci CLASS1_ENABLE_STORAGE_FAULT_INTR; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* Save, Step 49: 7478c2ecf20Sopenharmony_ci * Restore, Step 22: 7488c2ecf20Sopenharmony_ci * Reset and then enable interrupts, as 7498c2ecf20Sopenharmony_ci * needed by OS. 7508c2ecf20Sopenharmony_ci * 7518c2ecf20Sopenharmony_ci * This implementation enables only class1 7528c2ecf20Sopenharmony_ci * (translation) interrupts. 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_ci spin_lock_irq(&spu->register_lock); 7558c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); 7568c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK); 7578c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); 7588c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 0, 0ul); 7598c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 1, class1_mask); 7608c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 2, 0ul); 7618c2ecf20Sopenharmony_ci spin_unlock_irq(&spu->register_lock); 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic inline int send_mfc_dma(struct spu *spu, unsigned long ea, 7658c2ecf20Sopenharmony_ci unsigned int ls_offset, unsigned int size, 7668c2ecf20Sopenharmony_ci unsigned int tag, unsigned int rclass, 7678c2ecf20Sopenharmony_ci unsigned int cmd) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 7708c2ecf20Sopenharmony_ci union mfc_tag_size_class_cmd command; 7718c2ecf20Sopenharmony_ci unsigned int transfer_size; 7728c2ecf20Sopenharmony_ci volatile unsigned int status = 0x0; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci while (size > 0) { 7758c2ecf20Sopenharmony_ci transfer_size = 7768c2ecf20Sopenharmony_ci (size > MFC_MAX_DMA_SIZE) ? MFC_MAX_DMA_SIZE : size; 7778c2ecf20Sopenharmony_ci command.u.mfc_size = transfer_size; 7788c2ecf20Sopenharmony_ci command.u.mfc_tag = tag; 7798c2ecf20Sopenharmony_ci command.u.mfc_rclassid = rclass; 7808c2ecf20Sopenharmony_ci command.u.mfc_cmd = cmd; 7818c2ecf20Sopenharmony_ci do { 7828c2ecf20Sopenharmony_ci out_be32(&prob->mfc_lsa_W, ls_offset); 7838c2ecf20Sopenharmony_ci out_be64(&prob->mfc_ea_W, ea); 7848c2ecf20Sopenharmony_ci out_be64(&prob->mfc_union_W.all64, command.all64); 7858c2ecf20Sopenharmony_ci status = 7868c2ecf20Sopenharmony_ci in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32); 7878c2ecf20Sopenharmony_ci if (unlikely(status & 0x2)) { 7888c2ecf20Sopenharmony_ci cpu_relax(); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci } while (status & 0x3); 7918c2ecf20Sopenharmony_ci size -= transfer_size; 7928c2ecf20Sopenharmony_ci ea += transfer_size; 7938c2ecf20Sopenharmony_ci ls_offset += transfer_size; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic inline void save_ls_16kb(struct spu_state *csa, struct spu *spu) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)&csa->lscsa->ls[0]; 8018c2ecf20Sopenharmony_ci unsigned int ls_offset = 0x0; 8028c2ecf20Sopenharmony_ci unsigned int size = 16384; 8038c2ecf20Sopenharmony_ci unsigned int tag = 0; 8048c2ecf20Sopenharmony_ci unsigned int rclass = 0; 8058c2ecf20Sopenharmony_ci unsigned int cmd = MFC_PUT_CMD; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* Save, Step 50: 8088c2ecf20Sopenharmony_ci * Issue a DMA command to copy the first 16K bytes 8098c2ecf20Sopenharmony_ci * of local storage to the CSA. 8108c2ecf20Sopenharmony_ci */ 8118c2ecf20Sopenharmony_ci send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic inline void set_spu_npc(struct spu_state *csa, struct spu *spu) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* Save, Step 51: 8198c2ecf20Sopenharmony_ci * Restore, Step 31. 8208c2ecf20Sopenharmony_ci * Write SPU_NPC[IE]=0 and SPU_NPC[LSA] to entry 8218c2ecf20Sopenharmony_ci * point address of context save code in local 8228c2ecf20Sopenharmony_ci * storage. 8238c2ecf20Sopenharmony_ci * 8248c2ecf20Sopenharmony_ci * This implementation uses SPU-side save/restore 8258c2ecf20Sopenharmony_ci * programs with entry points at LSA of 0. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci out_be32(&prob->spu_npc_RW, 0); 8288c2ecf20Sopenharmony_ci eieio(); 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic inline void set_signot1(struct spu_state *csa, struct spu *spu) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 8348c2ecf20Sopenharmony_ci union { 8358c2ecf20Sopenharmony_ci u64 ull; 8368c2ecf20Sopenharmony_ci u32 ui[2]; 8378c2ecf20Sopenharmony_ci } addr64; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* Save, Step 52: 8408c2ecf20Sopenharmony_ci * Restore, Step 32: 8418c2ecf20Sopenharmony_ci * Write SPU_Sig_Notify_1 register with upper 32-bits 8428c2ecf20Sopenharmony_ci * of the CSA.LSCSA effective address. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci addr64.ull = (u64) csa->lscsa; 8458c2ecf20Sopenharmony_ci out_be32(&prob->signal_notify1, addr64.ui[0]); 8468c2ecf20Sopenharmony_ci eieio(); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic inline void set_signot2(struct spu_state *csa, struct spu *spu) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 8528c2ecf20Sopenharmony_ci union { 8538c2ecf20Sopenharmony_ci u64 ull; 8548c2ecf20Sopenharmony_ci u32 ui[2]; 8558c2ecf20Sopenharmony_ci } addr64; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Save, Step 53: 8588c2ecf20Sopenharmony_ci * Restore, Step 33: 8598c2ecf20Sopenharmony_ci * Write SPU_Sig_Notify_2 register with lower 32-bits 8608c2ecf20Sopenharmony_ci * of the CSA.LSCSA effective address. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci addr64.ull = (u64) csa->lscsa; 8638c2ecf20Sopenharmony_ci out_be32(&prob->signal_notify2, addr64.ui[1]); 8648c2ecf20Sopenharmony_ci eieio(); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic inline void send_save_code(struct spu_state *csa, struct spu *spu) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)&spu_save_code[0]; 8708c2ecf20Sopenharmony_ci unsigned int ls_offset = 0x0; 8718c2ecf20Sopenharmony_ci unsigned int size = sizeof(spu_save_code); 8728c2ecf20Sopenharmony_ci unsigned int tag = 0; 8738c2ecf20Sopenharmony_ci unsigned int rclass = 0; 8748c2ecf20Sopenharmony_ci unsigned int cmd = MFC_GETFS_CMD; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* Save, Step 54: 8778c2ecf20Sopenharmony_ci * Issue a DMA command to copy context save code 8788c2ecf20Sopenharmony_ci * to local storage and start SPU. 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_ci send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Save, Step 55: 8888c2ecf20Sopenharmony_ci * Restore, Step 38. 8898c2ecf20Sopenharmony_ci * Write PPU_QueryMask=1 (enable Tag Group 0) 8908c2ecf20Sopenharmony_ci * and issue eieio instruction. 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci out_be32(&prob->dma_querymask_RW, MFC_TAGID_TO_TAGMASK(0)); 8938c2ecf20Sopenharmony_ci eieio(); 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic inline void wait_tag_complete(struct spu_state *csa, struct spu *spu) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 8998c2ecf20Sopenharmony_ci u32 mask = MFC_TAGID_TO_TAGMASK(0); 9008c2ecf20Sopenharmony_ci unsigned long flags; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* Save, Step 56: 9038c2ecf20Sopenharmony_ci * Restore, Step 39. 9048c2ecf20Sopenharmony_ci * Restore, Step 39. 9058c2ecf20Sopenharmony_ci * Restore, Step 46. 9068c2ecf20Sopenharmony_ci * Poll PPU_TagStatus[gn] until 01 (Tag group 0 complete) 9078c2ecf20Sopenharmony_ci * or write PPU_QueryType[TS]=01 and wait for Tag Group 9088c2ecf20Sopenharmony_ci * Complete Interrupt. Write INT_Stat_Class0 or 9098c2ecf20Sopenharmony_ci * INT_Stat_Class2 with value of 'handled'. 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_ci POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci local_irq_save(flags); 9148c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); 9158c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); 9168c2ecf20Sopenharmony_ci local_irq_restore(flags); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 9228c2ecf20Sopenharmony_ci unsigned long flags; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* Save, Step 57: 9258c2ecf20Sopenharmony_ci * Restore, Step 40. 9268c2ecf20Sopenharmony_ci * Poll until SPU_Status[R]=0 or wait for SPU Class 0 9278c2ecf20Sopenharmony_ci * or SPU Class 2 interrupt. Write INT_Stat_class0 9288c2ecf20Sopenharmony_ci * or INT_Stat_class2 with value of handled. 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci local_irq_save(flags); 9338c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); 9348c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); 9358c2ecf20Sopenharmony_ci local_irq_restore(flags); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic inline int check_save_status(struct spu_state *csa, struct spu *spu) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 9418c2ecf20Sopenharmony_ci u32 complete; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* Save, Step 54: 9448c2ecf20Sopenharmony_ci * If SPU_Status[P]=1 and SPU_Status[SC] = "success", 9458c2ecf20Sopenharmony_ci * context save succeeded, otherwise context save 9468c2ecf20Sopenharmony_ci * failed. 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_ci complete = ((SPU_SAVE_COMPLETE << SPU_STOP_STATUS_SHIFT) | 9498c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_STOP); 9508c2ecf20Sopenharmony_ci return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0; 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic inline void terminate_spu_app(struct spu_state *csa, struct spu *spu) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci /* Restore, Step 4: 9568c2ecf20Sopenharmony_ci * If required, notify the "using application" that 9578c2ecf20Sopenharmony_ci * the SPU task has been terminated. TBD. 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic inline void suspend_mfc_and_halt_decr(struct spu_state *csa, 9628c2ecf20Sopenharmony_ci struct spu *spu) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* Restore, Step 7: 9678c2ecf20Sopenharmony_ci * Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend 9688c2ecf20Sopenharmony_ci * the queue and halt the decrementer. 9698c2ecf20Sopenharmony_ci */ 9708c2ecf20Sopenharmony_ci out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE | 9718c2ecf20Sopenharmony_ci MFC_CNTL_DECREMENTER_HALTED); 9728c2ecf20Sopenharmony_ci eieio(); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic inline void wait_suspend_mfc_complete(struct spu_state *csa, 9768c2ecf20Sopenharmony_ci struct spu *spu) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* Restore, Step 8: 9818c2ecf20Sopenharmony_ci * Restore, Step 47. 9828c2ecf20Sopenharmony_ci * Poll MFC_CNTL[Ss] until 11 is returned. 9838c2ecf20Sopenharmony_ci */ 9848c2ecf20Sopenharmony_ci POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) & 9858c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_DMA_STATUS_MASK) == 9868c2ecf20Sopenharmony_ci MFC_CNTL_SUSPEND_COMPLETE); 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic inline int suspend_spe(struct spu_state *csa, struct spu *spu) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* Restore, Step 9: 9948c2ecf20Sopenharmony_ci * If SPU_Status[R]=1, stop SPU execution 9958c2ecf20Sopenharmony_ci * and wait for stop to complete. 9968c2ecf20Sopenharmony_ci * 9978c2ecf20Sopenharmony_ci * Returns 1 if SPU_Status[R]=1 on entry. 9988c2ecf20Sopenharmony_ci * 0 otherwise 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ci if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) { 10018c2ecf20Sopenharmony_ci if (in_be32(&prob->spu_status_R) & 10028c2ecf20Sopenharmony_ci SPU_STATUS_ISOLATED_EXIT_STATUS) { 10038c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 10048c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci if ((in_be32(&prob->spu_status_R) & 10078c2ecf20Sopenharmony_ci SPU_STATUS_ISOLATED_LOAD_STATUS) 10088c2ecf20Sopenharmony_ci || (in_be32(&prob->spu_status_R) & 10098c2ecf20Sopenharmony_ci SPU_STATUS_ISOLATED_STATE)) { 10108c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); 10118c2ecf20Sopenharmony_ci eieio(); 10128c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 10138c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 10148c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, 0x2); 10158c2ecf20Sopenharmony_ci eieio(); 10168c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 10178c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci if (in_be32(&prob->spu_status_R) & 10208c2ecf20Sopenharmony_ci SPU_STATUS_WAITING_FOR_CHANNEL) { 10218c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); 10228c2ecf20Sopenharmony_ci eieio(); 10238c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 10248c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci return 1; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci return 0; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic inline void clear_spu_status(struct spu_state *csa, struct spu *spu) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* Restore, Step 10: 10368c2ecf20Sopenharmony_ci * If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1, 10378c2ecf20Sopenharmony_ci * release SPU from isolate state. 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_ci if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) { 10408c2ecf20Sopenharmony_ci if (in_be32(&prob->spu_status_R) & 10418c2ecf20Sopenharmony_ci SPU_STATUS_ISOLATED_EXIT_STATUS) { 10428c2ecf20Sopenharmony_ci spu_mfc_sr1_set(spu, 10438c2ecf20Sopenharmony_ci MFC_STATE1_MASTER_RUN_CONTROL_MASK); 10448c2ecf20Sopenharmony_ci eieio(); 10458c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); 10468c2ecf20Sopenharmony_ci eieio(); 10478c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 10488c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci if ((in_be32(&prob->spu_status_R) & 10518c2ecf20Sopenharmony_ci SPU_STATUS_ISOLATED_LOAD_STATUS) 10528c2ecf20Sopenharmony_ci || (in_be32(&prob->spu_status_R) & 10538c2ecf20Sopenharmony_ci SPU_STATUS_ISOLATED_STATE)) { 10548c2ecf20Sopenharmony_ci spu_mfc_sr1_set(spu, 10558c2ecf20Sopenharmony_ci MFC_STATE1_MASTER_RUN_CONTROL_MASK); 10568c2ecf20Sopenharmony_ci eieio(); 10578c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, 0x2); 10588c2ecf20Sopenharmony_ci eieio(); 10598c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 10608c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic inline void reset_ch_part1(struct spu_state *csa, struct spu *spu) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 10688c2ecf20Sopenharmony_ci u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 10698c2ecf20Sopenharmony_ci u64 idx; 10708c2ecf20Sopenharmony_ci int i; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* Restore, Step 20: 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* Reset CH 1 */ 10768c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, 1); 10778c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnldata_RW, 0UL); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* Reset the following CH: [0,3,4,24,25,27] */ 10808c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ch_indices); i++) { 10818c2ecf20Sopenharmony_ci idx = ch_indices[i]; 10828c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, idx); 10838c2ecf20Sopenharmony_ci eieio(); 10848c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnldata_RW, 0UL); 10858c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, 0UL); 10868c2ecf20Sopenharmony_ci eieio(); 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic inline void reset_ch_part2(struct spu_state *csa, struct spu *spu) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 10938c2ecf20Sopenharmony_ci u64 ch_indices[5] = { 21UL, 23UL, 28UL, 29UL, 30UL }; 10948c2ecf20Sopenharmony_ci u64 ch_counts[5] = { 16UL, 1UL, 1UL, 0UL, 1UL }; 10958c2ecf20Sopenharmony_ci u64 idx; 10968c2ecf20Sopenharmony_ci int i; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* Restore, Step 21: 10998c2ecf20Sopenharmony_ci * Reset the following CH: [21, 23, 28, 29, 30] 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 11028c2ecf20Sopenharmony_ci idx = ch_indices[i]; 11038c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, idx); 11048c2ecf20Sopenharmony_ci eieio(); 11058c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]); 11068c2ecf20Sopenharmony_ci eieio(); 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic inline void setup_spu_status_part1(struct spu_state *csa, 11118c2ecf20Sopenharmony_ci struct spu *spu) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci u32 status_P = SPU_STATUS_STOPPED_BY_STOP; 11148c2ecf20Sopenharmony_ci u32 status_I = SPU_STATUS_INVALID_INSTR; 11158c2ecf20Sopenharmony_ci u32 status_H = SPU_STATUS_STOPPED_BY_HALT; 11168c2ecf20Sopenharmony_ci u32 status_S = SPU_STATUS_SINGLE_STEP; 11178c2ecf20Sopenharmony_ci u32 status_S_I = SPU_STATUS_SINGLE_STEP | SPU_STATUS_INVALID_INSTR; 11188c2ecf20Sopenharmony_ci u32 status_S_P = SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_STOP; 11198c2ecf20Sopenharmony_ci u32 status_P_H = SPU_STATUS_STOPPED_BY_HALT |SPU_STATUS_STOPPED_BY_STOP; 11208c2ecf20Sopenharmony_ci u32 status_P_I = SPU_STATUS_STOPPED_BY_STOP |SPU_STATUS_INVALID_INSTR; 11218c2ecf20Sopenharmony_ci u32 status_code; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* Restore, Step 27: 11248c2ecf20Sopenharmony_ci * If the CSA.SPU_Status[I,S,H,P]=1 then add the correct 11258c2ecf20Sopenharmony_ci * instruction sequence to the end of the SPU based restore 11268c2ecf20Sopenharmony_ci * code (after the "context restored" stop and signal) to 11278c2ecf20Sopenharmony_ci * restore the correct SPU status. 11288c2ecf20Sopenharmony_ci * 11298c2ecf20Sopenharmony_ci * NOTE: Rather than modifying the SPU executable, we 11308c2ecf20Sopenharmony_ci * instead add a new 'stopped_status' field to the 11318c2ecf20Sopenharmony_ci * LSCSA. The SPU-side restore reads this field and 11328c2ecf20Sopenharmony_ci * takes the appropriate action when exiting. 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci status_code = 11368c2ecf20Sopenharmony_ci (csa->prob.spu_status_R >> SPU_STOP_STATUS_SHIFT) & 0xFFFF; 11378c2ecf20Sopenharmony_ci if ((csa->prob.spu_status_R & status_P_I) == status_P_I) { 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* SPU_Status[P,I]=1 - Illegal Instruction followed 11408c2ecf20Sopenharmony_ci * by Stop and Signal instruction, followed by 'br -4'. 11418c2ecf20Sopenharmony_ci * 11428c2ecf20Sopenharmony_ci */ 11438c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_I; 11448c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[1] = status_code; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci } else if ((csa->prob.spu_status_R & status_P_H) == status_P_H) { 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* SPU_Status[P,H]=1 - Halt Conditional, followed 11498c2ecf20Sopenharmony_ci * by Stop and Signal instruction, followed by 11508c2ecf20Sopenharmony_ci * 'br -4'. 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_H; 11538c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[1] = status_code; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci } else if ((csa->prob.spu_status_R & status_S_P) == status_S_P) { 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* SPU_Status[S,P]=1 - Stop and Signal instruction 11588c2ecf20Sopenharmony_ci * followed by 'br -4'. 11598c2ecf20Sopenharmony_ci */ 11608c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_P; 11618c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[1] = status_code; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci } else if ((csa->prob.spu_status_R & status_S_I) == status_S_I) { 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* SPU_Status[S,I]=1 - Illegal instruction followed 11668c2ecf20Sopenharmony_ci * by 'br -4'. 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_I; 11698c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[1] = status_code; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci } else if ((csa->prob.spu_status_R & status_P) == status_P) { 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* SPU_Status[P]=1 - Stop and Signal instruction 11748c2ecf20Sopenharmony_ci * followed by 'br -4'. 11758c2ecf20Sopenharmony_ci */ 11768c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P; 11778c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[1] = status_code; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci } else if ((csa->prob.spu_status_R & status_H) == status_H) { 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* SPU_Status[H]=1 - Halt Conditional, followed 11828c2ecf20Sopenharmony_ci * by 'br -4'. 11838c2ecf20Sopenharmony_ci */ 11848c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_H; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci } else if ((csa->prob.spu_status_R & status_S) == status_S) { 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci /* SPU_Status[S]=1 - Two nop instructions. 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci } else if ((csa->prob.spu_status_R & status_I) == status_I) { 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* SPU_Status[I]=1 - Illegal instruction followed 11958c2ecf20Sopenharmony_ci * by 'br -4'. 11968c2ecf20Sopenharmony_ci */ 11978c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_I; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic inline void setup_spu_status_part2(struct spu_state *csa, 12038c2ecf20Sopenharmony_ci struct spu *spu) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci u32 mask; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci /* Restore, Step 28: 12088c2ecf20Sopenharmony_ci * If the CSA.SPU_Status[I,S,H,P,R]=0 then 12098c2ecf20Sopenharmony_ci * add a 'br *' instruction to the end of 12108c2ecf20Sopenharmony_ci * the SPU based restore code. 12118c2ecf20Sopenharmony_ci * 12128c2ecf20Sopenharmony_ci * NOTE: Rather than modifying the SPU executable, we 12138c2ecf20Sopenharmony_ci * instead add a new 'stopped_status' field to the 12148c2ecf20Sopenharmony_ci * LSCSA. The SPU-side restore reads this field and 12158c2ecf20Sopenharmony_ci * takes the appropriate action when exiting. 12168c2ecf20Sopenharmony_ci */ 12178c2ecf20Sopenharmony_ci mask = SPU_STATUS_INVALID_INSTR | 12188c2ecf20Sopenharmony_ci SPU_STATUS_SINGLE_STEP | 12198c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_HALT | 12208c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING; 12218c2ecf20Sopenharmony_ci if (!(csa->prob.spu_status_R & mask)) { 12228c2ecf20Sopenharmony_ci csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_R; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci} 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_cistatic inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci /* Restore, Step 29: 12298c2ecf20Sopenharmony_ci * Restore RA_GROUP_ID register and the 12308c2ecf20Sopenharmony_ci * RA_ENABLE reigster from the CSA. 12318c2ecf20Sopenharmony_ci */ 12328c2ecf20Sopenharmony_ci spu_resource_allocation_groupID_set(spu, 12338c2ecf20Sopenharmony_ci csa->priv1.resource_allocation_groupID_RW); 12348c2ecf20Sopenharmony_ci spu_resource_allocation_enable_set(spu, 12358c2ecf20Sopenharmony_ci csa->priv1.resource_allocation_enable_RW); 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic inline void send_restore_code(struct spu_state *csa, struct spu *spu) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)&spu_restore_code[0]; 12418c2ecf20Sopenharmony_ci unsigned int ls_offset = 0x0; 12428c2ecf20Sopenharmony_ci unsigned int size = sizeof(spu_restore_code); 12438c2ecf20Sopenharmony_ci unsigned int tag = 0; 12448c2ecf20Sopenharmony_ci unsigned int rclass = 0; 12458c2ecf20Sopenharmony_ci unsigned int cmd = MFC_GETFS_CMD; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* Restore, Step 37: 12488c2ecf20Sopenharmony_ci * Issue MFC DMA command to copy context 12498c2ecf20Sopenharmony_ci * restore code to local storage. 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_ci send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic inline void setup_decr(struct spu_state *csa, struct spu *spu) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci /* Restore, Step 34: 12578c2ecf20Sopenharmony_ci * If CSA.MFC_CNTL[Ds]=1 (decrementer was 12588c2ecf20Sopenharmony_ci * running) then adjust decrementer, set 12598c2ecf20Sopenharmony_ci * decrementer running status in LSCSA, 12608c2ecf20Sopenharmony_ci * and set decrementer "wrapped" status 12618c2ecf20Sopenharmony_ci * in LSCSA. 12628c2ecf20Sopenharmony_ci */ 12638c2ecf20Sopenharmony_ci if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) { 12648c2ecf20Sopenharmony_ci cycles_t resume_time = get_cycles(); 12658c2ecf20Sopenharmony_ci cycles_t delta_time = resume_time - csa->suspend_time; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING; 12688c2ecf20Sopenharmony_ci if (csa->lscsa->decr.slot[0] < delta_time) { 12698c2ecf20Sopenharmony_ci csa->lscsa->decr_status.slot[0] |= 12708c2ecf20Sopenharmony_ci SPU_DECR_STATUS_WRAPPED; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci csa->lscsa->decr.slot[0] -= delta_time; 12748c2ecf20Sopenharmony_ci } else { 12758c2ecf20Sopenharmony_ci csa->lscsa->decr_status.slot[0] = 0; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic inline void setup_ppu_mb(struct spu_state *csa, struct spu *spu) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci /* Restore, Step 35: 12828c2ecf20Sopenharmony_ci * Copy the CSA.PU_MB data into the LSCSA. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci csa->lscsa->ppu_mb.slot[0] = csa->prob.pu_mb_R; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic inline void setup_ppuint_mb(struct spu_state *csa, struct spu *spu) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci /* Restore, Step 36: 12908c2ecf20Sopenharmony_ci * Copy the CSA.PUINT_MB data into the LSCSA. 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci csa->lscsa->ppuint_mb.slot[0] = csa->priv2.puint_mb_R; 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic inline int check_restore_status(struct spu_state *csa, struct spu *spu) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 12988c2ecf20Sopenharmony_ci u32 complete; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* Restore, Step 40: 13018c2ecf20Sopenharmony_ci * If SPU_Status[P]=1 and SPU_Status[SC] = "success", 13028c2ecf20Sopenharmony_ci * context restore succeeded, otherwise context restore 13038c2ecf20Sopenharmony_ci * failed. 13048c2ecf20Sopenharmony_ci */ 13058c2ecf20Sopenharmony_ci complete = ((SPU_RESTORE_COMPLETE << SPU_STOP_STATUS_SHIFT) | 13068c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_STOP); 13078c2ecf20Sopenharmony_ci return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic inline void restore_spu_privcntl(struct spu_state *csa, struct spu *spu) 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* Restore, Step 41: 13158c2ecf20Sopenharmony_ci * Restore SPU_PrivCntl from the CSA. 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ci out_be64(&priv2->spu_privcntl_RW, csa->priv2.spu_privcntl_RW); 13188c2ecf20Sopenharmony_ci eieio(); 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic inline void restore_status_part1(struct spu_state *csa, struct spu *spu) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 13248c2ecf20Sopenharmony_ci u32 mask; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* Restore, Step 42: 13278c2ecf20Sopenharmony_ci * If any CSA.SPU_Status[I,S,H,P]=1, then 13288c2ecf20Sopenharmony_ci * restore the error or single step state. 13298c2ecf20Sopenharmony_ci */ 13308c2ecf20Sopenharmony_ci mask = SPU_STATUS_INVALID_INSTR | 13318c2ecf20Sopenharmony_ci SPU_STATUS_SINGLE_STEP | 13328c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; 13338c2ecf20Sopenharmony_ci if (csa->prob.spu_status_R & mask) { 13348c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); 13358c2ecf20Sopenharmony_ci eieio(); 13368c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 13378c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic inline void restore_status_part2(struct spu_state *csa, struct spu *spu) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 13448c2ecf20Sopenharmony_ci u32 mask; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* Restore, Step 43: 13478c2ecf20Sopenharmony_ci * If all CSA.SPU_Status[I,S,H,P,R]=0 then write 13488c2ecf20Sopenharmony_ci * SPU_RunCntl[R0R1]='01', wait for SPU_Status[R]=1, 13498c2ecf20Sopenharmony_ci * then write '00' to SPU_RunCntl[R0R1] and wait 13508c2ecf20Sopenharmony_ci * for SPU_Status[R]=0. 13518c2ecf20Sopenharmony_ci */ 13528c2ecf20Sopenharmony_ci mask = SPU_STATUS_INVALID_INSTR | 13538c2ecf20Sopenharmony_ci SPU_STATUS_SINGLE_STEP | 13548c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_HALT | 13558c2ecf20Sopenharmony_ci SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING; 13568c2ecf20Sopenharmony_ci if (!(csa->prob.spu_status_R & mask)) { 13578c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); 13588c2ecf20Sopenharmony_ci eieio(); 13598c2ecf20Sopenharmony_ci POLL_WHILE_FALSE(in_be32(&prob->spu_status_R) & 13608c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 13618c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); 13628c2ecf20Sopenharmony_ci eieio(); 13638c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 13648c2ecf20Sopenharmony_ci SPU_STATUS_RUNNING); 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu) 13698c2ecf20Sopenharmony_ci{ 13708c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)&csa->lscsa->ls[0]; 13718c2ecf20Sopenharmony_ci unsigned int ls_offset = 0x0; 13728c2ecf20Sopenharmony_ci unsigned int size = 16384; 13738c2ecf20Sopenharmony_ci unsigned int tag = 0; 13748c2ecf20Sopenharmony_ci unsigned int rclass = 0; 13758c2ecf20Sopenharmony_ci unsigned int cmd = MFC_GET_CMD; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci /* Restore, Step 44: 13788c2ecf20Sopenharmony_ci * Issue a DMA command to restore the first 13798c2ecf20Sopenharmony_ci * 16kb of local storage from CSA. 13808c2ecf20Sopenharmony_ci */ 13818c2ecf20Sopenharmony_ci send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic inline void suspend_mfc(struct spu_state *csa, struct spu *spu) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* Restore, Step 47. 13898c2ecf20Sopenharmony_ci * Write MFC_Cntl[Sc,Sm]='1','0' to suspend 13908c2ecf20Sopenharmony_ci * the queue. 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ci out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE); 13938c2ecf20Sopenharmony_ci eieio(); 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic inline void clear_interrupts(struct spu_state *csa, struct spu *spu) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci /* Restore, Step 49: 13998c2ecf20Sopenharmony_ci * Write INT_MASK_class0 with value of 0. 14008c2ecf20Sopenharmony_ci * Write INT_MASK_class1 with value of 0. 14018c2ecf20Sopenharmony_ci * Write INT_MASK_class2 with value of 0. 14028c2ecf20Sopenharmony_ci * Write INT_STAT_class0 with value of -1. 14038c2ecf20Sopenharmony_ci * Write INT_STAT_class1 with value of -1. 14048c2ecf20Sopenharmony_ci * Write INT_STAT_class2 with value of -1. 14058c2ecf20Sopenharmony_ci */ 14068c2ecf20Sopenharmony_ci spin_lock_irq(&spu->register_lock); 14078c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 0, 0ul); 14088c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 1, 0ul); 14098c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 2, 0ul); 14108c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); 14118c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK); 14128c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); 14138c2ecf20Sopenharmony_ci spin_unlock_irq(&spu->register_lock); 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic inline void restore_mfc_queues(struct spu_state *csa, struct spu *spu) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 14198c2ecf20Sopenharmony_ci int i; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* Restore, Step 50: 14228c2ecf20Sopenharmony_ci * If MFC_Cntl[Se]!=0 then restore 14238c2ecf20Sopenharmony_ci * MFC command queues. 14248c2ecf20Sopenharmony_ci */ 14258c2ecf20Sopenharmony_ci if ((csa->priv2.mfc_control_RW & MFC_CNTL_DMA_QUEUES_EMPTY_MASK) == 0) { 14268c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 14278c2ecf20Sopenharmony_ci out_be64(&priv2->puq[i].mfc_cq_data0_RW, 14288c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data0_RW); 14298c2ecf20Sopenharmony_ci out_be64(&priv2->puq[i].mfc_cq_data1_RW, 14308c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data1_RW); 14318c2ecf20Sopenharmony_ci out_be64(&priv2->puq[i].mfc_cq_data2_RW, 14328c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data2_RW); 14338c2ecf20Sopenharmony_ci out_be64(&priv2->puq[i].mfc_cq_data3_RW, 14348c2ecf20Sopenharmony_ci csa->priv2.puq[i].mfc_cq_data3_RW); 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 14378c2ecf20Sopenharmony_ci out_be64(&priv2->spuq[i].mfc_cq_data0_RW, 14388c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data0_RW); 14398c2ecf20Sopenharmony_ci out_be64(&priv2->spuq[i].mfc_cq_data1_RW, 14408c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data1_RW); 14418c2ecf20Sopenharmony_ci out_be64(&priv2->spuq[i].mfc_cq_data2_RW, 14428c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data2_RW); 14438c2ecf20Sopenharmony_ci out_be64(&priv2->spuq[i].mfc_cq_data3_RW, 14448c2ecf20Sopenharmony_ci csa->priv2.spuq[i].mfc_cq_data3_RW); 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci eieio(); 14488c2ecf20Sopenharmony_ci} 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_cistatic inline void restore_ppu_querymask(struct spu_state *csa, struct spu *spu) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* Restore, Step 51: 14558c2ecf20Sopenharmony_ci * Restore the PPU_QueryMask register from CSA. 14568c2ecf20Sopenharmony_ci */ 14578c2ecf20Sopenharmony_ci out_be32(&prob->dma_querymask_RW, csa->prob.dma_querymask_RW); 14588c2ecf20Sopenharmony_ci eieio(); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_cistatic inline void restore_ppu_querytype(struct spu_state *csa, struct spu *spu) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* Restore, Step 52: 14668c2ecf20Sopenharmony_ci * Restore the PPU_QueryType register from CSA. 14678c2ecf20Sopenharmony_ci */ 14688c2ecf20Sopenharmony_ci out_be32(&prob->dma_querytype_RW, csa->prob.dma_querytype_RW); 14698c2ecf20Sopenharmony_ci eieio(); 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic inline void restore_mfc_csr_tsq(struct spu_state *csa, struct spu *spu) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* Restore, Step 53: 14778c2ecf20Sopenharmony_ci * Restore the MFC_CSR_TSQ register from CSA. 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_ci out_be64(&priv2->spu_tag_status_query_RW, 14808c2ecf20Sopenharmony_ci csa->priv2.spu_tag_status_query_RW); 14818c2ecf20Sopenharmony_ci eieio(); 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic inline void restore_mfc_csr_cmd(struct spu_state *csa, struct spu *spu) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* Restore, Step 54: 14898c2ecf20Sopenharmony_ci * Restore the MFC_CSR_CMD1 and MFC_CSR_CMD2 14908c2ecf20Sopenharmony_ci * registers from CSA. 14918c2ecf20Sopenharmony_ci */ 14928c2ecf20Sopenharmony_ci out_be64(&priv2->spu_cmd_buf1_RW, csa->priv2.spu_cmd_buf1_RW); 14938c2ecf20Sopenharmony_ci out_be64(&priv2->spu_cmd_buf2_RW, csa->priv2.spu_cmd_buf2_RW); 14948c2ecf20Sopenharmony_ci eieio(); 14958c2ecf20Sopenharmony_ci} 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_cistatic inline void restore_mfc_csr_ato(struct spu_state *csa, struct spu *spu) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* Restore, Step 55: 15028c2ecf20Sopenharmony_ci * Restore the MFC_CSR_ATO register from CSA. 15038c2ecf20Sopenharmony_ci */ 15048c2ecf20Sopenharmony_ci out_be64(&priv2->spu_atomic_status_RW, csa->priv2.spu_atomic_status_RW); 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci /* Restore, Step 56: 15108c2ecf20Sopenharmony_ci * Restore the MFC_TCLASS_ID register from CSA. 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_ci spu_mfc_tclass_id_set(spu, csa->priv1.mfc_tclass_id_RW); 15138c2ecf20Sopenharmony_ci eieio(); 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_cistatic inline void set_llr_event(struct spu_state *csa, struct spu *spu) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci u64 ch0_cnt, ch0_data; 15198c2ecf20Sopenharmony_ci u64 ch1_data; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci /* Restore, Step 57: 15228c2ecf20Sopenharmony_ci * Set the Lock Line Reservation Lost Event by: 15238c2ecf20Sopenharmony_ci * 1. OR CSA.SPU_Event_Status with bit 21 (Lr) set to 1. 15248c2ecf20Sopenharmony_ci * 2. If CSA.SPU_Channel_0_Count=0 and 15258c2ecf20Sopenharmony_ci * CSA.SPU_Wr_Event_Mask[Lr]=1 and 15268c2ecf20Sopenharmony_ci * CSA.SPU_Event_Status[Lr]=0 then set 15278c2ecf20Sopenharmony_ci * CSA.SPU_Event_Status_Count=1. 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_ci ch0_cnt = csa->spu_chnlcnt_RW[0]; 15308c2ecf20Sopenharmony_ci ch0_data = csa->spu_chnldata_RW[0]; 15318c2ecf20Sopenharmony_ci ch1_data = csa->spu_chnldata_RW[1]; 15328c2ecf20Sopenharmony_ci csa->spu_chnldata_RW[0] |= MFC_LLR_LOST_EVENT; 15338c2ecf20Sopenharmony_ci if ((ch0_cnt == 0) && !(ch0_data & MFC_LLR_LOST_EVENT) && 15348c2ecf20Sopenharmony_ci (ch1_data & MFC_LLR_LOST_EVENT)) { 15358c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[0] = 1; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_cistatic inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci /* Restore, Step 58: 15428c2ecf20Sopenharmony_ci * If the status of the CSA software decrementer 15438c2ecf20Sopenharmony_ci * "wrapped" flag is set, OR in a '1' to 15448c2ecf20Sopenharmony_ci * CSA.SPU_Event_Status[Tm]. 15458c2ecf20Sopenharmony_ci */ 15468c2ecf20Sopenharmony_ci if (!(csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED)) 15478c2ecf20Sopenharmony_ci return; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if ((csa->spu_chnlcnt_RW[0] == 0) && 15508c2ecf20Sopenharmony_ci (csa->spu_chnldata_RW[1] & 0x20) && 15518c2ecf20Sopenharmony_ci !(csa->spu_chnldata_RW[0] & 0x20)) 15528c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[0] = 1; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci csa->spu_chnldata_RW[0] |= 0x20; 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic inline void restore_ch_part1(struct spu_state *csa, struct spu *spu) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 15608c2ecf20Sopenharmony_ci u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 15618c2ecf20Sopenharmony_ci int i; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* Restore, Step 59: 15648c2ecf20Sopenharmony_ci * Restore the following CH: [0,3,4,24,25,27] 15658c2ecf20Sopenharmony_ci */ 15668c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ch_indices); i++) { 15678c2ecf20Sopenharmony_ci idx = ch_indices[i]; 15688c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, idx); 15698c2ecf20Sopenharmony_ci eieio(); 15708c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[idx]); 15718c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[idx]); 15728c2ecf20Sopenharmony_ci eieio(); 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic inline void restore_ch_part2(struct spu_state *csa, struct spu *spu) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 15798c2ecf20Sopenharmony_ci u64 ch_indices[3] = { 9UL, 21UL, 23UL }; 15808c2ecf20Sopenharmony_ci u64 ch_counts[3] = { 1UL, 16UL, 1UL }; 15818c2ecf20Sopenharmony_ci u64 idx; 15828c2ecf20Sopenharmony_ci int i; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* Restore, Step 60: 15858c2ecf20Sopenharmony_ci * Restore the following CH: [9,21,23]. 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci ch_counts[0] = 1UL; 15888c2ecf20Sopenharmony_ci ch_counts[1] = csa->spu_chnlcnt_RW[21]; 15898c2ecf20Sopenharmony_ci ch_counts[2] = 1UL; 15908c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 15918c2ecf20Sopenharmony_ci idx = ch_indices[i]; 15928c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, idx); 15938c2ecf20Sopenharmony_ci eieio(); 15948c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]); 15958c2ecf20Sopenharmony_ci eieio(); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_cistatic inline void restore_spu_lslr(struct spu_state *csa, struct spu *spu) 16008c2ecf20Sopenharmony_ci{ 16018c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci /* Restore, Step 61: 16048c2ecf20Sopenharmony_ci * Restore the SPU_LSLR register from CSA. 16058c2ecf20Sopenharmony_ci */ 16068c2ecf20Sopenharmony_ci out_be64(&priv2->spu_lslr_RW, csa->priv2.spu_lslr_RW); 16078c2ecf20Sopenharmony_ci eieio(); 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic inline void restore_spu_cfg(struct spu_state *csa, struct spu *spu) 16118c2ecf20Sopenharmony_ci{ 16128c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* Restore, Step 62: 16158c2ecf20Sopenharmony_ci * Restore the SPU_Cfg register from CSA. 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_ci out_be64(&priv2->spu_cfg_RW, csa->priv2.spu_cfg_RW); 16188c2ecf20Sopenharmony_ci eieio(); 16198c2ecf20Sopenharmony_ci} 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic inline void restore_pm_trace(struct spu_state *csa, struct spu *spu) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci /* Restore, Step 63: 16248c2ecf20Sopenharmony_ci * Restore PM_Trace_Tag_Wait_Mask from CSA. 16258c2ecf20Sopenharmony_ci * Not performed by this implementation. 16268c2ecf20Sopenharmony_ci */ 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cistatic inline void restore_spu_npc(struct spu_state *csa, struct spu *spu) 16308c2ecf20Sopenharmony_ci{ 16318c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci /* Restore, Step 64: 16348c2ecf20Sopenharmony_ci * Restore SPU_NPC from CSA. 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_ci out_be32(&prob->spu_npc_RW, csa->prob.spu_npc_RW); 16378c2ecf20Sopenharmony_ci eieio(); 16388c2ecf20Sopenharmony_ci} 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_cistatic inline void restore_spu_mb(struct spu_state *csa, struct spu *spu) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 16438c2ecf20Sopenharmony_ci int i; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* Restore, Step 65: 16468c2ecf20Sopenharmony_ci * Restore MFC_RdSPU_MB from CSA. 16478c2ecf20Sopenharmony_ci */ 16488c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcntptr_RW, 29UL); 16498c2ecf20Sopenharmony_ci eieio(); 16508c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]); 16518c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 16528c2ecf20Sopenharmony_ci out_be64(&priv2->spu_chnldata_RW, csa->spu_mailbox_data[i]); 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci eieio(); 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic inline void check_ppu_mb_stat(struct spu_state *csa, struct spu *spu) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 16608c2ecf20Sopenharmony_ci u32 dummy = 0; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci /* Restore, Step 66: 16638c2ecf20Sopenharmony_ci * If CSA.MB_Stat[P]=0 (mailbox empty) then 16648c2ecf20Sopenharmony_ci * read from the PPU_MB register. 16658c2ecf20Sopenharmony_ci */ 16668c2ecf20Sopenharmony_ci if ((csa->prob.mb_stat_R & 0xFF) == 0) { 16678c2ecf20Sopenharmony_ci dummy = in_be32(&prob->pu_mb_R); 16688c2ecf20Sopenharmony_ci eieio(); 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci} 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_cistatic inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 16758c2ecf20Sopenharmony_ci u64 dummy = 0UL; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci /* Restore, Step 66: 16788c2ecf20Sopenharmony_ci * If CSA.MB_Stat[I]=0 (mailbox empty) then 16798c2ecf20Sopenharmony_ci * read from the PPUINT_MB register. 16808c2ecf20Sopenharmony_ci */ 16818c2ecf20Sopenharmony_ci if ((csa->prob.mb_stat_R & 0xFF0000) == 0) { 16828c2ecf20Sopenharmony_ci dummy = in_be64(&priv2->puint_mb_R); 16838c2ecf20Sopenharmony_ci eieio(); 16848c2ecf20Sopenharmony_ci spu_int_stat_clear(spu, 2, CLASS2_ENABLE_MAILBOX_INTR); 16858c2ecf20Sopenharmony_ci eieio(); 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_cistatic inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci /* Restore, Step 69: 16928c2ecf20Sopenharmony_ci * Restore the MFC_SR1 register from CSA. 16938c2ecf20Sopenharmony_ci */ 16948c2ecf20Sopenharmony_ci spu_mfc_sr1_set(spu, csa->priv1.mfc_sr1_RW); 16958c2ecf20Sopenharmony_ci eieio(); 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic inline void set_int_route(struct spu_state *csa, struct spu *spu) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci struct spu_context *ctx = spu->ctx; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci spu_cpu_affinity_set(spu, ctx->last_ran); 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic inline void restore_other_spu_access(struct spu_state *csa, 17068c2ecf20Sopenharmony_ci struct spu *spu) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci /* Restore, Step 70: 17098c2ecf20Sopenharmony_ci * Restore other SPU mappings to this SPU. TBD. 17108c2ecf20Sopenharmony_ci */ 17118c2ecf20Sopenharmony_ci} 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_cistatic inline void restore_spu_runcntl(struct spu_state *csa, struct spu *spu) 17148c2ecf20Sopenharmony_ci{ 17158c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci /* Restore, Step 71: 17188c2ecf20Sopenharmony_ci * If CSA.SPU_Status[R]=1 then write 17198c2ecf20Sopenharmony_ci * SPU_RunCntl[R0R1]='01'. 17208c2ecf20Sopenharmony_ci */ 17218c2ecf20Sopenharmony_ci if (csa->prob.spu_status_R & SPU_STATUS_RUNNING) { 17228c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); 17238c2ecf20Sopenharmony_ci eieio(); 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci /* Restore, Step 72: 17328c2ecf20Sopenharmony_ci * Restore the MFC_CNTL register for the CSA. 17338c2ecf20Sopenharmony_ci */ 17348c2ecf20Sopenharmony_ci out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW); 17358c2ecf20Sopenharmony_ci eieio(); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci /* 17388c2ecf20Sopenharmony_ci * The queue is put back into the same state that was evident prior to 17398c2ecf20Sopenharmony_ci * the context switch. The suspend flag is added to the saved state in 17408c2ecf20Sopenharmony_ci * the csa, if the operational state was suspending or suspended. In 17418c2ecf20Sopenharmony_ci * this case, the code that suspended the mfc is responsible for 17428c2ecf20Sopenharmony_ci * continuing it. Note that SPE faults do not change the operational 17438c2ecf20Sopenharmony_ci * state of the spu. 17448c2ecf20Sopenharmony_ci */ 17458c2ecf20Sopenharmony_ci} 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cistatic inline void enable_user_access(struct spu_state *csa, struct spu *spu) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci /* Restore, Step 73: 17508c2ecf20Sopenharmony_ci * Enable user-space access (if provided) to this 17518c2ecf20Sopenharmony_ci * SPU by mapping the virtual pages assigned to 17528c2ecf20Sopenharmony_ci * the SPU memory-mapped I/O (MMIO) for problem 17538c2ecf20Sopenharmony_ci * state. TBD. 17548c2ecf20Sopenharmony_ci */ 17558c2ecf20Sopenharmony_ci} 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_cistatic inline void reset_switch_active(struct spu_state *csa, struct spu *spu) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci /* Restore, Step 74: 17608c2ecf20Sopenharmony_ci * Reset the "context switch active" flag. 17618c2ecf20Sopenharmony_ci * Not performed by this implementation. 17628c2ecf20Sopenharmony_ci */ 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic inline void reenable_interrupts(struct spu_state *csa, struct spu *spu) 17668c2ecf20Sopenharmony_ci{ 17678c2ecf20Sopenharmony_ci /* Restore, Step 75: 17688c2ecf20Sopenharmony_ci * Re-enable SPU interrupts. 17698c2ecf20Sopenharmony_ci */ 17708c2ecf20Sopenharmony_ci spin_lock_irq(&spu->register_lock); 17718c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 0, csa->priv1.int_mask_class0_RW); 17728c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 1, csa->priv1.int_mask_class1_RW); 17738c2ecf20Sopenharmony_ci spu_int_mask_set(spu, 2, csa->priv1.int_mask_class2_RW); 17748c2ecf20Sopenharmony_ci spin_unlock_irq(&spu->register_lock); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic int quiece_spu(struct spu_state *prev, struct spu *spu) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci /* 17808c2ecf20Sopenharmony_ci * Combined steps 2-18 of SPU context save sequence, which 17818c2ecf20Sopenharmony_ci * quiesce the SPU state (disable SPU execution, MFC command 17828c2ecf20Sopenharmony_ci * queues, decrementer, SPU interrupts, etc.). 17838c2ecf20Sopenharmony_ci * 17848c2ecf20Sopenharmony_ci * Returns 0 on success. 17858c2ecf20Sopenharmony_ci * 2 if failed step 2. 17868c2ecf20Sopenharmony_ci * 6 if failed step 6. 17878c2ecf20Sopenharmony_ci */ 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (check_spu_isolate(prev, spu)) { /* Step 2. */ 17908c2ecf20Sopenharmony_ci return 2; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci disable_interrupts(prev, spu); /* Step 3. */ 17938c2ecf20Sopenharmony_ci set_watchdog_timer(prev, spu); /* Step 4. */ 17948c2ecf20Sopenharmony_ci inhibit_user_access(prev, spu); /* Step 5. */ 17958c2ecf20Sopenharmony_ci if (check_spu_isolate(prev, spu)) { /* Step 6. */ 17968c2ecf20Sopenharmony_ci return 6; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci set_switch_pending(prev, spu); /* Step 7. */ 17998c2ecf20Sopenharmony_ci save_mfc_cntl(prev, spu); /* Step 8. */ 18008c2ecf20Sopenharmony_ci save_spu_runcntl(prev, spu); /* Step 9. */ 18018c2ecf20Sopenharmony_ci save_mfc_sr1(prev, spu); /* Step 10. */ 18028c2ecf20Sopenharmony_ci save_spu_status(prev, spu); /* Step 11. */ 18038c2ecf20Sopenharmony_ci save_mfc_stopped_status(prev, spu); /* Step 12. */ 18048c2ecf20Sopenharmony_ci halt_mfc_decr(prev, spu); /* Step 13. */ 18058c2ecf20Sopenharmony_ci save_timebase(prev, spu); /* Step 14. */ 18068c2ecf20Sopenharmony_ci remove_other_spu_access(prev, spu); /* Step 15. */ 18078c2ecf20Sopenharmony_ci do_mfc_mssync(prev, spu); /* Step 16. */ 18088c2ecf20Sopenharmony_ci issue_mfc_tlbie(prev, spu); /* Step 17. */ 18098c2ecf20Sopenharmony_ci handle_pending_interrupts(prev, spu); /* Step 18. */ 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci return 0; 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cistatic void save_csa(struct spu_state *prev, struct spu *spu) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci /* 18178c2ecf20Sopenharmony_ci * Combine steps 19-44 of SPU context save sequence, which 18188c2ecf20Sopenharmony_ci * save regions of the privileged & problem state areas. 18198c2ecf20Sopenharmony_ci */ 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci save_mfc_queues(prev, spu); /* Step 19. */ 18228c2ecf20Sopenharmony_ci save_ppu_querymask(prev, spu); /* Step 20. */ 18238c2ecf20Sopenharmony_ci save_ppu_querytype(prev, spu); /* Step 21. */ 18248c2ecf20Sopenharmony_ci save_ppu_tagstatus(prev, spu); /* NEW. */ 18258c2ecf20Sopenharmony_ci save_mfc_csr_tsq(prev, spu); /* Step 22. */ 18268c2ecf20Sopenharmony_ci save_mfc_csr_cmd(prev, spu); /* Step 23. */ 18278c2ecf20Sopenharmony_ci save_mfc_csr_ato(prev, spu); /* Step 24. */ 18288c2ecf20Sopenharmony_ci save_mfc_tclass_id(prev, spu); /* Step 25. */ 18298c2ecf20Sopenharmony_ci set_mfc_tclass_id(prev, spu); /* Step 26. */ 18308c2ecf20Sopenharmony_ci save_mfc_cmd(prev, spu); /* Step 26a - moved from 44. */ 18318c2ecf20Sopenharmony_ci purge_mfc_queue(prev, spu); /* Step 27. */ 18328c2ecf20Sopenharmony_ci wait_purge_complete(prev, spu); /* Step 28. */ 18338c2ecf20Sopenharmony_ci setup_mfc_sr1(prev, spu); /* Step 30. */ 18348c2ecf20Sopenharmony_ci save_spu_npc(prev, spu); /* Step 31. */ 18358c2ecf20Sopenharmony_ci save_spu_privcntl(prev, spu); /* Step 32. */ 18368c2ecf20Sopenharmony_ci reset_spu_privcntl(prev, spu); /* Step 33. */ 18378c2ecf20Sopenharmony_ci save_spu_lslr(prev, spu); /* Step 34. */ 18388c2ecf20Sopenharmony_ci reset_spu_lslr(prev, spu); /* Step 35. */ 18398c2ecf20Sopenharmony_ci save_spu_cfg(prev, spu); /* Step 36. */ 18408c2ecf20Sopenharmony_ci save_pm_trace(prev, spu); /* Step 37. */ 18418c2ecf20Sopenharmony_ci save_mfc_rag(prev, spu); /* Step 38. */ 18428c2ecf20Sopenharmony_ci save_ppu_mb_stat(prev, spu); /* Step 39. */ 18438c2ecf20Sopenharmony_ci save_ppu_mb(prev, spu); /* Step 40. */ 18448c2ecf20Sopenharmony_ci save_ppuint_mb(prev, spu); /* Step 41. */ 18458c2ecf20Sopenharmony_ci save_ch_part1(prev, spu); /* Step 42. */ 18468c2ecf20Sopenharmony_ci save_spu_mb(prev, spu); /* Step 43. */ 18478c2ecf20Sopenharmony_ci reset_ch(prev, spu); /* Step 45. */ 18488c2ecf20Sopenharmony_ci} 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_cistatic void save_lscsa(struct spu_state *prev, struct spu *spu) 18518c2ecf20Sopenharmony_ci{ 18528c2ecf20Sopenharmony_ci /* 18538c2ecf20Sopenharmony_ci * Perform steps 46-57 of SPU context save sequence, 18548c2ecf20Sopenharmony_ci * which save regions of the local store and register 18558c2ecf20Sopenharmony_ci * file. 18568c2ecf20Sopenharmony_ci */ 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci resume_mfc_queue(prev, spu); /* Step 46. */ 18598c2ecf20Sopenharmony_ci /* Step 47. */ 18608c2ecf20Sopenharmony_ci setup_mfc_slbs(prev, spu, spu_save_code, sizeof(spu_save_code)); 18618c2ecf20Sopenharmony_ci set_switch_active(prev, spu); /* Step 48. */ 18628c2ecf20Sopenharmony_ci enable_interrupts(prev, spu); /* Step 49. */ 18638c2ecf20Sopenharmony_ci save_ls_16kb(prev, spu); /* Step 50. */ 18648c2ecf20Sopenharmony_ci set_spu_npc(prev, spu); /* Step 51. */ 18658c2ecf20Sopenharmony_ci set_signot1(prev, spu); /* Step 52. */ 18668c2ecf20Sopenharmony_ci set_signot2(prev, spu); /* Step 53. */ 18678c2ecf20Sopenharmony_ci send_save_code(prev, spu); /* Step 54. */ 18688c2ecf20Sopenharmony_ci set_ppu_querymask(prev, spu); /* Step 55. */ 18698c2ecf20Sopenharmony_ci wait_tag_complete(prev, spu); /* Step 56. */ 18708c2ecf20Sopenharmony_ci wait_spu_stopped(prev, spu); /* Step 57. */ 18718c2ecf20Sopenharmony_ci} 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_cistatic void force_spu_isolate_exit(struct spu *spu) 18748c2ecf20Sopenharmony_ci{ 18758c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 18768c2ecf20Sopenharmony_ci struct spu_priv2 __iomem *priv2 = spu->priv2; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci /* Stop SPE execution and wait for completion. */ 18798c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); 18808c2ecf20Sopenharmony_ci iobarrier_rw(); 18818c2ecf20Sopenharmony_ci POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci /* Restart SPE master runcntl. */ 18848c2ecf20Sopenharmony_ci spu_mfc_sr1_set(spu, MFC_STATE1_MASTER_RUN_CONTROL_MASK); 18858c2ecf20Sopenharmony_ci iobarrier_w(); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* Initiate isolate exit request and wait for completion. */ 18888c2ecf20Sopenharmony_ci out_be64(&priv2->spu_privcntl_RW, 4LL); 18898c2ecf20Sopenharmony_ci iobarrier_w(); 18908c2ecf20Sopenharmony_ci out_be32(&prob->spu_runcntl_RW, 2); 18918c2ecf20Sopenharmony_ci iobarrier_rw(); 18928c2ecf20Sopenharmony_ci POLL_WHILE_FALSE((in_be32(&prob->spu_status_R) 18938c2ecf20Sopenharmony_ci & SPU_STATUS_STOPPED_BY_STOP)); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci /* Reset load request to normal. */ 18968c2ecf20Sopenharmony_ci out_be64(&priv2->spu_privcntl_RW, SPU_PRIVCNT_LOAD_REQUEST_NORMAL); 18978c2ecf20Sopenharmony_ci iobarrier_w(); 18988c2ecf20Sopenharmony_ci} 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci/** 19018c2ecf20Sopenharmony_ci * stop_spu_isolate 19028c2ecf20Sopenharmony_ci * Check SPU run-control state and force isolated 19038c2ecf20Sopenharmony_ci * exit function as necessary. 19048c2ecf20Sopenharmony_ci */ 19058c2ecf20Sopenharmony_cistatic void stop_spu_isolate(struct spu *spu) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci struct spu_problem __iomem *prob = spu->problem; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci if (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_STATE) { 19108c2ecf20Sopenharmony_ci /* The SPU is in isolated state; the only way 19118c2ecf20Sopenharmony_ci * to get it out is to perform an isolated 19128c2ecf20Sopenharmony_ci * exit (clean) operation. 19138c2ecf20Sopenharmony_ci */ 19148c2ecf20Sopenharmony_ci force_spu_isolate_exit(spu); 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci} 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_cistatic void harvest(struct spu_state *prev, struct spu *spu) 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci /* 19218c2ecf20Sopenharmony_ci * Perform steps 2-25 of SPU context restore sequence, 19228c2ecf20Sopenharmony_ci * which resets an SPU either after a failed save, or 19238c2ecf20Sopenharmony_ci * when using SPU for first time. 19248c2ecf20Sopenharmony_ci */ 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci disable_interrupts(prev, spu); /* Step 2. */ 19278c2ecf20Sopenharmony_ci inhibit_user_access(prev, spu); /* Step 3. */ 19288c2ecf20Sopenharmony_ci terminate_spu_app(prev, spu); /* Step 4. */ 19298c2ecf20Sopenharmony_ci set_switch_pending(prev, spu); /* Step 5. */ 19308c2ecf20Sopenharmony_ci stop_spu_isolate(spu); /* NEW. */ 19318c2ecf20Sopenharmony_ci remove_other_spu_access(prev, spu); /* Step 6. */ 19328c2ecf20Sopenharmony_ci suspend_mfc_and_halt_decr(prev, spu); /* Step 7. */ 19338c2ecf20Sopenharmony_ci wait_suspend_mfc_complete(prev, spu); /* Step 8. */ 19348c2ecf20Sopenharmony_ci if (!suspend_spe(prev, spu)) /* Step 9. */ 19358c2ecf20Sopenharmony_ci clear_spu_status(prev, spu); /* Step 10. */ 19368c2ecf20Sopenharmony_ci do_mfc_mssync(prev, spu); /* Step 11. */ 19378c2ecf20Sopenharmony_ci issue_mfc_tlbie(prev, spu); /* Step 12. */ 19388c2ecf20Sopenharmony_ci handle_pending_interrupts(prev, spu); /* Step 13. */ 19398c2ecf20Sopenharmony_ci purge_mfc_queue(prev, spu); /* Step 14. */ 19408c2ecf20Sopenharmony_ci wait_purge_complete(prev, spu); /* Step 15. */ 19418c2ecf20Sopenharmony_ci reset_spu_privcntl(prev, spu); /* Step 16. */ 19428c2ecf20Sopenharmony_ci reset_spu_lslr(prev, spu); /* Step 17. */ 19438c2ecf20Sopenharmony_ci setup_mfc_sr1(prev, spu); /* Step 18. */ 19448c2ecf20Sopenharmony_ci spu_invalidate_slbs(spu); /* Step 19. */ 19458c2ecf20Sopenharmony_ci reset_ch_part1(prev, spu); /* Step 20. */ 19468c2ecf20Sopenharmony_ci reset_ch_part2(prev, spu); /* Step 21. */ 19478c2ecf20Sopenharmony_ci enable_interrupts(prev, spu); /* Step 22. */ 19488c2ecf20Sopenharmony_ci set_switch_active(prev, spu); /* Step 23. */ 19498c2ecf20Sopenharmony_ci set_mfc_tclass_id(prev, spu); /* Step 24. */ 19508c2ecf20Sopenharmony_ci resume_mfc_queue(prev, spu); /* Step 25. */ 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic void restore_lscsa(struct spu_state *next, struct spu *spu) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci /* 19568c2ecf20Sopenharmony_ci * Perform steps 26-40 of SPU context restore sequence, 19578c2ecf20Sopenharmony_ci * which restores regions of the local store and register 19588c2ecf20Sopenharmony_ci * file. 19598c2ecf20Sopenharmony_ci */ 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci set_watchdog_timer(next, spu); /* Step 26. */ 19628c2ecf20Sopenharmony_ci setup_spu_status_part1(next, spu); /* Step 27. */ 19638c2ecf20Sopenharmony_ci setup_spu_status_part2(next, spu); /* Step 28. */ 19648c2ecf20Sopenharmony_ci restore_mfc_rag(next, spu); /* Step 29. */ 19658c2ecf20Sopenharmony_ci /* Step 30. */ 19668c2ecf20Sopenharmony_ci setup_mfc_slbs(next, spu, spu_restore_code, sizeof(spu_restore_code)); 19678c2ecf20Sopenharmony_ci set_spu_npc(next, spu); /* Step 31. */ 19688c2ecf20Sopenharmony_ci set_signot1(next, spu); /* Step 32. */ 19698c2ecf20Sopenharmony_ci set_signot2(next, spu); /* Step 33. */ 19708c2ecf20Sopenharmony_ci setup_decr(next, spu); /* Step 34. */ 19718c2ecf20Sopenharmony_ci setup_ppu_mb(next, spu); /* Step 35. */ 19728c2ecf20Sopenharmony_ci setup_ppuint_mb(next, spu); /* Step 36. */ 19738c2ecf20Sopenharmony_ci send_restore_code(next, spu); /* Step 37. */ 19748c2ecf20Sopenharmony_ci set_ppu_querymask(next, spu); /* Step 38. */ 19758c2ecf20Sopenharmony_ci wait_tag_complete(next, spu); /* Step 39. */ 19768c2ecf20Sopenharmony_ci wait_spu_stopped(next, spu); /* Step 40. */ 19778c2ecf20Sopenharmony_ci} 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_cistatic void restore_csa(struct spu_state *next, struct spu *spu) 19808c2ecf20Sopenharmony_ci{ 19818c2ecf20Sopenharmony_ci /* 19828c2ecf20Sopenharmony_ci * Combine steps 41-76 of SPU context restore sequence, which 19838c2ecf20Sopenharmony_ci * restore regions of the privileged & problem state areas. 19848c2ecf20Sopenharmony_ci */ 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci restore_spu_privcntl(next, spu); /* Step 41. */ 19878c2ecf20Sopenharmony_ci restore_status_part1(next, spu); /* Step 42. */ 19888c2ecf20Sopenharmony_ci restore_status_part2(next, spu); /* Step 43. */ 19898c2ecf20Sopenharmony_ci restore_ls_16kb(next, spu); /* Step 44. */ 19908c2ecf20Sopenharmony_ci wait_tag_complete(next, spu); /* Step 45. */ 19918c2ecf20Sopenharmony_ci suspend_mfc(next, spu); /* Step 46. */ 19928c2ecf20Sopenharmony_ci wait_suspend_mfc_complete(next, spu); /* Step 47. */ 19938c2ecf20Sopenharmony_ci issue_mfc_tlbie(next, spu); /* Step 48. */ 19948c2ecf20Sopenharmony_ci clear_interrupts(next, spu); /* Step 49. */ 19958c2ecf20Sopenharmony_ci restore_mfc_queues(next, spu); /* Step 50. */ 19968c2ecf20Sopenharmony_ci restore_ppu_querymask(next, spu); /* Step 51. */ 19978c2ecf20Sopenharmony_ci restore_ppu_querytype(next, spu); /* Step 52. */ 19988c2ecf20Sopenharmony_ci restore_mfc_csr_tsq(next, spu); /* Step 53. */ 19998c2ecf20Sopenharmony_ci restore_mfc_csr_cmd(next, spu); /* Step 54. */ 20008c2ecf20Sopenharmony_ci restore_mfc_csr_ato(next, spu); /* Step 55. */ 20018c2ecf20Sopenharmony_ci restore_mfc_tclass_id(next, spu); /* Step 56. */ 20028c2ecf20Sopenharmony_ci set_llr_event(next, spu); /* Step 57. */ 20038c2ecf20Sopenharmony_ci restore_decr_wrapped(next, spu); /* Step 58. */ 20048c2ecf20Sopenharmony_ci restore_ch_part1(next, spu); /* Step 59. */ 20058c2ecf20Sopenharmony_ci restore_ch_part2(next, spu); /* Step 60. */ 20068c2ecf20Sopenharmony_ci restore_spu_lslr(next, spu); /* Step 61. */ 20078c2ecf20Sopenharmony_ci restore_spu_cfg(next, spu); /* Step 62. */ 20088c2ecf20Sopenharmony_ci restore_pm_trace(next, spu); /* Step 63. */ 20098c2ecf20Sopenharmony_ci restore_spu_npc(next, spu); /* Step 64. */ 20108c2ecf20Sopenharmony_ci restore_spu_mb(next, spu); /* Step 65. */ 20118c2ecf20Sopenharmony_ci check_ppu_mb_stat(next, spu); /* Step 66. */ 20128c2ecf20Sopenharmony_ci check_ppuint_mb_stat(next, spu); /* Step 67. */ 20138c2ecf20Sopenharmony_ci spu_invalidate_slbs(spu); /* Modified Step 68. */ 20148c2ecf20Sopenharmony_ci restore_mfc_sr1(next, spu); /* Step 69. */ 20158c2ecf20Sopenharmony_ci set_int_route(next, spu); /* NEW */ 20168c2ecf20Sopenharmony_ci restore_other_spu_access(next, spu); /* Step 70. */ 20178c2ecf20Sopenharmony_ci restore_spu_runcntl(next, spu); /* Step 71. */ 20188c2ecf20Sopenharmony_ci restore_mfc_cntl(next, spu); /* Step 72. */ 20198c2ecf20Sopenharmony_ci enable_user_access(next, spu); /* Step 73. */ 20208c2ecf20Sopenharmony_ci reset_switch_active(next, spu); /* Step 74. */ 20218c2ecf20Sopenharmony_ci reenable_interrupts(next, spu); /* Step 75. */ 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic int __do_spu_save(struct spu_state *prev, struct spu *spu) 20258c2ecf20Sopenharmony_ci{ 20268c2ecf20Sopenharmony_ci int rc; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci /* 20298c2ecf20Sopenharmony_ci * SPU context save can be broken into three phases: 20308c2ecf20Sopenharmony_ci * 20318c2ecf20Sopenharmony_ci * (a) quiesce [steps 2-16]. 20328c2ecf20Sopenharmony_ci * (b) save of CSA, performed by PPE [steps 17-42] 20338c2ecf20Sopenharmony_ci * (c) save of LSCSA, mostly performed by SPU [steps 43-52]. 20348c2ecf20Sopenharmony_ci * 20358c2ecf20Sopenharmony_ci * Returns 0 on success. 20368c2ecf20Sopenharmony_ci * 2,6 if failed to quiece SPU 20378c2ecf20Sopenharmony_ci * 53 if SPU-side of save failed. 20388c2ecf20Sopenharmony_ci */ 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci rc = quiece_spu(prev, spu); /* Steps 2-16. */ 20418c2ecf20Sopenharmony_ci switch (rc) { 20428c2ecf20Sopenharmony_ci default: 20438c2ecf20Sopenharmony_ci case 2: 20448c2ecf20Sopenharmony_ci case 6: 20458c2ecf20Sopenharmony_ci harvest(prev, spu); 20468c2ecf20Sopenharmony_ci return rc; 20478c2ecf20Sopenharmony_ci break; 20488c2ecf20Sopenharmony_ci case 0: 20498c2ecf20Sopenharmony_ci break; 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci save_csa(prev, spu); /* Steps 17-43. */ 20528c2ecf20Sopenharmony_ci save_lscsa(prev, spu); /* Steps 44-53. */ 20538c2ecf20Sopenharmony_ci return check_save_status(prev, spu); /* Step 54. */ 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_cistatic int __do_spu_restore(struct spu_state *next, struct spu *spu) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci int rc; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* 20618c2ecf20Sopenharmony_ci * SPU context restore can be broken into three phases: 20628c2ecf20Sopenharmony_ci * 20638c2ecf20Sopenharmony_ci * (a) harvest (or reset) SPU [steps 2-24]. 20648c2ecf20Sopenharmony_ci * (b) restore LSCSA [steps 25-40], mostly performed by SPU. 20658c2ecf20Sopenharmony_ci * (c) restore CSA [steps 41-76], performed by PPE. 20668c2ecf20Sopenharmony_ci * 20678c2ecf20Sopenharmony_ci * The 'harvest' step is not performed here, but rather 20688c2ecf20Sopenharmony_ci * as needed below. 20698c2ecf20Sopenharmony_ci */ 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci restore_lscsa(next, spu); /* Steps 24-39. */ 20728c2ecf20Sopenharmony_ci rc = check_restore_status(next, spu); /* Step 40. */ 20738c2ecf20Sopenharmony_ci switch (rc) { 20748c2ecf20Sopenharmony_ci default: 20758c2ecf20Sopenharmony_ci /* Failed. Return now. */ 20768c2ecf20Sopenharmony_ci return rc; 20778c2ecf20Sopenharmony_ci break; 20788c2ecf20Sopenharmony_ci case 0: 20798c2ecf20Sopenharmony_ci /* Fall through to next step. */ 20808c2ecf20Sopenharmony_ci break; 20818c2ecf20Sopenharmony_ci } 20828c2ecf20Sopenharmony_ci restore_csa(next, spu); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci return 0; 20858c2ecf20Sopenharmony_ci} 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci/** 20888c2ecf20Sopenharmony_ci * spu_save - SPU context save, with locking. 20898c2ecf20Sopenharmony_ci * @prev: pointer to SPU context save area, to be saved. 20908c2ecf20Sopenharmony_ci * @spu: pointer to SPU iomem structure. 20918c2ecf20Sopenharmony_ci * 20928c2ecf20Sopenharmony_ci * Acquire locks, perform the save operation then return. 20938c2ecf20Sopenharmony_ci */ 20948c2ecf20Sopenharmony_ciint spu_save(struct spu_state *prev, struct spu *spu) 20958c2ecf20Sopenharmony_ci{ 20968c2ecf20Sopenharmony_ci int rc; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci acquire_spu_lock(spu); /* Step 1. */ 20998c2ecf20Sopenharmony_ci rc = __do_spu_save(prev, spu); /* Steps 2-53. */ 21008c2ecf20Sopenharmony_ci release_spu_lock(spu); 21018c2ecf20Sopenharmony_ci if (rc != 0 && rc != 2 && rc != 6) { 21028c2ecf20Sopenharmony_ci panic("%s failed on SPU[%d], rc=%d.\n", 21038c2ecf20Sopenharmony_ci __func__, spu->number, rc); 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci return 0; 21068c2ecf20Sopenharmony_ci} 21078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(spu_save); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci/** 21108c2ecf20Sopenharmony_ci * spu_restore - SPU context restore, with harvest and locking. 21118c2ecf20Sopenharmony_ci * @new: pointer to SPU context save area, to be restored. 21128c2ecf20Sopenharmony_ci * @spu: pointer to SPU iomem structure. 21138c2ecf20Sopenharmony_ci * 21148c2ecf20Sopenharmony_ci * Perform harvest + restore, as we may not be coming 21158c2ecf20Sopenharmony_ci * from a previous successful save operation, and the 21168c2ecf20Sopenharmony_ci * hardware state is unknown. 21178c2ecf20Sopenharmony_ci */ 21188c2ecf20Sopenharmony_ciint spu_restore(struct spu_state *new, struct spu *spu) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci int rc; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci acquire_spu_lock(spu); 21238c2ecf20Sopenharmony_ci harvest(NULL, spu); 21248c2ecf20Sopenharmony_ci spu->slb_replace = 0; 21258c2ecf20Sopenharmony_ci rc = __do_spu_restore(new, spu); 21268c2ecf20Sopenharmony_ci release_spu_lock(spu); 21278c2ecf20Sopenharmony_ci if (rc) { 21288c2ecf20Sopenharmony_ci panic("%s failed on SPU[%d] rc=%d.\n", 21298c2ecf20Sopenharmony_ci __func__, spu->number, rc); 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci return rc; 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(spu_restore); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_cistatic void init_prob(struct spu_state *csa) 21368c2ecf20Sopenharmony_ci{ 21378c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[9] = 1; 21388c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[21] = 16; 21398c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[23] = 1; 21408c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[28] = 1; 21418c2ecf20Sopenharmony_ci csa->spu_chnlcnt_RW[30] = 1; 21428c2ecf20Sopenharmony_ci csa->prob.spu_runcntl_RW = SPU_RUNCNTL_STOP; 21438c2ecf20Sopenharmony_ci csa->prob.mb_stat_R = 0x000400; 21448c2ecf20Sopenharmony_ci} 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_cistatic void init_priv1(struct spu_state *csa) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci /* Enable decode, relocate, tlbie response, master runcntl. */ 21498c2ecf20Sopenharmony_ci csa->priv1.mfc_sr1_RW = MFC_STATE1_LOCAL_STORAGE_DECODE_MASK | 21508c2ecf20Sopenharmony_ci MFC_STATE1_MASTER_RUN_CONTROL_MASK | 21518c2ecf20Sopenharmony_ci MFC_STATE1_PROBLEM_STATE_MASK | 21528c2ecf20Sopenharmony_ci MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci /* Enable OS-specific set of interrupts. */ 21558c2ecf20Sopenharmony_ci csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR | 21568c2ecf20Sopenharmony_ci CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR | 21578c2ecf20Sopenharmony_ci CLASS0_ENABLE_SPU_ERROR_INTR; 21588c2ecf20Sopenharmony_ci csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR | 21598c2ecf20Sopenharmony_ci CLASS1_ENABLE_STORAGE_FAULT_INTR; 21608c2ecf20Sopenharmony_ci csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR | 21618c2ecf20Sopenharmony_ci CLASS2_ENABLE_SPU_HALT_INTR | 21628c2ecf20Sopenharmony_ci CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR; 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_cistatic void init_priv2(struct spu_state *csa) 21668c2ecf20Sopenharmony_ci{ 21678c2ecf20Sopenharmony_ci csa->priv2.spu_lslr_RW = LS_ADDR_MASK; 21688c2ecf20Sopenharmony_ci csa->priv2.mfc_control_RW = MFC_CNTL_RESUME_DMA_QUEUE | 21698c2ecf20Sopenharmony_ci MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION | 21708c2ecf20Sopenharmony_ci MFC_CNTL_DMA_QUEUES_EMPTY_MASK; 21718c2ecf20Sopenharmony_ci} 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci/** 21748c2ecf20Sopenharmony_ci * spu_alloc_csa - allocate and initialize an SPU context save area. 21758c2ecf20Sopenharmony_ci * 21768c2ecf20Sopenharmony_ci * Allocate and initialize the contents of an SPU context save area. 21778c2ecf20Sopenharmony_ci * This includes enabling address translation, interrupt masks, etc., 21788c2ecf20Sopenharmony_ci * as appropriate for the given OS environment. 21798c2ecf20Sopenharmony_ci * 21808c2ecf20Sopenharmony_ci * Note that storage for the 'lscsa' is allocated separately, 21818c2ecf20Sopenharmony_ci * as it is by far the largest of the context save regions, 21828c2ecf20Sopenharmony_ci * and may need to be pinned or otherwise specially aligned. 21838c2ecf20Sopenharmony_ci */ 21848c2ecf20Sopenharmony_ciint spu_init_csa(struct spu_state *csa) 21858c2ecf20Sopenharmony_ci{ 21868c2ecf20Sopenharmony_ci int rc; 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci if (!csa) 21898c2ecf20Sopenharmony_ci return -EINVAL; 21908c2ecf20Sopenharmony_ci memset(csa, 0, sizeof(struct spu_state)); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci rc = spu_alloc_lscsa(csa); 21938c2ecf20Sopenharmony_ci if (rc) 21948c2ecf20Sopenharmony_ci return rc; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci spin_lock_init(&csa->register_lock); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci init_prob(csa); 21998c2ecf20Sopenharmony_ci init_priv1(csa); 22008c2ecf20Sopenharmony_ci init_priv2(csa); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci return 0; 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_civoid spu_fini_csa(struct spu_state *csa) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci spu_free_lscsa(csa); 22088c2ecf20Sopenharmony_ci} 2209