changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/pc/audioac97.c

changeset 4350: 1f9d7811d546
parent: 50317bf9946e
child: 4474608fd7cc
author: cinap_lenrek@felloff.net
date: Mon, 16 Mar 2015 05:46:08 +0100
permissions: -rw-r--r--
description: kernel: get rid of auxpage() and preserve cache index bits in Page.va in mount cache

the mount cache uses Page.va to store cached range offset and
limit, but mips kernel uses cache index bits from Page.va to
maintain page coloring. Page.va was not initialized by auxpage().

this change removes auxpage() which was primarily used only
by the mount cache and use newpage() with cache file offset
page as va so we will get a page of the right color.

mount cache keeps the index bits intact by only using the top
and buttom PGSHIFT bits of Page.va for the range offset/limit.
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 #include "../port/audioif.h"
9 
10 typedef struct Ring Ring;
11 typedef struct Hwdesc Hwdesc;
12 typedef struct Ctlr Ctlr;
13 
14 enum {
15  Ioc = 1<<31,
16  Bup = 1<<30,
17 };
18 
19 struct Hwdesc {
20  ulong addr;
21  ulong size;
22 };
23 
24 enum {
25  Ndesc = 32,
26  Bufsize = 32768, /* bytes, must be divisible by ndesc */
27  Blocksize = Bufsize/Ndesc,
28  Maxbusywait = 500000, /* microseconds, roughly */
29  BytesPerSample = 4,
30 };
31 
32 struct Ring
33 {
34  Rendez r;
35 
36  uchar *buf;
37  ulong nbuf;
38 
39  ulong ri;
40  ulong wi;
41 };
42 
43 struct Ctlr {
44  /* keep these first, they want to be 8-aligned */
45  Hwdesc indesc[Ndesc];
46  Hwdesc outdesc[Ndesc];
47  Hwdesc micdesc[Ndesc];
48 
49  Lock;
50 
51  ulong port;
52  ulong mixport;
53 
54  Ring inring, micring, outring;
55 
56  int sis7012;
57 
58  /* for probe */
59  Audio *adev;
60  Pcidev *pcidev;
61  Ctlr *next;
62 };
63 
64 #define iorl(c, r) (inl((c)->port+(r)))
65 #define iowl(c, r, l) (outl((c)->port+(r), (ulong)(l)))
66 
67 enum {
68  In = 0x00,
69  Out = 0x10,
70  Mic = 0x20,
71  Bar = 0x00, /* Base address register, 8-byte aligned */
72  /* a 32-bit read at 0x04 can be used to get civ:lvi:sr in one step */
73  Civ = 0x04, /* current index value (desc being processed) */
74  Lvi = 0x05, /* Last valid index (index of first unused entry!) */
75  Sr = 0x06, /* status register */
76  Fifoe = 1<<4, /* fifo error (r/wc) */
77  Bcis = 1<<3, /* buffer completion interrupt status (r/wc) */
78  Lvbci = 1<<2, /* last valid buffer completion(in)/fetched(out) interrupt (r/wc) */
79  Celv = 1<<1, /* current equals last valid (ro) */
80  Dch = 1<<0, /* dma controller halted (ro) */
81  Picb = 0x08, /* position in current buffer */
82  Piv = 0x0a, /* prefetched index value */
83  Cr = 0x0b, /* control register */
84  Ioce = 1<<4, /* interrupt on buffer completion (if bit set in hwdesc.size) (rw) */
85  Feie = 1<<3, /* fifo error interrupt enable (rw) */
86  Lvbie = 1<<2, /* last valid buffer interrupt enable (rw) */
87  RR = 1<<1, /* reset busmaster related regs, excl. ioce,feie,lvbie (rw) */
88  Rpbm = 1<<0, /* run/pause busmaster. 0 stops, 1 starts (rw) */
89  Cnt = 0x2c, /* global control */
90  Ena16bit = 0x0<<22,
91  Ena20bit = 0x1<<22,
92  Ena2chan = 0x0<<20,
93  Ena4chan = 0x1<<20,
94  Enam6chan = 0x2<<20,
95  EnaRESER = 0x3<<20,
96  Sr2ie = 1<<6, /* sdin2 interrupt enable (rw) */
97  Srie = 1<<5, /* sdin1 interrupt enable (rw) */
98  Prie = 1<<4, /* sdin0 interrupt enable (rw) */
99  Aclso = 1<<3, /* ac link shut-off (rw) */
100  Acwr = 1<<2, /* ac 97 warm reset (rw) */
101  Accr = 1<<1, /* ac 97 cold reset (rw) */
102  GPIie = 1<<0, /* GPI interrupt enable (rw) */
103  Sta = 0x30, /* global status */
104  Cap6chan = 1<<21,
105  Cap4chan = 1<<20,
106  Md3 = 1<<17, /* modem powerdown semaphore */
107  Ad3 = 1<<16, /* audio powerdown semaphore */
108  Rcs = 1<<15, /* read completion status (r/wc) */
109  S2ri = 1<<29, /* sdin2 resume interrupt (r/wc) */
110  Sri = 1<<11, /* sdin1 resume interrupt (r/wc) */
111  Pri = 1<<10, /* sdin0 resume interrupt (r/wc) */
112  S2cr = 1<<28, /* sdin2 codec ready (ro) */
113  Scr = 1<<9, /* sdin1 codec ready (ro) */
114  Pcr = 1<<8, /* sdin0 codec ready (ro) */
115  Mint = 1<<7, /* microphone in inetrrupt (ro) */
116  Point = 1<<6, /* pcm out interrupt (ro) */
117  Piint = 1<<5, /* pcm in interrupt (ro) */
118  Moint = 1<<2, /* modem out interrupt (ro) */
119  Miint = 1<<1, /* modem in interrupt (ro) */
120  Gsci = 1<<0, /* GPI status change interrupt */
121  Cas = 0x34, /* codec access semaphore */
122  Casp = 1<<0, /* set to 1 on read if zero, cleared by hardware */
123 };
124 
125 static long
126 buffered(Ring *r)
127 {
128  ulong ri, wi;
129 
130  ri = r->ri;
131  wi = r->wi;
132  if(wi >= ri)
133  return wi - ri;
134  else
135  return r->nbuf - (ri - wi);
136 }
137 
138 static long
139 available(Ring *r)
140 {
141  long m;
142 
143  m = (r->nbuf - BytesPerSample) - buffered(r);
144  if(m < 0)
145  m = 0;
146  return m;
147 }
148 
149 static long
150 readring(Ring *r, uchar *p, long n)
151 {
152  long n0, m;
153 
154  n0 = n;
155  while(n > 0){
156  if((m = buffered(r)) <= 0)
157  break;
158  if(m > n)
159  m = n;
160  if(p){
161  if(r->ri + m > r->nbuf)
162  m = r->nbuf - r->ri;
163  memmove(p, r->buf + r->ri, m);
164  p += m;
165  }
166  r->ri = (r->ri + m) % r->nbuf;
167  n -= m;
168  }
169  return n0 - n;
170 }
171 
172 static long
173 writering(Ring *r, uchar *p, long n)
174 {
175  long n0, m;
176 
177  n0 = n;
178  while(n > 0){
179  if((m = available(r)) <= 0)
180  break;
181  if(m > n)
182  m = n;
183  if(p){
184  if(r->wi + m > r->nbuf)
185  m = r->nbuf - r->wi;
186  memmove(r->buf + r->wi, p, m);
187  p += m;
188  }
189  r->wi = (r->wi + m) % r->nbuf;
190  n -= m;
191  }
192  return n0 - n;
193 }
194 
195 #define csr8r(c, r) (inb((c)->port+(r)))
196 #define csr16r(c, r) (ins((c)->port+(r)))
197 #define csr32r(c, r) (inl((c)->port+(r)))
198 #define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
199 #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
200 #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
201 
202 /* audioac97mix */
203 extern void ac97mixreset(Audio *,
204  void (*wr)(Audio*,int,ushort),
205  ushort (*rr)(Audio*,int));
206 
207 static void
208 ac97waitcodec(Audio *adev)
209 {
210  Ctlr *ctlr;
211  int i;
212  ctlr = adev->ctlr;
213  for(i = 0; i < Maxbusywait/10; i++){
214  if((csr8r(ctlr, Cas) & Casp) == 0)
215  break;
216  microdelay(10);
217  }
218  if(i == Maxbusywait)
219  print("#A%d: ac97 exhausted waiting codec access\n", adev->ctlrno);
220 }
221 
222 static void
223 ac97mixw(Audio *adev, int port, ushort val)
224 {
225  Ctlr *ctlr;
226  ac97waitcodec(adev);
227  ctlr = adev->ctlr;
228  outs(ctlr->mixport+port, val);
229 }
230 
231 static ushort
232 ac97mixr(Audio *adev, int port)
233 {
234  Ctlr *ctlr;
235  ac97waitcodec(adev);
236  ctlr = adev->ctlr;
237  return ins(ctlr->mixport+port);
238 }
239 
240 static void
241 ac97interrupt(Ureg *, void *arg)
242 {
243  Audio *adev;
244  Ctlr *ctlr;
245  ulong stat;
246 
247  adev = arg;
248  ctlr = adev->ctlr;
249  stat = csr32r(ctlr, Sta);
250  stat &= S2ri | Sri | Pri | Mint | Point | Piint | Moint | Miint | Gsci;
251  if(stat & (Point|Piint|Mint)){
252  ilock(ctlr);
253  if(stat & Point){
254  ctlr->outring.ri = csr8r(ctlr, Out + Civ) * Blocksize;
255  wakeup(&ctlr->outring.r);
256 
257  if(ctlr->sis7012)
258  csr16w(ctlr, Out + Picb, csr16r(ctlr, Out + Picb) & ~Dch);
259  else
260  csr16w(ctlr, Out + Sr, csr16r(ctlr, Out + Sr) & ~Dch);
261  stat &= ~Point;
262  }
263  if(stat & Piint){
264  ctlr->inring.wi = csr8r(ctlr, In + Civ) * Blocksize;
265  wakeup(&ctlr->inring.r);
266 
267  if(ctlr->sis7012)
268  csr16w(ctlr, In + Picb, csr16r(ctlr, In + Picb) & ~Dch);
269  else
270  csr16w(ctlr, In + Sr, csr16r(ctlr, In + Sr) & ~Dch);
271  stat &= ~Piint;
272  }
273  if(stat & Mint){
274  ctlr->micring.wi = csr8r(ctlr, Mic + Civ) * Blocksize;
275  wakeup(&ctlr->micring.r);
276 
277  if(ctlr->sis7012)
278  csr16w(ctlr, Mic + Picb, csr16r(ctlr, Mic + Picb) & ~Dch);
279  else
280  csr16w(ctlr, Mic + Sr, csr16r(ctlr, Mic + Sr) & ~Dch);
281  stat &= ~Mint;
282  }
283  iunlock(ctlr);
284  }
285  if(stat) /* have seen 0x400, which is sdin0 resume */
286  iprint("#A%d: ac97 unhandled interrupt(s): stat 0x%lux\n",
287  adev->ctlrno, stat);
288 }
289 
290 static long
291 ac97buffered(Audio *adev)
292 {
293  Ctlr *ctlr = adev->ctlr;
294  return buffered(&ctlr->outring);
295 }
296 
297 static long
298 ac97status(Audio *adev, void *a, long n, vlong)
299 {
300  Ctlr *ctlr = adev->ctlr;
301  return snprint((char*)a, n, "bufsize %6d buffered %6ld\n",
302  Blocksize, buffered(&ctlr->outring));
303 }
304 
305 static int
306 inavail(void *arg)
307 {
308  Ring *r = arg;
309  return buffered(r) > 0;
310 }
311 
312 static int
313 outavail(void *arg)
314 {
315  Ring *r = arg;
316  return available(r) > 0;
317 }
318 
319 static int
320 outrate(void *arg)
321 {
322  Ctlr *ctlr = arg;
323  int delay = ctlr->adev->delay*BytesPerSample;
324  return (delay <= 0) || (buffered(&ctlr->outring) <= delay);
325 }
326 
327 static long
328 ac97read(Audio *adev, void *vp, long n, vlong)
329 {
330  uchar *p, *e;
331  Ctlr *ctlr;
332  Ring *ring;
333  ulong oi, ni;
334 
335  p = vp;
336  e = p + n;
337  ctlr = adev->ctlr;
338  ring = &ctlr->inring;
339  while(p < e) {
340  oi = ring->ri / Blocksize;
341  if((n = readring(ring, p, e - p)) <= 0){
342  csr8w(ctlr, In + Lvi, (oi - 1) % Ndesc);
343  csr8w(ctlr, In + Cr, Ioce | Rpbm);
344  sleep(&ring->r, inavail, ring);
345  continue;
346  }
347  ni = ring->ri / Blocksize;
348  while(oi != ni){
349  csr8w(ctlr, In + Lvi, (oi - 1) % Ndesc);
350  csr8w(ctlr, In + Cr, Ioce | Rpbm);
351  oi = (oi + 1) % Ndesc;
352  }
353  p += n;
354  }
355  return p - (uchar*)vp;
356 }
357 
358 static long
359 ac97write(Audio *adev, void *vp, long n, vlong)
360 {
361  uchar *p, *e;
362  Ctlr *ctlr;
363  Ring *ring;
364  ulong oi, ni;
365 
366  p = vp;
367  e = p + n;
368  ctlr = adev->ctlr;
369  ring = &ctlr->outring;
370  while(p < e) {
371  oi = ring->wi / Blocksize;
372  if((n = writering(ring, p, e - p)) <= 0){
373  sleep(&ring->r, outavail, ring);
374  continue;
375  }
376  ni = ring->wi / Blocksize;
377  while(oi != ni){
378  csr8w(ctlr, Out+Lvi, oi);
379  csr8w(ctlr, Out+Cr, Ioce | Rpbm);
380  oi = (oi + 1) % Ndesc;
381  }
382  p += n;
383  }
384  while(outrate(ctlr) == 0)
385  sleep(&ring->r, outrate, ctlr);
386  return p - (uchar*)vp;
387 }
388 
389 static void
390 ac97close(Audio *adev, int mode)
391 {
392  Ctlr *ctlr;
393  Ring *ring;
394 
395  if(mode == OREAD)
396  return;
397 
398  ctlr = adev->ctlr;
399  ring = &ctlr->outring;
400  while(ring->wi % Blocksize)
401  if(writering(ring, (uchar*)"", 1) <= 0)
402  break;
403 }
404 
405 static Pcidev*
406 ac97match(Pcidev *p)
407 {
408  /* not all of the matched devices have been tested */
409  while(p = pcimatch(p, 0, 0))
410  switch((p->vid<<16)|p->did){
411  case (0x1039<<16)|0x7012:
412  case (0x1022<<16)|0x746d:
413  case (0x1022<<16)|0x7445:
414  case (0x10de<<16)|0x01b1:
415  case (0x10de<<16)|0x006a:
416  case (0x10de<<16)|0x00da:
417  case (0x10de<<16)|0x00ea:
418  case (0x8086<<16)|0x2415:
419  case (0x8086<<16)|0x2425:
420  case (0x8086<<16)|0x2445:
421  case (0x8086<<16)|0x2485:
422  case (0x8086<<16)|0x24c5:
423  case (0x8086<<16)|0x24d5:
424  case (0x8086<<16)|0x25a6:
425  case (0x8086<<16)|0x266e:
426  case (0x8086<<16)|0x7195:
427  return p;
428  }
429  return nil;
430 }
431 
432 static void
433 sethwp(Ctlr *ctlr, long off, void *ptr)
434 {
435  csr8w(ctlr, off+Cr, RR);
436  csr32w(ctlr, off+Bar, PCIWADDR(ptr));
437  csr8w(ctlr, off+Lvi, 0);
438 }
439 
440 static int
441 ac97reset(Audio *adev)
442 {
443  static Ctlr *cards = nil;
444  Pcidev *p;
445  int i, irq, tbdf;
446  Ctlr *ctlr;
447  ulong ctl, stat = 0;
448 
449  /* make a list of all ac97 cards if not already done */
450  if(cards == nil){
451  p = nil;
452  while(p = ac97match(p)){
453  ctlr = xspanalloc(sizeof(Ctlr), 8, 0);
454  memset(ctlr, 0, sizeof(Ctlr));
455  ctlr->pcidev = p;
456  ctlr->next = cards;
457  cards = ctlr;
458  }
459  }
460 
461  /* pick a card from the list */
462  for(ctlr = cards; ctlr; ctlr = ctlr->next){
463  if(p = ctlr->pcidev){
464  ctlr->pcidev = nil;
465  goto Found;
466  }
467  }
468  return -1;
469 
470 Found:
471  adev->ctlr = ctlr;
472  ctlr->adev = adev;
473 
474  if((p->mem[0].bar & 1) == 0 || (p->mem[1].bar & 1) == 0){
475  print("ac97: not i/o regions 0x%04lux 0x%04lux\n", p->mem[0].bar, p->mem[1].bar);
476  return -1;
477  }
478 
479  i = 1;
480  if(p->vid == 0x1039 && p->did == 0x7012){
481  ctlr->sis7012 = 1;
482  //i = 0; i/o bars swaped?
483  }
484  ctlr->port = p->mem[i].bar & ~3;
485  if(ioalloc(ctlr->port, p->mem[i].size, 0, "ac97") < 0){
486  print("ac97: ioalloc failed for port 0x%04lux\n", ctlr->port);
487  return -1;
488  }
489  i = (i+1) & 1;
490  ctlr->mixport = p->mem[i].bar & ~3;
491  if(ioalloc(ctlr->mixport, p->mem[i].size, 0, "ac97mix") < 0){
492  print("ac97: ioalloc failed for mixport 0x%04lux\n", ctlr->mixport);
493  iofree(ctlr->port);
494  return -1;
495  }
496 
497  irq = p->intl;
498  tbdf = p->tbdf;
499 
500  print("#A%d: ac97 port 0x%04lux mixport 0x%04lux irq %d\n",
501  adev->ctlrno, ctlr->port, ctlr->mixport, irq);
502 
503  pcisetbme(p);
504  pcisetioe(p);
505 
506  ctlr->micring.buf = xspanalloc(Bufsize, 8, 0);
507  ctlr->micring.nbuf = Bufsize;
508  ctlr->micring.ri = 0;
509  ctlr->micring.wi = 0;
510 
511  ctlr->inring.buf = xspanalloc(Bufsize, 8, 0);
512  ctlr->inring.nbuf = Bufsize;
513  ctlr->inring.ri = 0;
514  ctlr->inring.wi = 0;
515 
516  ctlr->outring.buf = xspanalloc(Bufsize, 8, 0);
517  ctlr->outring.nbuf = Bufsize;
518  ctlr->outring.ri = 0;
519  ctlr->outring.wi = 0;
520 
521  for(i = 0; i < Ndesc; i++){
522  int size, off = i * Blocksize;
523 
524  if(ctlr->sis7012)
525  size = Blocksize;
526  else
527  size = Blocksize / 2;
528  ctlr->micdesc[i].addr = PCIWADDR(ctlr->micring.buf + off);
529  ctlr->micdesc[i].size = Ioc | size;
530  ctlr->indesc[i].addr = PCIWADDR(ctlr->inring.buf + off);
531  ctlr->indesc[i].size = Ioc | size;
532  ctlr->outdesc[i].addr = PCIWADDR(ctlr->outring.buf + off);
533  ctlr->outdesc[i].size = Ioc | size;
534  }
535 
536  ctl = csr32r(ctlr, Cnt);
537  ctl &= ~(EnaRESER | Aclso);
538 
539  if((ctl & Accr) == 0){
540  print("#A%d: ac97 cold reset\n", adev->ctlrno);
541  ctl |= Accr;
542  }else{
543  print("#A%d: ac97 warm reset\n", adev->ctlrno);
544  ctl |= Acwr;
545  }
546 
547  csr32w(ctlr, Cnt, ctl);
548  for(i = 0; i < Maxbusywait; i++){
549  if((csr32r(ctlr, Cnt) & Acwr) == 0)
550  break;
551  microdelay(1);
552  }
553  if(i == Maxbusywait)
554  print("#A%d: ac97 gave up waiting Acwr to go down\n", adev->ctlrno);
555 
556  for(i = 0; i < Maxbusywait; i++){
557  if((stat = csr32r(ctlr, Sta)) & (Pcr | Scr | S2cr))
558  break;
559  microdelay(1);
560  }
561  if(i == Maxbusywait)
562  print("#A%d: ac97 gave up waiting codecs become ready\n", adev->ctlrno);
563 
564  print("#A%d: ac97 codecs ready:%s%s%s\n", adev->ctlrno,
565  (stat & Pcr) ? " sdin0" : "",
566  (stat & Scr) ? " sdin1" : "",
567  (stat & S2cr) ? " sdin2" : "");
568 
569  print("#A%d: ac97 codecs resumed:%s%s%s\n", adev->ctlrno,
570  (stat & Pri) ? " sdin0" : "",
571  (stat & Sri) ? " sdin1" : "",
572  (stat & S2ri) ? " sdin2" : "");
573 
574  sethwp(ctlr, In, ctlr->indesc);
575  sethwp(ctlr, Out, ctlr->outdesc);
576  sethwp(ctlr, Mic, ctlr->micdesc);
577 
578  csr8w(ctlr, In+Cr, Ioce); /* | Lvbie | Feie */
579  csr8w(ctlr, Out+Cr, Ioce); /* | Lvbie | Feie */
580  csr8w(ctlr, Mic+Cr, Ioce); /* | Lvbie | Feie */
581 
582  ac97mixreset(adev, ac97mixw, ac97mixr);
583 
584  adev->read = ac97read;
585  adev->write = ac97write;
586  adev->close = ac97close;
587  adev->buffered = ac97buffered;
588  adev->status = ac97status;
589 
590  intrenable(irq, ac97interrupt, adev, tbdf, adev->name);
591 
592  return 0;
593 }
594 
595 void
596 audioac97link(void)
597 {
598  addaudiocard("ac97", ac97reset);
599 }