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