]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/archacpi.c
24b3245bca1dad780fc8499cbec935cadc90a572
[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 void*
55 amlalloc(int n){
56         void *p;
57
58         if((p = malloc(n)) == nil)
59                 panic("amlalloc: no memory");
60         memset(p, 0, n);
61         return p;
62 }
63
64 void
65 amlfree(void *p){
66         free(p);
67 }
68
69 static ushort
70 get16(uchar *p){
71         return p[1]<<8 | p[0];
72 }
73
74 static uint
75 get32(uchar *p){
76         return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
77 }
78
79 static uvlong
80 get64(uchar *p){
81         uvlong u;
82
83         u = get32(p+4);
84         return u<<32 | get32(p);
85 }
86
87 static uint
88 tbldlen(Tbl *t){
89         return get32(t->len) - Tblsz;
90 }
91
92 static void
93 maptable(uvlong xpa)
94 {
95         uchar *p, *e;
96         uintptr pa;
97         u32int l;
98         Tbl *t;
99         int i;
100
101         pa = xpa;
102         if((uvlong)pa != xpa || pa == 0)
103                 return;
104         if(ntblpa >= nelem(tblpa) || ntblmap >= nelem(tblmap))
105                 return;
106
107         for(i=0; i<ntblpa; i++){
108                 if(pa == tblpa[i])
109                         return;
110         }
111         tblpa[ntblpa++] = pa;
112
113         if((t = vmap(pa, 8)) == nil)
114                 return;
115         l = get32(t->len);
116         if(l < Tblsz){
117                 vunmap(t, 8);
118                 return;
119         }
120         vunmap(t, 8);
121         if((t = vmap(pa, l)) == nil)
122                 return;
123         if(checksum(t, l)){
124                 vunmap(t, l);
125                 return;
126         }
127         tblmap[ntblmap++] = t;
128
129         p = (uchar*)t;
130         e = p + l;
131         if(memcmp("RSDT", t->sig, 4) == 0){
132                 for(p = t->data; p+3 < e; p += 4)
133                         maptable(get32(p));
134                 return;
135         }
136         if(memcmp("XSDT", t->sig, 4) == 0){
137                 for(p = t->data; p+7 < e; p += 8)
138                         maptable(get64(p));
139                 return;
140         }
141         if(memcmp("FACP", t->sig, 4) == 0){
142                 if(l < 44)
143                         return;
144                 maptable(get32(p + 40));
145                 if(l < 148)
146                         return;
147                 maptable(get64(p + 140));
148                 return;
149         }
150 }
151
152 static void
153 maptables(void)
154 {
155         if(rsd == nil || ntblmap > 0 || ntblpa > 0)
156                 return;
157         if(!checksum(rsd, 20))
158                 maptable(get32(rsd->raddr));
159         if(rsd->rev >= 2)
160                 if(!checksum(rsd, 36))
161                         maptable(get64(rsd->xaddr));
162 }
163
164 static Apic*
165 findapic(int gsi, int *pintin)
166 {
167         Apic *a;
168         int i;
169
170         for(i=0; i<=MaxAPICNO; i++){
171                 if((a = mpioapic[i]) == nil)
172                         continue;
173                 if((a->flags & PcmpEN) == 0)
174                         continue;
175                 if(gsi >= a->gsibase && gsi <= a->gsibase+a->mre){
176                         if(pintin)
177                                 *pintin = gsi - a->gsibase;
178                         return a;
179                 }
180         }
181         print("findapic: no ioapic found for gsi %d\n", gsi);
182         return nil;
183 }
184
185 static void
186 addirq(int gsi, int type, int busno, int irq, int flags)
187 {
188         Apic *a;
189         Bus *bus;
190         Aintr *ai;
191         PCMPintr *pi;
192         int intin;
193
194         if((a = findapic(gsi, &intin)) == nil)
195                 return;
196
197         for(bus = mpbus; bus; bus = bus->next)
198                 if(bus->type == type && bus->busno == busno)
199                         goto Foundbus;
200
201         if((bus = xalloc(sizeof(Bus))) == nil)
202                 panic("addirq: no memory for Bus");
203         bus->busno = busno;
204         bus->type = type;
205         if(type == BusISA){
206                 bus->po = PcmpHIGH;
207                 bus->el = PcmpEDGE;
208                 if(mpisabus == -1)
209                         mpisabus = busno;
210         } else {
211                 bus->po = PcmpLOW;
212                 bus->el = PcmpLEVEL;
213         }
214         if(mpbus)
215                 mpbuslast->next = bus;
216         else
217                 mpbus = bus;
218         mpbuslast = bus;
219
220 Foundbus:
221         for(ai = bus->aintr; ai; ai = ai->next)
222                 if(ai->intr->irq == irq)
223                         return;
224
225         if((pi = xalloc(sizeof(PCMPintr))) == nil)
226                 panic("addirq: no memory for PCMPintr");
227         pi->type = PcmpIOINTR;
228         pi->intr = PcmpINT;
229         pi->flags = flags & (PcmpPOMASK|PcmpELMASK);
230         pi->busno = busno;
231         pi->irq = irq;
232         pi->apicno = a->apicno;
233         pi->intin = intin;
234
235         if((ai = xalloc(sizeof(Aintr))) == nil)
236                 panic("addirq: no memory for Aintr");
237         ai->intr = pi;
238         ai->apic = a;
239         ai->next = bus->aintr;
240         bus->aintr = ai;
241 }
242
243 static char*
244 eisaid(void *v)
245 {
246         static char id[8];
247         ulong b, l;
248         int i;
249
250         if(amltag(v) == 's')
251                 return v;
252         b = amlint(v);
253         for(l = 0, i=24; i>=0; i -= 8, b >>= 8)
254                 l |= (b & 0xFF) << i;
255         id[7] = 0;
256         for(i=6; i>=3; i--, l >>= 4)
257                 id[i] = "0123456789ABCDEF"[l & 0xF];
258         for(i=2; i>=0; i--, l >>= 5)
259                 id[i] = '@' + (l & 0x1F);
260         return id;
261 }
262
263 static int
264 pcibusno(void *dot)
265 {
266         int bno, adr, tbdf;
267         Pcidev *pdev;
268         void *p, *x;
269         char *id;
270
271         id = nil;
272         if(x = amlwalk(dot, "^_HID")){
273                 p = nil;
274                 if(amleval(x, "", &p) == 0)
275                         id = eisaid(p);
276         }
277         if((x = amlwalk(dot, "^_BBN")) == nil)
278                 if((x = amlwalk(dot, "^_ADR")) == nil)
279                         return -1;
280         p = nil;
281         if(amleval(x, "", &p) < 0)
282                 return -1;
283         adr = amlint(p);
284         /* if root bridge, then we are done here */
285         if(id && (strcmp(id, "PNP0A03")==0 || strcmp(id, "PNP0A08")==0))
286                 return adr;
287         x = amlwalk(dot, "^");
288         if(x == nil || x == dot)
289                 return -1;
290         if((bno = pcibusno(x)) < 0)
291                 return -1;
292         tbdf = MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
293         pdev = pcimatchtbdf(tbdf);
294         if(pdev == nil || pdev->bridge == nil)
295                 return -1;
296         return BUSBNO(pdev->bridge->tbdf);
297 }
298
299 static int
300 enumprt(void *dot, void *)
301 {
302         void *p, **a, **b;
303         int bno, dno, pin;
304         int n, i;
305
306         bno = pcibusno(dot);
307         if(bno < 0)
308                 return 1;
309
310         /* evalulate _PRT method */
311         p = nil;
312         if(amleval(dot, "", &p) < 0)
313                 return 1;
314         if(amltag(p) != 'p')
315                 return 1;
316
317         n = amllen(p);
318         a = amlval(p);
319         for(i=0; i<n; i++){
320                 if(amltag(a[i]) != 'p')
321                         continue;
322                 if(amllen(a[i]) != 4)
323                         continue;
324                 b = amlval(a[i]);
325                 dno = amlint(b[0])>>16;
326                 pin = amlint(b[1]);
327                 if(amltag(b[2]) == 'N' || amlint(b[2])){
328                         print("enumprt: interrupt link not handled %V\n", b[2]);
329                         continue;
330                 }
331                 addirq(amlint(b[3]), BusPCI, bno, (dno<<2)|pin, 0);
332         }
333         return 1;
334 }
335
336 static void
337 acpiinit(void)
338 {
339         Tbl *t;
340         Apic *a;
341         void *va;
342         uchar *p, *e;
343         ulong lapicbase;
344         int machno, i, c;
345
346         maptables();
347
348         amlinit();
349
350         /* load DSDT */
351         for(i=0; i<ntblmap; i++){
352                 t = tblmap[i];
353                 if(memcmp(t->sig, "DSDT", 4) == 0){
354                         amlload(t->data, tbldlen(t));
355                         break;
356                 }
357         }
358
359         /* load SSDT, there can be multiple tables */
360         for(i=0; i<ntblmap; i++){
361                 t = tblmap[i];
362                 if(memcmp(t->sig, "SSDT", 4) == 0)
363                         amlload(t->data, tbldlen(t));
364         }
365
366         /* set APIC mode */
367         amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
368
369         for(i=0; i<ntblmap; i++){
370                 t = tblmap[i];
371                 if(memcmp(t->sig, "APIC", 4) == 0)
372                         goto Foundapic;
373         }
374         panic("acpiinit: no MADT (APIC) table");
375         return;
376
377 Foundapic:
378         p = t->data;
379         e = p + tbldlen(t);
380         lapicbase = get32(p); p += 8;
381         va = vmap(lapicbase, 1024);
382         print("LAPIC: %.8lux %.8lux\n", lapicbase, (ulong)va);
383         if(va == nil)
384                 panic("acpiinit: cannot map lapic %.8lux", lapicbase);
385
386         machno = 0;
387         for(; p < e; p += c){
388                 c = p[1];
389                 if(c < 2 || (p+c) > e)
390                         break;
391                 switch(*p){
392                 case 0x00:      /* Processor Local APIC */
393                         if(p[3] > MaxAPICNO)
394                                 break;
395                         if((a = xalloc(sizeof(Apic))) == nil)
396                                 panic("acpiinit: no memory for Apic");
397                         a->type = PcmpPROCESSOR;
398                         a->apicno = p[3];
399                         a->paddr = lapicbase;
400                         a->addr = va;
401                         a->lintr[0] = ApicIMASK;
402                         a->lintr[1] = ApicIMASK;
403                         a->flags = p[4] & PcmpEN;
404                         if(a->flags & PcmpEN){
405                                 a->machno = machno++;
406
407                                 /*
408                                  * platform firmware should list the boot processor
409                                  * as the first processor entry in the MADT
410                                  */
411                                 if(a->machno == 0)
412                                         a->flags |= PcmpBP;
413                         }
414                         mpapic[a->apicno] = a;
415                         break;
416                 case 0x01:      /* I/O APIC */
417                         if(p[2] > MaxAPICNO)
418                                 break;
419                         if((a = xalloc(sizeof(Apic))) == nil)
420                                 panic("acpiinit: no memory for io Apic");
421                         a->type = PcmpIOAPIC;
422                         a->apicno = p[2];
423                         a->paddr = get32(p+4);
424                         if((a->addr = vmap(a->paddr, 1024)) == nil)
425                                 panic("acpiinit: cannot map ioapic %.8lux", a->paddr);
426                         a->gsibase = get32(p+8);
427                         a->flags = PcmpEN;
428                         mpioapic[a->apicno] = a;
429                         ioapicinit(a, a->apicno);
430                         break;
431                 case 0x02:      /* Interrupt Source Override */
432                         addirq(get32(p+4), BusISA, 0, p[3], get16(p+8));
433                         break;
434                 case 0x03:      /* NMI Source */
435                 case 0x04:      /* Local APIC NMI */
436                 case 0x05:      /* Local APIC Address Override */
437                 case 0x06:      /* I/O SAPIC */
438                 case 0x07:      /* Local SAPIC */
439                 case 0x08:      /* Platform Interrupt Sources */
440                 case 0x09:      /* Processor Local x2APIC */
441                 case 0x0A:      /* x2APIC NMI */
442                 case 0x0B:      /* GIC */
443                 case 0x0C:      /* GICD */
444                         break;
445                 }
446         }
447
448         /* look for PCI interrupt mappings */
449         amlenum(amlroot, "_PRT", enumprt, nil);
450
451         /* add identity mapped legacy isa interrupts */
452         for(i=0; i<16; i++)
453                 addirq(i, BusISA, 0, i, 0);
454
455         /* free the AML interpreter */
456         amlexit();
457
458         /*
459          * Ininitalize local APIC and start application processors.
460          */
461         mpinit();
462 }
463
464 static int identify(void);
465
466 PCArch archacpi = {
467 .id=            "ACPI", 
468 .ident=         identify,
469 .reset=         mpshutdown,
470 .intrinit=      acpiinit,
471 .intrenable=    mpintrenable,
472 .intron=        lapicintron,
473 .introff=       lapicintroff,
474 .fastclock=     i8253read,
475 .timerset=      lapictimerset,
476 };
477
478 static long
479 readtbls(Chan*, void *v, long n, vlong o)
480 {
481         int i, l, m;
482         uchar *p;
483         Tbl *t;
484
485         maptables();
486
487         p = v;
488         for(i=0; n > 0 && i < ntblmap; i++){
489                 t = tblmap[i];
490                 l = get32(t->len);
491                 if(o >= l){
492                         o -= l;
493                         continue;
494                 }
495                 m = l - o;
496                 if(m > n)
497                         m = n;
498                 memmove(p, (uchar*)t + o, m);
499                 p += m;
500                 n -= m;
501                 o = 0;
502         }
503         return p - (uchar*)v;
504 }
505
506 static int
507 identify(void)
508 {
509         char *cp;
510
511         if((cp = getconf("*acpi")) == nil)
512                 return 1;
513         if((rsd = sigsearch("RSD PTR ")) == nil)
514                 return 1;
515         if(checksum(rsd, 20) && checksum(rsd, 36))
516                 return 1;
517         addarchfile("acpitbls", 0444, readtbls, nil);
518         if(strcmp(cp, "0") == 0)
519                 return 1;
520         if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
521                 return 1;
522         if(m->havetsc)
523                 archacpi.fastclock = tscticks;
524         return 0;
525 }