big acpi cleanup. - move all the table parsing, and boot-time aml running to acpi.c - move all the run-time action to devacpi.c - enable basic power button interception. - add #P/acpifadt - remove adjunct structures like the srat tracking structures, and remove unused acpi fixed table parsing. we don't need these at runtime, and they tend to shadow structures that already exist. so the memory color information now goes directly in the adr map, and the processor color information goes directly in the lapic. (the mach is likely not available early in boot, and the color does logically belong to the lapic, anyway.) about 1000 lines of code were removed. additional related work to do - write a user-space table decoder, and remove the #P/fadt - capture fan information - turn power button into events. - make the adr map portable. (very little to do here, except remove the assumptions about the pc memory map.) - more esoteric tables for highly numa machines. i don't have any, so this is still tbd. Reference: /n/atom/patch/applied2013/nixacpipwr Date: Tue Oct 8 22:18:57 CES 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/k10/main.c Tue Oct 8 22:09:07 2013 +++ /sys/src/nix/k10/main.c Tue Oct 8 22:09:08 2013 @@ -170,12 +170,9 @@ mallocinit(); archpciinit(); - /* - * Acpiinit will cause the first malloc. If the system dies here it's probably due - * to malloc not being initialized correctly, or the data segment is misaligned - * (it's amazing how far you can get with things like that completely broken). - */ - devacpiinit(); + if(getconf("*maxmach") != nil) + maxmach = atoi(getconf("*maxmach")); + mpsinit(maxmach); /* acpi */ umeminit(); trapinit(); @@ -189,9 +186,9 @@ i8259init(32); procinit0(); - if(getconf("*maxmach") != nil) - maxmach = atoi(getconf("*maxmach")); - mpsinit(maxmach); +// if(getconf("*maxmach") != nil) +// maxmach = atoi(getconf("*maxmach")); +// mpsinit(maxmach); lapiconline(); ioapiconline(); sipi(); --- /sys/src/nix/k10/acpi.c Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/acpi.c Tue Oct 8 22:09:08 2013 @@ -7,10 +7,10 @@ #include "adr.h" #include "apic.h" +#include "acpi.h" #include typedef struct Rsd Rsd; -typedef struct Tbl Tbl; struct Rsd { uchar sig[8]; @@ -24,19 +24,6 @@ uchar reserved[3]; }; -struct Tbl { - uchar sig[4]; - uchar len[4]; - uchar rev; - uchar csum; - uchar oemid[6]; - uchar oemtid[8]; - uchar oemrev[4]; - uchar cid[4]; - uchar crev[4]; - uchar data[]; -}; - enum { Tblsz = 4+4+1+1+6+8+4+4+4, Rdsz = 8+1+6+1+4+4+8+1+3, @@ -47,6 +34,7 @@ static uintmem tblpa[64]; static int ntblmap; /* successfully mapped tables */ static Tbl *tblmap[64]; + Fadt fadt; static int checksum(void *v, int n) @@ -60,8 +48,8 @@ return s; } -#define get16(p) getle((p), 2) -#define get32(p) getle((p), 4) +#define get16(p) ((u32int)getle((p), 2)) +#define get32(p) ((u32int)getle((p), 4)) #define get64(p) getle((p), 8) static uint @@ -70,8 +58,8 @@ return get32(t->len) - Tblsz; } -static Tbl* -findtable(void *sig) +Tbl* +acpigettbl(void *sig) { int i; for(i=0; isig, 4) == 0){ for(p = t->data; p+3 < e; p += 4) - maptable(get32(p)); - return; + acpimaptbl(get32(p)); } - if(memcmp("XSDT", t->sig, 4) == 0){ + else if(memcmp("XSDT", t->sig, 4) == 0){ for(p = t->data; p+7 < e; p += 8) - maptable(get64(p)); - return; + acpimaptbl(get64(p)); } - if(memcmp("FACP", t->sig, 4) == 0){ + else if(memcmp("FACP", t->sig, 4) == 0){ if(l < 44) return; - maptable(get32(p + 40)); + acpimaptbl(get32(p + 40)); if(l < 148) return; - maptable(get64(p + 140)); - return; + acpimaptbl(get64(p + 140)); } } @@ -181,7 +166,7 @@ } static void -loadrsd(void) +rsdload(void) { if((rsd = rsdsearch("RSD PTR ")) == nil) panic("acpi: no rsd ptr"); @@ -194,11 +179,11 @@ { if(ntblmap > 0 || ntblpa > 0) return; - loadrsd(); + rsdload(); if(rsd->rev >= 2 && !checksum(rsd, 36)) - maptable(get64(rsd->xaddr)); + acpimaptbl(get64(rsd->xaddr)); else if(!checksum(rsd, 20)) - maptable(get32(rsd->raddr)); + acpimaptbl(get32(rsd->raddr)); } enum { @@ -597,25 +582,22 @@ Lapicen = 1, }; -#define acpiinit(x) mpsinit(x) /* temporary hack */ -void -acpiinit(int maxmach) +typedef struct Parsedat Parsedat; +struct Parsedat { + int maxmach; /* for the apic structure */ +}; + +static void +parseapic(Tbl *t, Parsedat *dat) { uchar *p, *e; - int i, c, nmach; + int i, c, nmach, maxmach; uintmem lapicbase; - Tbl *t; - print("acpiinit\n"); - maptables(); - amlinit(); - loadtbls("DSDT", 0); - loadtbls("SSDT", 1); + maxmach = dat->maxmach; /* set APIC mode */ amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil); - if((t = findtable("APIC")) == nil) - panic("acpiinit: no APIC table"); p = t->data; e = p + tbldlen(t); @@ -666,10 +648,346 @@ /* add identity mapped legacy isa interrupts */ for(i=0; i<16; i++) addirq(i, BusISA, 0, i, 0); + DBG("acpiinit: %d maches\n", nmach); +} + +static void +parsesrat(Tbl *t, Parsedat*) +{ + uchar *p, *e; + + e = t->data + tbldlen(t); + for(p = t->data + 12; p < e; p += p[1]){ + switch(p[0]){ + case 0: /* apic */ + if(get32(p+4)&1) + lapicsetcolor(p[3], p[2] | p[9]<<24| p[10]<<16 | p[11]<<8); + break; + case 1: + if(get32(p+28)&1) + adrsetcolor(get64(p+8), get64(p+16), get32(p+2)); + break; + case 2: /* x2apic */ + if(get32(p+12)&1) + lapicsetcolor(get32(p+8), get32(p+4)); + break; + default: + print("acpi: SRAT type %.2ux unknown\n", p[0]); + break; + } + } +} + +static char* regnames[] = { + "mem", "io", "pcicfg", "embed", + "smb", "cmos", "pcibar", +}; + +static int +Gfmt(Fmt* f) +{ + Gas *g; + + g = va_arg(f->args, Gas*); + switch(g->spc){ + case MemSpace: + case IoSpace: + case EbctlSpace: + case SmbusSpace: + case CmosSpace: + case PcibarSpace: + case IpmiSpace: + fmtprint(f, "[%s", regnames[g->spc]); + break; + case PcicfgSpace: + fmtprint(f, "[pci %T", (int)g->addr); + break; + case FixedhwSpace: + fmtprint(f, "[hw"); + break; + default: + fmtprint(f, "[%#ux", g->spc); + break; + } + fmtprint(f, " %#llux", g->addr); + if(g->off != 0) + fmtprint(f, "+%d", g->off); + fmtprint(f, " len %d", g->len); + if(g->accsz != 0) + fmtprint(f, " accsz %d", g->accsz); + return fmtprint(f, "]"); +} + +static void +gasget(Gas *gas, uchar *p) +{ + gas->spc = p[0]; + gas->len = p[1]; + gas->off = p[2]; + gas->accsz = p[3]; + gas->addr = get64(p+4); +} + +static int +loadfacs(uintmem pa) +{ + USED(pa); + return 0; +} + +static long +readfadt(Chan*, void *a, long n, vlong o) +{ + char *s, *p, *e; + Fadt *f; + + s = smalloc(READSTR); + if(waserror()){ + free(s); + nexterror(); + } + p = s; + e = s+READSTR; + f = &fadt; + + p = seprint(p, e, "facs %#ux\n", f->facs); + p = seprint(p, e, "dsdt %#ux\n", f->dsdt); + p = seprint(p, e, "pmprofile %#ux\n", f->pmprofile); + p = seprint(p, e, "sciint %d\n", f->sciint); + p = seprint(p, e, "smicmd %#ux\n", f->smicmd); + p = seprint(p, e, "acpienable %#ux\n", f->acpienable); + p = seprint(p, e, "acpidisable %#ux\n", f->acpidisable); + p = seprint(p, e, "s4biosreq %#ux\n", f->s4biosreq); + p = seprint(p, e, "pstatecnt %#ux\n", f->pstatecnt); + p = seprint(p, e, "pm1aevtblk %#ux\n", f->pm1aevtblk); + p = seprint(p, e, "pm1bevtblk %#ux\n", f->pm1bevtblk); + p = seprint(p, e, "pm1acntblk %#ux\n", f->pm1acntblk); + p = seprint(p, e, "pm1bcntblk %#ux\n", f->pm1bcntblk); + p = seprint(p, e, "pm2cntblk %#ux\n", f->pm2cntblk); + p = seprint(p, e, "pmtmrblk %#ux\n", f->pmtmrblk); + p = seprint(p, e, "gpe0blk %#ux\n", f->gpe0blk); + p = seprint(p, e, "gpe1blk %#ux\n", f->gpe1blk); + p = seprint(p, e, "pm1evtlen %#ux\n", f->pm1evtlen); + p = seprint(p, e, "pm1cntlen %#ux\n", f->pm1cntlen); + p = seprint(p, e, "pm2cntlen %#ux\n", f->pm2cntlen); + p = seprint(p, e, "pmtmrlen %#ux\n", f->pmtmrlen); + p = seprint(p, e, "gpe0blklen %#ux\n", f->gpe0blklen); + p = seprint(p, e, "gpe1blklen %#ux\n", f->gpe1blklen); + p = seprint(p, e, "gp1base %#ux\n", f->gp1base); + p = seprint(p, e, "cstcnt %#ux\n", f->cstcnt); + p = seprint(p, e, "plvl2lat %#ux\n", f->plvl2lat); + p = seprint(p, e, "plvl3lat %#ux\n", f->plvl3lat); + p = seprint(p, e, "flushsz %#ux\n", f->flushsz); + p = seprint(p, e, "flushstride %#ux\n", f->flushstride); + p = seprint(p, e, "dutyoff %#ux\n", f->dutyoff); + p = seprint(p, e, "dutywidth %#ux\n", f->dutywidth); + p = seprint(p, e, "dayalrm %#ux\n", f->dayalrm); + p = seprint(p, e, "monalrm %#ux\n", f->monalrm); + p = seprint(p, e, "century %#ux\n", f->century); + p = seprint(p, e, "iapcbootarch %#ux\n", f->iapcbootarch); + p = seprint(p, e, "flags %#ux\n", f->flags); + p = seprint(p, e, "resetreg %G\n", &f->resetreg); + if(f->rev >= 3){ + p = seprint(p, e, "resetval %#ux\n", f->resetval); + p = seprint(p, e, "xfacs %#llux\n", f->xfacs); + p = seprint(p, e, "xdsdt %#llux\n", f->xdsdt); + p = seprint(p, e, "xpm1aevtblk %G\n", &f->xpm1aevtblk); + p = seprint(p, e, "xpm1bevtblk %G\n", &f->xpm1bevtblk); + p = seprint(p, e, "xpm1acntblk %G\n", &f->xpm1acntblk); + p = seprint(p, e, "xpm1bcntblk %G\n", &f->xpm1bcntblk); + p = seprint(p, e, "xpm2cntblk %G\n", &f->xpm2cntblk); + p = seprint(p, e, "xpmtmrblk %G\n", &f->xpmtmrblk); + p = seprint(p, e, "xgpe0blk %G\n", &f->xgpe0blk); + p = seprint(p, e, "xgpe1blk %G\n", &f->xgpe1blk); + } + USED(p); + + n = readstr(o, a, n, s); + poperror(); + free(s); + return n; +} + +static void +parsefadt(Tbl *t, Parsedat*) +{ + uchar *p; + Fadt *f; + + p = (uchar*)t; + f = &fadt; + f->rev = t->rev; + f->facs = get32(p + 36); + f->dsdt = get32(p + 40); + f->pmprofile = p[45]; + f->sciint = get16(p+46); + f->smicmd = get32(p+48); + f->acpienable = p[52]; + f->acpidisable = p[53]; + f->s4biosreq = p[54]; + f->pstatecnt = p[55]; + f->pm1aevtblk = get32(p+56); + f->pm1bevtblk = get32(p+60); + f->pm1acntblk = get32(p+64); + f->pm1bcntblk = get32(p+68); + f->pm2cntblk = get32(p+72); + f->pmtmrblk = get32(p+76); + f->gpe0blk = get32(p+80); + f->gpe1blk = get32(p+84); + f->pm1evtlen = p[88]; + f->pm1cntlen = p[89]; + f->pm2cntlen = p[90]; + f->pmtmrlen = p[91]; + f->gpe0blklen = p[92]; + f->gpe1blklen = p[93]; + f->gp1base = p[94]; + f->cstcnt = p[95]; + f->plvl2lat = get16(p+96); + f->plvl3lat = get16(p+98); + f->flushsz = get16(p+100); + f->flushstride = get16(p+102); + f->dutyoff = p[104]; + f->dutywidth = p[105]; + f->dayalrm = p[106]; + f->monalrm = p[107]; + f->century = p[108]; + f->iapcbootarch = get16(p+109); + f->flags = get32(p+112); + gasget(&f->resetreg, p+116); + + if(f->rev >= 3){ + f->resetval = p[128]; + f->xfacs = get64(p+132); + f->xdsdt = get64(p+140); + gasget(&f->xpm1aevtblk, p+148); + gasget(&f->xpm1bevtblk, p+160); + gasget(&f->xpm1acntblk, p+172); + gasget(&f->xpm1bcntblk, p+184); + gasget(&f->xpm2cntblk, p+196); + gasget(&f->xpmtmrblk, p+208); + gasget(&f->xgpe0blk, p+220); + gasget(&f->xgpe1blk, p+232); + } + +// dumpfadt(f); + if(f->xfacs != 0) + loadfacs(f->xfacs); + else + loadfacs(f->facs); +} + +typedef struct Hpet Hpet; +struct Hpet { + uchar id[4]; + uchar addr[12]; /* gas */ + uchar seqno; + uchar minticks[2]; + uchar attr; /* Page Protection */ +}; + +static void +parsehpet(Tbl *t, Parsedat*) +{ + int minticks; + Hpet *h; + Gas g; + extern void hpetinit(int, uintmem, int); + + h = (Hpet*)t->data; + gasget(&g, h->addr); + minticks = get16(h->minticks); + + DBG("acpi: hpet id %#ux addr %d %d %d %d %#p seqno %d ticks %d attr %#ux\n", + get32(h->id), g.spc, g.len, g.off, g.accsz, + g.addr, h->seqno, minticks, h->attr); +// hpetinit(h->seqno, g.addr, minticks); + USED(minticks); +} + +enum { + Blegacy = 1<<0, + B8042kbd = 1<<1, + Bnovga = 1<<2, + Bnomsi = 1<<3, + Bnocmos = 1<<4, +}; + +static void +iapcbootarch(void) +{ + int i; + + i = fadt.iapcbootarch; + + sys->nolegacyprobe = !(i&Blegacy); + sys->noi8042kbd = !(i&B8042kbd); + sys->novga = i&Bnovga; + sys->nomsi = i&Bnomsi; + sys->nocmos = i&Bnocmos; +} + +typedef struct Ptab Ptab; +struct Ptab { + char *sig; + void (*parse)(Tbl*, Parsedat*); + int required; +}; + +static Ptab ptab[] = { + "APIC", parseapic, 1, + "SRAT", parsesrat, 0, + "FACP", parsefadt, 0, + "HPET", parsehpet, 0, +}; + +static void +parsetables(Parsedat *dat) +{ + int i; + Tbl *t; + Ptab *p; + + print("parse tables: "); + for(i = 0; i < nelem(ptab); i++){ + p = ptab + i; + if((t = acpigettbl(p->sig)) != nil){ + p->parse(t, dat); + print("%s ", p->sig); + }else if(p->required) + panic("acpi: parsetables: no %s table\n", p->sig); + } + print("\n"); +} + +#define acpiinit(x) mpsinit(x) /* temporary hack */ +void +acpiinit(int maxmach) +{ + int i; + Parsedat dat; + + print("acpiinit\n"); + fmtinstall('G', Gfmt); + maptables(); + amlinit(); + loadtbls("DSDT", 0); + loadtbls("SSDT", 1); + + memset(&dat, 0, sizeof dat); + dat.maxmach = maxmach; + parsetables(&dat); + if(fadt.smicmd != 0) + iapcbootarch(); /* free the AML interpreter */ amlexit(); - print("acpiinit: %d maches\n", nmach); + addarchfile("acpifadt", 0444, readfadt, nil); /* hack */ addarchfile("acpitbls", 0444, readtbls, nil); + if(1||DBGFLG){ + print("loaded tables: "); + for(i = 0; i < ntblmap; i++) + print("%.4s ", (char*)tblmap[i]->sig); + print("\n"); + } } --- /sys/src/nix/k10/acpi.h Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/acpi.h Tue Oct 8 22:09:08 2013 @@ -1,346 +1,50 @@ -typedef struct Atable Atable; -typedef struct Facs Facs; -typedef struct Fadt Fadt; -typedef struct Gas Gas; -typedef struct Gpe Gpe; -typedef struct Rsdp Rsdp; -typedef struct Sdthdr Sdthdr; -typedef struct Parse Parse; -typedef struct Xsdt Xsdt; -typedef struct Regio Regio; -typedef struct Reg Reg; -typedef struct Madt Madt; -typedef struct Msct Msct; -typedef struct Mdom Mdom; -typedef struct Apicst Apicst; -typedef struct Srat Srat; - -enum -{ - - Sdthdrsz = 36, /* size of SDT header */ - - /* ACPI regions. Gas ids */ - Rsysmem = 0, - Rsysio, - Rpcicfg, - Rembed, - Rsmbus, - Rcmos, - Rpcibar, - Ripmi, - Rfixedhw = 0x7f, - - /* ACPI PM1 control */ - Pm1SciEn = 0x1, /* Generate SCI and not SMI */ - - /* ACPI tbdf as encoded in acpi region base addresses */ - Rpciregshift = 0, - Rpciregmask = 0xFFFF, - Rpcifunshift = 16, - Rpcifunmask = 0xFFFF, - Rpcidevshift = 32, - Rpcidevmask = 0xFFFF, - Rpcibusshift = 48, - Rpcibusmask = 0xFFFF, - - /* Apic structure types */ - ASlapic = 0, /* processor local apic */ - ASioapic, /* I/O apic */ - ASintovr, /* Interrupt source override */ - ASnmi, /* NMI source */ - ASlnmi, /* local apic nmi */ - ASladdr, /* local apic address override */ - ASiosapic, /* I/O sapic */ - ASlsapic, /* local sapic */ - ASintsrc, /* platform interrupt sources */ - ASlx2apic, /* local x2 apic */ - ASlx2nmi, /* local x2 apic NMI */ - - /* Apic flags */ - AFbus = 0, /* polarity/trigger like in ISA */ - AFhigh = 1, /* active high */ - AFlow = 3, /* active low */ - AFpmask = 3, /* polarity bits */ - AFedge = 1<<2, /* edge triggered */ - AFlevel = 3<<2, /* level triggered */ - AFtmask = 3<<2, /* trigger bits */ - - /* SRAT types */ - SRlapic = 0, /* Local apic/sapic affinity */ - SRmem, /* Memory affinity */ - SRlx2apic, /* x2 apic affinity */ - - /* Arg for _PIC */ - Ppic = 0, /* PIC interrupt model */ - Papic, /* APIC interrupt model */ - Psapic, /* SAPIC interrupt model */ - - - CMregion = 0, /* regio name spc base len accsz*/ - CMgpe, /* gpe name id */ - - Qdir = 0, - Qctl, - Qtbl, - Qio, -}; +typedef struct Fadt Fadt; +typedef struct Gas Gas; +typedef struct Tbl Tbl; /* - * ACPI table (sw) + * Header for ACPI description tables */ -struct Atable -{ - Atable* next; /* next table in list */ - int is64; /* uses 64bits */ - char sig[5]; /* signature */ - char oemid[7]; /* oem id str. */ - char oemtblid[9]; /* oem tbl. id str. */ - uchar* tbl; /* pointer to table in memory */ - long dlen; /* size of data in table, after Stdhdr */ +struct Tbl { + uchar sig[4]; /* e.g. "FACP" */ + uchar len[4]; + uchar rev; + uchar csum; + uchar oemid[6]; + uchar oemtblid[8]; + uchar oemrev[4]; + uchar creatorid[4]; + uchar creatorrev[4]; + uchar data[]; }; -struct Gpe -{ - uintptr stsio; /* port used for status */ - int stsbit; /* bit number */ - uintptr enio; /* port used for enable */ - int enbit; /* bit number */ - int nb; /* event number */ - char* obj; /* handler object */ - int id; /* id as supplied by user */ -}; - -struct Parse -{ - char* sig; - Atable* (*f)(uchar*, int); /* return nil to keep vmap */ -}; - -struct Regio{ - void *arg; - u8int (*get8)(uintptr, void*); - void (*set8)(uintptr, u8int, void*); - u16int (*get16)(uintptr, void*); - void (*set16)(uintptr, u16int, void*); - u32int (*get32)(uintptr, void*); - void (*set32)(uintptr, u32int, void*); - u64int (*get64)(uintptr, void*); - void (*set64)(uintptr, u64int, void*); -}; - -struct Reg -{ - char* name; - int spc; /* io space */ - u64int base; /* address, physical */ - uchar* p; /* address, kmapped */ - u64int len; - int tbdf; - int accsz; /* access size */ -}; - -/* Generic address structure. +/* + * Generic address structure. */ -#pragma pack on struct Gas { - u8int spc; /* address space id */ - u8int len; /* register size in bits */ - u8int off; /* bit offset */ - u8int accsz; /* 1: byte; 2: word; 3: dword; 4: qword */ + uchar spc; /* address space id */ + uchar len; /* register size in bits */ + uchar off; /* bit offset */ + uchar accsz; /* 1: byte; 2: word; 3: dword; 4: qword */ u64int addr; /* address (or acpi encoded tbdf + reg) */ }; -/* Root system description table pointer. - * Used to locate the root system description table RSDT - * (or the extended system description table from version 2) XSDT. - * The XDST contains (after the DST header) a list of pointers to tables: - * - FADT fixed acpi description table. - * It points to the DSDT, AML code making the acpi namespace. - * - SSDTs tables with AML code to add to the acpi namespace. - * - pointers to other tables for apics, etc. - */ - -struct Rsdp -{ - u8int signature[8]; /* "RSD PTR " */ - u8int rchecksum; - u8int oemid[6]; - u8int revision; - u8int raddr[4]; /* RSDT */ - u8int length[4]; - u8int xaddr[8]; /* XSDT */ - u8int xchecksum; /* XSDT */ - u8int _33_[3]; /* reserved */ -}; - -/* Header for ACPI description tables - */ -struct Sdthdr -{ - u8int sig[4]; /* "FACP" or whatever */ - u8int length[4]; - u8int rev; - u8int csum; - u8int oemid[6]; - u8int oemtblid[8]; - u8int oemrev[4]; - u8int creatorid[4]; - u8int creatorrev[4]; -}; - -/* Firmware control structure - */ -struct Facs -{ - u32int hwsig; - u32int wakingv; - u32int glock; - u32int flags; - u64int xwakingv; - u8int vers; - u32int ospmflags; -}; - -#pragma pack off - -/* Maximum System Characteristics table - */ -struct Msct -{ - int ndoms; /* number of domains */ - int nclkdoms; /* number of clock domains */ - u64int maxpa; /* max physical address */ - - Mdom* dom; /* domain information list */ -}; - -struct Mdom -{ - Mdom* next; - int start; /* start dom id */ - int end; /* end dom id */ - int maxproc; /* max processor capacity */ - u64int maxmem; /* max memory capacity */ -}; - -/* Multiple APIC description table - * Interrupts are virtualized by ACPI and each APIC has - * a `virtual interrupt base' where its interrupts start. - * Addresses are processor-relative physical addresses. - * Only enabled devices are linked, others are filtered out. - */ -struct Madt -{ - uintmem lapicpa; /* local APIC addr */ - int pcat; /* the machine has PC/AT 8259s */ - Apicst* st; /* list of Apic related structures */ -}; - -struct Apicst -{ - int type; - Apicst* next; - union{ - struct{ - int pid; /* processor id */ - int id; /* apic no */ - } lapic; - struct{ - int id; /* io apic id */ - int ibase; /* interrupt base addr. */ - uintmem addr; /* base address */ - } ioapic, iosapic; - struct{ - int irq; /* bus intr. source (ISA only) */ - int intr; /* system interrupt */ - int flags; /* apic flags */ - } intovr; - struct{ - int intr; /* system interrupt */ - int flags; /* apic flags */ - } nmi; - struct{ - int pid; /* processor id */ - int flags; /* lapic flags */ - int lint; /* lapic LINTn for nmi */ - } lnmi; - struct{ - int pid; /* processor id */ - int id; /* apic id */ - int eid; /* apic eid */ - int puid; /* processor uid */ - char* puids; /* same thing */ - } lsapic; - struct{ - int pid; /* processor id */ - int peid; /* processor eid */ - int iosv; /* io sapic vector */ - int intr; /* global sys intr. */ - int type; /* intr type */ - int flags; /* apic flags */ - int any; /* err sts at any proc */ - } intsrc; - struct{ - int id; /* x2 apic id */ - int puid; /* processor uid */ - } lx2apic; - struct{ - int puid; - int flags; - int intr; - } lx2nmi; - }; -}; - -/* System resource affinity table +/* + * Fixed ACPI description table. */ -struct Srat -{ - int type; - Srat* next; - union{ - struct{ - int dom; /* proximity domain */ - int apic; /* apic id */ - int sapic; /* sapic id */ - int clkdom; /* clock domain */ - } lapic; - struct{ - int dom; /* proximity domain */ - u64int addr; /* base address */ - u64int len; - int hplug; /* hot pluggable */ - int nvram; /* non volatile */ - } mem; - struct{ - int dom; /* proximity domain */ - int apic; /* x2 apic id */ - int clkdom; /* clock domain */ - } lx2apic; - }; -}; +struct Fadt { + int rev; -/* Fixed ACPI description table. - * Describes implementation and hardware registers. - * PM* blocks are low level functions. - * GPE* blocks refer to general purpose events. - * P_* blocks are for processor features. - * Has address for the DSDT. - */ -struct Fadt -{ u32int facs; u32int dsdt; - /* 1 reserved */ - u8int pmprofile; + uchar pmprofile; u16int sciint; u32int smicmd; - u8int acpienable; - u8int acpidisable; - u8int s4biosreq; - u8int pstatecnt; + uchar acpienable; + uchar acpidisable; + uchar s4biosreq; + uchar pstatecnt; u32int pm1aevtblk; u32int pm1bevtblk; u32int pm1acntblk; @@ -349,29 +53,27 @@ u32int pmtmrblk; u32int gpe0blk; u32int gpe1blk; - u8int pm1evtlen; - u8int pm1cntlen; - u8int pm2cntlen; - u8int pmtmrlen; - u8int gpe0blklen; - u8int gpe1blklen; - u8int gp1base; - u8int cstcnt; + uchar pm1evtlen; + uchar pm1cntlen; + uchar pm2cntlen; + uchar pmtmrlen; + uchar gpe0blklen; + uchar gpe1blklen; + uchar gp1base; + uchar cstcnt; u16int plvl2lat; u16int plvl3lat; u16int flushsz; u16int flushstride; - u8int dutyoff; - u8int dutywidth; - u8int dayalrm; - u8int monalrm; - u8int century; + uchar dutyoff; + uchar dutywidth; + uchar dayalrm; + uchar monalrm; + uchar century; u16int iapcbootarch; - /* 1 reserved */ u32int flags; Gas resetreg; - u8int resetval; - /* 3 reserved */ + uchar resetval; u64int xfacs; u64int xdsdt; Gas xpm1aevtblk; @@ -383,14 +85,8 @@ Gas xgpe0blk; Gas xgpe1blk; }; +#pragma varargck type "G" Gas* -/* XSDT/RSDT. 4/8 byte addresses starting at p. - */ -struct Xsdt -{ - int len; - int asize; - u8int* p; -}; +Tbl* acpigettbl(void*); -extern uintmem acpimblocksize(uintmem, int*); +extern Fadt fadt; --- /sys/src/nix/k10/devacpi.c Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/devacpi.c Tue Oct 8 22:09:08 2013 @@ -1,1270 +1,69 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" -#include "mp.h" -#include "acpi.h" - /* - * ACPI 4.0 Support. - * Still WIP. - * - * This driver locates tables and parses only the FADT - * and the XSDT. All other tables are mapped and kept there - * for the user-level interpreter. + * ACPI 5.0 support. overly ornate. + * - split table parsing out from file server */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "acpi.h" +#include -#define l16get(p) (((p)[1]<<8)|(p)[0]) -#define l32get(p) (((u32int)l16get(p+2)<<16)|l16get(p)) -static Atable* acpifadt(uchar*, int); -static Atable* acpitable(uchar*, int); -static Atable* acpimadt(uchar*, int); -static Atable* acpimsct(uchar*, int); -static Atable* acpisrat(uchar*, int); -static Atable* acpimcfg(uchar*, int); -static Atable* acpihpet(uchar*, int); - -#pragma varargck type "G" Gas* +typedef struct Aconf Aconf; -static Cmdtab ctls[] = -{ - {CMregion, "region", 6}, - {CMgpe, "gpe", 3}, +struct Aconf { + Lock; + int init; + void (*powerbutton)(void); }; -static Dirtab acpidir[]={ - ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, - "acpictl", {Qctl}, 0, 0666, - "acpitbl", {Qtbl}, 0, 0444, - "acpiregio", {Qio}, 0, 0666, -}; +/* internal */ +typedef struct Gpe Gpe; -/* - * The DSDT is always given to the user interpreter. - * Tables listed here are also loaded from the XSDT: - * MSCT, MADT, and FADT are processed by us, because they are - * required to do early initialization before we have user processes. - * Other tables are given to the user level interpreter for - * execution. - */ -static Parse ptables[] = -{ - "FACP", acpifadt, - "APIC", acpimadt, - "SRAT", acpisrat, - "MSCT", acpimsct, - "SSDT", acpitable, - "MCFG", acpimcfg, - "HPET", acpihpet, +enum { + /* ACPI PM1 control */ + Pm1SciEn = 0x1, /* Generate SCI and not SMI */ }; -static Facs* facs; /* Firmware ACPI control structure */ -static Fadt fadt; /* Fixed ACPI description. To reach ACPI registers */ -static Xsdt* xsdt; /* XSDT table */ -static Atable* tfirst; /* loaded DSDT/SSDT/... tables */ -static Atable* tlast; /* pointer to last table */ - Madt* apics; /* APIC info */ -static Srat* srat; /* System resource affinity, used by physalloc */ -static Msct* msct; /* Maximum system characteristics table */ -static Reg* reg; /* region used for I/O */ -static Gpe* gpes; /* General purpose events */ -static int ngpes; - -static char* regnames[] = { - "mem", "io", "pcicfg", "embed", - "smb", "cmos", "pcibar", +struct Gpe { + uintptr stsio; /* port used for status */ + int stsbit; /* bit number */ + uintptr enio; /* port used for enable */ + int enbit; /* bit number */ + int nb; /* event number */ + char* obj; /* handler object */ + int id; /* id as supplied by user */ }; -static char* -acpiregstr(int id) -{ - static char buf[20]; /* BUG */ - - if(id >= 0 && id < nelem(regnames)) - return regnames[id]; - seprint(buf, buf+sizeof(buf), "spc:%#x", id); - return buf; -} - -static int -acpiregid(char *s) -{ - int i; - - for(i = 0; i < nelem(regnames); i++) - if(strcmp(regnames[i], s) == 0) - return i; - return -1; -} - -static u64int -l64get(u8int* p) -{ - /* - * Doing this as a define - * #define l64get(p) (((u64int)l32get(p+4)<<32)|l32get(p)) - * causes 8c to abort with "out of fixed registers" in - * rsdlink() below. - */ - return (((u64int)l32get(p+4)<<32)|l32get(p)); -} - -static u8int -mget8(uintptr p, void*) -{ - u8int *cp = (u8int*)p; - return *cp; -} - -static void -mset8(uintptr p, u8int v, void*) -{ - u8int *cp = (u8int*)p; - *cp = v; -} - -static u16int -mget16(uintptr p, void*) -{ - u16int *cp = (u16int*)p; - return *cp; -} - -static void -mset16(uintptr p, u16int v, void*) -{ - u16int *cp = (u16int*)p; - *cp = v; -} - -static u32int -mget32(uintptr p, void*) -{ - u32int *cp = (u32int*)p; - return *cp; -} - -static void -mset32(uintptr p, u32int v, void*) -{ - u32int *cp = (u32int*)p; - *cp = v; -} - -static u64int -mget64(uintptr p, void*) -{ - u64int *cp = (u64int*)p; - return *cp; -} - -static void -mset64(uintptr p, u64int v, void*) -{ - u64int *cp = (u64int*)p; - *cp = v; -} - -static u8int -ioget8(uintptr p, void*) -{ - return inb(p); -} - -static void -ioset8(uintptr p, u8int v, void*) -{ - outb(p, v); -} - -static u16int -ioget16(uintptr p, void*) -{ - return ins(p); -} - -static void -ioset16(uintptr p, u16int v, void*) -{ - outs(p, v); -} - -static u32int -ioget32(uintptr p, void*) -{ - return inl(p); -} - -static void -ioset32(uintptr p, u32int v, void*) -{ - outl(p, v); -} - -static u8int -cfgget8(uintptr p, void* r) -{ - Reg *ro = r; - Pcidev d; - - d.tbdf = ro->tbdf; - return pcicfgr8(&d, p); -} - -static void -cfgset8(uintptr p, u8int v, void* r) -{ - Reg *ro = r; - Pcidev d; - - d.tbdf = ro->tbdf; - pcicfgw8(&d, p, v); -} - -static u16int -cfgget16(uintptr p, void* r) -{ - Reg *ro = r; - Pcidev d; - - d.tbdf = ro->tbdf; - return pcicfgr16(&d, p); -} - -static void -cfgset16(uintptr p, u16int v, void* r) -{ - Reg *ro = r; - Pcidev d; - - d.tbdf = ro->tbdf; - pcicfgw16(&d, p, v); -} - -static u32int -cfgget32(uintptr p, void* r) -{ - Reg *ro = r; - Pcidev d; - - d.tbdf = ro->tbdf; - return pcicfgr32(&d, p); -} - -static void -cfgset32(uintptr p, u32int v, void* r) -{ - Reg *ro = r; - Pcidev d; - - d.tbdf = ro->tbdf; - pcicfgw32(&d, p, v); -} - -static Regio memio = -{ - nil, - mget8, mset8, mget16, mset16, - mget32, mset32, mget64, mset64 +enum { + CMgpe, /* gpe name id */ + CMpowerbut, + CMpower, + + Qdir = 0, + Qctl, + Qtbl, }; -static Regio ioio = -{ - nil, - ioget8, ioset8, ioget16, ioset16, - ioget32, ioset32, nil, nil +static Cmdtab ctls[] = { + {CMgpe, "gpe", 3}, + {CMpowerbut, "powerbutton", 2}, + {CMpower, "power", 2}, }; -static Regio cfgio = -{ - nil, - cfgget8, cfgset8, cfgget16, cfgset16, - cfgget32, cfgset32, nil, nil +static Dirtab acpidir[]={ + ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, + "acpictl", {Qctl}, 0, 0666, + "acpitbl", {Qtbl}, 0, 0444, }; -/* - * Copy memory, 1/2/4/8-bytes at a time, to/from a region. - */ -static long -regcpy(Regio *dio, uintptr da, Regio *sio, uintptr sa, long len, int align) -{ - int n, i; - - DBG("regcpy %#ullx %#ullx %#ulx %#ux\n", da, sa, len, align); - if((len%align) != 0) - print("regcpy: bug: copy not aligned. truncated\n"); - n = len/align; - for(i = 0; i < n; i++){ - switch(align){ - case 1: - DBG("cpy8 %#p %#p\n", da, sa); - dio->set8(da, sio->get8(sa, sio->arg), dio->arg); - break; - case 2: - DBG("cpy16 %#p %#p\n", da, sa); - dio->set16(da, sio->get16(sa, sio->arg), dio->arg); - break; - case 4: - DBG("cpy32 %#p %#p\n", da, sa); - dio->set32(da, sio->get32(sa, sio->arg), dio->arg); - break; - case 8: - DBG("cpy64 %#p %#p\n", da, sa); - // dio->set64(da, sio->get64(sa, sio->arg), dio->arg); - break; - default: - panic("regcpy: align bug"); - } - da += align; - sa += align; - } - return n*align; -} - -/* - * Perform I/O within region in access units of accsz bytes. - * All units in bytes. - */ -static long -regio(Reg *r, void *p, usize len, uintptr off, int iswr) -{ - Regio rio; - uintptr rp; - - DBG("reg%s %s %#p %#ullx %#lx sz=%d\n", - iswr ? "out" : "in", r->name, p, off, len, r->accsz); - rp = 0; - if(off + len > r->len){ - print("regio: access outside limits"); - len = r->len - off; - } - if(len <= 0){ - print("regio: zero len\n"); - return 0; - } - switch(r->spc){ - case Rsysmem: -print("RSYMMEM %p %ld\n", r->base, len); - if(r->p == nil) - r->p = vmap(r->base, len); - if(r->p == nil) - error("regio: vmap failed"); - rp = (uintptr)r->p + off; - rio = memio; - break; - case Rsysio: - rp = r->base + off; - rio = ioio; - break; - case Rpcicfg: - rp = r->base + off; - rio = cfgio; - rio.arg = r; - break; - case Rpcibar: - case Rembed: - case Rsmbus: - case Rcmos: - case Ripmi: - case Rfixedhw: - print("regio: reg %s not supported\n", acpiregstr(r->spc)); - error("region not supported"); - } - if(iswr) - regcpy(&rio, rp, &memio, (uintptr)p, len, r->accsz); - else - regcpy(&memio, (uintptr)p, &rio, rp, len, r->accsz); - return len; -} - -static Atable* -newtable(uchar *p) -{ - Atable *t; - Sdthdr *h; - - t = malloc(sizeof(Atable)); - if(t == nil) - panic("no memory for more aml tables"); - t->tbl = p; - h = (Sdthdr*)t->tbl; - t->is64 = h->rev >= 2; - t->dlen = l32get(h->length) - Sdthdrsz; - memmove(t->sig, h->sig, sizeof(h->sig)); - t->sig[sizeof(t->sig)-1] = 0; - memmove(t->oemid, h->oemid, sizeof(h->oemid)); - t->oemtblid[sizeof(t->oemtblid)-1] = 0; - memmove(t->oemtblid, h->oemtblid, sizeof(h->oemtblid)); - t->oemtblid[sizeof(t->oemtblid)-1] = 0; - t->next = nil; - if(tfirst == nil) - tfirst = tlast = t; - else{ - tlast->next = t; - tlast = t; - } - return t; -} - -static void* -sdtchecksum(void* addr, int len) -{ - u8int *p, sum; - - sum = 0; - for(p = addr; len-- > 0; p++) - sum += *p; - if(sum == 0) - return addr; - - return nil; -} - -static void -sdtunmap(void *va, usize sz) -{ - /* first cut */ - USED(va, sz); -} - -static void* -sdtmap(uintmem pa, int *n, int cksum) -{ - Sdthdr* sdt; - - sdt = vmapoverlap(pa, sizeof *sdt); - if(sdt == nil){ - DBG("acpi: vmapoverlap: nil\n"); - return nil; - } - *n = l32get(sdt->length); - -if(*n>200000){ - char tsig[5]; - memmove(tsig, sdt, 4); - tsig[4] = 0; - print("%s (too big %d)", tsig, *n); - return nil; -} - - sdtunmap(sdt, sizeof(Sdthdr)); - if((sdt = vmapoverlap(pa, *n)) == nil){ - DBG("acpi: vmapoverlap: nil\n"); - return nil; - } - if(cksum != 0 && sdtchecksum(sdt, *n) == nil){ - DBG("acpi: SDT: bad checksum\n"); - sdtunmap(sdt, sizeof(Sdthdr)); - return nil; - } - return sdt; -} - -static void -·sdtunmap(void *va, usize sz) -{ - vunmap(va, sz); -} - -static void * -·sdtmap(uintmem pa, int *n, int cksum) -{ - Sdthdr* sdt; - - sdt = vmap(pa, sizeof(Sdthdr)); -print("a SDTMAP %#P → %#p (%d)\n", pa, sdt, sizeof(Sdthdr)); - if(sdt == nil){ - DBG("acpi: vmap1: nil\n"); - return nil; - } - *n = l32get(sdt->length); - - ·sdtunmap(sdt, sizeof(Sdthdr)); - if((sdt = vmap(pa, *n)) == nil){ - DBG("acpi: nil vmap\n"); - return nil; - } -print("b SDTMAP %#P → %#p (%d)\n", pa, sdt, *n); - if(cksum != 0 && sdtchecksum(sdt, *n) == nil){ - DBG("acpi: SDT: bad checksum\n"); - ·sdtunmap(sdt, sizeof(Sdthdr)); - return nil; - } - return sdt; -} - -static int -loadfacs(uintmem pa) -{ - int n; - - facs = sdtmap(pa, &n, 0); - if(facs == nil) - return -1; - if(memcmp(facs, "FACS", 4) != 0){ - sdtunmap(facs, n); - facs = nil; - return -1; - } - /* no unmap */ - - DBG("acpi: facs: hwsig: %#ux\n", facs->hwsig); - DBG("acpi: facs: wakingv: %#ux\n", facs->wakingv); - DBG("acpi: facs: flags: %#ux\n", facs->flags); - DBG("acpi: facs: glock: %#ux\n", facs->glock); - DBG("acpi: facs: xwakingv: %#llux\n", facs->xwakingv); - DBG("acpi: facs: vers: %#ux\n", facs->vers); - DBG("acpi: facs: ospmflags: %#ux\n", facs->ospmflags); - return 0; -} - -static void -loaddsdt(uintmem pa) -{ - int n; - uchar *dsdtp; - - dsdtp = sdtmap(pa, &n, 1); - if(dsdtp == nil) - return; - if(acpitable(dsdtp, n) == nil) - sdtunmap(dsdtp, n); -} - -static void -gasget(Gas *gas, uchar *p) -{ - gas->spc = p[0]; - gas->len = p[1]; - gas->off = p[2]; - gas->accsz = p[3]; - gas->addr = l64get(p+4); -} - -static void -dumpfadt(Fadt *fp) -{ - if(DBGFLG == 0) - return; - - DBG("acpi: fadt: facs: %#ux\n", fp->facs); - DBG("acpi: fadt: dsdt: %#ux\n", fp->dsdt); - DBG("acpi: fadt: pmprofile: %#ux\n", fp->pmprofile); - DBG("acpi: fadt: sciint: %#ux\n", fp->sciint); - DBG("acpi: fadt: smicmd: %#ux\n", fp->smicmd); - DBG("acpi: fadt: acpienable: %#ux\n", fp->acpienable); - DBG("acpi: fadt: acpidisable: %#ux\n", fp->acpidisable); - DBG("acpi: fadt: s4biosreq: %#ux\n", fp->s4biosreq); - DBG("acpi: fadt: pstatecnt: %#ux\n", fp->pstatecnt); - DBG("acpi: fadt: pm1aevtblk: %#ux\n", fp->pm1aevtblk); - DBG("acpi: fadt: pm1bevtblk: %#ux\n", fp->pm1bevtblk); - DBG("acpi: fadt: pm1acntblk: %#ux\n", fp->pm1acntblk); - DBG("acpi: fadt: pm1bcntblk: %#ux\n", fp->pm1bcntblk); - DBG("acpi: fadt: pm2cntblk: %#ux\n", fp->pm2cntblk); - DBG("acpi: fadt: pmtmrblk: %#ux\n", fp->pmtmrblk); - DBG("acpi: fadt: gpe0blk: %#ux\n", fp->gpe0blk); - DBG("acpi: fadt: gpe1blk: %#ux\n", fp->gpe1blk); - DBG("acpi: fadt: pm1evtlen: %#ux\n", fp->pm1evtlen); - DBG("acpi: fadt: pm1cntlen: %#ux\n", fp->pm1cntlen); - DBG("acpi: fadt: pm2cntlen: %#ux\n", fp->pm2cntlen); - DBG("acpi: fadt: pmtmrlen: %#ux\n", fp->pmtmrlen); - DBG("acpi: fadt: gpe0blklen: %#ux\n", fp->gpe0blklen); - DBG("acpi: fadt: gpe1blklen: %#ux\n", fp->gpe1blklen); - DBG("acpi: fadt: gp1base: %#ux\n", fp->gp1base); - DBG("acpi: fadt: cstcnt: %#ux\n", fp->cstcnt); - DBG("acpi: fadt: plvl2lat: %#ux\n", fp->plvl2lat); - DBG("acpi: fadt: plvl3lat: %#ux\n", fp->plvl3lat); - DBG("acpi: fadt: flushsz: %#ux\n", fp->flushsz); - DBG("acpi: fadt: flushstride: %#ux\n", fp->flushstride); - DBG("acpi: fadt: dutyoff: %#ux\n", fp->dutyoff); - DBG("acpi: fadt: dutywidth: %#ux\n", fp->dutywidth); - DBG("acpi: fadt: dayalrm: %#ux\n", fp->dayalrm); - DBG("acpi: fadt: monalrm: %#ux\n", fp->monalrm); - DBG("acpi: fadt: century: %#ux\n", fp->century); - DBG("acpi: fadt: iapcbootarch: %#ux\n", fp->iapcbootarch); - DBG("acpi: fadt: flags: %#ux\n", fp->flags); - DBG("acpi: fadt: resetreg: %G\n", &fp->resetreg); - DBG("acpi: fadt: resetval: %#ux\n", fp->resetval); - DBG("acpi: fadt: xfacs: %#llux\n", fp->xfacs); - DBG("acpi: fadt: xdsdt: %#llux\n", fp->xdsdt); - DBG("acpi: fadt: xpm1aevtblk: %G\n", &fp->xpm1aevtblk); - DBG("acpi: fadt: xpm1bevtblk: %G\n", &fp->xpm1bevtblk); - DBG("acpi: fadt: xpm1acntblk: %G\n", &fp->xpm1acntblk); - DBG("acpi: fadt: xpm1bcntblk: %G\n", &fp->xpm1bcntblk); - DBG("acpi: fadt: xpm2cntblk: %G\n", &fp->xpm2cntblk); - DBG("acpi: fadt: xpmtmrblk: %G\n", &fp->xpmtmrblk); - DBG("acpi: fadt: xgpe0blk: %G\n", &fp->xgpe0blk); - DBG("acpi: fadt: xgpe1blk: %G\n", &fp->xgpe1blk); -} - -static Atable* -acpifadt(uchar *p, int) -{ - Fadt *fp; - - fp = &fadt; - fp->facs = l32get(p + 36); - fp->dsdt = l32get(p + 40); - fp->pmprofile = p[45]; - fp->sciint = l16get(p+46); - fp->smicmd = l32get(p+48); - fp->acpienable = p[52]; - fp->acpidisable = p[53]; - fp->s4biosreq = p[54]; - fp->pstatecnt = p[55]; - fp->pm1aevtblk = l32get(p+56); - fp->pm1bevtblk = l32get(p+60); - fp->pm1acntblk = l32get(p+64); - fp->pm1bcntblk = l32get(p+68); - fp->pm2cntblk = l32get(p+72); - fp->pmtmrblk = l32get(p+76); - fp->gpe0blk = l32get(p+80); - fp->gpe1blk = l32get(p+84); - fp->pm1evtlen = p[88]; - fp->pm1cntlen = p[89]; - fp->pm2cntlen = p[90]; - fp->pmtmrlen = p[91]; - fp->gpe0blklen = p[92]; - fp->gpe1blklen = p[93]; - fp->gp1base = p[94]; - fp->cstcnt = p[95]; - fp->plvl2lat = l16get(p+96); - fp->plvl3lat = l16get(p+98); - fp->flushsz = l16get(p+100); - fp->flushstride = l16get(p+102); - fp->dutyoff = p[104]; - fp->dutywidth = p[105]; - fp->dayalrm = p[106]; - fp->monalrm = p[107]; - fp->century = p[108]; - fp->iapcbootarch = l16get(p+109); - fp->flags = l32get(p+112); - gasget(&fp->resetreg, p+116); - fp->resetval = p[128]; - fp->xfacs = l64get(p+132); - fp->xdsdt = l64get(p+140); - gasget(&fp->xpm1aevtblk, p+148); - gasget(&fp->xpm1bevtblk, p+160); - gasget(&fp->xpm1acntblk, p+172); - gasget(&fp->xpm1bcntblk, p+184); - gasget(&fp->xpm2cntblk, p+196); - gasget(&fp->xpmtmrblk, p+208); - gasget(&fp->xgpe0blk, p+220); - gasget(&fp->xgpe1blk, p+232); - - dumpfadt(fp); - if(fp->xfacs != 0) - loadfacs(fp->xfacs); - else - loadfacs(fp->facs); - - if(fp->xdsdt == ((u64int)fp->dsdt)) /* acpica */ - loaddsdt(fp->xdsdt); - else - loaddsdt(fp->dsdt); - - return nil; /* can be unmapped once parsed */ -} - -static void -dumpmsct(Msct *msct) -{ - Mdom *st; - - DBG("acpi: msct: %d doms %d clkdoms %#ullx maxpa\n", - msct->ndoms, msct->nclkdoms, msct->maxpa); - for(st = msct->dom; st != nil; st = st->next) - DBG("\t[%d:%d] %d maxproc %#ullx maxmmem\n", - st->start, st->end, st->maxproc, st->maxmem); - DBG("\n"); -} - -/* - * XXX: should perhaps update our idea of available memory. - * Else we should remove this code. - */ -static Atable* -acpimsct(uchar *p, int len) -{ - uchar *pe; - Mdom **stl, *st; - int off; - - msct = mallocz(sizeof(Msct), 1); - msct->ndoms = l32get(p+40) + 1; - msct->nclkdoms = l32get(p+44) + 1; - msct->maxpa = l64get(p+48); - msct->dom = nil; - stl = &msct->dom; - pe = p + len; - off = l32get(p+36); - for(p += off; p < pe; p += 22){ - st = mallocz(sizeof(Mdom), 1); - st->next = nil; - st->start = l32get(p+2); - st->end = l32get(p+6); - st->maxproc = l32get(p+10); - st->maxmem = l64get(p+14); - *stl = st; - stl = &st->next; - } - - dumpmsct(msct); - return nil; /* can be unmapped once parsed */ -} - -static void -dumpsrat(Srat *st) -{ - DBG("acpi: srat:\n"); - for(; st != nil; st = st->next) - switch(st->type){ - case SRlapic: - DBG("\tlapic: dom %d apic %d sapic %d clk %d\n", - st->lapic.dom, st->lapic.apic, - st->lapic.sapic, st->lapic.clkdom); - break; - case SRmem: - DBG("\tmem: dom %d %#ullx %#ullx %c%c\n", - st->mem.dom, st->mem.addr, st->mem.len, - st->mem.hplug?'h':'-', - st->mem.nvram?'n':'-'); - break; - case SRlx2apic: - DBG("\tlx2apic: dom %d apic %d clk %d\n", - st->lx2apic.dom, st->lx2apic.apic, - st->lx2apic.clkdom); - break; - default: - DBG("\t\n"); - } - DBG("\n"); -} - -static Atable* -acpisrat(uchar *p, int len) -{ - Srat **stl, *st; - uchar *pe; - int stlen, flags; - - if(srat != nil){ - print("acpi: two SRATs?\n"); - return nil; - } - - stl = &srat; - pe = p + len; - for(p += 48; p < pe; p += stlen){ - st = mallocz(sizeof(Srat), 1); - st->type = p[0]; - st->next = nil; - stlen = p[1]; - switch(st->type){ - case SRlapic: - st->lapic.dom = p[2] | p[9]<<24| p[10]<<16 | p[11]<<8; - st->lapic.apic = p[3]; - st->lapic.sapic = p[8]; - st->lapic.clkdom = l32get(p+12); - if(l32get(p+4) == 0){ - free(st); - st = nil; - } - break; - case SRmem: - st->mem.dom = l32get(p+2); - st->mem.addr = l64get(p+8); - st->mem.len = l64get(p+16); - flags = l32get(p+28); - if((flags&1) == 0){ /* not enabled */ - free(st); - st = nil; - }else{ - st->mem.hplug = flags & 2; - st->mem.nvram = flags & 4; - } - break; - case SRlx2apic: - st->lx2apic.dom = l32get(p+4); - st->lx2apic.apic = l32get(p+8); - st->lx2apic.clkdom = l32get(p+16); - if(l32get(p+12) == 0){ - free(st); - st = nil; - } - break; - default: - print("unknown SRAT structure\n"); - free(st); - st = nil; - } - if(st != nil){ - *stl = st; - stl = &st->next; - } - } - - dumpsrat(srat); - return nil; /* can be unmapped once parsed */ -} - -typedef struct { /* Mcfg Descriptor */ - u8int addr[8]; /* base address */ - u8int segno[2]; /* segment group number */ - u8int sbno; /* start bus number */ - u8int ebno; /* end bus number */ - u8int res[4]; /* reserved */ -} Mcfgd; - -typedef struct { /* PCI Memory Mapped Config */ - u8int sdthdr[36]; /* "Mcfg" + length[4] + [28] */ - u8int res[8]; /* reserved */ - Mcfgd mcfgd[]; /* descriptors */ -} Mcfg; - -static Atable* -acpimcfg(uchar *v, int) -{ - int i, n; - Mcfg *mcfg; - Mcfgd *mcfgd; - - mcfg = (Mcfg*)v; - n = l32get(&mcfg->sdthdr[4]); - mcfgd = mcfg->mcfgd; - for(i = offsetof(Mcfg, mcfgd[0]); i < n; i += sizeof(Mcfgd)){ - DBG("acpi: addr %#.16llux segno %d sbno %d ebno %d\n", - l64get(mcfgd->addr), l16get(mcfgd->segno), - mcfgd->sbno, mcfgd->ebno); - mcfgd++; - } - return nil; -} - -typedef struct { /* HPET DT */ - u8int sdthdr[36]; /* "FACP" + length[4] + [28] */ - u8int id[4]; /* Event Timer Bock ID */ - Gas addr; /* ACPI Format Address */ - u8int seqno; /* Sequence Number */ - u8int minticks[2]; /* Minimum Clock Tick */ - u8int attr; /* Page Protection */ -} Hpet; - -static Atable* -acpihpet(uchar *v, int) -{ - uintmem addr; - int minticks; - Hpet *h; - Gas *g; - extern void hpetinit(int, uintmem, int); - - h = (Hpet*)v; - g = &h->addr; - addr = g->addr; //l64get(g->addr); - minticks = l16get(h->minticks); - - print("acpi: hpet id %#ux addr %d %d %d %d %#p seqno %d ticks %d attr %#ux\n", - l32get(h->id), g->spc, g->len, g->off, g->accsz, - addr, h->seqno, minticks, h->attr); - -// hpetinit(h->seqno, addr, minticks); - return nil; -} - -uintmem -acpimblocksize(uintmem addr, int *dom) -{ - Srat *s; - - for(s = srat; s != nil; s = s->next) - if(s->type == SRmem) - if(s->mem.addr <= addr && s->mem.addr + s->mem.len > addr){ - *dom = s->mem.dom; - return s->mem.len - (addr - s->mem.addr); - } - return 0; -} - -int -machcolor(Mach *mp) -{ - Srat *s; - - for(s = srat; s != nil; s = s->next) - if(s->type == SRlapic) - if(s->lapic.apic == mp->apicno) - return s->lapic.dom; - return -1; -} - -static void -dumpmadt(Madt *apics) -{ - Apicst *st; - - DBG("acpi: madt lapic paddr %P pcat %d:\n", apics->lapicpa, apics->pcat); - for(st = apics->st; st != nil; st = st->next) - switch(st->type){ - case ASlapic: - DBG("\tlapic pid %d id %d\n", st->lapic.pid, st->lapic.id); - break; - case ASioapic: - case ASiosapic: - DBG("\tioapic id %d addr %#llux ibase %d\n", - st->ioapic.id, st->ioapic.addr, st->ioapic.ibase); - break; - case ASintovr: - DBG("\tintovr irq %d intr %d flags %#ux\n", - st->intovr.irq, st->intovr.intr,st->intovr.flags); - break; - case ASnmi: - DBG("\tnmi intr %d flags %#ux\n", - st->nmi.intr, st->nmi.flags); - break; - case ASlnmi: - DBG("\tlnmi pid %d lint %d flags %#ux\n", - st->lnmi.pid, st->lnmi.lint, st->lnmi.flags); - break; - case ASlsapic: - DBG("\tlsapic pid %d id %d eid %d puid %d puids %s\n", - st->lsapic.pid, st->lsapic.id, - st->lsapic.eid, st->lsapic.puid, - st->lsapic.puids); - break; - case ASintsrc: - DBG("\tintr type %d pid %d peid %d iosv %d intr %d %#x\n", - st->type, st->intsrc.pid, - st->intsrc.peid, st->intsrc.iosv, - st->intsrc.intr, st->intsrc.flags); - break; - case ASlx2apic: - DBG("\tlx2apic puid %d id %d\n", st->lx2apic.puid, st->lx2apic.id); - break; - case ASlx2nmi: - DBG("\tlx2nmi puid %d intr %d flags %#ux\n", - st->lx2nmi.puid, st->lx2nmi.intr, st->lx2nmi.flags); - break; - default: - DBG("\t\n"); - } - DBG("\n"); -} - -static Atable* -acpimadt(uchar *p, int len) -{ - uchar *pe; - Apicst *st, *l, **stl; - int stlen, id; - - apics = mallocz(sizeof(Madt), 1); - apics->lapicpa = l32get(p+36); - apics->pcat = l32get(p+40); - apics->st = nil; - stl = &apics->st; - pe = p + len; - for(p += 44; p < pe; p += stlen){ - st = mallocz(sizeof(Apicst), 1); - st->type = p[0]; - st->next = nil; - stlen = p[1]; - switch(st->type){ - case ASlapic: - st->lapic.pid = p[2]; - st->lapic.id = p[3]; - if(l32get(p+4) == 0){ - free(st); - st = nil; - } - break; - case ASioapic: - st->ioapic.id = id = p[2]; - st->ioapic.addr = l32get(p+4); - st->ioapic.ibase = l32get(p+8); - /* iosapic overrides any ioapic entry for the same id */ - for(l = apics->st; l != nil; l = l->next) - if(l->type == ASiosapic && l->iosapic.id == id){ - st->ioapic = l->iosapic; - /* we leave it linked; could be removed */ - break; - } - break; - case ASintovr: - st->intovr.irq = p[3]; - st->intovr.intr = l32get(p+4); - st->intovr.flags = l16get(p+8); - break; - case ASnmi: - st->nmi.flags = l16get(p+2); - st->nmi.intr = l32get(p+4); - break; - case ASlnmi: - st->lnmi.pid = p[2]; - st->lnmi.flags = l16get(p+3); - st->lnmi.lint = p[5]; - break; - case ASladdr: - if(sizeof(uintmem) == 8) - apics->lapicpa = l64get(p+8); - break; - case ASiosapic: - id = st->iosapic.id = p[2]; - st->iosapic.ibase = l32get(p+4); - st->iosapic.addr = l64get(p+8); - /* iosapic overrides any ioapic entry for the same id */ - for(l = apics->st; l != nil; l = l->next) - if(l->type == ASioapic && l->ioapic.id == id){ - l->ioapic = st->iosapic; - free(st); - st = nil; - break; - } - break; - case ASlsapic: - st->lsapic.pid = p[2]; - st->lsapic.id = p[3]; - st->lsapic.eid = p[4]; - st->lsapic.puid = l32get(p+12); - if(l32get(p+8) == 0){ - free(st); - st = nil; - }else - kstrdup(&st->lsapic.puids, (char*)p+16); - break; - case ASintsrc: - st->intsrc.flags = l16get(p+2); - st->type = p[4]; - st->intsrc.pid = p[5]; - st->intsrc.peid = p[6]; - st->intsrc.iosv = p[7]; - st->intsrc.intr = l32get(p+8); - st->intsrc.any = l32get(p+12); - break; - case ASlx2apic: - st->lx2apic.id = l32get(p+4); - st->lx2apic.puid = l32get(p+12); - if(l32get(p+8) == 0){ - free(st); - st = nil; - } - break; - case ASlx2nmi: - st->lx2nmi.flags = l16get(p+2); - st->lx2nmi.puid = l32get(p+4); - st->lx2nmi.intr = p[8]; - break; - default: - print("unknown APIC structure\n"); - free(st); - st = nil; - } - if(st != nil){ - *stl = st; - stl = &st->next; - } - } - - dumpmadt(apics); - return nil; /* can be unmapped once parsed */ -} - -/* - * Map the table and keep it there. - */ -static Atable* -acpitable(uchar *p, int len) -{ - if(len < Sdthdrsz) - return nil; - return newtable(p); -} - -static void -dumptable(char *sig, uchar *p, int l) -{ - int n, i; - - if(DBGFLG > 1){ - DBG("%s @ %#p\n", sig, p); - if(DBGFLG > 2) - n = l; - else - n = 256; - for(i = 0; i < n; i++){ - if((i % 16) == 0) - DBG("%x: ", i); - DBG(" %2.2ux", p[i]); - if((i % 16) == 15) - DBG("\n"); - } - DBG("\n"); - DBG("\n"); - } -} - -static char* -seprinttable(char *s, char *e, Atable *t) -{ - uchar *p; - int i, n; - - p = (uchar*)t->tbl; /* include header */ - n = Sdthdrsz + t->dlen; - s = seprint(s, e, "%s @ %#p\n", t->sig, p); - for(i = 0; i < n; i++){ - if((i % 16) == 0) - s = seprint(s, e, "%x: ", i); - s = seprint(s, e, " %2.2ux", p[i]); - if((i % 16) == 15) - s = seprint(s, e, "\n"); - } - return seprint(s, e, "\n\n"); -} - -/* - * process xsdt table and load tables with sig, or all if nil. - * (XXX: should be able to search for sig, oemid, oemtblid) - */ -static int -acpixsdtload(char *sig) -{ - int i, l, t, unmap, found; - uintmem dhpa; - uchar *sdt; - char tsig[5]; - - found = 0; - print("acpi: xsdt: "); - for(i = 0; i < xsdt->len; i += xsdt->asize){ - if(xsdt->asize == 8) - dhpa = l64get(xsdt->p+i); - else - dhpa = l32get(xsdt->p+i); - if((sdt = sdtmap(dhpa, &l, 1)) == nil) - continue; - unmap = 1; - memmove(tsig, sdt, 4); - tsig[4] = 0; - print("%s ", tsig); - if(sig == nil || strcmp(sig, tsig) == 0){ - DBG("acpi: %s addr %#p\n", tsig, sdt); - for(t = 0; t < nelem(ptables); t++) - if(strcmp(tsig, ptables[t].sig) == 0){ - dumptable(tsig, sdt, l); - unmap = ptables[t].f(sdt, l) == nil; - found = 1; - break; - } - } - if(unmap) - sdtunmap(sdt, l); - } - print("\n"); - return found; -} - -static void* -rsdscan(u8int* addr, int len, char* signature) -{ - int sl; - u8int *e, *p; - - e = addr+len; - sl = strlen(signature); - for(p = addr; p+sl < e; p += 16){ - if(memcmp(p, signature, sl)) - continue; - return p; - } - - return nil; -} - -static void* -rsdsearch(char* signature) -{ - uintmem p; - u8int *bda; - void *rsd; - - /* - * Search for the data structure signature: - * 1) in the first KB of the EBDA; - * 2) in the BIOS ROM between 0xE0000 and 0xFFFFF. - */ - if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4) == 0){ - bda = BIOSSEG(0x40); - if((p = (bda[0x0F]<<8)|bda[0x0E])){ - if(rsd = rsdscan(KADDR(p), 1024, signature)) - return rsd; - } - } - return rsdscan(BIOSSEG(0xE000), 0x20000, signature); -} - -static void -acpirsdptr(void) -{ - Rsdp *rsd; - int asize; - uintmem sdtpa; - - if((rsd = rsdsearch("RSD PTR ")) == nil) - return; - - assert(sizeof(Sdthdr) == 36); - - DBG("acpi: RSD PTR@ %#p, physaddr %#ux length %ud %#llux rev %d\n", - rsd, l32get(rsd->raddr), l32get(rsd->length), - l64get(rsd->xaddr), rsd->revision); - - if(rsd->revision >= 2){ - if(sdtchecksum(rsd, 36) == nil){ - DBG("acpi: RSD: bad checksum\n"); - return; - } - sdtpa = l64get(rsd->xaddr); - asize = 8; - } - else{ - if(sdtchecksum(rsd, 20) == nil){ - DBG("acpi: RSD: bad checksum\n"); - return; - } - sdtpa = l32get(rsd->raddr); - asize = 4; - } - - /* - * process the RSDT or XSDT table. - */ - xsdt = malloc(sizeof(Xsdt)); - if(xsdt == nil){ - DBG("acpi: malloc failed\n"); - return; - } - if((xsdt->p = sdtmap(sdtpa, &xsdt->len, 1)) == nil){ - DBG("acpi: sdtmap failed\n"); - return; - } - if((xsdt->p[0] != 'R' && xsdt->p[0] != 'X') || memcmp(xsdt->p+1, "SDT", 3) != 0){ - DBG("acpi: xsdt sig: %.4s\n", (char*)xsdt->p); - sdtunmap(xsdt, xsdt->len); - free(xsdt); - xsdt = nil; - return; - } - xsdt->p += sizeof(Sdthdr); - xsdt->len -= sizeof(Sdthdr); - xsdt->asize = asize; - acpixsdtload(nil); - /* xsdt is kept and not unmapped */ -} +static Gpe* gpes; /* General purpose events */ +static int ngpes; +static Aconf aconf; static int acpigen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp) @@ -1287,35 +86,6 @@ return 1; } -static int -Gfmt(Fmt* f) -{ - Gas *g; - - g = va_arg(f->args, Gas*); - switch(g->spc){ - case Rsysmem: - case Rsysio: - case Rembed: - case Rsmbus: - case Rcmos: - case Rpcibar: - case Ripmi: - fmtprint(f, "[%s ", regnames[g->spc]); - break; - case Rpcicfg: - fmtprint(f, "[pci %T", (int)g->addr); - break; - case Rfixedhw: - fmtprint(f, "[hw "); - break; - default: - fmtprint(f, "[spc=%#ux ", g->spc); - } - return fmtprint(f, "off %d len %d addr %#ullx sz%d]", - g->off, g->len, g->addr, g->accsz); -} - /* ra/rb are int not uintmem because inb/outb are in the i/o address space. */ static uint getbanked(int ra, int rb, int sz) @@ -1439,34 +209,85 @@ } static void +setpm1ctl(uint u) +{ + setbanked(fadt.pm1acntblk, fadt.pm1bcntblk, fadt.pm1cntlen, u); +} + +void +acpipoweroff(void) +{ + enum { + Go = 1<<13, + Sstate = 1<<10, + }; + + iprint("acpi: power button: power cycle\n"); + /* + * bug: we're assuming that this is a fixed function + */ + setpm1ctl(7*Sstate| Go); +} + +void +acpipowercycle(void) +{ + iprint("a %#.8ux %#.8ux %ux %ux\n", + fadt.pm1acntblk, fadt.pm1bcntblk, fadt.pm1cntlen, 13); + iprint("acpi: power button: power off\n"); +} + +void +acpipowernop(void) +{ + iprint("acpi: power button: power nop\n"); +} + +struct { + char *name; + void (*f)(void); +} pwrbuttab[] = { + "reset", acpipowercycle, /* sic */ + "off", acpipoweroff, + "nop", acpipowernop, +}; + +enum { + Etimer = 1<<0, + Ebme = 1<<4, + Eglobal = 1<<5, + Epowerbtn = 1<<8, /* power button pressed */ + Esleepbtn = 1<<9, + Ertc = 1<<10, + Epciewake = 1<<14, + Ewake = 1<<15, +}; + +static void acpiintr(Ureg*, void*) { int i; uint sts, en; - print("acpi: intr\n"); - for(i = 0; i < ngpes; i++) if(getgpests(i)){ - print("gpe %d on\n", i); + iprint("gpe %d on\n", i); en = getgpeen(i); setgpeen(i, 0); clrgpests(i); if(en != 0) - print("acpiitr: calling gpe %d\n", i); - // queue gpe for calling gpe->ho in the - // aml process. - // enable it again when it returns. + print("acpinitr: calling gpe %d\n", i); + /* queue gpe. reenable after done */ } - sts = getpm1sts(); + sts = getpm1sts(); /* § 4.8.3.3.1 */ en = getpm1en(); - print("acpiitr: pm1sts %#ux pm1en %#ux\n", sts, en); - if(sts&en) - print("have enabled events\n"); - if(sts&1) - print("power button\n"); - // XXX serve other interrupts here. + iprint("acpinitr: pm1sts %#ux pm1en %#ux\n", sts, en); + if(sts&en){ + iprint("acpinitr: have enabled events\n"); + } setpm1sts(sts); + if(sts&Epowerbtn) + aconf.powerbutton(); } static void @@ -1499,92 +320,59 @@ } static void -acpiioalloc(uint addr, int len) -{ - if(addr != 0) - ioalloc(addr, len, 0, "acpi"); -} - -enum { - Blegacy = 1<<0, - B8042kbd = 1<<1, - Bnovga = 1<<2, - Bnomsi = 1<<3, - Bnocmos = 1<<4, -}; - -static void -iapcbootarch(void) +acpiioalloc(uint addr, int len, char *name) { - int i; - - i = fadt.iapcbootarch; + char buf[32]; - sys->nolegacyprobe = !(i&Blegacy); - sys->noi8042kbd = !(i&B8042kbd); - sys->novga = i&Bnovga; - sys->nomsi = i&Bnomsi; - sys->nocmos = i&Bnocmos; -} - -int -devacpiinit(void) -{ - if(fadt.smicmd == 0){ - fmtinstall('G', Gfmt); - acpirsdptr(); - if(fadt.smicmd == 0) - return -1; - iapcbootarch(); + if(addr != 0){ + snprint(buf, sizeof buf, "acpi %s", name); + ioalloc(addr, len, 0, buf); } - return 0; } -static Chan* -acpiattach(char *spec) +static void +init(void) { int i; - /* - * This was written for the stock kernel. - * This code must use 64 registers to be acpi ready in nix. - */ - if(devacpiinit() < 0) - error("no acpi"); + aconf.powerbutton = acpipoweroff; - error("acpi disabled"); - - /* - * should use fadt->xpm* and fadt->xgpe* registers for 64 bits. - * We are not ready in this kernel for that. - */ - DBG("acpi io alloc\n"); - acpiioalloc(fadt.smicmd, 1); - acpiioalloc(fadt.pm1aevtblk, fadt.pm1evtlen); - acpiioalloc(fadt.pm1bevtblk, fadt.pm1evtlen ); - acpiioalloc(fadt.pm1acntblk, fadt.pm1cntlen); - acpiioalloc(fadt.pm1bcntblk, fadt.pm1cntlen); - acpiioalloc(fadt.pm2cntblk, fadt.pm2cntlen); - acpiioalloc(fadt.pmtmrblk, fadt.pmtmrlen); - acpiioalloc(fadt.gpe0blk, fadt.gpe0blklen); - acpiioalloc(fadt.gpe1blk, fadt.gpe1blklen); + /* should we use fadt->xpm* and fadt->xgpe* registers for 64 bits? */ + acpiioalloc(fadt.smicmd, 1, "scicmd"); + acpiioalloc(fadt.pm1aevtblk, fadt.pm1evtlen, "pm1aevt"); + acpiioalloc(fadt.pm1bevtblk, fadt.pm1evtlen, "pm1bevt"); + acpiioalloc(fadt.pm1acntblk, fadt.pm1cntlen, "pm1acnt"); + acpiioalloc(fadt.pm1bcntblk, fadt.pm1cntlen, "pm1bcnt"); + acpiioalloc(fadt.pm2cntblk, fadt.pm2cntlen, "pm2cnt"); + acpiioalloc(fadt.pmtmrblk, fadt.pmtmrlen, "pmtmr"); + acpiioalloc(fadt.gpe0blk, fadt.gpe0blklen, "gpe0"); + acpiioalloc(fadt.gpe1blk, fadt.gpe1blklen, "gpe1"); - DBG("acpi init gpes\n"); initgpes(); /* - * This starts ACPI, which may require we handle - * power mgmt events ourselves. Use with care. + * This starts ACPI, which requires we handle + * power mgmt events ourselves. */ - DBG("acpi starting\n"); + print("acpi: enable interrupt\n"); outb(fadt.smicmd, fadt.acpienable); - for(i = 0; i < 10; i++) + for(i = 0;; i++){ + if(i == 10){ + print("acpi: failed to enable\n"); + return; + } if(getpm1ctl() & Pm1SciEn) break; - if(i == 10) - error("acpi: failed to enable\n"); + } if(fadt.sciint != 0) intrenable(fadt.sciint, acpiintr, 0, BUSUNKNOWN, "acpi"); +} + +static Chan* +acpiattach(char *spec) +{ + if(fadt.smicmd == 0) + error("no acpi"); return devattach(L'α', spec); } @@ -1611,71 +399,45 @@ { } -static char*ttext; -static int tlen; - static long acpiread(Chan *c, void *a, long n, vlong off) { + char *s, *p, *e, buf[256]; + int i; long q; - Atable *t; - char *ns, *s, *e, *ntext; q = c->qid.path; switch(q){ case Qdir: return devdirread(c, a, n, acpidir, nelem(acpidir), acpigen); + case Qctl: + p = buf; + e = buf + sizeof buf; + for(i = 0; i < nelem(pwrbuttab); i++) + if(pwrbuttab[i].f == aconf.powerbutton) + break; + if(i == nelem(pwrbuttab)) + s = "??"; + else + s = pwrbuttab[i].name; + seprint(p, e, "powerbutton %s\n", s); + return readstr(off, a, n, buf); + case Qtbl: - if(ttext == nil){ - tlen = 1024; - ttext = malloc(tlen); - if(ttext == nil){ - print("acpi: no memory\n"); - return 0; - } - s = ttext; - e = ttext + tlen; - strcpy(s, "no tables\n"); - for(t = tfirst; t != nil; t = t->next){ - ns = seprinttable(s, e, t); - while(ns == e - 1){ - DBG("acpiread: allocated %d\n", tlen*2); - ntext = realloc(ttext, tlen*2); - if(ntext == nil) - panic("acpi: no memory"); - s = ntext + (ttext - s); - ttext = ntext; - tlen *= 2; - e = ttext + tlen; - ns = seprinttable(s, e, t); - } - s = ns; - } - - } - return readstr(off, a, n, ttext); - case Qio: - if(reg == nil) - error("region not configured"); - return regio(reg, a, n, off, 0); + s = ""; + return readstr(off, a, n, s); } error(Eperm); return -1; } static long -acpiwrite(Chan *c, void *a, long n, vlong off) +acpiwrite(Chan *c, void *a, long n, vlong) { + uint i; Cmdtab *ct; Cmdbuf *cb; - Reg *r; - uint rno, fun, dev, bus, i; - if(c->qid.path == Qio){ - if(reg == nil) - error("region not configured"); - return regio(reg, a, n, off, 1); - } if(c->qid.path != Qctl) error(Eperm); @@ -1685,41 +447,7 @@ nexterror(); } ct = lookupcmd(cb, ctls, nelem(ctls)); - DBG("acpi ctl %s\n", cb->f[0]); switch(ct->index){ - case CMregion: - r = reg; - if(r == nil){ - r = smalloc(sizeof(Reg)); - r->name = nil; - } - kstrdup(&r->name, cb->f[1]); - r->spc = acpiregid(cb->f[2]); - if(r->spc < 0){ - free(r); - reg = nil; - error("bad region type"); - } - if(r->spc == Rpcicfg || r->spc == Rpcibar){ - rno = r->base>>Rpciregshift & Rpciregmask; - fun = r->base>>Rpcifunshift & Rpcifunmask; - dev = r->base>>Rpcidevshift & Rpcidevmask; - bus = r->base>>Rpcibusshift & Rpcibusmask; - r->tbdf = MKBUS(BusPCI, bus, dev, fun); - r->base = rno; /* register ~ our base addr */ - } - r->base = strtoull(cb->f[3], nil, 0); - r->len = strtoull(cb->f[4], nil, 0); - r->accsz = strtoul(cb->f[5], nil, 0); - if(r->accsz < 1 || r->accsz > 4){ - free(r); - reg = nil; - error("bad region access size"); - } - reg = r; - DBG("region %s %s %llux %llux sz%d", - r->name, acpiregstr(r->spc), r->base, r->len, r->accsz); - break; case CMgpe: i = strtoul(cb->f[1], nil, 0); if(i >= ngpes) @@ -1728,8 +456,23 @@ DBG("gpe %d %s\n", i, gpes[i].obj); setgpeen(i, 1); break; - default: - panic("acpi: unknown ctl"); + case CMpowerbut: + for(i = 0; i < nelem(pwrbuttab); i++) + if(strcmp(cb->f[1], pwrbuttab[i].name) == 0){ + ilock(&aconf); + aconf.powerbutton = pwrbuttab[i].f; + iunlock(&aconf); + break; + } + if(i == nelem(pwrbuttab)) + error("unknown power button action"); + break; + case CMpower: + if(strcmp(cb->f[1], "off") == 0) + aconf.powerbutton(); + else + error("unknown power button command"); + break; } poperror(); free(cb); @@ -1741,7 +484,7 @@ "acpi", devreset, - devinit, + init, devshutdown, acpiattach, acpiwalk, --- /sys/src/nix/k10/adr.c Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/adr.c Tue Oct 8 22:09:08 2013 @@ -554,7 +554,7 @@ adr.pagecnt[a->use] -= npages(a); a->use = Mupage; adr.pagecnt[Mupage] += npages(a); - physinit(a->base, a->len, a->color); + physinit(a->base, a->len, a->color != Cnone? a->color: 0); } physallocdump(); } --- /sys/src/nix/k10/apic.h Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/apic.h Tue Oct 8 22:09:08 2013 @@ -19,6 +19,7 @@ struct Lapic { int machno; /* APIC */ + int color; u32int lvt[7]; int nlvt; @@ -92,6 +93,7 @@ Apic* lapiclookup(uint); int lapiconline(void); void lapicpri(int); +void lapicsetcolor(int, int); void lapicsipi(int, uintmem); int pcimsienable(Pcidev*, uvlong); --- /sys/src/nix/k10/lapic.c Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/lapic.c Tue Oct 8 22:09:08 2013 @@ -200,6 +200,28 @@ apic->machno = lapmachno++; } +void +lapicsetcolor(int lapicno, int color) +{ + Apic *apic; + + DBG("lapic%d: setcolor: %d\n", lapicno, color); + if(lapicno >= Napic){ + panic("lapic%d: lapiccolor: out of range", lapicno); + return; + } + if((apic = &xlapic[lapicno])->useable) + apic->color = color; + else + print("lapic%d: lapiccolor: not usable\n", lapicno); +} + +int +machcolor(Mach *mp) +{ + return xlapic[mp->apicno].color; +} + static void lapicdump0(Apic *apic, int i) { --- /sys/src/nix/k10/physalloc.c Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/physalloc.c Tue Oct 8 22:09:08 2013 @@ -427,68 +427,57 @@ * Called from umeminit to initialize user memory allocators. */ void -physinit(uintmem a, u64int size, int /*color*/) +physinit(uintmem addr, u64int len, int dom) { uintmem dtsz; Bal *b; - int i, dom; - uintmem addr, len; + int i; - DBG("physinit %#P %#llux\n", a, size); + DBG("physinit %#P %#llux color %d\n", addr, len, dom); - for(addr = a; addr < a+size; addr += len){ + /* + * Each block may belong to a different NUMA domain + * Create a buddy allocator for each domain, so we can + * explicitly allocate memory from different domains. + * + * This code assumes that dom is a small integer. + */ + if(dom < 0 || dom >= Ndoms){ + print("physinit: dom too big: %d\n", dom); dom = 0; - len = acpimblocksize(addr, &dom); - /* len can be zero if there's no acpi information about addr */ - if(len == 0 || addr + len > a + size) - len = a + size - addr; - /* - * Each block belongs to a different domain (ie. cpu/mem socket) - * We must create a buddy allocator for each block, so we could - * allocate memory from different domains. - * - * This code assumes that a domain may be extended later and - * that there is no interleaving of domains. Ok by now. - */ - DBG("physmem block dom %d addr %#P size %#P\n", dom, addr, len); - if(dom < 0 || dom >= Ndoms){ - print("physinit: invalid dom %d\n", dom); - dom = 0; - } - b = &bal[dom]; - if(dom >= ndoms) - ndoms = dom+1; - if(b->kmin == 0){ - b->base = addr; - b->size = len; - b->kmin = BKmin; - b->kmax = BKmax; - b->bminsz = (UNO<kmin); - b->memory = sys->pmstart; - b->kspan = log2ceil(sys->pmend); - dtsz = sizeof(Buddy)*(UNO<<(b->kspan-b->kmin+1)); - DBG("kspan %ud (arrysz %P)\n", b->kspan, dtsz); - b->blocks = malloc(dtsz); - if(b->blocks == nil) - panic("physinit: no blocks"); - memset(b->blocks, 0, dtsz); - b->avail = malloc(sizeof(Buddy)*(b->kmax+1)); - if(b->avail == nil) - panic("physinit: no avail"); - memset(b->avail, 0, sizeof(Buddy)*(b->kmax+1)); - }else{ - if(addr < b->base) - panic("physinit: decreasing base"); - if(b->base+b->size < addr + len) - b->size = (addr-b->base) + len; - for(i = 0; i < Ndoms; i++) - if(bal[i].kmin && &bal[i] != b) - if(bal[i].base < b->base + b->size && - bal[i].base + bal[i].size > b->base + b->size) - panic("physinit: doms overlap"); - } - assert(addr >= b->base && addr+len <= b->base + b->size); - - iimbchunk(b, addr, addr+len, 0); } + b = &bal[dom]; + if(dom >= ndoms) + ndoms = dom+1; + if(b->kmin == 0){ + b->base = addr; + b->size = len; + b->kmin = BKmin; + b->kmax = BKmax; + b->bminsz = (UNO<kmin); + b->memory = sys->pmstart; + b->kspan = log2ceil(sys->pmend); + dtsz = sizeof(Buddy)*(UNO<<(b->kspan-b->kmin+1)); + DBG("kspan %ud (arrysz %P)\n", b->kspan, dtsz); + b->blocks = malloc(dtsz); + if(b->blocks == nil) + panic("physinit: no blocks"); + memset(b->blocks, 0, dtsz); + b->avail = malloc(sizeof(Buddy)*(b->kmax+1)); + if(b->avail == nil) + panic("physinit: no avail"); + memset(b->avail, 0, sizeof(Buddy)*(b->kmax+1)); + }else{ + if(addr < b->base) + panic("physinit: decreasing base"); + if(b->base+b->size < addr + len) + b->size = (addr-b->base) + len; + for(i = 0; i < Ndoms; i++) + if(bal[i].kmin && &bal[i] != b) + if(bal[i].base < b->base + b->size && + bal[i].base + bal[i].size > b->base + b->size) + panic("physinit: doms overlap"); + } + assert(addr >= b->base && addr+len <= b->base + b->size); + iimbchunk(b, addr, addr+len, 0); } --- /sys/src/nix/k10/archk10.c Tue Oct 8 22:09:08 2013 +++ /sys/src/nix/k10/archk10.c Tue Oct 8 22:09:08 2013 @@ -219,7 +219,7 @@ for(p = nil; p = pcimatch(p, 0, 0); ) for(i=0; imem); i++) if(p->mem[i].bar && (p->mem[i].bar&1) == 0) - adrmapinit(p->mem[i].bar&~(uintmem)0xf, p->mem[i].size, Apcibar, Mfree); + adrmapinit(p->mem[i].bar&~(uintmem)0xf, p->mem[i].size, Apcibar, Mfree, Cnone); } void