Overhaul lock_test.R
[akaros.git] / kern / arch / x86 / ioapic.c
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
10 #include <slab.h>
11 #include <kmalloc.h>
12 #include <kref.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <assert.h>
16 #include <error.h>
17 #include <cpio.h>
18 #include <pmap.h>
19 #include <smp.h>
20 #include <net/ip.h>
21 #include <arch/io.h>
22 #include <acpi.h>
23 #include <trap.h>
24
25 /* Rbus chains, one for each device bus: each rbus matches a device to an rdt */
26 struct Rbus {
27         struct Rbus *next;
28         int devno;
29         struct Rdt *rdt;
30 };
31
32 /* Each rdt describes an ioapic input pin (intin, from the bus/device) */
33 struct Rdt {
34         struct apic *apic;
35         int intin;
36         uint32_t lo;            /* matches the lo in the intin, incl Im */
37         uint32_t hi;            /* matches the hi in the intin, incl routing */
38
39         int ref;                /* could map to multiple busses */
40         int enabled;            /* times enabled */
41 };
42
43 enum {                          /* IOAPIC registers */
44         Ioregsel = 0x00,        /* indirect register address */
45         Iowin = 0x10,           /* indirect register data */
46         Ioipa = 0x08,           /* IRQ Pin Assertion */
47         Ioeoi = 0x10,           /* EOI */
48
49         Ioapicid = 0x00,        /* Identification */
50         Ioapicver = 0x01,       /* Version */
51         Ioapicarb = 0x02,       /* Arbitration */
52         Ioabcfg = 0x03,         /* Boot Coniguration */
53         Ioredtbl = 0x10,        /* Redirection Table */
54 };
55
56 static struct Rdt rdtarray[Nrdt];
57 static int nrdtarray;
58 static struct Rbus *rdtbus[Nbus];
59 /* reverse mapping of IDT vector to the RDT/IOAPIC entry triggering vector */
60 static struct Rdt *rdtvecno[IdtMAX + 1];
61
62 struct apic xioapic[Napic];
63
64 static bool ioapic_exists(void)
65 {
66         /* not foolproof, if we called this before parsing */
67         for (int i = 0; i < Napic; i++)
68                 if (xioapic[i].useable)
69                         return TRUE;
70         return FALSE;
71 }
72
73 static void rtblget(struct apic *apic, int sel, uint32_t * hi, uint32_t * lo)
74 {
75         sel = Ioredtbl + 2 * sel;
76
77         write_mmreg32(apic->addr + Ioregsel, sel + 1);
78         *hi = read_mmreg32(apic->addr + Iowin);
79         write_mmreg32(apic->addr + Ioregsel, sel);
80         *lo = read_mmreg32(apic->addr + Iowin);
81 }
82
83 static void rtblput(struct apic *apic, int sel, uint32_t hi, uint32_t lo)
84 {
85         sel = Ioredtbl + 2 * sel;
86
87         write_mmreg32(apic->addr + Ioregsel, sel + 1);
88         write_mmreg32(apic->addr + Iowin, hi);
89         write_mmreg32(apic->addr + Ioregsel, sel);
90         write_mmreg32(apic->addr + Iowin, lo);
91 }
92
93 struct Rdt *rdtlookup(struct apic *apic, int intin)
94 {
95         int i;
96         struct Rdt *r;
97
98         for (i = 0; i < nrdtarray; i++) {
99                 r = rdtarray + i;
100                 if (apic == r->apic && intin == r->intin)
101                         return r;
102         }
103         return NULL;
104 }
105
106 struct Rdt *rbus_get_rdt(int busno, int devno)
107 {
108         struct Rbus *rbus;
109
110         for (rbus = rdtbus[busno]; rbus != NULL; rbus = rbus->next) {
111                 if (rbus->devno == devno)
112                         return rbus->rdt;
113         }
114         return 0;
115 }
116
117 /* builds RDT and Rbus entries, given the wiring of bus:dev to ioapicno:intin.
118  * - busno is the source bus
119  * - devno is the device number in the style of a PCI Interrupt Assignment
120  * Entry.  Which is the irq << 2 (check MP spec D.3).
121  * - ioapic is the ioapic the device is connected to
122  * - intin is the INTIN pin on the ioapic
123  * - lo is the lower part of the IOAPIC apic-message, which has the polarity and
124  * trigger mode flags. */
125 void ioapicintrinit(int busno, int ioapicno, int intin, int devno, int lo)
126 {
127         struct Rbus *rbus;
128         struct Rdt *rdt;
129         struct apic *ioapic;
130
131         if (busno >= Nbus || ioapicno >= Napic || nrdtarray >= Nrdt) {
132                 printk("Bad bus %d ioapic %d or nrdtarray %d too big\n", busno,
133                        ioapicno, nrdtarray);
134                 return;
135         }
136         ioapic = &xioapic[ioapicno];
137         if (!ioapic->useable || intin >= ioapic->nrdt) {
138                 printk("IOAPIC unusable (%d) or not enough nrdt (%d) for %d\n",
139                        ioapic->useable, ioapic->nrdt, intin);
140                 return;
141         }
142
143         rdt = rdtlookup(ioapic, intin);
144         if (rdt == NULL) {
145                 rdt = &rdtarray[nrdtarray++];
146                 rdt->apic = ioapic;
147                 rdt->intin = intin;
148                 rdt->lo = lo;
149                 rdt->hi = 0;
150         } else {
151                 /* Polarity/trigger check.  Stored lo also has the vector in
152                  * 0xff */
153                 if (lo != (rdt->lo & ~0xff)) {
154                         printk("multi-irq botch bus %d %d/%d/%d lo %d vs %d\n",
155                                busno, ioapicno, intin, devno, lo, rdt->lo);
156                         return;
157                 }
158         }
159         /* TODO: this shit is racy.  (refcnt, linked list addition) */
160         rdt->ref++;
161         rbus = kzmalloc(sizeof *rbus, 0);
162         rbus->rdt = rdt;
163         rbus->devno = devno;
164         rbus->next = rdtbus[busno];
165         rdtbus[busno] = rbus;
166 }
167
168 static int map_polarity[4] = {
169         -1, IPhigh, -1, IPlow
170 };
171
172 static int map_edge_level[4] = {
173         -1, TMedge, -1, TMlevel
174 };
175
176 static int acpi_irq2ioapic(int irq)
177 {
178         int ioapic_idx = 0;
179         struct apic *ioapic;
180         /* with acpi, the ioapics map a global interrupt space.  each covers a
181          * window of the space from [ibase, ibase + nrdt). */
182         for (ioapic = xioapic; ioapic < &xioapic[Napic]; ioapic++, ioapic_idx++)
183         {
184                 /* addr check is just for sanity */
185                 if (!ioapic->useable || !ioapic->addr)
186                         continue;
187                 if ((ioapic->ibase <= irq) &&
188                     (irq < ioapic->ibase + ioapic->nrdt))
189                         return ioapic_idx;
190         }
191         return -1;
192 }
193
194 /* Build an RDT route, like we would have had from the MP tables had they been
195  * parsed, via ACPI.
196  *
197  * This only really deals with the ISA IRQs and maybe PCI ones that happen to
198  * have an override.  FWIW, on qemu the PCI NIC shows up as an ACPI intovr.
199  *
200  * From Brendan http://f.osdev.org/viewtopic.php?f=1&t=25951:
201  *
202  *      Before parsing the MADT you should begin by assuming that redirection
203  *      entries 0 to 15 are used for ISA IRQs 0 to 15. The MADT's "Interrupt
204  *      Source Override Structures" will tell you when this initial/default
205  *      assumption is wrong. For example, the MADT might tell you that ISA IRQ 9
206  *      is connected to IO APIC 44 and is level triggered; and (in this case)
207  *      it'd be silly to assume that ISA IRQ 9 is also connected to IO APIC
208  *      input 9 just because IO APIC input 9 is not listed.
209  *
210  *      For PCI IRQs, the MADT tells you nothing and you can't assume anything
211  *      at all. Sadly, you have to interpret the ACPI AML to determine how PCI
212  *      IRQs are connected to IO APIC inputs (or find some other work-around;
213  *      like implementing a motherboard driver for each different motherboard,
214  *      or some complex auto-detection scheme, or just configure PCI devices to
215  *      use MSI instead). */
216 static int acpi_make_rdt(int tbdf, int irq, int busno, int devno)
217 {
218         struct Atable *at;
219         struct Apicst *st, *lst;
220         uint32_t lo;
221         int pol, edge_level, ioapic_nr, gsi_irq;
222
223         at = apics;
224         st = NULL;
225         for (int i = 0; i < at->nchildren; i++) {
226                 lst = at->children[i]->tbl;
227                 if (lst->type == ASintovr) {
228                         if (lst->intovr.irq == irq) {
229                                 st = lst;
230                                 break;
231                         }
232                 }
233         }
234         if (st) {
235                 pol = map_polarity[st->intovr.flags & AFpmask];
236                 if (pol < 0) {
237                         printk("ACPI override had bad polarity\n");
238                         return -1;
239                 }
240                 edge_level = map_edge_level[(st->intovr.flags & AFlevel) >> 2];
241                 if (edge_level < 0) {
242                         printk("ACPI override had bad edge/level\n");
243                         return -1;
244                 }
245                 lo = pol | edge_level;
246                 gsi_irq = st->intovr.intr;
247         } else {
248                 if (BUSTYPE(tbdf) == BusISA) {
249                         lo = IPhigh | TMedge;
250                         gsi_irq = irq;
251                 } else {
252                         /* Need to query ACPI at some point to handle this */
253                         printk("Non-ISA IRQ %d not found in MADT, aborting\n",
254                                irq);
255                         return -1;
256                 }
257         }
258         ioapic_nr = acpi_irq2ioapic(gsi_irq);
259         if (ioapic_nr < 0) {
260                 printk("Could not find an IOAPIC for global irq %d!\n",
261                        gsi_irq);
262                 return -1;
263         }
264         ioapicintrinit(busno, ioapic_nr, gsi_irq - xioapic[ioapic_nr].ibase,
265                        devno, lo);
266         return 0;
267 }
268
269 void ioapicinit(int id, int ibase, uintptr_t pa)
270 {
271         struct apic *apic;
272         static int base;
273
274         assert((IOAPIC_PBASE <= pa) &&
275                (pa + PGSIZE <= IOAPIC_PBASE + APIC_SIZE));
276         /*
277          * Mark the IOAPIC useable if it has a good ID
278          * and the registers can be mapped.
279          */
280         if (id >= Napic)
281                 return;
282
283         apic = &xioapic[id];
284         apic->addr = IOAPIC_BASE + (pa - IOAPIC_PBASE);
285         if (apic->useable)
286                 return;
287         apic->useable = 1;
288         apic->paddr = pa;
289
290         /*
291          * Initialise the I/O APIC.
292          * The MultiProcessor Specification says it is the
293          * responsibility of the O/S to set the APIC ID.
294          */
295         spin_lock(&apic->lock);
296         write_mmreg32(apic->addr + Ioregsel, Ioapicver);
297         apic->nrdt = ((read_mmreg32(apic->addr + Iowin) >> 16) & 0xff) + 1;
298         /* the ibase is the global system interrupt base, told to us by ACPI.
299          * if it's -1, we're called from mpparse, and just guess/make up our own
300          * assignments. */
301         if (ibase != -1)
302                 apic->ibase = ibase;
303         else {
304                 apic->ibase = base;
305                 base += apic->nrdt;
306         }
307         write_mmreg32(apic->addr + Ioregsel, Ioapicid);
308         write_mmreg32(apic->addr + Iowin, id << 24);
309         spin_unlock(&apic->lock);
310         printk("IOAPIC initialized at %p, nrdt %d, ibase %d\n", apic->addr,
311                apic->nrdt, apic->ibase);
312 }
313
314 char *ioapicdump(char *start, char *end)
315 {
316         int i, n;
317         struct Rbus *rbus;
318         struct Rdt *rdt;
319         struct apic *apic;
320         uint32_t hi, lo;
321
322         if (!2)
323                 return start;
324         for (i = 0; i < Napic; i++) {
325                 apic = &xioapic[i];
326                 if (!apic->useable || apic->addr == 0)
327                         continue;
328                 start = seprintf(start, end,
329                                  "ioapic %d addr %p nrdt %d ibase %d\n",
330                                  i, apic->addr, apic->nrdt, apic->ibase);
331                 for (n = 0; n < apic->nrdt; n++) {
332                         spin_lock(&apic->lock);
333                         rtblget(apic, n, &hi, &lo);
334                         spin_unlock(&apic->lock);
335                         start = seprintf(start, end, " rdt %2.2d %p %p\n",
336                                          n, hi, lo);
337                 }
338         }
339         for (i = 0; i < Nbus; i++) {
340                 if ((rbus = rdtbus[i]) == NULL)
341                         continue;
342                 start = seprintf(start, end, "iointr bus %d:\n", i);
343                 for (; rbus != NULL; rbus = rbus->next) {
344                         rdt = rbus->rdt;
345                         start = seprintf(start, end,
346                                          " apic %ld devno %p(%d %d) intin %d hi %p lo %p\n",
347                                          rdt->apic - xioapic, rbus->devno,
348                                          rbus->devno >> 2, rbus->devno & 0x03,
349                                          rdt->intin, rdt->hi, rdt->lo);
350                 }
351         }
352         return start;
353 }
354
355 /* Zeros and masks every redirect entry in every IOAPIC */
356 void ioapiconline(void)
357 {
358         int i;
359         struct apic *apic;
360
361         for (apic = xioapic; apic < &xioapic[Napic]; apic++) {
362                 if (!apic->useable || !apic->addr)
363                         continue;
364                 for (i = 0; i < apic->nrdt; i++) {
365                         spin_lock(&apic->lock);
366                         rtblput(apic, i, 0, Im);
367                         spin_unlock(&apic->lock);
368                 }
369         }
370 }
371
372 static void msi_mask_irq(struct irq_handler *irq_h, int apic_vector)
373 {
374         pci_msi_mask(irq_h->dev_private);
375 }
376
377 static void msi_unmask_irq(struct irq_handler *irq_h, int apic_vector)
378 {
379         pci_msi_unmask(irq_h->dev_private);
380 }
381
382 static void msi_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
383 {
384         pci_msi_route(irq_h->dev_private, dest);
385 }
386
387 static void msi_cleanup_irq(struct irq_handler *irq_h)
388 {
389         pci_msi_reset_vector(irq_h->dev_private);
390         put_irq_vector(irq_h->apic_vector);
391 }
392
393 static void msix_mask_irq(struct irq_handler *irq_h, int apic_vector)
394 {
395         pci_msix_mask_vector(irq_h->dev_private);
396 }
397
398 static void msix_unmask_irq(struct irq_handler *irq_h, int apic_vector)
399 {
400         pci_msix_unmask_vector(irq_h->dev_private);
401 }
402
403 static void msix_route_irq(struct irq_handler *irq_h, int apic_vector, int dest)
404 {
405         pci_msix_route_vector(irq_h->dev_private, dest);
406 }
407
408 static void msix_cleanup_irq(struct irq_handler *irq_h)
409 {
410         pci_msix_reset_vector(irq_h->dev_private);
411         kfree(irq_h->dev_private);
412         put_irq_vector(irq_h->apic_vector);
413 }
414
415 static int msi_irq_enable(struct irq_handler *irq_h, struct pci_device *p)
416 {
417         unsigned int vno, lo, hi = 0;
418         uint64_t msivec;
419         struct msix_irq_vector *linkage;
420
421         vno = get_irq_vector();
422         if (!vno) {
423                 printk("[kernel] Unable to get a vector for MSI(X)!\n");
424                 return -1;
425         }
426
427         /* routing the IRQ to core 0 (hi = 0) in physical mode (Pm) */
428         lo = IPlow | TMedge | Pm | vno;
429
430         msivec = (uint64_t) hi << 32 | lo;
431         irq_h->dev_private = pci_msix_enable(p, msivec);
432         if (!irq_h->dev_private) {
433                 if (pci_msi_enable(p, msivec) == -1) {
434                         put_irq_vector(vno);
435                         return -1;
436                 }
437                 irq_h->dev_private = p;
438                 irq_h->check_spurious = lapic_check_spurious;
439                 irq_h->eoi = lapic_send_eoi;
440                 irq_h->mask = msi_mask_irq;
441                 irq_h->unmask = msi_unmask_irq;
442                 irq_h->route_irq = msi_route_irq;
443                 irq_h->cleanup = msi_cleanup_irq;
444                 irq_h->type = "msi";
445                 printk("MSI irq: (%02x:%02x.%x): %s vector %d\n",
446                            p->bus, p->dev, p->func, irq_h->name, vno);
447                 return vno;
448         }
449         irq_h->check_spurious = lapic_check_spurious;
450         irq_h->eoi = lapic_send_eoi;
451         irq_h->mask = msix_mask_irq;
452         irq_h->unmask = msix_unmask_irq;
453         irq_h->route_irq = msix_route_irq;
454         irq_h->cleanup = msix_cleanup_irq;
455         irq_h->type = "msi-x";
456         printk("MSI-X irq: (%02x,%02x,%x): %s vector %d\n",
457                p->bus, p->dev, p->func, irq_h->name, vno);
458         return vno;
459 }
460
461 static struct Rdt *ioapic_vector2rdt(int apic_vector)
462 {
463         struct Rdt *rdt;
464
465         if (apic_vector < IdtIOAPIC || apic_vector > MaxIdtIOAPIC) {
466                 warn("ioapic vector %d out of range", apic_vector);
467                 return 0;
468         }
469         /* Fortunately rdtvecno[vecno] is static once assigned. o/w, we'll need
470          * some global sync for the callers, both for lookup and keeping rdt
471          * valid. */
472         rdt = rdtvecno[apic_vector];
473         if (!rdt) {
474                 warn("vector %d has no RDT! (did you enable it?)", apic_vector);
475                 return 0;
476         }
477         return rdt;
478 }
479
480 /* Routes the IRQ to the hw_coreid.  Will take effect immediately.  Route
481  * masking from rdt->lo will take effect.  The early return cases are probably
482  * bugs in IOAPIC irq_h setup. */
483 static void ioapic_route_irq(struct irq_handler *unused, int apic_vector,
484                              int hw_coreid)
485 {
486         struct Rdt *rdt = ioapic_vector2rdt(apic_vector);
487
488         if (!rdt) {
489                 printk("Missing IOAPIC route for vector!\n", apic_vector);
490                 return;
491         }
492         spin_lock(&rdt->apic->lock);
493         /* this bit gets set in apicinit, only if we found it via MP or ACPI */
494         if (!xlapic[hw_coreid].useable) {
495                 printk("Can't route to uninitialized LAPIC %d!\n", hw_coreid);
496                 spin_unlock(&rdt->apic->lock);
497                 return;
498         }
499         rdt->hi = hw_coreid << 24;
500         rdt->lo |= Pm | MTf;
501         rtblput(rdt->apic, rdt->intin, rdt->hi, rdt->lo);
502         spin_unlock(&rdt->apic->lock);
503 }
504
505 static void ioapic_mask_irq(struct irq_handler *unused, int apic_vector)
506 {
507         /* could store the rdt in the irq_h */
508         struct Rdt *rdt = ioapic_vector2rdt(apic_vector);
509
510         if (!rdt)
511                 return;
512         spin_lock(&rdt->apic->lock);
513         /* don't allow shared vectors to be masked.  whatever. */
514         if (rdt->enabled > 1) {
515                 spin_unlock(&rdt->apic->lock);
516                 return;
517         }
518         rdt->lo |= Im;
519         rtblput(rdt->apic, rdt->intin, rdt->hi, rdt->lo);
520         spin_unlock(&rdt->apic->lock);
521 }
522
523 static void ioapic_unmask_irq(struct irq_handler *unused, int apic_vector)
524 {
525         struct Rdt *rdt = ioapic_vector2rdt(apic_vector);
526         if (!rdt)
527                 return;
528         spin_lock(&rdt->apic->lock);
529         rdt->lo &= ~Im;
530         rtblput(rdt->apic, rdt->intin, rdt->hi, rdt->lo);
531         spin_unlock(&rdt->apic->lock);
532 }
533
534 /* Attempts to init a bus interrupt, initializes irq_h, and returns the IDT
535  * vector to use (-1 on error).  If routable, the IRQ will route to core 0.  The
536  * IRQ will be masked, if possible.  Call irq_h->unmask() when you're ready.
537  *
538  * This will determine the type of bus the device is on (LAPIC, IOAPIC, PIC,
539  * etc), and set the appropriate fields in isr_h.  If applicable, it'll also
540  * allocate an IDT vector, such as for an IOAPIC, and route the IOAPIC entries
541  * appropriately.
542  *
543  * Callers init irq_h->dev_irq and ->tbdf.  tbdf encodes the bus type and the
544  * classic PCI bus:dev:func.  dev_irq may be ignored based on the bus type (e.g.
545  * PCI, esp MSI).
546  *
547  * In plan9, this was ioapicintrenable(), which also unmasked.  We don't have a
548  * deinit/disable method that would tear down the route yet.  All the plan9 one
549  * did was dec enabled and mask the entry. */
550 int bus_irq_setup(struct irq_handler *irq_h)
551 {
552         struct Rbus *rbus;
553         struct Rdt *rdt;
554         int busno, devno, vecno;
555         struct pci_device *pcidev;
556
557         if (!ioapic_exists()) {
558                 switch (BUSTYPE(irq_h->tbdf)) {
559                         case BusLAPIC:
560                         case BusIPI:
561                                 break;
562                         default:
563                                 irq_h->check_spurious = pic_check_spurious;
564                                 irq_h->eoi = pic_send_eoi;
565                                 irq_h->mask = pic_mask_irq;
566                                 irq_h->unmask = pic_unmask_irq;
567                                 irq_h->route_irq = 0;
568                                 irq_h->type = "pic";
569                                 /* PIC devices have vector = irq + 32 */
570                                 return irq_h->dev_irq + IdtPIC;
571                 }
572         }
573         switch (BUSTYPE(irq_h->tbdf)) {
574         case BusLAPIC:
575                 /* nxm used to set the initial 'isr' method (i think equiv to
576                  * our check_spurious) to apiceoi for non-spurious lapic
577                  * vectors.  in effect, i think they were sending the EOI early,
578                  * and their eoi method was 0.  we're not doing that (unless we
579                  * have to). */
580                 irq_h->check_spurious = lapic_check_spurious;
581                 irq_h->eoi = lapic_send_eoi;
582                 irq_h->mask = lapic_mask_irq;
583                 irq_h->unmask = lapic_unmask_irq;
584                 irq_h->route_irq = 0;
585                 irq_h->type = "lapic";
586                 /* For the LAPIC, irq == vector */
587                 return irq_h->dev_irq;
588         case BusIPI:
589                 /* similar to LAPIC, but we don't actually have LVT entries */
590                 irq_h->check_spurious = lapic_check_spurious;
591                 irq_h->eoi = lapic_send_eoi;
592                 irq_h->mask = 0;
593                 irq_h->unmask = 0;
594                 irq_h->route_irq = 0;
595                 irq_h->type = "IPI";
596                 return irq_h->dev_irq;
597         case BusISA:
598                 if (mpisabusno == -1)
599                         panic("No ISA bus allocated");
600                 busno = mpisabusno;
601                 /* need to track the irq in devno in PCI interrupt assignment
602                  * entry format (see mp.c or MP spec D.3). */
603                 devno = irq_h->dev_irq << 2;
604                 break;
605         case BusPCI:
606                 pcidev = pci_match_tbdf(irq_h->tbdf);
607                 if (!pcidev) {
608                         warn("No PCI dev for tbdf %p!", irq_h->tbdf);
609                         return -1;
610                 }
611                 if ((vecno = msi_irq_enable(irq_h, pcidev)) != -1)
612                         return vecno;
613                 busno = BUSBNO(irq_h->tbdf);
614                 assert(busno == pcidev->bus);
615                 devno = pcidev_read8(pcidev, PciINTP);
616
617                 /* this might not be a big deal - some PCI devices have no INTP.
618                  * if so, change our devno - 1 below. */
619                 if (devno == 0)
620                         panic("no INTP for tbdf %p", irq_h->tbdf);
621                 /* remember, devno is the device shifted with irq pin in bits
622                  * 0-1.  we subtract 1, since the PCI intp maps 1 -> INTA, 2 ->
623                  * INTB, etc, and the MP spec uses 0 -> INTA, 1 -> INTB, etc. */
624                 devno = BUSDNO(irq_h->tbdf) << 2 | (devno - 1);
625                 break;
626         default:
627                 panic("Unknown bus type, TBDF %p", irq_h->tbdf);
628         }
629         /* busno and devno are set, regardless of the bustype, enough to find
630          * rdt.  these may differ from the values in tbdf. */
631         rdt = rbus_get_rdt(busno, devno);
632         if (!rdt) {
633                 /* second chance.  if we didn't find the item the first time,
634                  * then (if it exists at all), it wasn't in the MP tables (or we
635                  * had no tables).  So maybe we can figure it out via ACPI. */
636                 acpi_make_rdt(irq_h->tbdf, irq_h->dev_irq, busno, devno);
637                 rdt = rbus_get_rdt(busno, devno);
638         }
639         if (!rdt) {
640                 printk("Unable to build IOAPIC route for irq %d\n",
641                        irq_h->dev_irq);
642                 return -1;
643         }
644         /*
645          * what to do about devices that intrenable/intrdisable frequently?
646          * 1) there is no ioapicdisable yet;
647          * 2) it would be good to reuse freed vectors.
648          * Oh bugger.
649          * brho: plus the diff btw mask/unmask and enable/disable is unclear
650          */
651         /*
652          * This is a low-frequency event so just lock
653          * the whole IOAPIC to initialise the RDT entry
654          * rather than putting a Lock in each entry.
655          */
656         spin_lock(&rdt->apic->lock);
657         /* if a destination has already been picked, we store it in the lo.
658          * this stays around regardless of enabled/disabled, since we don't reap
659          * vectors yet.  nor do we really mess with enabled... */
660         if ((rdt->lo & 0xff) == 0) {
661                 vecno = get_irq_vector();
662                 if (!vecno) {
663                         printk("[kernel] unable to get an IOAPIC vector\n");
664                         spin_unlock(&rdt->apic->lock);
665                         return -1;
666                 }
667                 rdt->lo |= vecno;
668                 rdtvecno[vecno] = rdt;
669         } else {
670                 printd("%p: mutiple irq bus %d dev %d\n", irq_h->tbdf, busno,
671                        devno);
672         }
673         rdt->enabled++;
674         rdt->hi = 0;                    /* route to 0 by default */
675         rdt->lo |= Pm | MTf;
676         rtblput(rdt->apic, rdt->intin, rdt->hi, rdt->lo);
677         vecno = rdt->lo & 0xff;
678         spin_unlock(&rdt->apic->lock);
679
680         irq_h->check_spurious = lapic_check_spurious;
681         irq_h->eoi = lapic_send_eoi;
682         irq_h->mask = ioapic_mask_irq;
683         irq_h->unmask = ioapic_unmask_irq;
684         irq_h->route_irq = ioapic_route_irq;
685         irq_h->type = "ioapic";
686
687         return vecno;
688 }