diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-06 16:50:43 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-06 16:50:43 +0200 |
commit | 616eb1f9ba8e74bbdc2601257743ad832197cfb2 (patch) | |
tree | 7e561d49f20345144b03756395b15b789ffe2a96 /sys/src | |
parent | 9add5b765f713b78b77736214b17da9d90645a01 (diff) |
archacpi: experimental handling of interrupt link devices, io access
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/9/pc/archacpi.c | 365 |
1 files changed, 338 insertions, 27 deletions
diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c index 9a27f79c7..9abd290b6 100644 --- a/sys/src/9/pc/archacpi.c +++ b/sys/src/9/pc/archacpi.c @@ -51,21 +51,6 @@ static uintptr tblpa[64]; 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]; @@ -269,20 +254,17 @@ pcibusno(void *dot) 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) @@ -297,10 +279,145 @@ pcibusno(void *dot) } 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; + int gsi, gsi2, i, n; + 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 = gsi2 = -1; + print("setuplink: %N: EL=%s%s PO=%s%s INTIN=[ ", link, + (*pflags & PcmpELMASK) == PcmpEDGE ? "EDGE" : "", + (*pflags & PcmpELMASK) == PcmpLEVEL ? "LEVEL" : "", + (*pflags & PcmpPOMASK) == PcmpHIGH ? "HIGH" : "", + (*pflags & PcmpPOMASK) == PcmpLOW ? "LOW" : ""); + for(i=0; i<256; i++){ + im = 1<<(i%8); + if(pm[i/8] & im){ + if(cm[i/8] & im){ + gsi = i; + print("*"); + } + print("%d ", i); + gsi2 = i; + } + } + print("]\n"); + + if(getconf("*nopcirouting") == nil) + if(gsi <= 0 && gsi2 > 0 && (c = setirq(r, gsi2)) != nil){ + if(amleval(amlwalk(link, "_SRS"), "b", c, nil) == 0){ + gsi = gsi2; + print("setuplink: %N -> %d\n", link, gsi); + } + } + + return gsi; +} + +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); @@ -314,6 +431,7 @@ enumprt(void *dot, void *) if(amltag(p) != 'p') return 1; + amltake(p); n = amllen(p); a = amlval(p); for(i=0; i<n; i++){ @@ -321,15 +439,20 @@ enumprt(void *dot, void *) 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; } @@ -528,3 +651,191 @@ identify(void) 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); +} |