static int ntblmap;
static Tbl *tblmap[64];
-void*
-amlalloc(int n){
- void *p;
-
- if((p = malloc(n)) == nil)
- panic("amlalloc: no memory");
- memset(p, 0, n);
- return p;
-}
-
-void
-amlfree(void *p){
- free(p);
-}
-
static ushort
get16(uchar *p){
return p[1]<<8 | p[0];
char *id;
id = nil;
- if(x = amlwalk(dot, "^_HID")){
- p = nil;
- if(amleval(x, "", &p) == 0)
+ if((x = amlwalk(dot, "^_HID")) != nil)
+ if((p = amlval(x)) != nil)
id = eisaid(p);
- }
if((x = amlwalk(dot, "^_BBN")) == nil)
if((x = amlwalk(dot, "^_ADR")) == nil)
return -1;
- p = nil;
- if(amleval(x, "", &p) < 0)
+ if((p = amlval(x)) == nil)
return -1;
adr = amlint(p);
/* if root bridge, then we are done here */
- if(id && (strcmp(id, "PNP0A03")==0 || strcmp(id, "PNP0A08")==0))
+ if(id != nil && (strcmp(id, "PNP0A03")==0 || strcmp(id, "PNP0A08")==0))
return adr;
x = amlwalk(dot, "^");
if(x == nil || x == dot)
return -1;
tbdf = MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
pdev = pcimatchtbdf(tbdf);
- if(pdev == nil || pdev->bridge == nil)
+ if(pdev == nil)
return -1;
+ if(pdev->bridge == nil)
+ return bno;
return BUSBNO(pdev->bridge->tbdf);
}
+static int
+pciaddr(void *dot)
+{
+ int adr, bno;
+ void *x;
+
+ for(;;){
+ if((x = amlwalk(dot, "_ADR")) == nil){
+ x = amlwalk(dot, "^");
+ if(x == nil || x == dot)
+ break;
+ dot = x;
+ continue;
+ }
+ if((bno = pcibusno(x)) < 0)
+ break;
+ if((x = amlval(x)) == nil)
+ break;
+ adr = amlint(x);
+ return MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
+ }
+ return -1;
+}
+
+static int
+getirqs(void *d, uchar pmask[32], int *pflags)
+{
+ int i, n, m;
+ uchar *p;
+
+ *pflags = 0;
+ memset(pmask, 0, 32);
+ if(amltag(d) != 'b')
+ return -1;
+ p = amlval(d);
+ if(amllen(d) >= 2 && (p[0] == 0x22 || p[0] == 0x23)){
+ pmask[0] = p[1];
+ pmask[1] = p[2];
+ if(amllen(d) >= 3 && p[0] == 0x23)
+ *pflags = ((p[3] & (1<<0)) ? PcmpEDGE : PcmpLEVEL)
+ | ((p[3] & (1<<3)) ? PcmpLOW : PcmpHIGH);
+ return 0;
+ }
+ if(amllen(d) >= 5 && p[0] == 0x89){
+ n = p[4];
+ if(amllen(d) < 5+n*4)
+ return -1;
+ for(i=0; i<n; i++){
+ m = get32(p+5 + i*4);
+ if(m >= 0 && m < 256)
+ pmask[m/8] |= 1<<(m%8);
+ }
+ *pflags = ((p[3] & (1<<1)) ? PcmpEDGE : PcmpLEVEL)
+ | ((p[3] & (1<<2)) ? PcmpLOW : PcmpHIGH);
+ return 0;
+ }
+ return -1;
+}
+
+static uchar*
+setirq(void *d, uint irq)
+{
+ uchar *p;
+
+ if(amltag(d) != 'b')
+ return nil;
+ p = amlnew('b', amllen(d));
+ memmove(p, d, amllen(p));
+ if(p[0] == 0x22 || p[0] == 0x23){
+ irq = 1<<irq;
+ p[1] = irq;
+ p[2] = irq>>8;
+ }
+ if(p[0] == 0x89){
+ p[4] = 1;
+ p[5] = irq;
+ p[6] = irq>>8;
+ p[7] = irq>>16;
+ p[8] = irq>>24;
+ }
+ return p;
+}
+
+static int
+setuplink(void *link, int *pflags)
+{
+ uchar im, pm[32], cm[32], *c;
+ static int lastirq = 1;
+ int gsi, i;
+ void *r;
+
+ if(amltag(link) != 'N')
+ return -1;
+
+ r = nil;
+ if(amleval(amlwalk(link, "_PRS"), "", &r) < 0)
+ return -1;
+ if(getirqs(r, pm, pflags) < 0)
+ return -1;
+
+ r = nil;
+ if(amleval(amlwalk(link, "_CRS"), "", &r) < 0)
+ return -1;
+ if(getirqs(r, cm, pflags) < 0)
+ return -1;
+
+ gsi = -1;
+ for(i=0; i<256; i++){
+ im = 1<<(i%8);
+ if(pm[i/8] & im){
+ if(cm[i/8] & im)
+ gsi = i;
+ }
+ }
+
+ if(gsi > 0 || getconf("*nopcirouting") != nil)
+ return gsi;
+
+ for(i=0; i<256; i++){
+ gsi = lastirq++ & 0xFF; /* round robin */
+ im = 1<<(gsi%8);
+ if(pm[gsi/8] & im){
+ if((c = setirq(r, gsi)) == nil)
+ break;
+ if(amleval(amlwalk(link, "_SRS"), "b", c, nil) < 0)
+ break;
+ return gsi;
+ }
+ }
+ return -1;
+}
+
static int
enumprt(void *dot, void *)
{
void *p, **a, **b;
- int bno, dno, pin;
+ int bno, dno, pin, gsi, flags;
int n, i;
bno = pcibusno(dot);
if(amltag(p) != 'p')
return 1;
+ amltake(p);
n = amllen(p);
a = amlval(p);
for(i=0; i<n; i++){
continue;
if(amllen(a[i]) != 4)
continue;
+ flags = 0;
b = amlval(a[i]);
dno = amlint(b[0])>>16;
pin = amlint(b[1]);
- if(amltag(b[2]) == 'N' || amlint(b[2])){
- print("enumprt: interrupt link not handled %V\n", b[2]);
- continue;
+ gsi = amlint(b[3]);
+ if(gsi==0){
+ gsi = setuplink(b[2], &flags);
+ if(gsi <= 0)
+ continue;
}
- addirq(amlint(b[3]), BusPCI, bno, (dno<<2)|pin, 0);
+ addirq(gsi, BusPCI, bno, (dno<<2)|pin, flags);
}
+ amldrop(p);
+
return 1;
}
Tbl *t;
Apic *a;
void *va;
- uchar *p, *e;
+ uchar *s, *p, *e;
ulong lapicbase;
int machno, i, c;
return;
Foundapic:
- p = t->data;
- e = p + tbldlen(t);
- lapicbase = get32(p); p += 8;
+ s = t->data;
+ e = s + tbldlen(t);
+ lapicbase = get32(s); s += 8;
va = vmap(lapicbase, 1024);
- print("LAPIC: %.8lux %.8lux\n", lapicbase, (ulong)va);
+ print("LAPIC: %.8lux %#p\n", lapicbase, va);
if(va == nil)
panic("acpiinit: cannot map lapic %.8lux", lapicbase);
machno = 0;
- for(; p < e; p += c){
+ for(p = s; p < e; p += c){
c = p[1];
if(c < 2 || (p+c) > e)
break;
a->lintr[0] = ApicIMASK;
a->lintr[1] = ApicIMASK;
a->flags = p[4] & PcmpEN;
- if(a->flags & PcmpEN){
- a->machno = machno++;
-
- /*
- * platform firmware should list the boot processor
- * as the first processor entry in the MADT
- */
- if(a->machno == 0)
- a->flags |= PcmpBP;
+
+ /* skip disabled processors */
+ if((a->flags & PcmpEN) == 0 || mpapic[a->apicno] != nil){
+ xfree(a);
+ break;
}
+ a->machno = machno++;
+
+ /*
+ * platform firmware should list the boot processor
+ * as the first processor entry in the MADT
+ */
+ if(a->machno == 0)
+ a->flags |= PcmpBP;
+
mpapic[a->apicno] = a;
break;
case 0x01: /* I/O APIC */
mpioapic[a->apicno] = a;
ioapicinit(a, a->apicno);
break;
+ }
+ }
+
+ /*
+ * need 2nd pass as vbox puts interrupt overrides
+ * *before* the ioapic entries (!)
+ */
+ for(p = s; p < e; p += c){
+ c = p[1];
+ if(c < 2 || (p+c) > e)
+ break;
+ switch(*p){
case 0x02: /* Interrupt Source Override */
addirq(get32(p+4), BusISA, 0, p[3], get16(p+8));
break;
static int
identify(void)
{
+ uintptr pa;
char *cp;
if((cp = getconf("*acpi")) == nil)
return 1;
- if((rsd = sigsearch("RSD PTR ")) == nil)
+ pa = (uintptr)strtoull(cp, nil, 16);
+ if(pa <= 1)
+ rsd = sigsearch("RSD PTR ");
+ else
+ rsd = vmap(pa, sizeof(Rsd));
+ if(rsd == nil)
return 1;
if(checksum(rsd, 20) && checksum(rsd, 36))
return 1;
return 1;
if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
return 1;
- if(m->havetsc)
+ if(m->havetsc && getconf("*notsc") == nil)
archacpi.fastclock = tscticks;
return 0;
}
+
+static int
+readpcicfg(Amlio *io, void *data, int n, int offset)
+{
+ ulong r, x;
+ Pcidev *p;
+ uchar *a;
+ int i;
+
+ a = data;
+ p = io->aux;
+ if(p == nil)
+ return -1;
+ offset += io->off;
+ if(offset > 256)
+ return 0;
+ if(n+offset > 256)
+ n = 256-offset;
+ r = offset;
+ if(!(r & 3) && n == 4){
+ x = pcicfgr32(p, r);
+ PBIT32(a, x);
+ return 4;
+ }
+ if(!(r & 1) && n == 2){
+ x = pcicfgr16(p, r);
+ PBIT16(a, x);
+ return 2;
+ }
+ for(i = 0; i < n; i++){
+ x = pcicfgr8(p, r);
+ PBIT8(a, x);
+ a++;
+ r++;
+ }
+ return i;
+}
+
+static int
+writepcicfg(Amlio *io, void *data, int n, int offset)
+{
+ ulong r, x;
+ Pcidev *p;
+ uchar *a;
+ int i;
+
+ a = data;
+ p = io->aux;
+ if(p == nil)
+ return -1;
+ offset += io->off;
+ if(offset > 256)
+ return 0;
+ if(n+offset > 256)
+ n = 256-offset;
+ r = offset;
+ if(!(r & 3) && n == 4){
+ x = GBIT32(a);
+ pcicfgw32(p, r, x);
+ return 4;
+ }
+ if(!(r & 1) && n == 2){
+ x = GBIT16(a);
+ pcicfgw16(p, r, x);
+ return 2;
+ }
+ for(i = 0; i < n; i++){
+ x = GBIT8(a);
+ pcicfgw8(p, r, x);
+ a++;
+ r++;
+ }
+ return i;
+}
+
+static int
+readioport(Amlio *io, void *data, int len, int port)
+{
+ uchar *a;
+
+ a = data;
+ port += io->off;
+ switch(len){
+ case 4:
+ PBIT32(a, inl(port));
+ return 4;
+ case 2:
+ PBIT16(a, ins(port));
+ return 2;
+ case 1:
+ PBIT8(a, inb(port));
+ return 1;
+ }
+ return -1;
+}
+
+static int
+writeioport(Amlio *io, void *data, int len, int port)
+{
+ uchar *a;
+
+ a = data;
+ port += io->off;
+ switch(len){
+ case 4:
+ outl(port, GBIT32(a));
+ return 4;
+ case 2:
+ outs(port, GBIT16(a));
+ return 2;
+ case 1:
+ outb(port, GBIT8(a));
+ return 1;
+ }
+ return -1;
+}
+
+int
+amlmapio(Amlio *io)
+{
+ int tbdf;
+ Pcidev *pdev;
+ char buf[64];
+
+ switch(io->space){
+ default:
+ print("amlmapio: address space %x not implemented\n", io->space);
+ break;
+ case MemSpace:
+ if((io->va = vmap(io->off, io->len)) == nil){
+ print("amlmapio: vmap failed\n");
+ break;
+ }
+ return 0;
+ case IoSpace:
+ snprint(buf, sizeof(buf), "%N", io->name);
+ if(ioalloc(io->off, io->len, 0, buf) < 0){
+ print("amlmapio: ioalloc failed\n");
+ break;
+ }
+ io->read = readioport;
+ io->write = writeioport;
+ return 0;
+ case PcicfgSpace:
+ if((tbdf = pciaddr(io->name)) < 0){
+ print("amlmapio: no address\n");
+ break;
+ }
+ if((pdev = pcimatchtbdf(tbdf)) == nil){
+ print("amlmapio: no device %T\n", tbdf);
+ break;
+ }
+ io->aux = pdev;
+ io->read = readpcicfg;
+ io->write = writepcicfg;
+ return 0;
+ }
+ print("amlmapio: mapping %N failed\n", io->name);
+ return -1;
+}
+
+void
+amlunmapio(Amlio *io)
+{
+ switch(io->space){
+ case MemSpace:
+ vunmap(io->va, io->len);
+ break;
+ case IoSpace:
+ iofree(io->off);
+ break;
+ }
+}
+
+void*
+amlalloc(int n){
+ void *p;
+
+ if((p = malloc(n)) == nil)
+ panic("amlalloc: no memory");
+ memset(p, 0, n);
+ return p;
+}
+
+void
+amlfree(void *p){
+ free(p);
+}
+
+void
+amldelay(int us)
+{
+ microdelay(us);
+}
+
+/*
+ * reset machine by writing acpi reset register.
+ */
+void
+acpireset(void)
+{
+ uchar *p;
+ Tbl *t;
+ int i;
+
+ for(i=0; i < ntblmap; i++){
+ t = tblmap[i];
+ if(memcmp(t->sig, "FACP", 4) != 0)
+ continue;
+ if(get32(t->len) <= 128)
+ break;
+ p = (uchar*)t;
+ if((get32(p + 112) & (1<<10)) == 0)
+ break;
+ if(p[116+0] != IoSpace)
+ break;
+ outb(get32(p+116+4), p[128]);
+ break;
+ }
+}