ioapic.c 20 KB

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