experimental acpi support for apic irq routing

This commit is contained in:
cinap_lenrek 2012-06-17 23:12:19 +02:00
parent 9cb66f310b
commit a47521a3ed
13 changed files with 2876 additions and 644 deletions

36
sys/include/aml.h Normal file
View file

@ -0,0 +1,36 @@
#pragma lib "libaml.a"
#pragma src "/sys/src/libaml"
/*
* b uchar* buffer amllen() returns number of bytes
* s char* string amllen() is strlen()
* i uvlong* integer
* p void** package amllen() is # of elements
* r void* region
* f void* field
* u void* bufferfield
* N void* name
* R void* reference
*/
int amltag(void *);
void* amlval(void *);
uvlong amlint(void *);
int amllen(void *);
void amlinit(void);
void amlexit(void);
int amlload(uchar *data, int len);
void* amlwalk(void *dot, char *name);
int amleval(void *dot, char *fmt, ...);
void amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg);
void* amlroot;
int amldebug;
#pragma varargck type "V" void*
#pragma varargck type "N" void*
/* to be provided by operating system */
extern void* amlalloc(int);
extern void amlfree(void*);

View file

@ -1,219 +0,0 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
typedef struct Rsd Rsd;
typedef struct Tbl Tbl;
struct Rsd {
uchar sig[8];
uchar csum;
uchar oemid[6];
uchar rev;
uchar raddr[4];
uchar len[4];
uchar xaddr[8];
uchar xcsum;
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[];
};
static int ntbltab;
static Tbl *tbltab[64];
static ushort
get16(uchar *p){
return p[1]<<8 | p[0];
}
static uint
get32(uchar *p){
return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
}
static uvlong
get64(uchar *p){
uvlong u;
u = get32(p+4);
return u<<32 | get32(p);
}
static int
checksum(void *v, int n)
{
uchar *p, s;
s = 0;
p = v;
while(n-- > 0)
s += *p++;
return s;
}
static void*
rsdscan(uchar* addr, int len, char* sig)
{
int sl;
uchar *e, *p;
e = addr+len;
sl = strlen(sig);
for(p = addr; p+sl < e; p += 16){
if(memcmp(p, sig, sl))
continue;
return p;
}
return nil;
}
static void*
rsdsearch(char* sig)
{
uintptr p;
uchar *bda;
Rsd *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 = KADDR(0x400);
if((p = (bda[0x0F]<<8)|bda[0x0E]))
if(rsd = rsdscan(KADDR(p), 1024, sig))
return rsd;
}
return rsdscan(KADDR(0xE0000), 0x20000, sig);
}
static void
maptable(uvlong xpa)
{
uchar *p, *e;
Tbl *t, *a;
uintptr pa;
u32int l;
int i;
pa = xpa;
if((uvlong)pa != xpa || pa == 0)
return;
if(ntbltab >= nelem(tbltab))
return;
if((t = vmap(pa, 8)) == nil)
return;
l = get32(t->len);
if(l < sizeof(Tbl) || t->sig[0] == 0){
vunmap(t, 8);
return;
}
for(i=0; i<ntbltab; i++){
if(memcmp(tbltab[i]->sig, t->sig, sizeof(t->sig)) == 0)
break;
}
vunmap(t, 8);
if(i < ntbltab)
return;
if((a = malloc(l)) == nil)
return;
if((t = vmap(pa, l)) == nil){
free(a);
return;
}
if(checksum(t, l)){
vunmap(t, l);
free(a);
return;
}
memmove(a, t, l);
vunmap(t, l);
tbltab[ntbltab++] = t = a;
if(0) print("acpi: %llux %.4s %d\n", xpa, (char*)t->sig, l);
p = (uchar*)t;
e = p + l;
if(memcmp("RSDT", t->sig, 4) == 0){
for(p = t->data; p+3 < e; p += 4)
maptable(get32(p));
return;
}
if(memcmp("XSDT", t->sig, 4) == 0){
for(p = t->data; p+7 < e; p += 8)
maptable(get64(p));
return;
}
if(memcmp("FACP", t->sig, 4) == 0){
if(l < 44)
return;
maptable(get32(p + 40));
if(l < 148)
return;
maptable(get64(p + 140));
return;
}
}
static long
readtbls(Chan*, void *v, long n, vlong o)
{
int i, l, m;
uchar *p;
Tbl *t;
p = v;
for(i=0; n > 0 && i < ntbltab; i++){
t = tbltab[i];
l = get32(t->len);
if(o >= l){
o -= l;
continue;
}
m = l - o;
if(m > n)
m = n;
memmove(p, (uchar*)t + o, m);
p += m;
n -= m;
o = 0;
}
return p - (uchar*)v;
}
void
acpilink(void)
{
Rsd *r;
/*
* this is a debug driver to dump the acpi tables.
* do nothing unless *acpi gets explicitly enabled.
*/
if(getconf("*acpi") == nil)
return;
if((r = rsdsearch("RSD PTR ")) == nil)
return;
if(checksum(r, 20) == 0)
maptable(get32(r->raddr));
if(r->rev >= 2)
if(checksum(r, 36) == 0)
maptable(get64(r->xaddr));
addarchfile("acpitbls", 0444, readtbls, nil);
}

525
sys/src/9/pc/archacpi.c Normal file
View file

