]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/archacpi.c
devkbd: bits bad! revert repeat/delay, better patches welcome
[plan9front.git] / sys / src / 9 / pc / archacpi.c
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
9 #include "mp.h"
10
11 #include <aml.h>
12
13 typedef struct Rsd Rsd;
14 typedef struct Tbl Tbl;
15
16 struct Rsd {
17         uchar   sig[8];
18         uchar   csum;
19         uchar   oemid[6];
20         uchar   rev;
21         uchar   raddr[4];
22         uchar   len[4];
23         uchar   xaddr[8];
24         uchar   xcsum;
25         uchar   reserved[3];
26 };
27
28 struct Tbl {
29         uchar   sig[4];
30         uchar   len[4];
31         uchar   rev;
32         uchar   csum;
33         uchar   oemid[6];
34         uchar   oemtid[8];
35         uchar   oemrev[4];
36         uchar   cid[4];
37         uchar   crev[4];
38         uchar   data[];
39 };
40
41 enum {
42         Tblsz   = 4+4+1+1+6+8+4+4+4,
43 };
44
45 static Rsd *rsd;
46
47 /* physical addresses visited by maptable() */
48 static int ntblpa;
49 static uintptr tblpa[64];
50
51 /* successfully mapped tables */
52 static int ntblmap;
53 static Tbl *tblmap[64];
54
55 static ushort
56 get16(uchar *p){
57         return p[1]<<8 | p[0];
58 }
59
60 static uint
61 get32(uchar *p){
62         return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
63 }
64
65 static uvlong
66 get64(uchar *p){
67         uvlong u;
68
69         u = get32(p+4);
70         return u<<32 | get32(p);
71 }
72
73 static uint
74 tbldlen(Tbl *t){
75         return get32(t->len) - Tblsz;
76 }
77
78 static long
79 memcheck(uintptr pa, long len)
80 {
81         int i;
82         uintptr pe;
83         Confmem *cm;
84
85         if(len <= 0)
86                 return len;
87         pe = pa + len-1;
88         if(pe < pa){
89                 len = -pa;
90                 pe = pa + len-1;
91         }
92         if(pa < PADDR(CPU0END))
93                 return 0;
94         if(pe >= PADDR(KTZERO) && pa < PADDR(end))
95                 return PADDR(KTZERO) - pa;
96         for(i=0; i<nelem(conf.mem); i++){
97                 cm = &conf.mem[i];
98                 if(cm->npage == 0)
99                         continue;
100                 if(pe >= cm->base && pa <= cm->base + cm->npage*BY2PG - 1)
101                         return cm->base - pa;
102         }
103         return len;
104 }
105
106 static void
107 maptable(uvlong xpa)
108 {
109         uchar *p, *e;
110         uintptr pa;
111         u32int l;
112         Tbl *t;
113         int i;
114
115         pa = xpa;
116         if((uvlong)pa != xpa || pa == 0)
117                 return;
118         if(ntblpa >= nelem(tblpa) || ntblmap >= nelem(tblmap))
119                 return;
120
121         for(i=0; i<ntblpa; i++){
122                 if(pa == tblpa[i])
123                         return;
124         }
125         tblpa[ntblpa++] = pa;
126
127         if((t = vmap(pa, 8)) == nil)
128                 return;
129         l = get32(t->len);
130         if(l < Tblsz){
131                 vunmap(t, 8);
132                 return;
133         }
134         if(memcheck(pa, l) != l){
135                 print("maptable: ignoring %.4s at [%#p-%#p); overlaps usable memory\n",
136                         (char*)t->sig, pa, pa+l);
137                 vunmap(t, 8);
138                 return;
139         }
140         vunmap(t, 8);
141
142         if((t = vmap(pa, l)) == nil)
143                 return;
144         if(checksum(t, l)){
145                 vunmap(t, l);
146                 return;
147         }
148         tblmap[ntblmap++] = t;
149
150         p = (uchar*)t;
151         e = p + l;
152         if(memcmp("RSDT", t->sig, 4) == 0){
153                 for(p = t->data; p+3 < e; p += 4)
154                         maptable(get32(p));
155                 return;
156         }
157         if(memcmp("XSDT", t->sig, 4) == 0){
158                 for(p = t->data; p+7 < e; p += 8)
159                         maptable(get64(p));
160                 return;
161         }
162         if(memcmp("FACP", t->sig, 4) == 0){
163                 if(l < 44)
164                         return;
165                 maptable(get32(p + 40));
166                 if(l < 148)
167                         return;
168                 maptable(get64(p + 140));
169                 return;
170         }
171 }
172
173 static void
174 maptables(void)
175 {
176         if(rsd == nil || ntblmap > 0 || ntblpa > 0)
177                 return;
178         if(!checksum(rsd, 20))
179                 maptable(get32(rsd->raddr));
180         if(rsd->rev >= 2)
181                 if(!checksum(rsd, 36))
182                         maptable(get64(rsd->xaddr));
183 }
184
185 static Apic*
186 findapic(int gsi, int *pintin)
187 {
188         Apic *a;
189         int i;
190
191         for(i=0; i<=MaxAPICNO; i++){
192                 if((a = mpioapic[i]) == nil)
193                         continue;
194                 if((a->flags & PcmpEN) == 0)
195                         continue;
196                 if(gsi >= a->gsibase && gsi <= a->gsibase+a->mre){
197                         if(pintin)
198                                 *pintin = gsi - a->gsibase;
199                         return a;
200                 }
201         }
202         print("findapic: no ioapic found for gsi %d\n", gsi);
203         return nil;
204 }
205
206 static void
207 addirq(int gsi, int type, int busno, int irq, int flags)
208 {
209         Apic *a;
210         Bus *bus;
211         Aintr *ai;
212         PCMPintr *pi;
213         int intin;
214
215         if((a = findapic(gsi, &intin)) == nil)
216                 return;
217
218         for(bus = mpbus; bus; bus = bus->next)
219                 if(bus->type == type && bus->busno == busno)
220                         goto Foundbus;
221
222         if((bus = xalloc(sizeof(Bus))) == nil)
223                 panic("addirq: no memory for Bus");
224         bus->busno = busno;
225         bus->type = type;
226         if(type == BusISA){
227                 bus->po = PcmpHIGH;
228                 bus->el = PcmpEDGE;
229                 if(mpisabus == -1)
230                         mpisabus = busno;
231         } else {
232                 bus->po = PcmpLOW;
233                 bus->el = PcmpLEVEL;
234         }
235         if(mpbus)
236                 mpbuslast->next = bus;
237         else
238                 mpbus = bus;
239         mpbuslast = bus;
240
241 Foundbus:
242         for(ai = bus->aintr; ai; ai = ai->next)
243                 if(ai->intr->irq == irq)
244                         return;
245
246         if((pi = xalloc(sizeof(PCMPintr))) == nil)
247                 panic("addirq: no memory for PCMPintr");
248         pi->type = PcmpIOINTR;
249         pi->intr = PcmpINT;
250         pi->flags = flags & (PcmpPOMASK|PcmpELMASK);
251         pi->busno = busno;
252         pi->irq = irq;
253         pi->apicno = a->apicno;
254         pi->intin = intin;
255
256         if((ai = xalloc(sizeof(Aintr))) == nil)
257                 panic("addirq: no memory for Aintr");
258         ai->intr = pi;
259         ai->apic = a;
260         ai->next = bus->aintr;
261         bus->aintr = ai;
262 }
263
264 static char*
265 eisaid(void *v)
266 {
267         static char id[8];
268         ulong b, l;
269         int i;
270
271         if(amltag(v) == 's')
272                 return v;
273         b = amlint(v);
274         for(l = 0, i=24; i>=0; i -= 8, b >>= 8)
275                 l |= (b & 0xFF) << i;
276         id[7] = 0;
277         for(i=6; i>=3; i--, l >>= 4)
278                 id[i] = "0123456789ABCDEF"[l & 0xF];
279         for(i=2; i>=0; i--, l >>= 5)
280                 id[i] = '@' + (l & 0x1F);
281         return id;
282 }
283
284 static int
285 pcibusno(void *dot)
286 {
287         int bno, adr, tbdf;
288         Pcidev *pdev;
289         void *p, *x;
290         char *id;
291
292         id = nil;
293         if((x = amlwalk(dot, "^_HID")) != nil)
294                 if((p = amlval(x)) != nil)
295                         id = eisaid(p);
296         if((x = amlwalk(dot, "^_BBN")) == nil)
297                 if((x = amlwalk(dot, "^_ADR")) == nil)
298                         return -1;
299         p = nil;
300         if(amleval(x, "", &p) < 0)
301                 return -1;
302         adr = amlint(p);
303         /* if root bridge, then we are done here */
304         if(id != nil && (strcmp(id, "PNP0A03")==0 || strcmp(id, "PNP0A08")==0))
305                 return adr;
306         x = amlwalk(dot, "^");
307         if(x == nil || x == dot)
308                 return -1;
309         if((bno = pcibusno(x)) < 0)
310                 return -1;
311         tbdf = MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
312         pdev = pcimatchtbdf(tbdf);
313         if(pdev == nil)
314                 return -1;
315         if(pdev->bridge == nil)
316                 return bno;
317         return BUSBNO(pdev->bridge->tbdf);
318 }
319
320 static int
321 pciaddr(void *dot)
322 {
323         int adr, bno;
324         void *x, *p;
325
326         for(;;){
327                 if((x = amlwalk(dot, "_ADR")) == nil){
328                         x = amlwalk(dot, "^");
329                         if(x == nil || x == dot)
330                                 break;
331                         dot = x;
332                         continue;
333                 }
334                 if((bno = pcibusno(x)) < 0)
335                         break;
336                 p = nil;
337                 if(amleval(x, "", &p) < 0)
338                         break;
339                 adr = amlint(p);
340                 return MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
341         }
342         return -1;
343 }
344
345 static int
346 getirqs(void *d, uchar pmask[32], int *pflags)
347 {
348         int i, n, m;
349         uchar *p;
350
351         *pflags = 0;
352         memset(pmask, 0, 32);
353         if(amltag(d) != 'b')
354                 return -1;
355         p = amlval(d);
356         if(amllen(d) >= 2 && (p[0] == 0x22 || p[0] == 0x23)){
357                 pmask[0] = p[1];
358                 pmask[1] = p[2];
359                 if(amllen(d) >= 3 && p[0] == 0x23)
360                         *pflags = ((p[3] & (1<<0)) ? PcmpEDGE : PcmpLEVEL)
361                                 | ((p[3] & (1<<3)) ? PcmpLOW : PcmpHIGH);
362                 return 0;
363         }
364         if(amllen(d) >= 5 && p[0] == 0x89){
365                 n = p[4];
366                 if(amllen(d) < 5+n*4)
367                         return -1;
368                 for(i=0; i<n; i++){
369                         m = get32(p+5 + i*4);
370                         if(m >= 0 && m < 256)
371                                 pmask[m/8] |= 1<<(m%8);
372                 }
373                 *pflags = ((p[3] & (1<<1)) ? PcmpEDGE : PcmpLEVEL)
374                         | ((p[3] & (1<<2)) ? PcmpLOW : PcmpHIGH);
375                 return 0;
376         }
377         return -1;
378 }
379
380 static uchar*
381 setirq(void *d, uint irq)
382 {
383         uchar *p;
384
385         if(amltag(d) != 'b')
386                 return nil;
387         p = amlnew('b', amllen(d));
388         memmove(p, d, amllen(p));
389         if(p[0] == 0x22 || p[0] == 0x23){
390                 irq = 1<<irq;
391                 p[1] = irq;
392                 p[2] = irq>>8;
393         }
394         if(p[0] == 0x89){
395                 p[4] = 1;
396                 p[5] = irq;
397                 p[6] = irq>>8;
398                 p[7] = irq>>16;
399                 p[8] = irq>>24;
400         }
401         return p;
402 }
403
404 static int
405 setuplink(void *link, int *pflags)
406 {
407         uchar im, pm[32], cm[32], *c;
408         static int lastirq = 1;
409         int gsi, i;
410         void *r;
411
412         if(amltag(link) != 'N')
413                 return -1;
414
415         r = nil;
416         if(amleval(amlwalk(link, "_PRS"), "", &r) < 0)
417                 return -1;
418         if(getirqs(r, pm, pflags) < 0)
419                 return -1;
420
421         r = nil;
422         if(amleval(amlwalk(link, "_CRS"), "", &r) < 0)
423                 return -1;
424         if(getirqs(r, cm, pflags) < 0)
425                 return -1;
426         
427         gsi = -1;
428         for(i=0; i<256; i++){
429                 im = 1<<(i%8);
430                 if(pm[i/8] & im){
431                         if(cm[i/8] & im)
432                                 gsi = i;
433                 }
434         }
435
436         if(gsi > 0 || getconf("*nopcirouting") != nil)
437                 return gsi;
438
439         for(i=0; i<256; i++){
440                 gsi = lastirq++ & 0xFF; /* round robin */
441                 im = 1<<(gsi%8);
442                 if(pm[gsi/8] & im){
443                         if((c = setirq(r, gsi)) == nil)
444                                 break;
445                         if(amleval(amlwalk(link, "_SRS"), "b", c, nil) < 0)
446                                 break;
447                         return gsi;
448                 }
449         }
450         return -1;
451 }
452
453 static int
454 enumprt(void *dot, void *)
455 {
456         void *p, **a, **b;
457         int bno, dno, pin, gsi, flags;
458         int n, i;
459
460         bno = pcibusno(dot);
461         if(bno < 0)
462                 return 1;
463
464         /* evalulate _PRT method */
465         p = nil;
466         if(amleval(dot, "", &p) < 0)
467                 return 1;
468         if(amltag(p) != 'p')
469                 return 1;
470
471         amltake(p);
472         n = amllen(p);
473         a = amlval(p);
474         for(i=0; i<n; i++){
475                 if(amltag(a[i]) != 'p')
476                         continue;
477                 if(amllen(a[i]) != 4)
478                         continue;
479                 flags = 0;
480                 b = amlval(a[i]);
481                 dno = amlint(b[0])>>16;
482                 pin = amlint(b[1]);
483                 gsi = amlint(b[3]);
484                 if(gsi==0){
485                         gsi = setuplink(b[2], &flags);
486                         if(gsi <= 0)
487                                 continue;
488                 }
489                 addirq(gsi, BusPCI, bno, (dno<<2)|pin, flags);
490         }
491         amldrop(p);
492
493         return 1;
494 }
495
496 static int
497 enumec(void *dot, void *)
498 {
499         int cmdport, dataport;
500         uchar *b;
501         void *x;
502         char *id;
503
504         b = nil;
505         id = eisaid(amlval(amlwalk(dot, "^_HID")));
506         if(id == nil || strcmp(id, "PNP0C09") != 0)
507                 return 1;
508         if((x = amlwalk(dot, "^_CRS")) == nil)
509                 return 1;
510         if(amleval(x, "", &b) < 0 || amltag(b) != 'b' || amllen(b) < 16)
511                 return 1;
512         if(b[0] != 0x47 || b[8] != 0x47)        /* two i/o port descriptors */
513                 return 1;
514         dataport = b[0+2] | b[0+3]<<8;
515         cmdport = b[8+2] | b[8+3]<<8;
516         ecinit(cmdport, dataport);
517         return 1;
518 }
519
520 static long
521 readmem(Chan*, void *v, long n, vlong o)
522 {
523         uintptr pa = (uintptr)o;
524         void *t;
525
526         if((n = memcheck(pa, n)) <= 0)
527                 return 0;
528         if((t = vmap(pa, n)) == nil)
529                 error(Enovmem);
530         if(waserror()){
531                 vunmap(t, n);
532                 nexterror();
533         }
534         memmove(v, t, n);
535         vunmap(t, n);
536         poperror();
537         return n;
538 }
539
540 static long
541 writemem(Chan*, void *v, long n, vlong o)
542 {
543         uintptr pa = (uintptr)o;
544         void *t;
545
546         if(memcheck(pa, n) != n)
547                 error(Eio);
548         if((t = vmap(pa, n)) == nil)
549                 error(Enovmem);
550         if(waserror()){
551                 vunmap(t, n);
552                 nexterror();
553         }
554         memmove(t, v, n);
555         vunmap(t, n);
556         poperror();
557         return n;
558 }
559
560 static void
561 acpiinit(void)
562 {
563         Tbl *t;
564         Apic *a;
565         void *va;
566         uchar *s, *p, *e;
567         ulong lapicbase;
568         int machno, i, c;
569
570         maptables();
571
572         amlinit();
573
574         /* load DSDT */
575         for(i=0; i<ntblmap; i++){
576                 t = tblmap[i];
577                 if(memcmp(t->sig, "DSDT", 4) == 0){
578                         amlintmask = (~0ULL) >> (t->rev <= 1)*32;
579                         amlload(t->data, tbldlen(t));
580                         break;
581                 }
582         }
583
584         /* load SSDT, there can be multiple tables */
585         for(i=0; i<ntblmap; i++){
586                 t = tblmap[i];
587                 if(memcmp(t->sig, "SSDT", 4) == 0)
588                         amlload(t->data, tbldlen(t));
589         }
590
591         /* set APIC mode */
592         amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
593
594         for(i=0; i<ntblmap; i++){
595                 t = tblmap[i];
596                 if(memcmp(t->sig, "APIC", 4) == 0)
597                         goto Foundapic;
598         }
599         panic("acpiinit: no MADT (APIC) table");
600         return;
601
602 Foundapic:
603         s = t->data;
604         e = s + tbldlen(t);
605         lapicbase = get32(s); s += 8;
606         va = vmap(lapicbase, 1024);
607         print("LAPIC: %.8lux %#p\n", lapicbase, va);
608         if(va == nil)
609                 panic("acpiinit: cannot map lapic %.8lux", lapicbase);
610
611         machno = 0;
612         for(p = s; p < e; p += c){
613                 c = p[1];
614                 if(c < 2 || (p+c) > e)
615                         break;
616                 switch(*p){
617                 case 0x00:      /* Processor Local APIC */
618                         if(p[3] > MaxAPICNO)
619                                 break;
620                         if((a = xalloc(sizeof(Apic))) == nil)
621                                 panic("acpiinit: no memory for Apic");
622                         a->type = PcmpPROCESSOR;
623                         a->apicno = p[3];
624                         a->paddr = lapicbase;
625                         a->addr = va;
626                         a->lintr[0] = ApicIMASK;
627                         a->lintr[1] = ApicIMASK;
628                         a->flags = p[4] & PcmpEN;
629
630                         /* skip disabled processors */
631                         if((a->flags & PcmpEN) == 0 || mpapic[a->apicno] != nil){
632                                 xfree(a);
633                                 break;
634                         }
635                         a->machno = machno++;
636
637                         /*
638                          * platform firmware should list the boot processor
639                          * as the first processor entry in the MADT
640                          */
641                         if(a->machno == 0)
642                                 a->flags |= PcmpBP;
643
644                         mpapic[a->apicno] = a;
645                         break;
646                 case 0x01:      /* I/O APIC */
647                         if(p[2] > MaxAPICNO)
648                                 break;
649                         if((a = xalloc(sizeof(Apic))) == nil)
650                                 panic("acpiinit: no memory for io Apic");
651                         a->type = PcmpIOAPIC;
652                         a->apicno = p[2];
653                         a->paddr = get32(p+4);
654                         if((a->addr = vmap(a->paddr, 1024)) == nil)
655                                 panic("acpiinit: cannot map ioapic %.8lux", a->paddr);
656                         a->gsibase = get32(p+8);
657                         a->flags = PcmpEN;
658                         mpioapic[a->apicno] = a;
659                         ioapicinit(a, a->apicno);
660                         break;
661                 }
662         }
663
664         /*
665          * need 2nd pass as vbox puts interrupt overrides
666          * *before* the ioapic entries (!)
667          */
668         for(p = s; p < e; p += c){
669                 c = p[1];
670                 if(c < 2 || (p+c) > e)
671                         break;
672                 switch(*p){
673                 case 0x02:      /* Interrupt Source Override */
674                         addirq(get32(p+4), BusISA, 0, p[3], get16(p+8));
675                         break;
676                 case 0x03:      /* NMI Source */
677                 case 0x04:      /* Local APIC NMI */
678                 case 0x05:      /* Local APIC Address Override */
679                 case 0x06:      /* I/O SAPIC */
680                 case 0x07:      /* Local SAPIC */
681                 case 0x08:      /* Platform Interrupt Sources */
682                 case 0x09:      /* Processor Local x2APIC */
683                 case 0x0A:      /* x2APIC NMI */
684                 case 0x0B:      /* GIC */
685                 case 0x0C:      /* GICD */
686                         break;
687                 }
688         }
689
690         /* find embedded controller */
691         amlenum(amlroot, "_HID", enumec, nil);
692
693         /* look for PCI interrupt mappings */
694         amlenum(amlroot, "_PRT", enumprt, nil);
695
696         /* add identity mapped legacy isa interrupts */
697         for(i=0; i<16; i++)
698                 addirq(i, BusISA, 0, i, 0);
699
700         /* free the AML interpreter */
701         amlexit();
702
703         /*
704          * Ininitalize local APIC and start application processors.
705          */
706         mpinit();
707 }
708
709 static void
710 acpireset(void)
711 {
712         uchar *p;
713         Tbl *t;
714         int i;
715
716         /* stop application processors */
717         mpshutdown();
718
719         /* locate and write platform reset register */
720         for(i=0; i < ntblmap; i++){
721                 t = tblmap[i];
722                 if(memcmp(t->sig, "FACP", 4) != 0)
723                         continue;
724                 if(get32(t->len) <= 128)
725                         break;
726                 p = (uchar*)t;
727                 if((get32(p + 112) & (1<<10)) == 0)
728                         break;
729                 if(p[116+0] != IoSpace)
730                         break;
731                 outb(get32(p+116+4), p[128]);
732                 break;
733         }
734
735         /* acpi shutdown failed, try generic reset */
736         archreset();
737 }
738
739 static int identify(void);
740
741 PCArch archacpi = {
742 .id=            "ACPI", 
743 .ident=         identify,
744 .reset=         acpireset,
745 .intrinit=      acpiinit,
746 .intrenable=    mpintrenable,
747 .intron=        lapicintron,
748 .introff=       lapicintroff,
749 .fastclock=     i8253read,
750 .timerset=      lapictimerset,
751 };
752
753 static long
754 readtbls(Chan*, void *v, long n, vlong o)
755 {
756         int i, l, m;
757         uchar *p;
758         Tbl *t;
759
760         maptables();
761
762         p = v;
763         for(i=0; n > 0 && i < ntblmap; i++){
764                 t = tblmap[i];
765                 l = get32(t->len);
766                 if(o >= l){
767                         o -= l;
768                         continue;
769                 }
770                 m = l - o;
771                 if(m > n)
772                         m = n;
773                 memmove(p, (uchar*)t + o, m);
774                 p += m;
775                 n -= m;
776                 o = 0;
777         }
778         return p - (uchar*)v;
779 }
780
781 static int
782 identify(void)
783 {
784         uintptr pa;
785         char *cp;
786
787         if((cp = getconf("*acpi")) == nil)
788                 return 1;
789         pa = (uintptr)strtoull(cp, nil, 16);
790         if(pa <= 1)
791                 rsd = rsdsearch();
792         else if(pa < MemMin)
793                 rsd = KADDR(pa);
794         else
795                 rsd = vmap(pa, sizeof(Rsd));
796         if(rsd == nil)
797                 return 1;
798         if(checksum(rsd, 20) && checksum(rsd, 36))
799                 return 1;
800         addarchfile("acpitbls", 0444, readtbls, nil);
801         addarchfile("acpimem", 0600, readmem, writemem);
802         if(strcmp(cp, "0") == 0)
803                 return 1;
804         if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
805                 return 1;
806         if(m->havetsc && getconf("*notsc") == nil)
807                 archacpi.fastclock = tscticks;
808         return 0;
809 }
810
811 static int
812 readpcicfg(Amlio *io, void *data, int n, int offset)
813 {
814         ulong r, x;
815         Pcidev *p;
816         uchar *a;
817         int i;
818
819         a = data;
820         p = io->aux;
821         if(p == nil)
822                 return -1;
823         offset += io->off;
824         if(offset > 256)
825                 return 0;
826         if(n+offset > 256)
827                 n = 256-offset;
828         r = offset;
829         if(!(r & 3) && n == 4){
830                 x = pcicfgr32(p, r);
831                 PBIT32(a, x);
832                 return 4;
833         }
834         if(!(r & 1) && n == 2){
835                 x = pcicfgr16(p, r);
836                 PBIT16(a, x);
837                 return 2;
838         }
839         for(i = 0; i <  n; i++){
840                 x = pcicfgr8(p, r);
841                 PBIT8(a, x);
842                 a++;
843                 r++;
844         }
845         return i;
846 }
847
848 static int
849 readec(Amlio *io, void *data, int n, int off)
850 {
851         int port, v;
852         uchar *p;
853
854         USED(io);
855         if(off < 0 || off >= 256)
856                 return 0;
857         if(off+n > 256)
858                 n = 256 - off;
859         p = data;
860         for(port = off; port < off+n; port++){
861                 if((v = ecread(port)) < 0)
862                         break;
863                 *p++ = v;
864         }
865         return n;
866 }
867
868 static int
869 writeec(Amlio *io, void *data, int n, int off)
870 {
871         int port;
872         uchar *p;
873
874         USED(io);
875         if(off < 0 || off+n > 256)
876                 return -1;
877         p = data;
878         for(port = off; port < off+n; port++)
879                 if(ecwrite(port, *p++) < 0)
880                         break;
881         return n;
882 }
883
884 static int
885 writepcicfg(Amlio *io, void *data, int n, int offset)
886 {
887         ulong r, x;
888         Pcidev *p;
889         uchar *a;
890         int i;
891
892         a = data;
893         p = io->aux;
894         if(p == nil)
895                 return -1;
896         offset += io->off;
897         if(offset > 256)
898                 return 0;
899         if(n+offset > 256)
900                 n = 256-offset;
901         r = offset;
902         if(!(r & 3) && n == 4){
903                 x = GBIT32(a);
904                 pcicfgw32(p, r, x);
905                 return 4;
906         }
907         if(!(r & 1) && n == 2){
908                 x = GBIT16(a);
909                 pcicfgw16(p, r, x);
910                 return 2;
911         }
912         for(i = 0; i <  n; i++){
913                 x = GBIT8(a);
914                 pcicfgw8(p, r, x);
915                 a++;
916                 r++;
917         }
918         return i;
919 }
920
921 static int
922 readioport(Amlio *io, void *data, int len, int port)
923 {
924         uchar *a;
925
926         a = data;
927         port += io->off;
928         switch(len){
929         case 4:
930                 PBIT32(a, inl(port));
931                 return 4;
932         case 2:
933                 PBIT16(a, ins(port));
934                 return 2;
935         case 1:
936                 PBIT8(a, inb(port));
937                 return 1;
938         }
939         return -1;
940 }
941
942 static int
943 writeioport(Amlio *io, void *data, int len, int port)
944 {
945         uchar *a;
946
947         a = data;
948         port += io->off;
949         switch(len){
950         case 4:
951                 outl(port, GBIT32(a));
952                 return 4;
953         case 2:
954                 outs(port, GBIT16(a));
955                 return 2;
956         case 1:
957                 outb(port, GBIT8(a));
958                 return 1;
959         }
960         return -1;
961 }
962
963 int
964 amlmapio(Amlio *io)
965 {
966         int tbdf;
967         Pcidev *pdev;
968         char buf[64];
969
970         switch(io->space){
971         default:
972                 print("amlmapio: address space %x not implemented\n", io->space);
973                 break;
974         case MemSpace:
975                 if(memcheck(io->off, io->len) != io->len){
976                         print("amlmapio: [%#p-%#p) overlaps usable memory\n",
977                                 (uintptr)io->off, (uintptr)(io->off+io->len));
978                         break;
979                 }
980                 if((io->va = vmap(io->off, io->len)) == nil){
981                         print("amlmapio: vmap failed\n");
982                         break;
983                 }
984                 return 0;
985         case IoSpace:
986                 snprint(buf, sizeof(buf), "%N", io->name);
987                 if(ioalloc(io->off, io->len, 0, buf) < 0){
988                         print("amlmapio: ioalloc failed\n");
989                         break;
990                 }
991                 io->read = readioport;
992                 io->write = writeioport;
993                 return 0;
994         case PcicfgSpace:
995                 if((tbdf = pciaddr(io->name)) < 0){
996                         print("amlmapio: no address\n");
997                         break;
998                 }
999                 if((pdev = pcimatchtbdf(tbdf)) == nil){
1000                         print("amlmapio: no device %T\n", tbdf);
1001                         break;
1002                 }
1003                 io->aux = pdev;
1004                 io->read = readpcicfg;
1005                 io->write = writepcicfg;
1006                 return 0;
1007         case EbctlSpace:
1008                 io->read = readec;
1009                 io->write = writeec;
1010                 return 0;
1011         }
1012         print("amlmapio: mapping %N failed\n", io->name);
1013         return -1;
1014 }
1015
1016 void
1017 amlunmapio(Amlio *io)
1018 {
1019         switch(io->space){
1020         case MemSpace:
1021                 vunmap(io->va, io->len);
1022                 break;
1023         case IoSpace:
1024                 iofree(io->off);
1025                 break;
1026         }
1027 }
1028
1029 void*
1030 amlalloc(int n){
1031         void *p;
1032
1033         if((p = malloc(n)) == nil)
1034                 panic("amlalloc: no memory");
1035         memset(p, 0, n);
1036         return p;
1037 }
1038
1039 void
1040 amlfree(void *p){
1041         free(p);
1042 }
1043
1044 void
1045 amldelay(int us)
1046 {
1047         microdelay(us);
1048 }