#include "ureg.h"
#include "mp.h"
-#include "apbootstrap.h"
+#include "apbootstrap.i"
/* filled in by pcmpinit or acpiinit */
Bus* mpbus;
return v;
}
-static void
-checkmtrr(void)
-{
- int i, vcnt;
- Mach *mach0;
-
- /*
- * If there are MTRR registers, snarf them for validation.
- */
- if(!(m->cpuiddx & Mtrr))
- return;
-
- rdmsr(0x0FE, &m->mtrrcap);
- rdmsr(0x2FF, &m->mtrrdef);
- if(m->mtrrcap & 0x0100){
- rdmsr(0x250, &m->mtrrfix[0]);
- rdmsr(0x258, &m->mtrrfix[1]);
- rdmsr(0x259, &m->mtrrfix[2]);
- for(i = 0; i < 8; i++)
- rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
- }
- vcnt = m->mtrrcap & 0x00FF;
- if(vcnt > nelem(m->mtrrvar))
- vcnt = nelem(m->mtrrvar);
- for(i = 0; i < vcnt; i++)
- rdmsr(0x200+i, &m->mtrrvar[i]);
-
- /*
- * If not the bootstrap processor, compare.
- */
- if(m->machno == 0)
- return;
-
- mach0 = MACHP(0);
- if(mach0->mtrrcap != m->mtrrcap)
- print("mtrrcap%d: %lluX %lluX\n",
- m->machno, mach0->mtrrcap, m->mtrrcap);
- if(mach0->mtrrdef != m->mtrrdef)
- print("mtrrdef%d: %lluX %lluX\n",
- m->machno, mach0->mtrrdef, m->mtrrdef);
- for(i = 0; i < 11; i++){
- if(mach0->mtrrfix[i] != m->mtrrfix[i])
- print("mtrrfix%d: i%d: %lluX %lluX\n",
- m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
- }
- for(i = 0; i < vcnt; i++){
- if(mach0->mtrrvar[i] != m->mtrrvar[i])
- print("mtrrvar%d: i%d: %lluX %lluX\n",
- m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
- }
-}
-
uvlong
tscticks(uvlong *hz)
{
}
}
-static void
-squidboy(Apic* apic)
-{
-// iprint("Hello Squidboy\n");
-
- machinit();
- mmuinit();
-
- cpuidentify();
- cpuidprint();
- checkmtrr();
-
- apic->online = 1;
-
- lapicinit(apic);
- lapiconline();
- syncclock();
- timersinit();
-
- fpoff();
-
- lock(&active);
- active.machs |= 1<<m->machno;
- unlock(&active);
-
- while(!active.thunderbirdsarego)
- microdelay(100);
-
- schedinit();
-}
-
-static void
-mpstartap(Apic* apic)
-{
- ulong *apbootp, *pdb, *pte;
- Mach *mach, *mach0;
- int i, machno;
- uchar *p;
-
- mach0 = MACHP(0);
-
- /*
- * Initialise the AP page-tables and Mach structure. The page-tables
- * are the same as for the bootstrap processor with the exception of
- * the PTE for the Mach structure.
- * Xspanalloc will panic if an allocation can't be made.
- */
- p = xspanalloc(4*BY2PG, BY2PG, 0);
- pdb = (ulong*)p;
- memmove(pdb, mach0->pdb, BY2PG);
- p += BY2PG;
-
- if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
- return;
- memmove(p, KADDR(PPN(*pte)), BY2PG);
- *pte = PADDR(p)|PTEWRITE|PTEVALID;
- if(mach0->havepge)
- *pte |= PTEGLOBAL;
- p += BY2PG;
-
- mach = (Mach*)p;
- if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
- return;
- *pte = PADDR(mach)|PTEWRITE|PTEVALID;
- if(mach0->havepge)
- *pte |= PTEGLOBAL;
- p += BY2PG;
-
- machno = apic->machno;
- MACHP(machno) = mach;
- mach->machno = machno;
- mach->pdb = pdb;
- mach->gdt = (Segdesc*)p; /* filled by mmuinit */
-
- /*
- * Tell the AP where its kernel vector and pdb are.
- * The offsets are known in the AP bootstrap code.
- */
- apbootp = (ulong*)(APBOOTSTRAP+0x08);
- *apbootp++ = (ulong)squidboy;
- *apbootp++ = PADDR(pdb);
- *apbootp = (ulong)apic;
-
- /*
- * Universal Startup Algorithm.
- */
- p = KADDR(0x467);
- *p++ = PADDR(APBOOTSTRAP);
- *p++ = PADDR(APBOOTSTRAP)>>8;
- i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
- /* code assumes i==0 */
- if(i != 0)
- print("mp: bad APBOOTSTRAP\n");
- *p++ = i;
- *p = i>>8;
-
- nvramwrite(0x0F, 0x0A);
- lapicstartap(apic, PADDR(APBOOTSTRAP));
- for(i = 0; i < 1000; i++){
- if(apic->online)
- break;
- delay(10);
- }
- nvramwrite(0x0F, 0x00);
-}
-
void
mpinit(void)
{
for(i=0; i<=MaxAPICNO; i++){
if(apic = mpapic[i])
- print("LAPIC%d: pa=%lux va=%lux flags=%x\n",
- i, apic->paddr, (ulong)apic->addr, apic->flags);
+ print("LAPIC%d: pa=%lux va=%#p flags=%x\n",
+ i, apic->paddr, apic->addr, apic->flags);
if(apic = mpioapic[i])
- print("IOAPIC%d: pa=%lux va=%lux flags=%x gsibase=%d mre=%d\n",
- i, apic->paddr, (ulong)apic->addr, apic->flags, apic->gsibase, apic->mre);
+ print("IOAPIC%d: pa=%lux va=%#p flags=%x gsibase=%d mre=%d\n",
+ i, apic->paddr, apic->addr, apic->flags, apic->gsibase, apic->mre);
}
for(b = mpbus; b; b = b->next){
print("BUS%d type=%d flags=%x\n", b->busno, b->type, b->po|b->el);
return;
}
apic->online = 1;
+
lapicinit(apic);
/*
intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
lapiconline();
- checkmtrr();
-
/*
* Initialise the application processors.
*/
for(i=0; i<nelem(mpapic); i++){
if((apic = mpapic[i]) == nil)
continue;
+ if(apic->machno >= MAXMACH)
+ continue;
if(ncpu <= 1)
break;
if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN){
* set conf.copymode here if nmach > 1.
* Should look for an ExtINT line and enable it.
*/
- if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
+ if(m->cpuidfamily == 3 || conf.nmach > 1)
conf.copymode = 1;
}
MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
};
+enum {
+ HTMSIMapping = 0xA8,
+ HTMSIFlags = 0x02,
+ HTMSIFlagsEn = 0x01,
+};
+
+static int
+htmsicapenable(Pcidev *p)
+{
+ int cap, flags;
+
+ if((cap = pcihtcap(p, HTMSIMapping)) <= 0)
+ return -1;
+ flags = pcicfgr8(p, cap + HTMSIFlags);
+ if((flags & HTMSIFlagsEn) == 0)
+ pcicfgw8(p, cap + HTMSIFlags, flags | HTMSIFlagsEn);
+ return 0;
+}
+
+static int
+htmsienable(Pcidev *pdev)
+{
+ Pcidev *p;
+
+ p = nil;
+ while((p = pcimatch(p, 0x1022, 0)) != nil)
+ if(p->did == 0x1103 || p->did == 0x1203)
+ break;
+
+ if(p == nil)
+ return 0; /* not hypertransport platform */
+
+ p = nil;
+ while((p = pcimatch(p, 0x10de, 0)) != nil){
+ switch(p->did){
+ case 0x02f0: /* NVIDIA NFORCE C51 MEMC0 */
+ case 0x02f1: /* NVIDIA NFORCE C51 MEMC1 */
+ case 0x02f2: /* NVIDIA NFORCE C51 MEMC2 */
+ case 0x02f3: /* NVIDIA NFORCE C51 MEMC3 */
+ case 0x02f4: /* NVIDIA NFORCE C51 MEMC4 */
+ case 0x02f5: /* NVIDIA NFORCE C51 MEMC5 */
+ case 0x02f6: /* NVIDIA NFORCE C51 MEMC6 */
+ case 0x02f7: /* NVIDIA NFORCE C51 MEMC7 */
+ case 0x0369: /* NVIDIA NFORCE MCP55 MEMC */
+ htmsicapenable(p);
+ break;
+ }
+ }
+
+ if(htmsicapenable(pdev) == 0)
+ return 0;
+
+ for(p = pdev->parent; p != nil; p = p->parent)
+ if(htmsicapenable(p) == 0)
+ return 0;
+
+ return -1;
+}
+
static int
msiintrenable(Vctl *v)
{
print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
return -1;
}
+ if(htmsienable(pci) < 0)
+ return -1;
cap = pcicap(pci, PciCapMSI);
if(cap < 0)
return -1;
return -1;
}
-
void
mpshutdown(void)
{
- static Lock shutdownlock;
-
/*
- * To be done...
+ * Park application processors.
*/
- if(!canlock(&shutdownlock)){
- /*
- * If this processor received the CTRL-ALT-DEL from
- * the keyboard, acknowledge it. Send an INIT to self.
- */
-#ifdef FIXTHIS
- if(lapicisr(VectorKBD))
- lapiceoi(VectorKBD);
-#endif /* FIX THIS */
+ if(m->machno != 0){
+ splhi();
arch->introff();
- idle();
+ for(;;) idle();
}
-
- print("apshutdown: active = %#8.8ux\n", active.machs);
delay(1000);
splhi();
lapicicrw(0, 0x000C0000|ApicINIT);
pcireset();
- i8042reset();
-
- /*
- * Often the BIOS hangs during restart if a conventional 8042
- * warm-boot sequence is tried. The following is Intel specific and
- * seems to perform a cold-boot, but at least it comes back.
- * And sometimes there is no keyboard...
- *
- * The reset register (0xcf9) is usually in one of the bridge
- * chips. The actual location and sequence could be extracted from
- * ACPI but why bother, this is the end of the line anyway.
- */
- print("no kbd; trying bios warm boot...");
- *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */
- outb(0xCF9, 0x02);
- outb(0xCF9, 0x06);
-
- print("can't reset\n");
- for(;;)
- idle();
}