summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/archmp.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-06-17 23:12:19 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-06-17 23:12:19 +0200
commita47521a3ede91ef06bf7938722c490893d5458f6 (patch)
tree9337bcdee5c2cea704a9a28652abb5b873947c32 /sys/src/9/pc/archmp.c
parent9cb66f310b16b51526fd3f5480b69a54589e229e (diff)
experimental acpi support for apic irq routing
Diffstat (limited to 'sys/src/9/pc/archmp.c')
-rw-r--r--sys/src/9/pc/archmp.c392
1 files changed, 355 insertions, 37 deletions
diff --git a/sys/src/9/pc/archmp.c b/sys/src/9/pc/archmp.c
index 1df3c3fbc..7d72e0462 100644
--- a/sys/src/9/pc/archmp.c
+++ b/sys/src/9/pc/archmp.c
@@ -7,7 +7,352 @@
#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_*
mpscan(uchar *addr, int len)
@@ -60,7 +405,7 @@ PCArch archmp = {
.id= "_MP_",
.ident= identify,
.reset= mpshutdown,
-.intrinit= mpinit,
+.intrinit= pcmpinit,
.intrenable= mpintrenable,
.intron= lapicintron,
.introff= lapicintroff,
@@ -72,7 +417,7 @@ static int
identify(void)
{
char *cp;
- PCMP *pcmp;
+ _MP_ *_mp_;
uchar *p, sum;
ulong length;
@@ -90,50 +435,23 @@ identify(void)
return 1;
pcmp = KADDR(_mp_->physaddr);
- if(memcmp(pcmp, "PCMP", 4))
+ if(memcmp(pcmp, "PCMP", 4)){
+ pcmp = nil;
return 1;
+ }
length = pcmp->length;
sum = 0;
for(p = (uchar*)pcmp; length; length--)
sum += *p++;
- if(sum || (pcmp->version != 1 && pcmp->version != 4))
+ if(sum || (pcmp->version != 1 && pcmp->version != 4)){
+ pcmp = nil;
return 1;
+ }
if(cpuserver && m->havetsc)
archmp.fastclock = tscticks;
- 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;
+ return 0;
}