@ -0,0 +1,525 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "mp.h"
#include <aml.h>
typedef struct Rsd Rsd;
typedef struct Tbl Tbl;
struct Rsd {
uchar sig[8];
uchar csum;
uchar oemid[6];
uchar rev;
uchar raddr[4];
uchar len[4];
uchar xaddr[8];
uchar xcsum;
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[];
};
static Rsd *rsd;
static int ntbltab;
static Tbl *tbltab[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];
}
static uint
get32(uchar *p){
return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
}
static uvlong
get64(uchar *p){
uvlong u;
u = get32(p+4);
return u<<32 | get32(p);
}
static uint
tbldlen(Tbl *t){
return get32(t->len) - sizeof(Tbl);
}
static int
checksum(void *v, int n)
{
uchar *p, s;
s = 0;
p = v;
while(n-- > 0)
s += *p++;
return s;
}
static void*
rsdscan(uchar* addr, int len, char* sig)
{
int sl;
uchar *e, *p;
e = addr+len;
sl = strlen(sig);
for(p = addr; p+sl < e; p += 16){
if(memcmp(p, sig, sl))
continue;
return p;
}
return nil;
}
static void*
rsdsearch(char* sig)
{
uintptr p;
uchar *bda;
Rsd *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 = KADDR(0x400);
if((p = (bda[0x0F]<<8)|bda[0x0E]))
if(rsd = rsdscan(KADDR(p), 1024, sig))
return rsd;
}
return rsdscan(KADDR(0xE0000), 0x20000, sig);
}
static Tbl*
findtable(void *sig){
int i;
for(i=0; i<ntbltab; i++)
if(memcmp(tbltab[i]->sig, sig, 4) == 0)
return tbltab[i];
return nil;
}
static void
maptable(uvlong xpa)
{
uchar *p, *e;
uintptr pa;
u32int l;
Tbl *t;
pa = xpa;
if((uvlong)pa != xpa || pa == 0)
return;
if(ntbltab >= nelem(tbltab))
return;
if((t = vmap(pa, 8)) == nil)
return;
l = get32(t->len);
if(l < sizeof(Tbl) || findtable(t->sig)){
vunmap(t, 8);
return;
}
vunmap(t, 8);
if((t = vmap(pa, l)) == nil)
return;
if(checksum(t, l)){
vunmap(t, l);
return;
}
tbltab[ntbltab++] = t;
p = (uchar*)t;
e = p + l;
if(memcmp("RSDT", t->sig, 4) == 0){
for(p = t->data; p+3 < e; p += 4)
maptable(get32(p));
return;
}
if(memcmp("XSDT", t->sig, 4) == 0){
for(p = t->data; p+7 < e; p += 8)
maptable(get64(p));
return;
}
if(memcmp("FACP", t->sig, 4) == 0){
if(l < 44)
return;
maptable(get32(p + 40));
if(l < 148)
return;
maptable(get64(p + 140));
return;
}
}
static void
maptables(void)
{
if(rsd == nil || ntbltab > 0)
return;
if(!checksum(rsd, 20))
maptable(get32(rsd->raddr));
if(rsd->rev >= 2)
if(!checksum(rsd, 36))
maptable(get64(rsd->xaddr));
}
static Apic*
findapic(int gsi, int *pintin)
{
Apic *a;
int i;
for(i=0; i<=MaxAPICNO; i++){
if((a = mpioapic[i]) == nil)
continue;
if((a->flags & PcmpEN) == 0)
continue;
if(gsi >= a->gsibase && gsi < a->gsibase+a->mre){
if(pintin)
*pintin = gsi - a->gsibase;
return a;
}
}
print("findapic: no ioapic found for gsi %d\n", gsi);
return nil;
}
static void
addirq(int gsi, int type, int busno, int irq, int flags)
{
Apic *a;
Bus *bus;
Aintr *ai;
PCMPintr *pi;
int intin;
if((a = findapic(gsi, &intin)) == nil)
return;
for(bus = mpbus; bus; bus = bus->next)
if(bus->type == type && bus->busno == busno)
goto Foundbus;
if((bus = xalloc(sizeof(Bus))) == nil)
panic("addirq: no memory for Bus");
bus->busno = busno;
bus->type = type;
if(type == BusISA){
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
if(mpisabus == -1)
mpisabus = busno;
} else {
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
}
if(mpbus)
mpbuslast->next = bus;
else
mpbus = bus;
mpbuslast = bus;
Foundbus:
for(ai = bus->aintr; ai; ai = ai->next)
if(ai->intr->irq == irq)
return;
if((pi = xalloc(sizeof(PCMPintr))) == nil)
panic("addirq: no memory for PCMPintr");
pi->type = PcmpIOINTR;
pi->intr = PcmpINT;
pi->flags = flags & (PcmpPOMASK|PcmpELMASK);
pi->busno = busno;
pi->irq = irq;
pi->apicno = a->apicno;
pi->intin = intin;
if((ai = xalloc(sizeof(Aintr))) == nil)
panic("addirq: no memory for Aintr");
ai->intr = pi;
ai->apic = a;
ai->next = bus->aintr;
bus->aintr = ai;
}
static int
pcibusno(void *dot)
{
int bno, adr, tbdf;
Pcidev *pdev;
void *p, *x;
p = nil;
if(x = amlwalk(dot, "^_BBN")){
if(amleval(x, "", &p) < 0)
return -1;
return amlint(p);
}
if((x = amlwalk(dot, "^_ADR")) == nil)
return -1;
if(amleval(x, "", &p) < 0)
return -1;
adr = amlint(p);
x = amlwalk(dot, "^");
if(x == nil || x == dot)
return -1;
if((bno = pcibusno(x)) < 0)
return -1;
tbdf = MKBUS(BusPCI, bno, adr>>16, adr&0xFFFF);
pdev = pcimatchtbdf(tbdf);
if(pdev == nil || pdev->bridge == nil){
print("pcibusno: bridge tbdf %luX not found\n", (ulong)tbdf);
return -1;
}
return BUSBNO(pdev->bridge->tbdf);
}
static int
enumprt(void *dot, void *)
{
void *p, **a, **b;
int bno, dno, pin;
int n, i;
bno = pcibusno(dot);
if(bno < 0){
print("enumprt: cannot get pci bus number for %V\n", dot);
return 1;
}
/* evalulate _PRT method */
p = nil;
if(amleval(dot, "", &p) < 0)
return 1;
if(amltag(p) != 'p')
return 1;
n = amllen(p);
a = amlval(p);
for(i=0; i<n; i++){
if(amltag(a[i]) != 'p')
continue;
if(amllen(a[i]) != 4)
continue;
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;
}
addirq(amlint(b[3]), BusPCI, bno, (dno<<2)|pin, 0);
}
return 1;
}
static void
acpiinit(void)
{
Tbl *t;
Apic *a;
void *va;
uchar *p, *e;
ulong lapicbase;
int machno, i, c;
maptables();
amlinit();
if(t = findtable("DSDT"))
amlload(t->data, tbldlen(t));
if(t = findtable("SSDT"))
amlload(t->data, tbldlen(t));
/* set APIC mode */
amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
if((t = findtable("APIC")) == nil)
panic("acpiinit: no APIC table found");
p = t->data;
e = p + tbldlen(t);
lapicbase = get32(p); p += 8;
va = vmap(lapicbase, 1024);
print("LAPIC: %.8lux %.8lux\n", lapicbase, (ulong)va);
if(va == nil)
panic("acpiinit: cannot map lapic %.8lux", lapicbase);
machno = 0;
for(; p < e; p += c){
c = p[1];
if(c < 2 || (p+c) > e)
break;
switch(*p){
case 0x00: /* Processor Local APIC */
if(p[3] > MaxAPICNO)
break;
if((a = xalloc(sizeof(Apic))) == nil)
panic("acpiinit: no memory for Apic");
a->type = PcmpPROCESSOR;
a->apicno = p[3];
a->paddr = lapicbase;
a->addr = va;
a->lintr[0] = ApicIMASK;
a->lintr[1] = ApicIMASK;
a->flags = (p[4] & PcmpEN);
if(a->flags & PcmpEN){
a->machno = machno++;
/*
* how do we know if this is the
* bootstrap processors apic?
*/
if(a->machno == 0)
a->flags |= PcmpBP;
}
mpapic[a->apicno] = a;
break;
case 0x01: /* I/O APIC */
if(p[2] > MaxAPICNO)
break;
if((a = xalloc(sizeof(Apic))) == nil)
panic("acpiinit: no memory for io Apic");
a->type = PcmpIOAPIC;
a->apicno = p[2];
a->paddr = get32(p+4);
if((a->addr = vmap(a->paddr, 1024)) == nil)
panic("acpiinit: cannot map ioapic %.8lux", a->paddr);
a->gsibase = get32(p+8);
a->flags = PcmpEN;
mpioapic[a->apicno] = a;
ioapicinit(a, a->apicno);
break;
case 0x02: /* Interrupt Source Override */
addirq(get32(p+4), BusISA, 0, p[3], get16(p+8));
break;
case 0x03: /* NMI Source */
case 0x04: /* Local APIC NMI */
case 0x05: /* Local APIC Address Override */
case 0x06: /* I/O SAPIC */
case 0x07: /* Local SAPIC */
case 0x08: /* Platform Interrupt Sources */
case 0x09: /* Processor Local x2APIC */
case 0x0A: /* x2APIC NMI */
case 0x0B: /* GIC */
case 0x0C: /* GICD */
break;
}
}
/* look for PCI interrupt mappings */
amlenum(amlroot, "_PRT", enumprt, nil);
/* add identity mapped legacy isa interrupts */
for(i=0; i<16; i++)
addirq(i, BusISA, 0, i, 0);
/* free the AML interpreter */
amlexit();
/*
* Ininitalize local APIC and start application processors.
*/
mpinit();
}
static int identify(void);
PCArch archacpi = {
.id= "ACPI",
.ident= identify,
.reset= mpshutdown,
.intrinit= acpiinit,
.intrenable= mpintrenable,
.intron= lapicintron,
.introff= lapicintroff,
.fastclock= i8253read,
.timerset= lapictimerset,
};
static long
readtbls(Chan*, void *v, long n, vlong o)
{
int i, l, m;
uchar *p;
Tbl *t;
maptables();
p = v;
for(i=0; n > 0 && i < ntbltab; i++){
t = tbltab[i];
l = get32(t->len);
if(o >= l){
o -= l;
continue;
}
m = l - o;
if(m > n)
m = n;
memmove(p, (uchar*)t + o, m);
p += m;
n -= m;
o = 0;
}
return p - (uchar*)v;
}
static int
identify(void)
{
char *cp;
if((cp = getconf("*acpi")) == nil)
return 1;
if((rsd = rsdsearch("RSD PTR ")) == nil)
return 1;
addarchfile("acpitbls", 0444, readtbls, nil);
if(strcmp(cp, "0") == 0)
return 1;
if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
return 1;
if(cpuserver && m->havetsc)
archacpi.fastclock = tscticks;
return 0;
}

