ioapic.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "apic.h"
  15. #include "io.h"
  16. #include "acpi.h"
  17. typedef struct Rbus Rbus;
  18. typedef struct Rdt Rdt;
  19. /* this cross-dependency from acpi to ioapic is from akaros, and
  20. * kind of breaks the clean model we had before, where table
  21. * parsing and hardware were completely separate. We'll try to
  22. * clean it up later.
  23. */
  24. extern Atable *apics; /* APIC info */
  25. int mpisabusno = -1;
  26. struct Rbus {
  27. Rbus *next;
  28. int devno;
  29. Rdt *rdt;
  30. };
  31. struct Rdt {
  32. Apic *apic;
  33. int intin;
  34. uint32_t lo;
  35. uint32_t hi;
  36. int ref; /* could map to multiple busses */
  37. int enabled; /* times enabled */
  38. };
  39. enum { /* IOAPIC registers */
  40. Ioregsel = 0x00, /* indirect register address */
  41. Iowin = 0x04, /* indirect register data */
  42. Ioipa = 0x08, /* IRQ Pin Assertion */
  43. Ioeoi = 0x10, /* EOI */
  44. Ioapicid = 0x00, /* Identification */
  45. Ioapicver = 0x01, /* Version */
  46. Ioapicarb = 0x02, /* Arbitration */
  47. Ioabcfg = 0x03, /* Boot Coniguration */
  48. Ioredtbl = 0x10, /* Redirection Table */
  49. };
  50. static Rdt rdtarray[Nrdt];
  51. static int nrdtarray;
  52. static int gsib;
  53. static Rbus* rdtbus[Nbus];
  54. static Rdt* rdtvecno[IdtMAX+1];
  55. static Lock idtnolock;
  56. static int idtno = IdtIOAPIC;
  57. Apic xioapic[Napic];
  58. static int map_polarity[4] = {
  59. -1, IPhigh, -1, IPlow
  60. };
  61. static int map_edge_level[4] = {
  62. -1, TMedge, -1, TMlevel
  63. };
  64. /* TODO: use the slice library for this. */
  65. typedef struct {
  66. Vctl v;
  67. uint32_t lo;
  68. int valid;
  69. } Vinfo;
  70. static Vinfo todo[1<<13];
  71. /* this is a guess. */
  72. static char todostring[1024];
  73. char *readtodo(void)
  74. {
  75. int bus, dev, i;
  76. char *p = todostring;
  77. char *e = p + sizeof(todostring);
  78. for(i = 0; i < nelem(todo); i++) {
  79. if (!todo[i].valid)
  80. continue;
  81. bus = BUSBNO(todo[i].v.Vkey.tbdf);
  82. dev = BUSDNO(todo[i].v.Vkey.tbdf);
  83. p = seprint(p, e, "0x%x 0x%x\n", bus, dev);
  84. }
  85. return todostring;
  86. }
  87. static uint32_t ioapicread(Apic*apic, int reg)
  88. {
  89. volatile uint32_t *sel = apic->Ioapic.addr+Ioregsel;
  90. volatile uint32_t *data = apic->Ioapic.addr+Iowin;
  91. *sel = reg;
  92. return *data;
  93. }
  94. static void ioapicwrite(Apic*apic, int reg, uint32_t val)
  95. {
  96. volatile uint32_t *sel = apic->Ioapic.addr+Ioregsel;
  97. volatile uint32_t *data = apic->Ioapic.addr+Iowin;
  98. *sel = reg;
  99. *data = val;
  100. }
  101. static void
  102. rtblget(Apic* apic, int sel, uint32_t* hi, uint32_t* lo)
  103. {
  104. sel = Ioredtbl + 2*sel;
  105. *hi = ioapicread(apic, sel+1);
  106. *lo = ioapicread(apic, sel);
  107. }
  108. static void
  109. rtblput(Apic* apic, int sel, uint32_t hi, uint32_t lo)
  110. {
  111. sel = Ioredtbl + 2*sel;
  112. ioapicwrite(apic, sel+1, hi);
  113. ioapicwrite(apic, sel, lo);
  114. }
  115. Rdt*
  116. rdtlookup(Apic *apic, int intin)
  117. {
  118. int i;
  119. Rdt *r;
  120. for(i = 0; i < nrdtarray; i++){
  121. r = rdtarray + i;
  122. if(apic == r->apic && intin == r->intin)
  123. return r;
  124. }
  125. return nil;
  126. }
  127. int compatible(uint32_t new, uint32_t old)
  128. {
  129. uint32_t newtop = new & ~0xff;
  130. uint32_t oldtop = old & ~0xff;
  131. uint32_t newvno = new & 0xff;
  132. print("compatible: new 0x%x, old 0x%x\n", new, old);
  133. if (new == old)
  134. return 1;
  135. print("not the same\n");
  136. if ((newvno == 0) && (newtop == oldtop))
  137. return 1;
  138. print("REALLY not the same\n");
  139. return 0;
  140. }
  141. void
  142. ioapicintrinit(int busno, int apicno, int intin, int devno, uint32_t lo)
  143. {
  144. Rbus *rbus;
  145. Rdt *rdt;
  146. Apic *apic;
  147. if(busno >= Nbus){
  148. print("ioapicintrinit: botch: Busno %d >= Nbus %d\n", busno, Nbus);
  149. return;
  150. }
  151. if (apicno >= Napic) {
  152. print("ioapicintrinit: botch: acpicno %d >= Napic %d\n", apicno, Napic);
  153. return;
  154. }
  155. if (nrdtarray >= Nrdt){
  156. print("ioapicintrinit: botch: nrdtarray %d >= Nrdt %d\n", nrdtarray, Nrdt);
  157. return;
  158. }
  159. apic = &xioapic[apicno];
  160. if(!apic->useable) {
  161. print("ioapicintrinit: botch: apic %d not marked usable\n", apicno);
  162. return;
  163. }
  164. if (intin >= apic->Ioapic.nrdt){
  165. print("ioapicintrinit: botch: initin %d >= apic->Ioapic.nrdt %d\n", intin, apic->Ioapic.nrdt);
  166. return;
  167. }
  168. rdt = rdtlookup(apic, intin);
  169. if(rdt == nil){
  170. rdt = &rdtarray[nrdtarray++];
  171. rdt->apic = apic;
  172. rdt->intin = intin;
  173. rdt->lo = lo;
  174. }else{
  175. if(! compatible(lo, rdt->lo)){
  176. print("ioapicintrinit: multiple irq botch bus %d %d/%d/%d lo %d vs %d\n",
  177. busno, apicno, intin, devno, lo, rdt->lo);
  178. return;
  179. }
  180. print("dup rdt %d %d %d %d %.8x\n", busno, apicno, intin, devno, lo);
  181. }
  182. rdt->ref++;
  183. rbus = malloc(sizeof *rbus);
  184. rbus->rdt = rdt;
  185. rbus->devno = devno;
  186. rbus->next = rdtbus[busno];
  187. rdtbus[busno] = rbus;
  188. print("%s: success\n", __func__);
  189. }
  190. static int acpi_irq2ioapic(int irq)
  191. {
  192. int ioapic_idx = 0;
  193. Apic *apic;
  194. /* with acpi, the ioapics map a global interrupt space. each covers a
  195. * window of the space from [ibase, ibase + nrdt). */
  196. for (apic = xioapic; apic < &xioapic[Napic]; apic++, ioapic_idx++) {
  197. /* addr check is just for sanity */
  198. if (!apic->useable || !apic->Ioapic.addr)
  199. continue;
  200. if ((apic->Ioapic.gsib <= irq) && (irq < apic->Ioapic.gsib + apic->Ioapic.nrdt))
  201. return ioapic_idx;
  202. }
  203. return -1;
  204. }
  205. /* Build an RDT route, like we would have had from the MP tables had they been
  206. * parsed, via ACPI.
  207. *
  208. * This only really deals with the ISA IRQs and maybe PCI ones that happen to
  209. * have an override. FWIW, on qemu the PCI NIC shows up as an ACPI intovr.
  210. *
  211. * From Brendan http://f.osdev.org/viewtopic.php?f=1&t=25951:
  212. *
  213. * Before parsing the MADT you should begin by assuming that redirection
  214. * entries 0 to 15 are used for ISA IRQs 0 to 15. The MADT's "Interrupt
  215. * Source Override Structures" will tell you when this initial/default
  216. * assumption is wrong. For example, the MADT might tell you that ISA IRQ 9
  217. * is connected to IO APIC 44 and is level triggered; and (in this case)
  218. * it'd be silly to assume that ISA IRQ 9 is also connected to IO APIC
  219. * input 9 just because IO APIC input 9 is not listed.
  220. *
  221. * For PCI IRQs, the MADT tells you nothing and you can't assume anything
  222. * at all. Sadly, you have to interpret the ACPI AML to determine how PCI
  223. * IRQs are connected to IO APIC inputs (or find some other work-around;
  224. * like implementing a motherboard driver for each different motherboard,
  225. * or some complex auto-detection scheme, or just configure PCI devices to
  226. * use MSI instead). */
  227. static int acpi_make_rdt(Vctl *v, int tbdf, int irq, int busno, int devno)
  228. {
  229. Atable *at;
  230. Apicst *st, *lst;
  231. uint32_t lo = 0;
  232. int pol, edge_level, ioapic_nr, gsi_irq;
  233. //print("acpi_make_rdt(0x%x %d %d 0x%x)\n", tbdf, irq, busno, devno);
  234. //die("acpi.make.rdt)\n");
  235. at = apics;
  236. st = nil;
  237. for (int i = 0; i < at->nchildren; i++) {
  238. lst = at->children[i]->tbl;
  239. if (lst->type == ASintovr) {
  240. if (lst->intovr.irq == irq) {
  241. st = lst;
  242. break;
  243. }
  244. }
  245. }
  246. if (st) {
  247. pol = map_polarity[st->intovr.flags & AFpmask];
  248. if (pol < 0) {
  249. print("ACPI override had bad polarity\n");
  250. return -1;
  251. }
  252. edge_level = map_edge_level[(st->intovr.flags & AFlevel) >> 2];
  253. if (edge_level < 0) {
  254. print("ACPI override had bad edge/level\n");
  255. return -1;
  256. }
  257. lo = pol | edge_level;
  258. gsi_irq = st->intovr.intr;
  259. } else {
  260. if (BUSTYPE(tbdf) == BusISA) {
  261. lo = IPhigh | TMedge;
  262. gsi_irq = irq;
  263. } else {
  264. /* Need to query ACPI at some point to handle this */
  265. print("Non-ISA IRQ %d not found in MADT, aborting\n", irq);
  266. todo[(tbdf>>11)&0x1fff].v = *v;
  267. todo[(tbdf>>11)&0x1fff].lo = lo | TMlevel | IPlow | Im;
  268. todo[(tbdf>>11)&0x1fff].valid = 1;
  269. print("Set todo[0x%x] to valid\n", (tbdf>>11)&0x1fff);
  270. return -1;
  271. }
  272. }
  273. ioapic_nr = acpi_irq2ioapic(gsi_irq);
  274. if (ioapic_nr < 0) {
  275. print("Could not find an IOAPIC for global irq %d!\n", gsi_irq);
  276. return -1;
  277. }
  278. ioapicintrinit(busno, ioapic_nr, gsi_irq - xioapic[ioapic_nr].Ioapic.gsib,
  279. devno, lo);
  280. return 0;
  281. }
  282. void
  283. ioapicinit(int id, int ibase, uintptr_t pa)
  284. {
  285. Apic *apic;
  286. /*
  287. * Mark the IOAPIC useable if it has a good ID
  288. * and the registers can be mapped.
  289. */
  290. if(id >= Napic) {
  291. print("NOT setting ioapic %d useable; id must be < %d\n", id, Napic);
  292. return;
  293. }
  294. apic = &xioapic[id];
  295. if(apic->useable || (apic->Ioapic.addr = vmap(pa, 1024)) == nil)
  296. return;
  297. apic->useable = 1;
  298. apic->Ioapic.paddr = pa;
  299. /*
  300. * Initialise the I/O APIC.
  301. * The MultiProcessor Specification says it is the
  302. * responsibility of the O/S to set the APIC ID.
  303. */
  304. lock(&apic->Ioapic.l);
  305. apic->Ioapic.nrdt = ((ioapicread(apic, Ioapicver)>>16) & 0xff) + 1;
  306. if (ibase == -1) {
  307. apic->Ioapic.gsib = gsib;
  308. gsib += apic->Ioapic.nrdt;
  309. } else {
  310. apic->Ioapic.gsib = ibase;
  311. }
  312. ioapicwrite(apic, Ioapicid, id<<24);
  313. unlock(&apic->Ioapic.l);
  314. }
  315. void
  316. ioapicdump(void)
  317. {
  318. int i, n;
  319. Rbus *rbus;
  320. Rdt *rdt;
  321. Apic *apic;
  322. uint32_t hi, lo;
  323. if(!DBGFLG)
  324. return;
  325. for(i = 0; i < Napic; i++){
  326. apic = &xioapic[i];
  327. if(!apic->useable || apic->Ioapic.addr == 0)
  328. continue;
  329. print("ioapic %d addr %#p nrdt %d gsib %d\n",
  330. i, apic->Ioapic.addr, apic->Ioapic.nrdt, apic->Ioapic.gsib);
  331. for(n = 0; n < apic->Ioapic.nrdt; n++){
  332. lock(&apic->Ioapic.l);
  333. rtblget(apic, n, &hi, &lo);
  334. unlock(&apic->Ioapic.l);
  335. print(" rdt %2.2d %#8.8x %#8.8x\n", n, hi, lo);
  336. }
  337. }
  338. for(i = 0; i < Nbus; i++){
  339. if((rbus = rdtbus[i]) == nil)
  340. continue;
  341. print("iointr bus %d:\n", i);
  342. for(; rbus != nil; rbus = rbus->next){
  343. rdt = rbus->rdt;
  344. print(" apic %ld devno %#x (%d %d) intin %d lo %#x ref %d\n",
  345. rdt->apic-xioapic, rbus->devno, rbus->devno>>2,
  346. rbus->devno & 0x03, rdt->intin, rdt->lo, rdt->ref);
  347. }
  348. }
  349. }
  350. void
  351. ioapiconline(void)
  352. {
  353. int i;
  354. Apic *apic;
  355. for(apic = xioapic; apic < &xioapic[Napic]; apic++){
  356. if(!apic->useable || apic->Ioapic.addr == nil)
  357. continue;
  358. for(i = 0; i < apic->Ioapic.nrdt; i++){
  359. lock(&apic->Ioapic.l);
  360. rtblput(apic, i, 0, Im);
  361. unlock(&apic->Ioapic.l);
  362. }
  363. }
  364. ioapicdump();
  365. }
  366. void
  367. irqenable(void)
  368. {
  369. int i;
  370. Apic *apic;
  371. uint32_t hi, lo;
  372. for(apic = xioapic; apic < &xioapic[Napic]; apic++){
  373. if(!apic->useable || apic->Ioapic.addr == nil)
  374. continue;
  375. for(i = 0; i < apic->Ioapic.nrdt; i++){
  376. lock(&apic->Ioapic.l);
  377. rtblget(apic, i, &hi, &lo);
  378. /* if something is set in the vector, enable the
  379. * rdtentry */
  380. if (lo&0xff != 0)
  381. rtblput(apic, i, hi, lo & ~Im);
  382. unlock(&apic->Ioapic.l);
  383. }
  384. }
  385. ioapicdump();
  386. }
  387. static int dfpolicy = 0;
  388. static void
  389. ioapicintrdd(uint32_t* hi, uint32_t* lo)
  390. {
  391. int i;
  392. static int df;
  393. static Lock dflock;
  394. /*
  395. * Set delivery mode (lo) and destination field (hi),
  396. * according to interrupt routing policy.
  397. */
  398. /*
  399. * The bulk of this code was written ~1995, when there was
  400. * one architecture and one generation of hardware, the number
  401. * of CPUs was up to 4(8) and the choices for interrupt routing
  402. * were physical, or flat logical (optionally with lowest
  403. * priority interrupt). Logical mode hasn't scaled well with
  404. * the increasing number of packages/cores/threads, so the
  405. * fall-back is to physical mode, which works across all processor
  406. * generations, both AMD and Intel, using the APIC and xAPIC.
  407. *
  408. * Interrupt routing policy can be set here.
  409. */
  410. switch(dfpolicy){
  411. default: /* noise core 0 */
  412. *hi = sys->machptr[0]->apicno<<24;
  413. break;
  414. case 1: /* round-robin */
  415. /*
  416. * Assign each interrupt to a different CPU on a round-robin
  417. * Some idea of the packages/cores/thread topology would be
  418. * useful here, e.g. to not assign interrupts to more than one
  419. * thread in a core. But, as usual, Intel make that an onerous
  420. * task.
  421. */
  422. lock(&dflock);
  423. for(;;){
  424. i = df++;
  425. if(df >= sys->nmach+1)
  426. df = 0;
  427. if(sys->machptr[i] == nil || !sys->machptr[i]->online)
  428. continue;
  429. i = sys->machptr[i]->apicno;
  430. if(xlapic[i].useable && xlapic[i].Ioapic.addr == 0)
  431. break;
  432. }
  433. unlock(&dflock);
  434. *hi = i<<24;
  435. break;
  436. }
  437. *lo |= Pm|MTf;
  438. }
  439. int
  440. nextvec(void)
  441. {
  442. uint vecno;
  443. lock(&idtnolock);
  444. vecno = idtno;
  445. idtno = (idtno+8) % IdtMAX;
  446. if(idtno < IdtIOAPIC)
  447. idtno += IdtIOAPIC;
  448. unlock(&idtnolock);
  449. return vecno;
  450. }
  451. static int
  452. msimask(Vkey *v, int mask)
  453. {
  454. Pcidev *p;
  455. p = pcimatchtbdf(v->tbdf);
  456. if(p == nil)
  457. return -1;
  458. return pcimsimask(p, mask);
  459. }
  460. static int
  461. intrenablemsi(Vctl* v, Pcidev *p)
  462. {
  463. uint vno, lo, hi;
  464. uint64_t msivec;
  465. vno = nextvec();
  466. lo = IPlow | TMedge | vno;
  467. ioapicintrdd(&hi, &lo);
  468. if(lo & Lm)
  469. lo |= MTlp;
  470. msivec = (uint64_t)hi<<32 | lo;
  471. if(pcimsienable(p, msivec) == -1)
  472. return -1;
  473. v->isr = apicisr;
  474. v->eoi = apiceoi;
  475. v->vno = vno;
  476. v->type = "msi";
  477. v->mask = msimask;
  478. DBG("msiirq: %T: enabling %.16llx %s irq %d vno %d\n", p->tbdf, msivec, v->name, v->Vkey.irq, vno);
  479. return vno;
  480. }
  481. int
  482. disablemsi(Vctl* v, Pcidev *p)
  483. {
  484. if(p == nil)
  485. return -1;
  486. return pcimsimask(p, 1);
  487. }
  488. int
  489. ioapicintrdisable(int vecno)
  490. {
  491. Rdt *rdt;
  492. /*
  493. * FOV. Oh dear. This isn't very good.
  494. * Fortunately rdtvecno[vecno] is static
  495. * once assigned.
  496. * Must do better.
  497. *
  498. * What about any pending interrupts?
  499. */
  500. if(vecno < 0 || vecno > MaxVectorAPIC){
  501. panic("ioapicintrdisable: vecno %d out of range", vecno);
  502. return -1;
  503. }
  504. if((rdt = rdtvecno[vecno]) == nil){
  505. panic("ioapicintrdisable: vecno %d has no rdt", vecno);
  506. return -1;
  507. }
  508. lock(&rdt->apic->Ioapic.l);
  509. rdt->enabled--;
  510. if(rdt->enabled == 0)
  511. rtblput(rdt->apic, rdt->intin, 0, rdt->lo);
  512. unlock(&rdt->apic->Ioapic.l);
  513. return 0;
  514. }
  515. /* From Akaros, not sure we want this but for now ... */
  516. static int ioapic_exists(void)
  517. {
  518. /* not foolproof, if we called this before parsing */
  519. for (int i = 0; i < Napic; i++)
  520. if (xioapic[i].useable)
  521. return 1;
  522. return 0;
  523. }
  524. Rdt *rbus_get_rdt(int busno, int devno)
  525. {
  526. Rbus *rbus;
  527. for (rbus = rdtbus[busno]; rbus != nil; rbus = rbus->next) {
  528. if (rbus->devno == devno)
  529. return rbus->rdt;
  530. }
  531. return 0;
  532. }
  533. /* Attempts to init a bus interrupt, initializes Vctl, and returns the IDT
  534. * vector to use (-1 on error). If routable, the IRQ will route to core 0. The
  535. * IRQ will be masked, if possible. Call Vctl->unmask() when you're ready.
  536. *
  537. * This will determine the type of bus the device is on (LAPIC, IOAPIC, PIC,
  538. * etc), and set the appropriate fields in isr_h. If applicable, it'll also
  539. * allocate an IDT vector, such as for an IOAPIC, and route the IOAPIC entries
  540. * appropriately.
  541. *
  542. * Callers init Vctl->dev_irq and ->tbdf. tbdf encodes the bus type and the
  543. * classic PCI bus:dev:func. dev_irq may be ignored based on the bus type (e.g.
  544. * PCI, esp MSI).
  545. *
  546. * In plan9, this was ioapicintrenable(), which also unmasked. We don't have a
  547. * deinit/disable method that would tear down the route yet. All the plan9 one
  548. * did was dec enabled and mask the entry. */
  549. int bus_irq_setup(Vctl *v)
  550. {
  551. //Rbus *rbus;
  552. Rdt *rdt;
  553. int busno = -1, devno = -1, vno;
  554. Pcidev *p;
  555. if (!ioapic_exists()) {
  556. panic("%s: no ioapics?", __func__);
  557. switch (BUSTYPE(v->Vkey.tbdf)) {
  558. //case BusLAPIC:
  559. //case BusIPI:
  560. //break;
  561. default:
  562. //irq_h->check_spurious = pic_check_spurious;
  563. //v->eoi = pic_send_eoi;
  564. //irq_h->mask = pic_mask_irq;
  565. //irq_h->unmask = pic_unmask_irq;
  566. //irq_h->route_irq = 0;
  567. //irq_h->type = "pic";
  568. /* PIC devices have vector = irq + 32 */
  569. return -1; //irq_h->dev_irq + IdtPIC;
  570. }
  571. }
  572. switch (BUSTYPE(v->Vkey.tbdf)) {
  573. case BusLAPIC:
  574. /* nxm used to set the initial 'isr' method (i think equiv to our
  575. * check_spurious) to apiceoi for non-spurious lapic vectors. in
  576. * effect, i think they were sending the EOI early, and their eoi
  577. * method was 0. we're not doing that (unless we have to). */
  578. //v->check_spurious = lapic_check_spurious;
  579. v->eoi = nil; //apiceoi;
  580. v->isr = apiceoi;
  581. //v->mask = lapic_mask_irq;
  582. //v->unmask = lapic_unmask_irq;
  583. //v->route_irq = 0;
  584. v->type = "lapic";
  585. /* For the LAPIC, irq == vector */
  586. return v->Vkey.irq;
  587. case BusIPI:
  588. /* similar to LAPIC, but we don't actually have LVT entries */
  589. //v->check_spurious = lapic_check_spurious;
  590. v->eoi = apiceoi;
  591. //v->mask = 0;
  592. //v->unmask = 0;
  593. //v->route_irq = 0;
  594. v->type = "IPI";
  595. return v->Vkey.irq;
  596. case BusISA:
  597. if (mpisabusno == -1)
  598. panic("No ISA bus allocated");
  599. busno = mpisabusno;
  600. /* need to track the irq in devno in PCI interrupt assignment entry
  601. * format (see mp.c or MP spec D.3). */
  602. devno = v->Vkey.irq << 2;
  603. break;
  604. case BusPCI:
  605. p = pcimatchtbdf(v->Vkey.tbdf);
  606. if (!p) {
  607. print("No PCI dev for tbdf %p!", v->Vkey.tbdf);
  608. return -1;
  609. }
  610. if ((vno = intrenablemsi(v, p))!= -1)
  611. return vno;
  612. busno = BUSBNO(v->Vkey.tbdf);
  613. devno = pcicfgr8(p, PciINTP);
  614. /* this might not be a big deal - some PCI devices have no INTP. if
  615. * so, change our devno - 1 below. */
  616. if (devno == 0)
  617. panic("no INTP for tbdf %p", v->Vkey.tbdf);
  618. /* remember, devno is the device shifted with irq pin in bits 0-1.
  619. * we subtract 1, since the PCI intp maps 1 -> INTA, 2 -> INTB, etc,
  620. * and the MP spec uses 0 -> INTA, 1 -> INTB, etc. */
  621. devno = BUSDNO(v->Vkey.tbdf) << 2 | (devno - 1);
  622. break;
  623. default:
  624. panic("Unknown bus type, TBDF %p", v->Vkey.tbdf);
  625. }
  626. /* busno and devno are set, regardless of the bustype, enough to find rdt.
  627. * these may differ from the values in tbdf. */
  628. rdt = rbus_get_rdt(busno, devno);
  629. if (!rdt) {
  630. /* second chance. if we didn't find the item the first time, then (if
  631. * it exists at all), it wasn't in the MP tables (or we had no tables).
  632. * So maybe we can figure it out via ACPI. */
  633. acpi_make_rdt(v, v->Vkey.tbdf, v->Vkey.irq, busno, devno);
  634. rdt = rbus_get_rdt(busno, devno);
  635. }
  636. if (!rdt) {
  637. print("Unable to build IOAPIC route for irq %d\n", v->Vkey.irq);
  638. return -1;
  639. }
  640. /*
  641. * what to do about devices that intrenable/intrdisable frequently?
  642. * 1) there is no ioapicdisable yet;
  643. * 2) it would be good to reuse freed vectors.
  644. * Oh bugger.
  645. * brho: plus the diff btw mask/unmask and enable/disable is unclear
  646. */
  647. /*
  648. * This is a low-frequency event so just lock
  649. * the whole IOAPIC to initialise the RDT entry
  650. * rather than putting a Lock in each entry.
  651. */
  652. lock(&rdt->apic->Ioapic.l);
  653. /* if a destination has already been picked, we store it in the lo. this
  654. * stays around regardless of enabled/disabled, since we don't reap vectors
  655. * yet. nor do we really mess with enabled... */
  656. if ((rdt->lo & 0xff) == 0) {
  657. vno = nextvec();
  658. rdt->lo |= vno;
  659. rdtvecno[vno] = rdt;
  660. } else {
  661. print("bus_irq_setup: %p: multiple irq bus %d dev %d\n", v->Vkey.tbdf, busno, devno);
  662. }
  663. rdt->enabled++;
  664. rdt->hi = 0; /* route to 0 by default */
  665. rdt->lo |= Pm | MTf;
  666. rtblput(rdt->apic, rdt->intin, rdt->hi, rdt->lo);
  667. vno = rdt->lo & 0xff;
  668. unlock(&rdt->apic->Ioapic.l);
  669. v->type = "ioapic";
  670. v->eoi = apiceoi;
  671. v->vno = vno;
  672. v->mask = msimask;
  673. return vno;
  674. }
  675. int acpiirq(uint32_t tbdf, int gsi)
  676. {
  677. Proc *up = externup();
  678. int ioapic_nr;
  679. int busno = BUSBNO(tbdf);
  680. int pin, devno;
  681. int ix = (BUSBNO(tbdf) << 5) | BUSDNO(tbdf);
  682. Pcidev *pcidev;
  683. Vctl *v;
  684. int acpiintrenable(Vctl *v);
  685. /* for now we know it's PCI, just ignore what they told us. */
  686. tbdf = MKBUS(BusPCI, busno, BUSDNO(tbdf), 0);
  687. if((pcidev = pcimatchtbdf(tbdf)) == nil)
  688. error("No such device (any more?)");
  689. if((pin = pcicfgr8(pcidev, PciINTP)) == 0)
  690. error("no INTP for that device, which is impossible");
  691. // pcicfgw8(pcidev, PciINTL, gsi);
  692. //print("ix is %x\n", ix);
  693. if (!todo[ix].valid)
  694. error("Invalid tbdf");
  695. v = malloc(sizeof(*v));
  696. if (waserror()) {
  697. print("well, that went badly\n");
  698. free(v);
  699. nexterror();
  700. }
  701. *v = todo[ix].v;
  702. v->Vkey.irq = gsi;
  703. devno = BUSDNO(v->Vkey.tbdf)<<2|(pin-1);
  704. if (DBGFLG)
  705. print("acpiirq: tbdf %#8.8x busno %d devno %d\n",
  706. v->Vkey.tbdf, busno, devno);
  707. ioapic_nr = acpi_irq2ioapic(gsi);
  708. if (DBGFLG)
  709. print("ioapic_nr for gsi %d is %d\n", gsi, ioapic_nr);
  710. if (ioapic_nr < 0) {
  711. error("Could not find an IOAPIC for global irq!\n");
  712. }
  713. //ioapicdump();
  714. ioapicintrinit(busno, ioapic_nr, gsi - xioapic[ioapic_nr].Ioapic.gsib,
  715. devno, todo[ix].lo);
  716. if (DBGFLG)
  717. print("ioapicinrinit seems to have worked\n");
  718. poperror();
  719. todo[ix].valid = 0;
  720. //ioapicdump();
  721. acpiintrenable(v);
  722. //ioapicdump();
  723. return 0;
  724. }