mp.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "ureg.h"
  8. #include "mp.h"
  9. #include "apbootstrap.h"
  10. #define dprint(...) if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
  11. /* from mpacpi.c */
  12. Apic *bootapic;
  13. int mpdebug;
  14. void (*mpacpifunc)(void);
  15. static PCMP* mppcmp;
  16. static Bus* mpbus;
  17. static Bus* mpbuslast;
  18. static int mpisabus = -1;
  19. static int mpeisabus = -1;
  20. extern int i8259elcr; /* mask of level-triggered interrupts */
  21. /* static */ Apic mpapic[MaxAPICNO+1];
  22. /* static */ int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */
  23. /* static */ Apic ioapic[MaxAPICNO+1];
  24. static Ref mpvnoref; /* unique vector assignment */
  25. static int mpmachno = 1;
  26. static Lock mpphysidlock;
  27. static int mpphysid;
  28. static char* buses[] = {
  29. "CBUSI ",
  30. "CBUSII",
  31. "EISA ",
  32. "FUTURE",
  33. "INTERN",
  34. "ISA ",
  35. "MBI ",
  36. "MBII ",
  37. "MCA ",
  38. "MPI ",
  39. "MPSA ",
  40. "NUBUS ",
  41. "PCI ",
  42. "PCMCIA",
  43. "TC ",
  44. "VL ",
  45. "VME ",
  46. "XPRESS",
  47. 0,
  48. };
  49. static Apic*
  50. mkprocessor(PCMPprocessor* p)
  51. {
  52. int apicno;
  53. Apic *apic;
  54. apicno = p->apicno;
  55. if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
  56. return 0;
  57. apic = &mpapic[apicno];
  58. apic->type = PcmpPROCESSOR;
  59. apic->apicno = apicno;
  60. apic->flags = p->flags;
  61. apic->lintr[0] = ApicIMASK;
  62. apic->lintr[1] = ApicIMASK;
  63. if(p->flags & PcmpBP){
  64. machno2apicno[0] = apicno;
  65. apic->machno = 0;
  66. }
  67. else{
  68. machno2apicno[mpmachno] = apicno;
  69. apic->machno = mpmachno;
  70. mpmachno++;
  71. }
  72. return apic;
  73. }
  74. static Bus*
  75. mkbus(PCMPbus* p)
  76. {
  77. Bus *bus;
  78. int i;
  79. for(i = 0; buses[i]; i++){
  80. if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
  81. break;
  82. }
  83. if(buses[i] == 0)
  84. return 0;
  85. bus = xalloc(sizeof(Bus));
  86. if(mpbus)
  87. mpbuslast->next = bus;
  88. else
  89. mpbus = bus;
  90. mpbuslast = bus;
  91. bus->type = i;
  92. bus->busno = p->busno;
  93. if(bus->type == BusEISA){
  94. bus->po = PcmpLOW;
  95. bus->el = PcmpLEVEL;
  96. if(mpeisabus != -1)
  97. print("mkbus: more than one EISA bus\n");
  98. mpeisabus = bus->busno;
  99. }
  100. else if(bus->type == BusPCI){
  101. bus->po = PcmpLOW;
  102. bus->el = PcmpLEVEL;
  103. }
  104. else if(bus->type == BusISA){
  105. bus->po = PcmpHIGH;
  106. bus->el = PcmpEDGE;
  107. if(mpisabus != -1)
  108. print("mkbus: more than one ISA bus\n");
  109. mpisabus = bus->busno;
  110. }
  111. else{
  112. bus->po = PcmpHIGH;
  113. bus->el = PcmpEDGE;
  114. }
  115. return bus;
  116. }
  117. static Bus*
  118. mpgetbus(int busno)
  119. {
  120. Bus *bus;
  121. for(bus = mpbus; bus; bus = bus->next){
  122. if(bus->busno == busno)
  123. return bus;
  124. }
  125. print("mpgetbus: can't find bus %d\n", busno);
  126. return 0;
  127. }
  128. static Apic*
  129. mkioapic(PCMPioapic* p)
  130. {
  131. void *va;
  132. int apicno;
  133. Apic *apic;
  134. apicno = p->apicno;
  135. if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
  136. return 0;
  137. /*
  138. * Map the I/O APIC.
  139. */
  140. if((va = vmap(p->addr, 1024)) == nil)
  141. return 0;
  142. apic = &ioapic[apicno];
  143. apic->type = PcmpIOAPIC;
  144. apic->apicno = apicno;
  145. apic->addr = va;
  146. apic->paddr = p->addr;
  147. apic->flags = p->flags;
  148. return apic;
  149. }
  150. static Aintr*
  151. mkiointr(PCMPintr* p)
  152. {
  153. Bus *bus;
  154. Aintr *aintr;
  155. PCMPintr* pcmpintr;
  156. /*
  157. * According to the MultiProcessor Specification, a destination
  158. * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
  159. * It's unclear how that can possibly be correct so treat it as
  160. * an error for now.
  161. */
  162. if(p->apicno == 0xFF)
  163. return 0;
  164. if((bus = mpgetbus(p->busno)) == 0)
  165. return 0;
  166. aintr = xalloc(sizeof(Aintr));
  167. aintr->intr = p;
  168. if(0)
  169. dprint("mkiointr: type %d intr type %d flags %#o "
  170. "bus %d irq %d apicno %d intin %d\n",
  171. p->type, p->intr, p->flags,
  172. p->busno, p->irq, p->apicno, p->intin);
  173. /*
  174. * Hack for Intel SR1520ML motherboard, which BIOS describes
  175. * the i82575 dual ethernet controllers incorrectly.
  176. */
  177. if(mppcmp && memcmp(mppcmp->product, "INTEL X38MLST ", 20) == 0){
  178. if(p->busno == 1 && p->intin == 16 && p->irq == 1){
  179. pcmpintr = malloc(sizeof(PCMPintr));
  180. if(pcmpintr == nil)
  181. panic("mkiointr: no memory");
  182. memmove(pcmpintr, p, sizeof(PCMPintr));
  183. print("mkiointr: %20.20s bus %d intin %d irq %d\n",
  184. (char*)mppcmp->product,
  185. pcmpintr->busno, pcmpintr->intin,
  186. pcmpintr->irq);
  187. pcmpintr->intin = 17;
  188. aintr->intr = pcmpintr;
  189. }
  190. }
  191. if ((unsigned)p->apicno >= nelem(mpapic))
  192. panic("mkiointr: apic %d out of range", p->apicno);
  193. aintr->apic = &ioapic[p->apicno];
  194. aintr->next = bus->aintr;
  195. bus->aintr = aintr;
  196. return aintr;
  197. }
  198. static int
  199. mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
  200. {
  201. int el, po, v;
  202. /*
  203. * Parse an I/O or Local APIC interrupt table entry and
  204. * return the encoded vector.
  205. */
  206. v = vno;
  207. po = intr->flags & PcmpPOMASK;
  208. el = intr->flags & PcmpELMASK;
  209. switch(intr->intr){
  210. default: /* PcmpINT */
  211. v |= ApicFIXED; /* no-op */
  212. break;
  213. case PcmpNMI:
  214. v |= ApicNMI;
  215. po = PcmpHIGH;
  216. el = PcmpEDGE;
  217. break;
  218. case PcmpSMI:
  219. v |= ApicSMI;
  220. break;
  221. case PcmpExtINT:
  222. v |= ApicExtINT;
  223. /*
  224. * The AMI Goliath doesn't boot successfully with it's LINTR0
  225. * entry which decodes to low+level. The PPro manual says ExtINT
  226. * should be level, whereas the Pentium is edge. Setting the
  227. * Goliath to edge+high seems to cure the problem. Other PPro
  228. * MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes
  229. * to edge+high, so who knows.
  230. * Perhaps it would be best just to not set an ExtINT entry at
  231. * all, it shouldn't be needed for SMP mode.
  232. */
  233. po = PcmpHIGH;
  234. el = PcmpEDGE;
  235. break;
  236. }
  237. /*
  238. */
  239. if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){
  240. po = PcmpHIGH;
  241. el = PcmpEDGE;
  242. }
  243. if(!po)
  244. po = bus->po;
  245. if(po == PcmpLOW)
  246. v |= ApicLOW;
  247. else if(po != PcmpHIGH){
  248. print("mpintrinit: bad polarity 0x%uX\n", po);
  249. return ApicIMASK;
  250. }
  251. if(!el)
  252. el = bus->el;
  253. if(el == PcmpLEVEL)
  254. v |= ApicLEVEL;
  255. else if(el != PcmpEDGE){
  256. print("mpintrinit: bad trigger 0x%uX\n", el);
  257. return ApicIMASK;
  258. }
  259. return v;
  260. }
  261. static int
  262. mklintr(PCMPintr* p)
  263. {
  264. Apic *apic;
  265. Bus *bus;
  266. int intin, v;
  267. /*
  268. * The offsets of vectors for LINT[01] are known to be
  269. * 0 and 1 from the local APIC vector space at VectorLAPIC.
  270. */
  271. if((bus = mpgetbus(p->busno)) == 0)
  272. return 0;
  273. intin = p->intin;
  274. /*
  275. * Pentium Pros have problems if LINT[01] are set to ExtINT
  276. * so just bag it, SMP mode shouldn't need ExtINT anyway.
  277. */
  278. if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
  279. v = ApicIMASK;
  280. else
  281. v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
  282. if(p->apicno == 0xFF){
  283. for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
  284. if((apic->flags & PcmpEN)
  285. && apic->type == PcmpPROCESSOR)
  286. apic->lintr[intin] = v;
  287. }
  288. }
  289. else{
  290. if ((unsigned)p->apicno >= nelem(mpapic))
  291. panic("mklintr: ioapic %d out of range", p->apicno);
  292. apic = &mpapic[p->apicno];
  293. if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR)
  294. apic->lintr[intin] = v;
  295. }
  296. return v;
  297. }
  298. static void
  299. checkmtrr(void)
  300. {
  301. int i, vcnt;
  302. Mach *mach0;
  303. /*
  304. * If there are MTRR registers, snarf them for validation.
  305. */
  306. if(!(m->cpuiddx & Mtrr))
  307. return;
  308. rdmsr(0x0FE, &m->mtrrcap);
  309. rdmsr(0x2FF, &m->mtrrdef);
  310. if(m->mtrrcap & 0x0100){
  311. rdmsr(0x250, &m->mtrrfix[0]);
  312. rdmsr(0x258, &m->mtrrfix[1]);
  313. rdmsr(0x259, &m->mtrrfix[2]);
  314. for(i = 0; i < 8; i++)
  315. rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
  316. }
  317. vcnt = m->mtrrcap & 0x00FF;
  318. if(vcnt > nelem(m->mtrrvar))
  319. vcnt = nelem(m->mtrrvar);
  320. for(i = 0; i < vcnt; i++)
  321. rdmsr(0x200+i, &m->mtrrvar[i]);
  322. /*
  323. * If not the bootstrap processor, compare.
  324. */
  325. if(m->machno == 0)
  326. return;
  327. mach0 = MACHP(0);
  328. if(mach0->mtrrcap != m->mtrrcap)
  329. print("mtrrcap%d: %lluX %lluX\n",
  330. m->machno, mach0->mtrrcap, m->mtrrcap);
  331. if(mach0->mtrrdef != m->mtrrdef)
  332. print("mtrrdef%d: %lluX %lluX\n",
  333. m->machno, mach0->mtrrdef, m->mtrrdef);
  334. for(i = 0; i < 11; i++){
  335. if(mach0->mtrrfix[i] != m->mtrrfix[i])
  336. print("mtrrfix%d: i%d: %lluX %lluX\n",
  337. m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
  338. }
  339. for(i = 0; i < vcnt; i++){
  340. if(mach0->mtrrvar[i] != m->mtrrvar[i])
  341. print("mtrrvar%d: i%d: %lluX %lluX\n",
  342. m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
  343. }
  344. }
  345. static void
  346. squidboy(Apic* apic)
  347. {
  348. // iprint("Hello Squidboy\n");
  349. machinit();
  350. mmuinit();
  351. cpuidentify();
  352. cpuidprint();
  353. checkmtrr();
  354. apic->online = 1;
  355. coherence();
  356. lapicinit(apic);
  357. lapiconline();
  358. syncclock();
  359. timersinit();
  360. fpoff();
  361. lock(&active);
  362. active.machs |= 1<<m->machno;
  363. unlock(&active);
  364. while(!active.thunderbirdsarego)
  365. microdelay(100);
  366. schedinit();
  367. }
  368. static void
  369. mpstartap(Apic* apic)
  370. {
  371. ulong *apbootp, *pdb, *pte;
  372. Mach *mach, *mach0;
  373. int i, machno;
  374. uchar *p;
  375. mach0 = MACHP(0);
  376. /*
  377. * Initialise the AP page-tables and Mach structure. The page-tables
  378. * are the same as for the bootstrap processor with the exception of
  379. * the PTE for the Mach structure.
  380. * Xspanalloc will panic if an allocation can't be made.
  381. */
  382. p = xspanalloc(4*BY2PG, BY2PG, 0);
  383. pdb = (ulong*)p;
  384. memmove(pdb, mach0->pdb, BY2PG);
  385. p += BY2PG;
  386. if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
  387. return;
  388. memmove(p, KADDR(PPN(*pte)), BY2PG);
  389. *pte = PADDR(p)|PTEWRITE|PTEVALID;
  390. if(mach0->havepge)
  391. *pte |= PTEGLOBAL;
  392. p += BY2PG;
  393. mach = (Mach*)p;
  394. if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
  395. return;
  396. *pte = PADDR(mach)|PTEWRITE|PTEVALID;
  397. if(mach0->havepge)
  398. *pte |= PTEGLOBAL;
  399. p += BY2PG;
  400. machno = apic->machno;
  401. MACHP(machno) = mach;
  402. mach->machno = machno;
  403. mach->pdb = pdb;
  404. mach->gdt = (Segdesc*)p; /* filled by mmuinit */
  405. /*
  406. * Tell the AP where its kernel vector and pdb are.
  407. * The offsets are known in the AP bootstrap code.
  408. */
  409. apbootp = (ulong*)(APBOOTSTRAP+0x08);
  410. *apbootp++ = (ulong)squidboy; /* assembler jumps here eventually */
  411. *apbootp++ = PADDR(pdb);
  412. *apbootp = (ulong)apic;
  413. /*
  414. * Universal Startup Algorithm.
  415. */
  416. p = KADDR(0x467); /* warm-reset vector */
  417. *p++ = PADDR(APBOOTSTRAP);
  418. *p++ = PADDR(APBOOTSTRAP)>>8;
  419. i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
  420. /* code assumes i==0 */
  421. if(i != 0)
  422. print("mp: bad APBOOTSTRAP\n");
  423. *p++ = i;
  424. *p = i>>8;
  425. coherence();
  426. nvramwrite(0x0F, 0x0A); /* shutdown code: warm reset upon init ipi */
  427. lapicstartap(apic, PADDR(APBOOTSTRAP));
  428. for(i = 0; i < 1000; i++){
  429. if(apic->online)
  430. break;
  431. delay(10);
  432. }
  433. nvramwrite(0x0F, 0x00);
  434. }
  435. static void
  436. trympacpi(void)
  437. {
  438. if (mpacpifunc != nil) {
  439. print("mpinit: scanning acpi madt for extra cpus\n");
  440. (*mpacpifunc)();
  441. }
  442. }
  443. void
  444. mpinit(void)
  445. {
  446. int ncpu, cpuson;
  447. char *cp;
  448. PCMP *pcmp;
  449. uchar *e, *p;
  450. Apic *apic, *bpapic;
  451. void *va;
  452. mpdebug = getconf("*debugmp") != nil;
  453. i8259init();
  454. syncclock();
  455. bpapic = nil;
  456. cpuson = 0;
  457. if(_mp_ == 0) {
  458. /*
  459. * We can easily get processor info from ACPI, but
  460. * interrupt routing, etc. would require interpreting AML.
  461. */
  462. print("mpinit: no mp table found, assuming uniprocessor\n");
  463. archrevert();
  464. return;
  465. }
  466. pcmp = KADDR(_mp_->physaddr);
  467. /*
  468. * Map the local APIC.
  469. */
  470. if((va = vmap(pcmp->lapicbase, 1024)) == nil)
  471. return;
  472. mppcmp = pcmp;
  473. print("LAPIC: %#lux %#lux\n", pcmp->lapicbase, (ulong)va);
  474. /*
  475. * Run through the table saving information needed for starting
  476. * application processors and initialising any I/O APICs. The table
  477. * is guaranteed to be in order such that only one pass is necessary.
  478. */
  479. p = ((uchar*)pcmp)+sizeof(PCMP);
  480. e = ((uchar*)pcmp)+pcmp->length;
  481. while(p < e) switch(*p){
  482. default:
  483. print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
  484. *p, e-p);
  485. while(p < e){
  486. print("%uX ", *p);
  487. p++;
  488. }
  489. break;
  490. case PcmpPROCESSOR:
  491. if(apic = mkprocessor((PCMPprocessor*)p)){
  492. /*
  493. * Must take a note of bootstrap processor APIC
  494. * now as it will be needed in order to start the
  495. * application processors later and there's no
  496. * guarantee that the bootstrap processor appears
  497. * first in the table before the others.
  498. */
  499. apic->addr = va;
  500. apic->paddr = pcmp->lapicbase;
  501. if(apic->flags & PcmpBP)
  502. bpapic = apic;
  503. cpuson++;
  504. }
  505. p += sizeof(PCMPprocessor);
  506. continue;
  507. case PcmpBUS:
  508. mkbus((PCMPbus*)p);
  509. p += sizeof(PCMPbus);
  510. continue;
  511. case PcmpIOAPIC:
  512. if(apic = mkioapic((PCMPioapic*)p))
  513. ioapicinit(apic, ((PCMPioapic*)p)->apicno);
  514. p += sizeof(PCMPioapic);
  515. continue;
  516. case PcmpIOINTR:
  517. mkiointr((PCMPintr*)p);
  518. p += sizeof(PCMPintr);
  519. continue;
  520. case PcmpLINTR:
  521. mklintr((PCMPintr*)p);
  522. p += sizeof(PCMPintr);
  523. continue;
  524. }
  525. dprint("mpinit: mp table describes %d cpus\n", cpuson);
  526. /* For now, always scan ACPI's MADT for processors that MP missed. */
  527. trympacpi();
  528. if (bpapic == nil)
  529. bpapic = bootapic;
  530. /*
  531. * No bootstrap processor, no need to go further.
  532. */
  533. if(bpapic == 0)
  534. return;
  535. bpapic->online = 1;
  536. lapicinit(bpapic);
  537. /*
  538. * These interrupts are local to the processor
  539. * and do not appear in the I/O APIC so it is OK
  540. * to set them now.
  541. */
  542. intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
  543. intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
  544. intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
  545. lapiconline();
  546. checkmtrr();
  547. /*
  548. * Initialise the application processors.
  549. */
  550. if(cp = getconf("*ncpu")){
  551. ncpu = strtol(cp, 0, 0);
  552. if(ncpu < 1)
  553. ncpu = 1;
  554. else if(ncpu > MAXMACH)
  555. ncpu = MAXMACH;
  556. }
  557. else
  558. ncpu = MAXMACH;
  559. memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
  560. for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
  561. if(ncpu <= 1)
  562. break;
  563. if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN
  564. && apic->type == PcmpPROCESSOR){
  565. mpstartap(apic);
  566. conf.nmach++;
  567. ncpu--;
  568. }
  569. }
  570. /*
  571. * we don't really know the number of processors till
  572. * here.
  573. *
  574. * set conf.copymode here if nmach > 1.
  575. * Should look for an ExtINT line and enable it.
  576. */
  577. if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
  578. conf.copymode = 1;
  579. }
  580. static int
  581. mpintrcpu(void)
  582. {
  583. int i;
  584. /*
  585. * The bulk of this code was written ~1995, when there was
  586. * one architecture and one generation of hardware, the number
  587. * of CPUs was up to 4(8) and the choices for interrupt routing
  588. * were physical, or flat logical (optionally with lowest
  589. * priority interrupt). Logical mode hasn't scaled well with
  590. * the increasing number of packages/cores/threads, so the
  591. * fall-back is to physical mode, which works across all processor
  592. * generations, both AMD and Intel, using the APIC and xAPIC.
  593. *
  594. * Interrupt routing policy can be set here.
  595. * Currently, just assign each interrupt to a different CPU on
  596. * a round-robin basis. Some idea of the packages/cores/thread
  597. * topology would be useful here, e.g. to not assign interrupts
  598. * to more than one thread in a core, or to use a "noise" core.
  599. * But, as usual, Intel make that an onerous task.
  600. */
  601. /*
  602. * temporary workaround for many-core intel (non-amd) systems:
  603. * always use cpu 0. (TODO)
  604. */
  605. if(strncmp(m->cpuidid, "AuthenticAMD", 12) != 0 && conf.nmach > 8)
  606. return 0;
  607. lock(&mpphysidlock);
  608. for(;;){
  609. i = mpphysid++;
  610. if(mpphysid >= MaxAPICNO+1)
  611. mpphysid = 0;
  612. if(mpapic[i].online)
  613. break;
  614. }
  615. unlock(&mpphysidlock);
  616. return mpapic[i].apicno;
  617. }
  618. static int
  619. mpintrenablex(Vctl* v, int tbdf)
  620. {
  621. Bus *bus;
  622. Aintr *aintr;
  623. Apic *apic;
  624. Pcidev *pcidev;
  625. int bno, dno, hi, irq, lo, n, type, vno;
  626. char *typenm;
  627. /*
  628. * Find the bus.
  629. */
  630. type = BUSTYPE(tbdf);
  631. bno = BUSBNO(tbdf);
  632. dno = BUSDNO(tbdf);
  633. if(type == BusISA)
  634. bno = mpisabus;
  635. vno = -1;
  636. for(bus = mpbus; bus != nil; bus = bus->next){
  637. if(bus->type != type)
  638. continue;
  639. if(bus->busno == bno)
  640. break;
  641. }
  642. if(bus == nil){
  643. typenm = type < 0 || type >= nelem(buses)? "": buses[type];
  644. print("mpintrenablex: can't find bus type %d (%s) for irq %d "
  645. "%s busno %d\n", type, typenm, v->irq, v->name, bno);
  646. return -1;
  647. }
  648. /*
  649. * For PCI devices the interrupt pin (INT[ABCD]) and device
  650. * number are encoded into the entry irq field, so create something
  651. * to match on. The interrupt pin used by the device has to be
  652. * obtained from the PCI config space.
  653. */
  654. if(bus->type == BusPCI){
  655. pcidev = pcimatchtbdf(tbdf);
  656. if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0)
  657. irq = (dno<<2)|(n-1);
  658. else
  659. irq = -1;
  660. //print("pcidev %#uX: irq %#uX v->irq %#uX\n", tbdf, irq, v->irq);
  661. }
  662. else
  663. irq = v->irq;
  664. /*
  665. * Find a matching interrupt entry from the list of interrupts
  666. * attached to this bus.
  667. */
  668. for(aintr = bus->aintr; aintr; aintr = aintr->next){
  669. if(aintr->intr->irq != irq)
  670. continue;
  671. if (0) {
  672. PCMPintr* p = aintr->intr;
  673. print("mpintrenablex: bus %d intin %d irq %d\n",
  674. p->busno, p->intin, p->irq);
  675. }
  676. /*
  677. * Check if already enabled. Multifunction devices may share
  678. * INT[A-D]# so, if already enabled, check the polarity matches
  679. * and the trigger is level.
  680. *
  681. * Should check the devices differ only in the function number,
  682. * but that can wait for the planned enable/disable rewrite.
  683. * The RDT read here is safe for now as currently interrupts
  684. * are never disabled once enabled.
  685. */
  686. apic = aintr->apic;
  687. ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
  688. if(!(lo & ApicIMASK)){
  689. vno = lo & 0xFF;
  690. //print("%s vector %d (!imask)\n", v->name, vno);
  691. n = mpintrinit(bus, aintr->intr, vno, v->irq);
  692. n |= ApicPHYSICAL; /* no-op */
  693. lo &= ~(ApicRemoteIRR|ApicDELIVS);
  694. if(n != lo || !(n & ApicLEVEL)){
  695. print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
  696. v->irq, tbdf, lo, n);
  697. return -1;
  698. }
  699. break;
  700. }
  701. /*
  702. * With the APIC a unique vector can be assigned to each
  703. * request to enable an interrupt. There are two reasons this
  704. * is a good idea:
  705. * 1) to prevent lost interrupts, no more than 2 interrupts
  706. * should be assigned per block of 16 vectors (there is an
  707. * in-service entry and a holding entry for each priority
  708. * level and there is one priority level per block of 16
  709. * interrupts).
  710. * 2) each input pin on the IOAPIC will receive a different
  711. * vector regardless of whether the devices on that pin use
  712. * the same IRQ as devices on another pin.
  713. */
  714. vno = VectorAPIC + (incref(&mpvnoref)-1)*8;
  715. //print("%s vector %d (imask)\n", v->name, vno);
  716. if(vno > MaxVectorAPIC){
  717. print("mpintrenable: vno %d, irq %d, tbdf %uX\n",
  718. vno, v->irq, tbdf);
  719. return -1;
  720. }
  721. hi = mpintrcpu()<<24;
  722. lo = mpintrinit(bus, aintr->intr, vno, v->irq);
  723. //print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n",
  724. // lo, bus->busno, aintr->intr->irq, vno,
  725. // v->irq, i8259elcr);
  726. if(lo & ApicIMASK)
  727. return -1;
  728. lo |= ApicPHYSICAL; /* no-op */
  729. if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
  730. ioapicrdtw(apic, aintr->intr->intin, hi, lo);
  731. //else
  732. // print("lo not enabled 0x%uX %d\n",
  733. // apic->flags, apic->type);
  734. break;
  735. }
  736. if (aintr) {
  737. v->isr = lapicisr;
  738. v->eoi = lapiceoi;
  739. }
  740. return vno;
  741. }
  742. int
  743. mpintrenable(Vctl* v)
  744. {
  745. int irq, tbdf, vno;
  746. /*
  747. * If the bus is known, try it.
  748. * BUSUNKNOWN is given both by [E]ISA devices and by
  749. * interrupts local to the processor (local APIC, coprocessor
  750. * breakpoint and page-fault).
  751. */
  752. tbdf = v->tbdf;
  753. if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
  754. return vno;
  755. irq = v->irq;
  756. if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
  757. if(irq != IrqSPURIOUS)
  758. v->isr = lapiceoi;
  759. return VectorPIC+irq;
  760. }
  761. if(irq < 0 || irq > MaxIrqPIC){
  762. print("mpintrenable: irq %d out of range\n", irq);
  763. return -1;
  764. }
  765. /*
  766. * Either didn't find it or have to try the default buses
  767. * (ISA and EISA). This hack is due to either over-zealousness
  768. * or laziness on the part of some manufacturers.
  769. *
  770. * The MP configuration table on some older systems
  771. * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
  772. * but none for ISA. It also has the interrupt type and
  773. * polarity set to 'default for this bus' which wouldn't
  774. * be compatible with ISA.
  775. */
  776. if(mpeisabus != -1){
  777. vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
  778. if(vno != -1)
  779. return vno;
  780. }
  781. if(mpisabus != -1){
  782. vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
  783. if(vno != -1)
  784. return vno;
  785. }
  786. print("mpintrenable: out of choices eisa %d isa %d tbdf %#ux irq %d\n",
  787. mpeisabus, mpisabus, v->tbdf, v->irq);
  788. return -1;
  789. }
  790. static Lock mpshutdownlock;
  791. void
  792. mpshutdown(void)
  793. {
  794. /*
  795. * To be done...
  796. */
  797. if(!canlock(&mpshutdownlock)){
  798. /*
  799. * If this processor received the CTRL-ALT-DEL from
  800. * the keyboard, acknowledge it. Send an INIT to self.
  801. */
  802. #ifdef FIXTHIS
  803. if(lapicisr(VectorKBD))
  804. lapiceoi(VectorKBD);
  805. #endif /* FIX THIS */
  806. arch->introff();
  807. idle();
  808. }
  809. if(active.rebooting)
  810. return;
  811. print("apshutdown: active = %#8.8ux\n", active.machs);
  812. delay(1000);
  813. splhi();
  814. arch->resetothers();
  815. pcireset();
  816. i8042reset();
  817. /*
  818. * Often the BIOS hangs during restart if a conventional 8042
  819. * warm-boot sequence is tried. The following is Intel specific and
  820. * seems to perform a cold-boot, but at least it comes back.
  821. * And sometimes there is no keyboard...
  822. *
  823. * The reset register (0xcf9) is usually in one of the bridge
  824. * chips. The actual location and sequence could be extracted from
  825. * ACPI but why bother, this is the end of the line anyway.
  826. */
  827. print("no kbd; trying bios warm boot...");
  828. *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */
  829. outb(0xCF9, 0x02);
  830. outb(0xCF9, 0x06);
  831. print("can't reset\n");
  832. for(;;)
  833. idle();
  834. }