View file

@ -7,7 +7,352 @@
#include "mp.h" #include "mp.h"
_MP_ *_mp_; static PCMP *pcmp;
static char* buses[] = {
"CBUSI ",
"CBUSII",
"EISA ",
"FUTURE",
"INTERN",
"ISA ",
"MBI ",
"MBII ",
"MCA ",
"MPI ",
"MPSA ",
"NUBUS ",
"PCI ",
"PCMCIA",
"TC ",
"VL ",
"VME ",
"XPRESS",
0,
};
static Bus*
mpgetbus(int busno)
{
Bus *bus;
for(bus = mpbus; bus; bus = bus->next)
if(bus->busno == busno)
return bus;
print("mpgetbus: can't find bus %d\n", busno);
return 0;
}
static Apic*
mkprocessor(PCMPprocessor* p)
{
static int machno = 1;
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpapic[apicno] != nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkprocessor: no memory for Apic");
apic->type = PcmpPROCESSOR;
apic->apicno = apicno;
apic->flags = p->flags;
apic->lintr[0] = ApicIMASK;
apic->lintr[1] = ApicIMASK;
if(p->flags & PcmpBP)
apic->machno = 0;
else
apic->machno = machno++;
mpapic[apicno] = apic;
return apic;
}
static Bus*
mkbus(PCMPbus* p)
{
Bus *bus;
int i;
for(i = 0; buses[i]; i++)
if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
break;
if(buses[i] == 0)
return 0;
if((bus = xalloc(sizeof(Bus))) == nil)
panic("mkbus: no memory for Bus");
if(mpbus)
mpbuslast->next = bus;
else
mpbus = bus;
mpbuslast = bus;
bus->type = i;
bus->busno = p->busno;
if(bus->type == BusEISA){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
if(mpeisabus != -1)
print("mkbus: more than one EISA bus\n");
mpeisabus = bus->busno;
}
else if(bus->type == BusPCI){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
}
else if(bus->type == BusISA){
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
if(mpisabus != -1)
print("mkbus: more than one ISA bus\n");
mpisabus = bus->busno;
}
else{
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
}
return bus;
}
static Apic*
mkioapic(PCMPioapic* p)
{
void *va;
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpioapic[apicno] != nil)
return 0;
/*
* Map the I/O APIC.
*/
if((va = vmap(p->addr, 1024)) == nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkioapic: no memory for Apic");
apic->type = PcmpIOAPIC;
apic->apicno = apicno;
apic->addr = va;
apic->paddr = p->addr;
apic->flags = p->flags;
mpioapic[apicno] = apic;
return apic;
}
static Aintr*
mkiointr(PCMPintr* p)
{
Bus *bus;
Aintr *aintr;
PCMPintr* pcmpintr;
/*
* According to the MultiProcessor Specification, a destination
* I/O APIC of 0xFF means the signal is routed to all I/O APICs.
* It's unclear how that can possibly be correct so treat it as
* an error for now.
*/
if(p->apicno > MaxAPICNO || mpioapic[p->apicno] == nil)
return 0;
if((bus = mpgetbus(p->busno)) == 0)
return 0;
if((aintr = xalloc(sizeof(Aintr))) == nil)
panic("mkiointr: no memory for Aintr");
aintr->intr = p;
if(0)
print("mkiointr: type %d intr type %d flags %#o "
"bus %d irq %d apicno %d intin %d\n",
p->type, p->intr, p->flags,
p->busno, p->irq, p->apicno, p->intin);
/*
* Hack for Intel SR1520ML motherboard, which BIOS describes
* the i82575 dual ethernet controllers incorrectly.
*/
if(memcmp(pcmp->product, "INTEL X38MLST ", 20) == 0){
if(p->busno == 1 && p->intin == 16 && p->irq == 1){
if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
panic("iointr: no memory for PCMPintr");
memmove(pcmpintr, p, sizeof(PCMPintr));
print("mkiointr: %20.20s bus %d intin %d irq %d\n",
(char*)pcmp->product,
pcmpintr->busno, pcmpintr->intin,
pcmpintr->irq);
pcmpintr->intin = 17;
aintr->intr = pcmpintr;
}
}
aintr->apic = mpioapic[p->apicno];
aintr->next = bus->aintr;
bus->aintr = aintr;
return aintr;
}
static int
mklintr(PCMPintr* p)
{
Apic *apic;
Bus *bus;
int i, intin, v;
/*
* The offsets of vectors for LINT[01] are known to be
* 0 and 1 from the local APIC vector space at VectorLAPIC.
*/
if((bus = mpgetbus(p->busno)) == 0)
return 0;
intin = p->intin;
/*
* Pentium Pros have problems if LINT[01] are set to ExtINT
* so just bag it, SMP mode shouldn't need ExtINT anyway.
*/
if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
v = ApicIMASK;
else
v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
if(p->apicno == 0xFF){
for(i=0; i<=MaxAPICNO; i++){
if((apic = mpapic[i]) == nil)
continue;
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
}
else{
if(apic = mpapic[p->apicno])
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
return v;
}
static void
dumpmp(uchar *p, uchar *e)
{
int i;
for(i = 0; p < e; p++) {
if((i % 16) == 0) print("*mp%d=", i/16);
print("%.2x ", *p);
if((++i % 16) == 0) print("\n");
}
if((i % 16) != 0) print("\n");
}
static void
mpoverride(uchar** newp, uchar** e)
{
int size, i, j;
char buf[20];
uchar* p;
char* s;
size = atoi(getconf("*mp"));
if(size == 0) panic("mpoverride: invalid size in *mp");
*newp = p = xalloc(size);
if(p == nil) panic("mpoverride: can't allocate memory");
*e = p + size;
for(i = 0; ; i++){
snprint(buf, sizeof buf, "*mp%d", i);
s = getconf(buf);
if(s == nil) break;
while(*s){
j = strtol(s, &s, 16);
if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
if(p >= *e) panic("mpoverride: overflow in %s", buf);
*p++ = j;
}
}
if(p != *e) panic("mpoverride: size doesn't match");
}
static void
pcmpinit(void)
{
uchar *p, *e;
Apic *apic;
void *va;
/*
* Map the local APIC.
*/
va = vmap(pcmp->lapicbase, 1024);
print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
if(va == nil)
panic("pcmpinit: cannot map lapic %.8lux", pcmp->lapicbase);
p = ((uchar*)pcmp)+sizeof(PCMP);
e = ((uchar*)pcmp)+pcmp->length;
if(getconf("*dumpmp") != nil)
dumpmp(p, e);
if(getconf("*mp") != nil)
mpoverride(&p, &e);
/*
* Run through the table saving information needed for starting
* application processors and initialising any I/O APICs. The table
* is guaranteed to be in order such that only one pass is necessary.
*/
while(p < e) switch(*p){
default:
print("pcmpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
*p, e-p);
while(p < e){
print("%uX ", *p);
p++;
}
break;
case PcmpPROCESSOR:
if(apic = mkprocessor((PCMPprocessor*)p)){
apic->addr = va;
apic->paddr = pcmp->lapicbase;
}
p += sizeof(PCMPprocessor);
continue;
case PcmpBUS:
mkbus((PCMPbus*)p);
p += sizeof(PCMPbus);
continue;
case PcmpIOAPIC:
if(apic = mkioapic((PCMPioapic*)p))
ioapicinit(apic, apic->apicno);
p += sizeof(PCMPioapic);
continue;
case PcmpIOINTR:
mkiointr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
case PcmpLINTR:
mklintr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
}
/*
* Ininitalize local APIC and start application processors.
*/
mpinit();
}
static _MP_* static _MP_*
mpscan(uchar *addr, int len) mpscan(uchar *addr, int len)
@ -60,7 +405,7 @@ PCArch archmp = {
.id= "_MP_", .id= "_MP_",
.ident= identify, .ident= identify,
.reset= mpshutdown, .reset= mpshutdown,
.intrinit= mpinit, .intrinit= pcmpinit,
.intrenable= mpintrenable, .intrenable= mpintrenable,
.intron= lapicintron, .intron= lapicintron,
.introff= lapicintroff, .introff= lapicintroff,
@ -72,7 +417,7 @@ static int
identify(void) identify(void)
{ {
char *cp; char *cp;
PCMP *pcmp; _MP_ *_mp_;
uchar *p, sum; uchar *p, sum;
ulong length; ulong length;
@ -90,50 +435,23 @@ identify(void)
return 1; return 1;
pcmp = KADDR(_mp_->physaddr); pcmp = KADDR(_mp_->physaddr);
if(memcmp(pcmp, "PCMP", 4)) if(memcmp(pcmp, "PCMP", 4)){
pcmp = nil;
return 1; return 1;
}
length = pcmp->length; length = pcmp->length;
sum = 0; sum = 0;
for(p = (uchar*)pcmp; length; length--) for(p = (uchar*)pcmp; length; length--)
sum += *p++; sum += *p++;
if(sum || (pcmp->version != 1 && pcmp->version != 4)) if(sum || (pcmp->version != 1 && pcmp->version != 4)){
pcmp = nil;
return 1; return 1;
}
if(cpuserver && m->havetsc) if(cpuserver && m->havetsc)
archmp.fastclock = tscticks; archmp.fastclock = tscticks;
return 0; return 0;
} }
Lock mpsynclock;
void
syncclock(void)
{
uvlong x;
if(arch->fastclock != tscticks)
return;
if(m->machno == 0){
wrmsr(0x10, 0);
m->tscticks = 0;
} else {
x = MACHP(0)->tscticks;
while(x == MACHP(0)->tscticks)
;
wrmsr(0x10, MACHP(0)->tscticks);
cycles(&m->tscticks);
}
}
uvlong
tscticks(uvlong *hz)
{
if(hz != nil)
*hz = m->cpuhz;
cycles(&m->tscticks); /* Uses the rdtsc instruction */
return m->tscticks;
}

View file

@ -271,6 +271,7 @@ struct Pcidev
Pcidev* list; Pcidev* list;
Pcidev* link; /* next device on this bno */ Pcidev* link; /* next device on this bno */
Pcidev* parent; /* up a bus */
Pcidev* bridge; /* down a bus */ Pcidev* bridge; /* down a bus */
struct { struct {
ulong bar; ulong bar;

View file

@ -68,6 +68,7 @@ LIB=\
/$objtype/lib/libsec.a\ /$objtype/lib/libsec.a\
/$objtype/lib/libmp.a\ /$objtype/lib/libmp.a\
/$objtype/lib/libfis.a\ /$objtype/lib/libfis.a\
/$objtype/lib/libaml.a\
ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'} ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
VGA=`{echo devvga.c screen.c vga*.c | sed 's/\.c/.'$O'/g'} VGA=`{echo devvga.c screen.c vga*.c | sed 's/\.c/.'$O'/g'}

View file

@ -9,209 +9,15 @@
#include "mp.h" #include "mp.h"
#include "apbootstrap.h" #include "apbootstrap.h"
static PCMP* mppcmp; /* filled in by pcmpinit or acpiinit */
static Bus* mpbus; Bus* mpbus;
static Bus* mpbuslast; Bus* mpbuslast;
static int mpisabus = -1; int mpisabus = -1;
static int mpeisabus = -1; int mpeisabus = -1;
extern int i8259elcr; /* mask of level-triggered interrupts */ Apic *mpioapic[MaxAPICNO+1];
static Apic *mpioapic[MaxAPICNO+1]; Apic *mpapic[MaxAPICNO+1];
static Apic *mpapic[MaxAPICNO+1];
static int mpmachno = 1;
static Lock mpphysidlock;
static int mpphysid;
static char* buses[] = { int
"CBUSI ",
"CBUSII",
"EISA ",
"FUTURE",
"INTERN",
"ISA ",
"MBI ",
"MBII ",
"MCA ",
"MPI ",
"MPSA ",
"NUBUS ",
"PCI ",
"PCMCIA",
"TC ",
"VL ",
"VME ",
"XPRESS",
0,
};
static Apic*
mkprocessor(PCMPprocessor* p)
{
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno >= nelem(mpapic) || mpapic[apicno] != nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkprocessor: no memory for Apic");
apic->type = PcmpPROCESSOR;
apic->apicno = apicno;
apic->flags = p->flags;
apic->lintr[0] = ApicIMASK;
apic->lintr[1] = ApicIMASK;
if(p->flags & PcmpBP)
apic->machno = 0;
else
apic->machno = mpmachno++;
mpapic[apicno] = apic;
return apic;
}
static Bus*
mkbus(PCMPbus* p)
{
Bus *bus;
int i;
for(i = 0; buses[i]; i++){
if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
break;
}
if(buses[i] == 0)
return 0;
if((bus = xalloc(sizeof(Bus))) == nil)
panic("mkbus: no memory for Bus");
if(mpbus)
mpbuslast->next = bus;
else
mpbus = bus;
mpbuslast = bus;
bus->type = i;
bus->busno = p->busno;
if(bus->type == BusEISA){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
if(mpeisabus != -1)
print("mkbus: more than one EISA bus\n");
mpeisabus = bus->busno;
}
else if(bus->type == BusPCI){
bus->po = PcmpLOW;
bus->el = PcmpLEVEL;
}
else if(bus->type == BusISA){
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
if(mpisabus != -1)
print("mkbus: more than one ISA bus\n");
mpisabus = bus->busno;
}
else{
bus->po = PcmpHIGH;
bus->el = PcmpEDGE;
}
return bus;
}
static Bus*
mpgetbus(int busno)
{
Bus *bus;
for(bus = mpbus; bus; bus = bus->next){
if(bus->busno == busno)
return bus;
}
print("mpgetbus: can't find bus %d\n", busno);
return 0;
}
static Apic*
mkioapic(PCMPioapic* p)
{
void *va;
int apicno;
Apic *apic;
apicno = p->apicno;
if(!(p->flags & PcmpEN) || apicno >= nelem(mpioapic) || mpioapic[apicno] != nil)
return 0;
/*
* Map the I/O APIC.
*/
if((va = vmap(p->addr, 1024)) == nil)
return 0;
if((apic = xalloc(sizeof(Apic))) == nil)
panic("mkioapic: no memory for Apic");
apic->type = PcmpIOAPIC;
apic->apicno = apicno;
apic->addr = va;
apic->paddr = p->addr;
apic->flags = p->flags;
mpioapic[apicno] = apic;
return apic;
}
static Aintr*
mkiointr(PCMPintr* p)
{
Bus *bus;
Aintr *aintr;
PCMPintr* pcmpintr;
/*
* According to the MultiProcessor Specification, a destination
* I/O APIC of 0xFF means the signal is routed to all I/O APICs.
* It's unclear how that can possibly be correct so treat it as
* an error for now.
*/
if(p->apicno >= nelem(mpioapic) || mpioapic[p->apicno] == nil)
return 0;
if((bus = mpgetbus(p->busno)) == 0)
return 0;
if((aintr = xalloc(sizeof(Aintr))) == nil)
panic("iointr: no memory for Aintr");
aintr->intr = p;
if(0)
print("iointr: type %d intr type %d flags %#o "
"bus %d irq %d apicno %d intin %d\n",
p->type, p->intr, p->flags,
p->busno, p->irq, p->apicno, p->intin);
/*
* Hack for Intel SR1520ML motherboard, which BIOS describes
* the i82575 dual ethernet controllers incorrectly.
*/
if(memcmp(mppcmp->product, "INTEL X38MLST ", 20) == 0){
if(p->busno == 1 && p->intin == 16 && p->irq == 1){
if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
panic("iointr: no memory for PCMPintr");
memmove(pcmpintr, p, sizeof(PCMPintr));
print("mkiointr: %20.20s bus %d intin %d irq %d\n",
(char*)mppcmp->product,
pcmpintr->busno, pcmpintr->intin,
pcmpintr->irq);
pcmpintr->intin = 17;
aintr->intr = pcmpintr;
}
}
aintr->apic = mpioapic[p->apicno];
aintr->next = bus->aintr;
bus->aintr = aintr;
return aintr;
}
static int
mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/) mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
{ {
int el, po, v; int el, po, v;
@ -284,47 +90,6 @@ mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
return v; return v;
} }
static int
mklintr(PCMPintr* p)
{
Apic *apic;
Bus *bus;
int i, intin, v;
/*
* The offsets of vectors for LINT[01] are known to be
* 0 and 1 from the local APIC vector space at VectorLAPIC.
*/
if((bus = mpgetbus(p->busno)) == 0)
return 0;
intin = p->intin;
/*
* Pentium Pros have problems if LINT[01] are set to ExtINT
* so just bag it, SMP mode shouldn't need ExtINT anyway.
*/
if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
v = ApicIMASK;
else
v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
if(p->apicno == 0xFF){
for(i=0; i<nelem(mpapic); i++){
if((apic = mpapic[i]) == nil)
continue;
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
}
else{
if(apic = mpapic[p->apicno])
if(apic->flags & PcmpEN)
apic->lintr[intin] = v;
}
return v;
}
static void static void
checkmtrr(void) checkmtrr(void)
{ {
@ -377,6 +142,36 @@ checkmtrr(void)
} }
} }
uvlong
tscticks(uvlong *hz)
{
if(hz != nil)
*hz = m->cpuhz;
cycles(&m->tscticks); /* Uses the rdtsc instruction */
return m->tscticks;
}
void
syncclock(void)
{
uvlong x;
if(arch->fastclock != tscticks)
return;
if(m->machno == 0){
wrmsr(0x10, 0);
m->tscticks = 0;
} else {
x = MACHP(0)->tscticks;
while(x == MACHP(0)->tscticks)
;
wrmsr(0x10, MACHP(0)->tscticks);
cycles(&m->tscticks);
}
}
static void static void
squidboy(Apic* apic) squidboy(Apic* apic)
{ {
@ -483,141 +278,56 @@ mpstartap(Apic* apic)
nvramwrite(0x0F, 0x00); nvramwrite(0x0F, 0x00);
} }
static void
dumpmp(uchar *p, uchar *e)
{
int i;
for(i = 0; p < e; p++) {
if((i % 16) == 0) print("*mp%d=", i/16);
print("%.2x ", *p);
if((++i % 16) == 0) print("\n");
}
if((i % 16) != 0) print("\n");
}
static void
mpoverride(uchar** newp, uchar** e)
{
int size, i, j;
char buf[20];
uchar* p;
char* s;
size = atoi(getconf("*mp"));
if(size == 0) panic("mpoverride: invalid size in *mp");
*newp = p = xalloc(size);
if(p == nil) panic("mpoverride: can't allocate memory");
*e = p + size;
for(i = 0; ; i++){
snprint(buf, sizeof buf, "*mp%d", i);
s = getconf(buf);
if(s == nil) break;
while(*s){
j = strtol(s, &s, 16);
if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
if(p >= *e) panic("mpoverride: overflow in %s", buf);
*p++ = j;
}
}
if(p != *e) panic("mpoverride: size doesn't match");
}
void void
mpinit(void) mpinit(void)
{ {
int ncpu, i; int ncpu, i;
Apic *apic;
char *cp; char *cp;
PCMP *pcmp;
uchar *e, *p;
Apic *apic, *bpapic;
void *va;
i8259init(); i8259init();
syncclock(); syncclock();
if(_mp_ == 0) if(getconf("*apicdebug")){
return; Bus *b;
pcmp = KADDR(_mp_->physaddr); Aintr *ai;
PCMPintr *pi;
/* for(i=0; i<=MaxAPICNO; i++){
* Map the local APIC. if(apic = mpapic[i])
*/ print("LAPIC%d: pa=%lux va=%lux flags=%x\n",
if((va = vmap(pcmp->lapicbase, 1024)) == nil) i, apic->paddr, (ulong)apic->addr, apic->flags);
return; if(apic = mpioapic[i])
mppcmp = pcmp; print("IOAPIC%d: pa=%lux va=%lux flags=%x gsibase=%d mre=%d\n",
print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va); i, apic->paddr, (ulong)apic->addr, apic->flags, apic->gsibase, apic->mre);
bpapic = nil;
/*
* Run through the table saving information needed for starting
* application processors and initialising any I/O APICs. The table
* is guaranteed to be in order such that only one pass is necessary.
*/
p = ((uchar*)pcmp)+sizeof(PCMP);
e = ((uchar*)pcmp)+pcmp->length;
if(getconf("*dumpmp") != nil)
dumpmp(p, e);
if(getconf("*mp") != nil)
mpoverride(&p, &e);
while(p < e) switch(*p){
default:
print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
*p, e-p);
while(p < e){
print("%uX ", *p);
p++;
} }
break; for(b = mpbus; b; b = b->next){
print("BUS%d type=%d flags=%x\n", b->busno, b->type, b->po|b->el);
case PcmpPROCESSOR: for(ai = b->aintr; ai; ai = ai->next){
if(apic = mkprocessor((PCMPprocessor*)p)){ if(pi = ai->intr)
/* print("\ttype=%d irq=%d (%d [%c]) apic=%d intin=%d flags=%x\n",
* Must take a note of bootstrap processor APIC pi->type, pi->irq, pi->irq>>2, "ABCD"[pi->irq&3],
* now as it will be needed in order to start the pi->apicno, pi->intin, pi->flags);
* application processors later and there's no }
* guarantee that the bootstrap processor appears
* first in the table before the others.
*/
apic->addr = va;
apic->paddr = pcmp->lapicbase;
if(apic->flags & PcmpBP)
bpapic = apic;
} }
p += sizeof(PCMPprocessor);
continue;
case PcmpBUS:
mkbus((PCMPbus*)p);
p += sizeof(PCMPbus);
continue;
case PcmpIOAPIC:
if(apic = mkioapic((PCMPioapic*)p))
ioapicinit(apic, ((PCMPioapic*)p)->apicno);
p += sizeof(PCMPioapic);
continue;
case PcmpIOINTR:
mkiointr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
case PcmpLINTR:
mklintr((PCMPintr*)p);
p += sizeof(PCMPintr);
continue;
} }
/* apic = nil;
* No bootstrap processor, no need to go further. for(i=0; i<=MaxAPICNO; i++){
*/ if(mpapic[i] == nil)
if(bpapic == 0) continue;
return; if(mpapic[i]->flags & PcmpBP){
bpapic->online = 1; apic = mpapic[i];
break;
}
}
lapicinit(bpapic); if(apic == nil){
panic("mpinit: no bootstrap processor");
return;
}
apic->online = 1;
lapicinit(apic);
/* /*
* These interrupts are local to the processor * These interrupts are local to the processor
@ -670,6 +380,8 @@ mpinit(void)
static int static int
mpintrcpu(void) mpintrcpu(void)
{ {
static Lock physidlock;
static int physid;
int i; int i;
/* /*
@ -689,17 +401,17 @@ mpintrcpu(void)
* to more than one thread in a core, or to use a "noise" core. * to more than one thread in a core, or to use a "noise" core.
* But, as usual, Intel make that an onerous task. * But, as usual, Intel make that an onerous task.
*/ */
lock(&mpphysidlock); lock(&physidlock);
for(;;){ for(;;){
i = mpphysid++; i = physid++;
if(mpphysid >= nelem(mpapic)) if(physid >= nelem(mpapic))
mpphysid = 0; physid = 0;
if(mpapic[i] == nil) if(mpapic[i] == nil)
continue; continue;
if(mpapic[i]->online) if(mpapic[i]->online)
break; break;
} }
unlock(&mpphysidlock); unlock(&physidlock);
return mpapic[i]->apicno; return mpapic[i]->apicno;
} }
@ -741,23 +453,41 @@ mpintrenablex(Vctl* v, int tbdf)
Aintr *aintr; Aintr *aintr;
Apic *apic; Apic *apic;
Pcidev *pcidev; Pcidev *pcidev;
int bno, dno, hi, irq, lo, n, type, vno; int bno, dno, pin, hi, irq, lo, n, type, vno;
/*
* Find the bus.
*/
type = BUSTYPE(tbdf); type = BUSTYPE(tbdf);
bno = BUSBNO(tbdf); bno = BUSBNO(tbdf);
dno = BUSDNO(tbdf); dno = BUSDNO(tbdf);
if(type == BusISA)
pin = 0;
pcidev = nil;
if(type == BusPCI){
if(pcidev = pcimatchtbdf(tbdf))
pin = pcicfgr8(pcidev, PciINTP);
} else if(type == BusISA)
bno = mpisabus; bno = mpisabus;
Findbus:
for(bus = mpbus; bus != nil; bus = bus->next){ for(bus = mpbus; bus != nil; bus = bus->next){
if(bus->type != type) if(bus->type != type)
continue; continue;
if(bus->busno == bno) if(bus->busno == bno)
break; break;
} }
if(bus == nil){ if(bus == nil){
/*
* if the PCI device is behind a PCI-PCI bridge thats not described
* by the MP or ACPI tables then walk up the bus translating interrupt
* pin to parent bus.
*/
if(pcidev && pcidev->parent && pin > 0){
pin = ((dno+(pin-1))%4)+1;
pcidev = pcidev->parent;
bno = BUSBNO(pcidev->tbdf);
dno = BUSDNO(pcidev->tbdf);
goto Findbus;
}
print("mpintrenable: can't find bus type %d, number %d\n", type, bno); print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
return -1; return -1;
} }
@ -765,13 +495,11 @@ mpintrenablex(Vctl* v, int tbdf)
/* /*
* For PCI devices the interrupt pin (INT[ABCD]) and device * For PCI devices the interrupt pin (INT[ABCD]) and device
* number are encoded into the entry irq field, so create something * number are encoded into the entry irq field, so create something
* to match on. The interrupt pin used by the device has to be * to match on.
* obtained from the PCI config space.
*/ */
if(bus->type == BusPCI){ if(bus->type == BusPCI){
pcidev = pcimatchtbdf(tbdf); if(pin > 0)
if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0) irq = (dno<<2)|(pin-1);
irq = (dno<<2)|(n-1);
else else
irq = -1; irq = -1;
} }
@ -932,15 +660,16 @@ mpintrenable(Vctl* v)
return -1; return -1;
} }
static Lock mpshutdownlock;
void void
mpshutdown(void) mpshutdown(void)
{ {
static Lock shutdownlock;
/* /*
* To be done... * To be done...
*/ */
if(!canlock(&mpshutdownlock)){ if(!canlock(&shutdownlock)){
/* /*
* If this processor received the CTRL-ALT-DEL from * If this processor received the CTRL-ALT-DEL from
* the keyboard, acknowledge it. Send an INIT to self. * the keyboard, acknowledge it. Send an INIT to self.

View file

@ -162,6 +162,7 @@ typedef struct Apic {
Lock; /* I/O APIC: register access */ Lock; /* I/O APIC: register access */
int mre; /* I/O APIC: maximum redirection entry */ int mre; /* I/O APIC: maximum redirection entry */
int gsibase; /* I/O APIC: global system interrupt base (acpi) */
int lintr[2]; /* Local APIC */ int lintr[2]; /* Local APIC */
int machno; int machno;
@ -228,8 +229,14 @@ extern void lapicspurious(Ureg*, void*);
extern void lapicstartap(Apic*, int); extern void lapicstartap(Apic*, int);
extern void lapictimerset(uvlong); extern void lapictimerset(uvlong);
extern int mpintrinit(Bus*, PCMPintr*, int, int);
extern void mpinit(void); extern void mpinit(void);
extern int mpintrenable(Vctl*); extern int mpintrenable(Vctl*);
extern void mpshutdown(void); extern void mpshutdown(void);
extern _MP_ *_mp_; extern Bus* mpbus;
extern Bus* mpbuslast;
extern int mpisabus;
extern int mpeisabus;
extern Apic *mpioapic[];
extern Apic *mpapic[];

View file

@ -41,7 +41,6 @@ link
devpccard devpccard
devi82365 devi82365
cputemp cputemp
acpi
apm apmjump apm apmjump
ether2000 ether8390 ether2000 ether8390
ether2114x pci ether2114x pci
@ -79,6 +78,7 @@ link
audiohda audiohda
misc misc
archacpi mp apic
archmp mp apic archmp mp apic
mtrr mtrr

View file

@ -42,7 +42,6 @@ link
devpccard devpccard
devi82365 devi82365
cputemp cputemp
acpi
apm apmjump apm apmjump
ether2000 ether8390 ether2000 ether8390
ether2114x pci ether2114x pci
@ -81,6 +80,7 @@ link
audiohda audiohda
misc misc
archacpi mp apic
archmp mp apic archmp mp apic
mtrr mtrr

View file

@ -367,7 +367,7 @@ pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
} }
static int static int
pcilscan(int bno, Pcidev** list) pcilscan(int bno, Pcidev** list, Pcidev *parent)
{ {
Pcidev *p, *head, *tail; Pcidev *p, *head, *tail;
int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn; int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
@ -453,6 +453,7 @@ pcilscan(int bno, Pcidev** list)
break; break;
} }
p->parent = parent;
if(head != nil) if(head != nil)
tail->link = p; tail->link = p;
else else
@ -494,7 +495,7 @@ pcilscan(int bno, Pcidev** list)
l = (MaxUBN<<16)|(sbn<<8)|bno; l = (MaxUBN<<16)|(sbn<<8)|bno;
pcicfgw32(p, PciPBN, l); pcicfgw32(p, PciPBN, l);
pcicfgw16(p, PciSPSR, 0xFFFF); pcicfgw16(p, PciSPSR, 0xFFFF);
maxubn = pcilscan(sbn, &p->bridge); maxubn = pcilscan(sbn, &p->bridge, p);
l = (maxubn<<16)|(sbn<<8)|bno; l = (maxubn<<16)|(sbn<<8)|bno;
pcicfgw32(p, PciPBN, l); pcicfgw32(p, PciPBN, l);
@ -502,7 +503,7 @@ pcilscan(int bno, Pcidev** list)
else { else {
if(ubn > maxubn) if(ubn > maxubn)
maxubn = ubn; maxubn = ubn;
pcilscan(sbn, &p->bridge); pcilscan(sbn, &p->bridge, p);
} }
} }
@ -515,7 +516,7 @@ pciscan(int bno, Pcidev **list)
int ubn; int ubn;
lock(&pcicfginitlock); lock(&pcicfginitlock);
ubn = pcilscan(bno, list); ubn = pcilscan(bno, list, nil);
unlock(&pcicfginitlock); unlock(&pcicfginitlock);
return ubn; return ubn;
} }
@ -1004,7 +1005,7 @@ pcicfginit(void)
list = &pciroot; list = &pciroot;
for(bno = 0; bno <= pcimaxbno; bno++) { for(bno = 0; bno <= pcimaxbno; bno++) {
int sbno = bno; int sbno = bno;
bno = pcilscan(bno, list); bno = pcilscan(bno, list, nil);
while(*list) while(*list)
list = &(*list)->link; list = &(*list)->link;

1818
sys/src/libaml/aml.c Normal file

File diff suppressed because it is too large Load diff

15
sys/src/libaml/mkfile Normal file
View file

@ -0,0 +1,15 @@
</$objtype/mkfile
LIB=/$objtype/lib/libaml.a
OFILES=\
aml.$O\
HFILES=/sys/include/aml.h
UPDATE=\
mkfile\
$HFILES\
${OFILES:%.$O=%.c}\
${LIB:/$objtype/%=/386/%}\
</sys/src/cmd/mksyslib