ioapic.c 20 KB

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