1 /* 2 * DSP support functions 3 */ 4 5 #include "u.h" 6 #include "../port/lib.h" 7 #include "mem.h" 8 #include "dat.h" 9 #include "fns.h" 10 #include "../port/error.h" 11 12 #include "io.h" 13 14 #include "dsp.h" 15 16 enum { 17 Ndsp = 2, /* determined by hardware */ 18 19 NHOLES= 64 20 }; 21 22 typedef struct DSPparam DSPparam; 23 struct DSPparam { 24 ulong fdbase; /* function descriptor table physical base address */ 25 ulong fd_ptr; /* function descriptor pointer */ 26 ulong dstate; /* DSP state */ 27 ulong resvd[2]; 28 ushort dstatus; /* current function descriptor status */ 29 ushort i; /* number of iterations */ 30 ushort tap; /* number of TAPs */ 31 ushort cbase; 32 ushort anon1; /* sample buffer size-1 */ 33 ushort xptr; /* pointer to sample */ 34 ushort anon2; /* output buffer size-1 */ 35 ushort yptr; /* pointer to output */ 36 ushort m; /* sample buffer size-1 */ 37 ushort anon3; /* sample buffer pointer */ 38 ushort n; /* output buffer size -1 */ 39 ushort anon4; /* output buffer pointer */ 40 ushort k; /* coefficient buffer size - 1 */ 41 ushort anon5; /* coefficient buffer pointer */ 42 }; 43 44 struct DSP { 45 Lock; /* protects state */ 46 void (*done)(void*); 47 void* arg; 48 DSPparam* par; 49 CPMdev* cpm; 50 51 QLock; /* protects busyr */ 52 int busy; 53 Rendez busyr; 54 }; 55 56 static DSP dsps[Ndsp]; 57 static Lock dsplock; 58 static int dspinit; 59 static struct { 60 QLock; 61 ulong avail; 62 Rendez wantr; 63 } dspalloc; 64 65 static Map fndmapv[NHOLES]; 66 static RMap fndmap = {"DSP function descriptors"}; 67 68 static void 69 dspinterrupt(Ureg*, void*) 70 { 71 int i; 72 ushort events; 73 DSP *dsp; 74 75 events = m->iomem->sdsr; 76 m->iomem->sdsr = events; 77 if(events & (1<<7)) 78 panic("dsp: SDMA channel bus error sdar=#%lux", m->iomem->sdar); 79 for(i=0; i<Ndsp; i++) 80 if(events & (1<<i)){ 81 dsp = &dsps[i]; 82 if(dsp->busy){ 83 dsp->busy = 0; 84 if(dsp->done) 85 dsp->done(dsp->arg); 86 else 87 wakeup(&dsp->busyr); 88 }else 89 print("dsp%d: empty interrupt\n", i); 90 } 91 } 92 93 /* 94 * called by system initialisation to set up the DSPs 95 */ 96 void 97 dspinitialise(void) 98 { 99 CPMdev *d; 100 101 ilock(&dsplock); 102 if(dspinit == 0){ 103 mapinit(&fndmap, fndmapv, sizeof(fndmapv)); 104 d = cpmdev(CPdsp1); 105 dsps[0].cpm = d; 106 dsps[0].par = d->param; 107 d = cpmdev(CPdsp2); 108 dsps[1].cpm = d; 109 dsps[1].par = d->param; 110 intrenable(VectorCPIC+d->irq, dspinterrupt, nil, BUSUNKNOWN, "dsp"); 111 dspalloc.avail = (1<<Ndsp)-1; 112 dspinit = 1; 113 } 114 iunlock(&dsplock); 115 } 116 117 static int 118 dspavail(void*) 119 { 120 return dspalloc.avail != 0; 121 } 122 123 /* 124 * wait for a DSP to become available, and return a reference to it. 125 * if done is not nil, it will be called (with the given arg) when that 126 * DSP completes each function (if set to interrupt). 127 */ 128 DSP* 129 dspacquire(void (*done)(void*), void *arg) 130 { 131 DSP *dsp; 132 int i; 133 134 if(dspinit == 0) 135 dspinitialise(); 136 qlock(&dspalloc); 137 if(waserror()){ 138 qunlock(&dspalloc); 139 nexterror(); 140 } 141 for(i=0;; i++){ 142 if(i >= Ndsp){ 143 sleep(&dspalloc.wantr, dspavail, nil); 144 i = 0; 145 } 146 if(dspalloc.avail & (1<<i)) 147 break; 148 } 149 dsp = &dsps[i]; 150 if(dsp->busy) 151 panic("dspacquire"); 152 dsp->done = done; 153 dsp->arg = arg; 154 poperror(); 155 qunlock(&dspalloc); 156 return dsp; 157 } 158 159 /* 160 * relinquish access to the given DSP 161 */ 162 void 163 dsprelease(DSP *dsp) 164 { 165 ulong bit; 166 167 if(dsp == nil) 168 return; 169 bit = 1 << (dsp-dsps); 170 if(dspalloc.avail & bit) 171 panic("dsprelease"); 172 dspalloc.avail |= bit; 173 wakeup(&dspalloc.wantr); 174 } 175 176 /* 177 * execute f[0] to f[n-1] on the given DSP 178 */ 179 void 180 dspexec(DSP *dsp, FnD *f, ulong n) 181 { 182 dspsetfn(dsp, f, n); 183 dspstart(dsp); 184 } 185 186 /* 187 * set the DSP to execute f[0] to f[n-1] 188 */ 189 void 190 dspsetfn(DSP *dsp, FnD *f, ulong n) 191 { 192 f[n-1].status |= FnWrap; 193 ilock(dsp); 194 dsp->par->fdbase = PADDR(f); 195 iunlock(dsp); 196 cpmop(dsp->cpm, InitDSP, 0); 197 } 198 199 /* 200 * start execution of the preset function(s) 201 */ 202 void 203 dspstart(DSP *dsp) 204 { 205 ilock(dsp); 206 dsp->busy = 1; 207 iunlock(dsp); 208 cpmop(dsp->cpm, StartDSP, 0); 209 } 210 211 static int 212 dspdone(void *a) 213 { 214 return ((DSP*)a)->busy; 215 } 216 217 /* 218 * wait until the DSP has completed execution 219 */ 220 void 221 dspsleep(DSP *dsp) 222 { 223 sleep(&dsp->busyr, dspdone, dsp); 224 } 225 226 /* 227 * allocate n function descriptors 228 */ 229 FnD* 230 fndalloc(ulong n) 231 { 232 ulong a, nb, pgn; 233 FnD *f; 234 235 if(n == 0) 236 return nil; 237 if(dspinit == 0) 238 dspinitialise(); 239 nb = n*sizeof(FnD); 240 while((a = rmapalloc(&fndmap, 0, nb, sizeof(FnD))) != 0){ 241 /* expected to loop just once, but might lose a race with another dsp user */ 242 pgn = (nb+BY2PG-1)&~(BY2PG-1); 243 a = PADDR(xspanalloc(pgn, sizeof(FnD), 0)); 244 if(a == 0) 245 return nil; 246 mapfree(&fndmap, a, pgn); 247 } 248 f = KADDR(a); 249 f[n-1].status = FnWrap; 250 return f; 251 } 252 253 /* 254 * free n function descriptors 255 */ 256 void 257 fndfree(FnD *f, ulong n) 258 { 259 if(f != nil) 260 mapfree(&fndmap, PADDR(f), n*sizeof(FnD)); 261 } 262 263 /* 264 * allocate an IO buffer region in shared memory for use by the DSP 265 */ 266 void* 267 dspmalloc(ulong n) 268 { 269 ulong i; 270 271 n = (n+3)&~4; 272 i = n; 273 if(n & (n-1)){ 274 /* align on a power of two */ 275 for(i=1; i < n; i <<= 1) 276 ; 277 } 278 return cpmalloc(n, i); /* this seems to be what 16.3.3.2 is trying to say */ 279 } 280 281 /* 282 * free DSP buffer memory 283 */ 284 void 285 dspfree(void *p, ulong n) 286 { 287 if(p != nil) 288 cpmfree(p, (n+3)&~4); 289 } 290