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