1 /* 2 * utils.h: Utilities for SPU-side of the context switch operation. 3 * 4 * (C) Copyright IBM 2005 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 #ifndef _SPU_CONTEXT_UTILS_H_ 22 #define _SPU_CONTEXT_UTILS_H_ 23 24 /* 25 * 64-bit safe EA. 26 */ 27 typedef union { 28 unsigned long long ull; 29 unsigned int ui[2]; 30 } addr64; 31 32 /* 33 * 128-bit register template. 34 */ 35 typedef union { 36 unsigned int slot[4]; 37 vector unsigned int v; 38 } spu_reg128v; 39 40 /* 41 * DMA list structure. 42 */ 43 struct dma_list_elem { 44 unsigned int size; 45 unsigned int ea_low; 46 }; 47 48 /* 49 * Declare storage for 8-byte aligned DMA list. 50 */ 51 struct dma_list_elem dma_list[15] __attribute__ ((aligned(8))); 52 53 /* 54 * External definition for storage 55 * declared in crt0. 56 */ 57 extern spu_reg128v regs_spill[NR_SPU_SPILL_REGS]; 58 59 /* 60 * Compute LSCSA byte offset for a given field. 61 */ 62 static struct spu_lscsa *dummy = (struct spu_lscsa *)0; 63 #define LSCSA_BYTE_OFFSET(_field) \ 64 ((char *)(&(dummy->_field)) - (char *)(&(dummy->gprs[0].slot[0]))) 65 #define LSCSA_QW_OFFSET(_field) (LSCSA_BYTE_OFFSET(_field) >> 4) 66 67 static inline void set_event_mask(void) 68 { 69 unsigned int event_mask = 0; 70 71 /* Save, Step 4: 72 * Restore, Step 1: 73 * Set the SPU_RdEventMsk channel to zero to mask 74 * all events. 75 */ 76 spu_writech(SPU_WrEventMask, event_mask); 77 } 78 79 static inline void set_tag_mask(void) 80 { 81 unsigned int tag_mask = 1; 82 83 /* Save, Step 5: 84 * Restore, Step 2: 85 * Set the SPU_WrTagMsk channel to '01' to unmask 86 * only tag group 0. 87 */ 88 spu_writech(MFC_WrTagMask, tag_mask); 89 } 90 91 static inline void build_dma_list(addr64 lscsa_ea) 92 { 93 unsigned int ea_low; 94 int i; 95 96 /* Save, Step 6: 97 * Restore, Step 3: 98 * Update the effective address for the CSA in the 99 * pre-canned DMA-list in local storage. 100 */ 101 ea_low = lscsa_ea.ui[1]; 102 ea_low += LSCSA_BYTE_OFFSET(ls[16384]); 103 104 for (i = 0; i < 15; i++, ea_low += 16384) { 105 dma_list[i].size = 16384; 106 dma_list[i].ea_low = ea_low; 107 } 108 } 109 110 static inline void enqueue_putllc(addr64 lscsa_ea) 111 { 112 unsigned int ls = 0; 113 unsigned int size = 128; 114 unsigned int tag_id = 0; 115 unsigned int cmd = 0xB4; /* PUTLLC */ 116 117 /* Save, Step 12: 118 * Restore, Step 7: 119 * Send a PUTLLC (tag 0) command to the MFC using 120 * an effective address in the CSA in order to 121 * remove any possible lock-line reservation. 122 */ 123 spu_writech(MFC_LSA, ls); 124 spu_writech(MFC_EAH, lscsa_ea.ui[0]); 125 spu_writech(MFC_EAL, lscsa_ea.ui[1]); 126 spu_writech(MFC_Size, size); 127 spu_writech(MFC_TagID, tag_id); 128 spu_writech(MFC_Cmd, cmd); 129 } 130 131 static inline void set_tag_update(void) 132 { 133 unsigned int update_any = 1; 134 135 /* Save, Step 15: 136 * Restore, Step 8: 137 * Write the MFC_TagUpdate channel with '01'. 138 */ 139 spu_writech(MFC_WrTagUpdate, update_any); 140 } 141 142 static inline void read_tag_status(void) 143 { 144 /* Save, Step 16: 145 * Restore, Step 9: 146 * Read the MFC_TagStat channel data. 147 */ 148 spu_readch(MFC_RdTagStat); 149 } 150 151 static inline void read_llar_status(void) 152 { 153 /* Save, Step 17: 154 * Restore, Step 10: 155 * Read the MFC_AtomicStat channel data. 156 */ 157 spu_readch(MFC_RdAtomicStat); 158 } 159 160 #endif /* _SPU_CONTEXT_UTILS_H_ */ 161