More cleanup.
[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 <vfs.h>
11 #include <kfs.h>
12 #include <slab.h>
13 #include <kmalloc.h>
14 #include <kref.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <assert.h>
18 #include <error.h>
19 #include <cpio.h>
20 #include <pmap.h>
21 #include <smp.h>
22 #include <ip.h>
23 #include <arch/io.h>
24 #include <acpi.h>
25
26 struct Rbus {
27         struct Rbus     *next;
28         int     devno;
29         struct Rdt      *rdt;
30 };
31
32 struct Rdt {
33         struct apic     *apic;
34         int     intin;
35         uint32_t        lo;
36
37         int     ref;                            /* could map to multiple busses */
38         int     enabled;                                /* times enabled */
39 };
40
41 enum {                                          /* IOAPIC registers */
42         Ioregsel        = 0x00,                 /* indirect register address */
43         Iowin           = 0x04,                 /* indirect register data */
44         Ioipa           = 0x08,                 /* IRQ Pin Assertion */
45         Ioeoi           = 0x10,                 /* EOI */
46
47         Ioapicid        = 0x00,                 /* Identification */
48         Ioapicver       = 0x01,                 /* Version */
49         Ioapicarb       = 0x02,                 /* Arbitration */
50         Ioabcfg         = 0x03,                 /* Boot Coniguration */
51         Ioredtbl        = 0x10,                 /* Redirection Table */
52 };
53
54 static struct Rdt rdtarray[Nrdt];
55 static int nrdtarray;
56 static struct Rbus* rdtbus[Nbus];
57 static struct Rdt* rdtvecno[IdtMAX+1];
58
59 static spinlock_t idtnolock;
60 static int idtno = IdtIOAPIC;
61
62 struct apic     xioapic[Napic];
63 int apiceoi(int);
64 int apicisr(int);
65 static void
66 rtblget(struct apic* apic, int sel, uint32_t* hi, uint32_t* lo)
67 {
68         sel = Ioredtbl + 2*sel;
69
70         *(apic->addr+Ioregsel) = sel+1;
71         *hi = *(apic->addr+Iowin);
72         *(apic->addr+Ioregsel) = sel;
73         *lo = *(apic->addr+Iowin);
74 }
75
76 static void
77 rtblput(struct apic* apic, int sel, uint32_t hi, uint32_t lo)
78 {
79         sel = Ioredtbl + 2*sel;
80
81         *(apic->addr+Ioregsel) = sel+1;
82         *(apic->addr+Iowin) = hi;
83         *(apic->addr+Ioregsel) = sel;
84         *(apic->addr+Iowin) = lo;
85 }
86
87 struct Rdt*
88 rdtlookup(struct apic *apic, int intin)
89 {
90         int i;
91         struct Rdt *r;
92
93         for(i = 0; i < nrdtarray; i++){
94                 r = rdtarray + i;
95                 if(apic == r->apic && intin == r->intin)
96                         return r;
97         }
98         return NULL;
99 }
100
101 /* busno is the source bus
102  * apic is the destination apic
103  * intin is the INTIN pin on the destination apic
104  * devno is the device number in the style of a PCI Interrupt
105  * Assignment Entry. Which is devno << 2? 
106  * lo is the vector table entry. We need to figure out how
107  * to compute this from acpi. We used to get it from the
108  * mptable but we would like to avoid that.
109  */
110 void
111 ioapicintrinit(int busno, int apicno, int intin, int devno, uint32_t lo)
112 {
113         struct Rbus *rbus;
114         struct Rdt *rdt;
115         struct apic *apic;
116
117         if(busno >= Nbus || apicno >= Napic || nrdtarray >= Nrdt)
118                 return;
119         apic = &xioapic[apicno];
120         if(!apic->useable || intin >= apic->nrdt)
121                 return;
122
123         rdt = rdtlookup(apic, intin);
124         if(rdt == NULL){
125                 rdt = &rdtarray[nrdtarray++];
126                 rdt->apic = apic;
127                 rdt->intin = intin;
128                 rdt->lo = lo;
129         }else{
130                 if(lo != rdt->lo){
131                         printd("mutiple irq botch bus %d %d/%d/%d lo %d vs %d\n",
132                                busno, apicno, intin, devno, lo, rdt->lo);
133                         return;
134                 }
135                 printk("dup rdt %d %d %d %d %.8ux\n", busno, apicno, intin, devno, lo);
136         }
137         rdt->ref++;
138         rbus = kzmalloc(sizeof *rbus, 0);
139         rbus->rdt = rdt;
140         rbus->devno = devno;
141         rbus->next = rdtbus[busno];
142         rdtbus[busno] = rbus;
143 }
144
145 static int map_polarity[4] = {
146         -1, IPhigh, -1, IPlow
147 };
148
149 static int map_edge_level[4] = {
150         -1, TMedge, -1, TMlevel
151 };
152 int
153 ioapic_route_irq(int irq, int apicno)
154 {
155         extern struct Madt *apics;
156         struct Madt *a = apics;
157         struct Apicst *st;
158         uint32_t lo;
159         int pol, edge_level;
160         printk("%s(%d,%d);\n", __func__, irq, apicno);
161         /* find it. */
162         for(st = apics->st; st != NULL; st = st->next){
163                 printk("Check %d, ", st->type);
164                 if (st->type == ASintovr){
165                         printk("irq of st is %d\n", st->intovr.irq);
166                         if (st->intovr.irq == irq)
167                                 break;
168                 }
169         }
170         if (! st) {
171                 printk("IRQ %d not found in MADT\n", irq);
172                 return -1;
173         }
174         
175         pol = map_polarity[st->intovr.flags & AFpmask];
176         if (pol < 0) {
177                 printk("BAD POLARITY\n");
178                 return -1;
179         }
180         
181         edge_level = map_edge_level[(st->intovr.flags&AFlevel)>>2];
182         if (edge_level < 0) {
183                 printk("BAD edge/level\n");
184                 return -1;
185         }
186         lo = pol | edge_level;
187         ioapicintrinit(0, 0, irq, /* ah shit int devno*/ 0, lo);
188         printk("FOUND the MADT for %d\n", irq);
189         return 0;
190 }
191 void
192 ioapicinit(int id, int ibase, uintptr_t pa)
193 {
194         struct apic *apic;
195         static int base;
196
197         /*
198          * Mark the IOAPIC useable if it has a good ID
199          * and the registers can be mapped.
200          */
201         if(id >= Napic)
202                 return;
203
204         apic = &xioapic[id];
205         if(apic->useable || (apic->addr = KADDR(pa)/*vmap(pa, 1024)*/) == NULL)
206                 return;
207         apic->useable = 1;
208         apic->paddr = pa;
209
210         /*
211          * Initialise the I/O APIC.
212          * The MultiProcessor Specification says it is the
213          * responsibility of the O/S to set the APIC ID.
214          */
215         spin_lock(&apic->lock);
216         *(apic->addr+Ioregsel) = Ioapicver;
217         apic->nrdt = ((*(apic->addr+Iowin)>>16) & 0xff) + 1;
218         if(ibase != -1)
219                 apic->ibase = ibase;
220         else{
221                 apic->ibase = base;
222                 base += apic->nrdt;
223         }
224         *(apic->addr+Ioregsel) = Ioapicid;
225         *(apic->addr+Iowin) = id<<24;
226         spin_unlock(&apic->lock);
227 }
228
229 char *
230 ioapicdump(char *start, char *end)
231 {
232         int i, n;
233         struct Rbus *rbus;
234         struct Rdt *rdt;
235         struct apic *apic;
236         uint32_t hi, lo;
237
238         if(!2)
239                 return start;
240         for(i = 0; i < Napic; i++){
241                 apic = &xioapic[i];
242                 if(!apic->useable || apic->addr == 0)
243                         continue;
244                 start = seprintf(start, end, "ioapic %d addr %#p nrdt %d ibase %d\n",
245                                  i, apic->addr, apic->nrdt, apic->ibase);
246                 for(n = 0; n < apic->nrdt; n++){
247                         spin_lock(&apic->lock);
248                         rtblget(apic, n, &hi, &lo);
249                         spin_unlock(&apic->lock);
250                         start = seprintf(start, end, " rdt %2.2d %#8.8p %#8.8p\n", n, hi, lo);
251                 }
252         }
253         for(i = 0; i < Nbus; i++){
254                 if((rbus = rdtbus[i]) == NULL)
255                         continue;
256                 start = seprintf(start, end, "iointr bus %d:\n", i);
257                 for(; rbus != NULL; rbus = rbus->next){
258                         rdt = rbus->rdt;
259                         start = seprintf(start, end,
260                                          " apic %ld devno %#p (%d %d) intin %d lo %#p ref %d\n",
261                                          rdt->apic-xioapic, rbus->devno, rbus->devno>>2,
262                                          rbus->devno & 0x03, rdt->intin, rdt->lo, rdt->ref);
263                 }
264         }
265         return start;
266 }
267
268 void
269 ioapiconline(void)
270 {
271         int i;
272         struct apic *apic;
273
274         for(apic = xioapic; apic < &xioapic[Napic]; apic++){
275                 if(!apic->useable || apic->addr == NULL)
276                         continue;
277                 for(i = 0; i < apic->nrdt; i++){
278                         spin_lock(&apic->lock);
279                         rtblput(apic, i, 0, Im);
280                         spin_unlock(&apic->lock);
281                 }
282         }
283 }
284
285 static int dfpolicy = 0;
286
287 static void
288 ioapicintrdd(uint32_t* hi, uint32_t* lo)
289 {
290         int i;
291         static int df;
292         static spinlock_t dflock;
293
294         /*
295          * Set delivery mode (lo) and destination field (hi),
296          * according to interrupt routing policy.
297          */
298         /*
299          * The bulk of this code was written ~1995, when there was
300          * one architecture and one generation of hardware, the number
301          * of CPUs was up to 4(8) and the choices for interrupt routing
302          * were physical, or flat logical (optionally with lowest
303          * priority interrupt). Logical mode hasn't scaled well with
304          * the increasing number of packages/cores/threads, so the
305          * fall-back is to physical mode, which works across all processor
306          * generations, both AMD and Intel, using the APIC and xAPIC.
307          *
308          * Interrupt routing policy can be set here.
309          */
310         switch(dfpolicy){
311         default:                                /* noise core 0 */
312 #warning "sys->machptr[0]->apicno --- what is this in Akaros?"
313                 *hi = 0; //sys->machptr[0]->apicno<<24;
314                 break;
315         case 1:                                 /* round-robin */
316                 /*
317                  * Assign each interrupt to a different CPU on a round-robin
318                  * Some idea of the packages/cores/thread topology would be
319                  * useful here, e.g. to not assign interrupts to more than one
320                  * thread in a core. But, as usual, Intel make that an onerous
321                  * task.
322                  */
323                 spin_lock(&dflock);
324                 for(;;){
325 #if 0
326                         i = df++;
327                         if(df >= sys->nmach+1)
328                                 df = 0;
329                         if(sys->machptr[i] == NULL || !sys->machptr[i]->online)
330                                 continue;
331                         i = sys->machptr[i]->apicno;
332 #endif
333 #warning "always picking acpino 0"
334                         i = 0;
335                         if(xlapic[i].useable && xlapic[i].addr == 0)
336                                 break;
337                 }
338                 spin_unlock(&dflock);
339
340                 *hi = i<<24;
341                 break;
342         }
343         *lo |= Pm|MTf;
344 }
345
346 int
347 nextvec(void)
348 {
349         unsigned int vecno;
350
351         spin_lock(&idtnolock);
352         vecno = idtno;
353         idtno = (idtno+8) % IdtMAX;
354         if(idtno < IdtIOAPIC)
355                 idtno += IdtIOAPIC;
356         spin_unlock(&idtnolock);
357
358         return vecno;
359 }
360
361 #warning "no msi mask yet"
362 static int
363 msimask(struct Vkey *v, int mask)
364 {
365 #if 0
366         Pcidev *p;
367         
368         p = pcimatchtbdf(v->tbdf);
369         if(p == NULL)
370                 return -1;
371         return pcimsimask(p, mask);
372 #else
373         return -1;
374 #endif
375 }
376
377 #warning "No msi yet"
378 #if 0
379 static int
380 intrenablemsi(struct vctl* v, Pcidev *p)
381 {
382         unsigned int vno, lo, hi;
383         uint64_t msivec;
384
385         vno = nextvec();
386
387         lo = IPlow | TMedge | vno;
388         ioapicintrdd(&hi, &lo);
389
390         if(lo & Lm)
391                 lo |= MTlp;
392
393         msivec = (uint64_t)hi<<32 | lo;
394         if(pcimsienable(p, msivec) == -1)
395                 return -1;
396         v->isr = apicisr;
397         v->eoi = apiceoi;
398         v->vno = vno;
399         v->type = "msi";
400         v->mask = msimask;
401
402         printk("msiirq: %T: enabling %.16llux %s irq %d vno %d\n", p->tbdf, msivec, v->name, v->irq, vno);
403         return vno;
404 }
405 #endif
406 #warning "no disable msi yet"
407 #if 0
408 int
409 disablemsi(Vctl*, Pcidev *p)
410 {
411         if(p == NULL)
412                 return -1;
413         return pcimsimask(p, 1);
414 }
415 #endif
416 int
417 ioapicintrenable(Vctl* v)
418 {
419         struct Rbus *rbus;
420         struct Rdt *rdt;
421         uint32_t hi, lo;
422         int busno = 0, devno, vecno;
423
424 /*
425  * Bridge between old and unspecified new scheme,
426  * the work in progress...
427  */
428         if(v->tbdf == BUSUNKNOWN){
429 printk("%s; BUSUNKNOWN\n", __func__);
430                 if(v->irq >= IrqLINT0 && v->irq <= MaxIrqLAPIC){
431                         if(v->irq != IrqSPURIOUS)
432                                 v->isr = apiceoi;
433                         v->type = "lapic";
434                         return v->irq;
435                 }
436                 else{
437 printk("%s; legacy isa\n", __func__);
438
439                         /*
440                          * Legacy ISA.
441                          * Make a busno and devno using the
442                          * ISA bus number and the irq.
443                          */
444 #if 0
445                         extern int mpisabusno;
446                         
447                         if(mpisabusno == -1)
448                                 panic("no ISA bus allocated");
449                         busno = mpisabusno;
450 #endif
451                         busno = 0;
452                         devno = v->irq<<2;
453                 }
454         }
455         else if(BUSTYPE(v->tbdf) == BusPCI){
456 printk("%s; BusPCI \n", __func__);
457                 /*
458                  * PCI.
459                  * Make a devno from BUSDNO(tbdf) and pcidev->intp.
460                  */
461                 /* we'll assume it's there. */
462 #if 0
463                 Pcidev *pcidev;
464                 
465                 busno = BUSBNO(v->tbdf);
466                 if((pcidev = pcimatchtbdf(v->tbdf)) == NULL)
467                         panic("no PCI dev for tbdf %#8.8ux", v->tbdf);
468                 if((vecno = intrenablemsi(v, pcidev)) != -1)
469                         return vecno;
470                 disablemsi(v, pcidev);
471 #endif
472
473                 struct pci_device pcidev;
474                 
475                 explode_tbdf(v->tbdf);
476                 devno = pcidev_read8(&pcidev, PciINTP);
477 printk("INTP is %d\n", devno);
478
479                 if(devno == 0)
480                         panic("no INTP for tbdf %#8.8ux", v->tbdf);
481                 devno = BUSDNO(v->tbdf)<<2|(devno-1);
482 printk("devno is %08lx\n", devno);
483                 printk("ioapicintrenable: tbdf %#8.8p busno %d devno %d\n",
484                        v->tbdf, busno, devno);
485         }
486         else{
487                 //SET(busno, devno);
488                 busno = devno = 0;
489                 panic("unknown tbdf %#8.8px", v->tbdf);
490         }
491         
492         rdt = NULL;
493         for(rbus = rdtbus[busno]; rbus != NULL; rbus = rbus->next){
494                 printk("Check rbus->devno %p devno %p\n", rbus->devno, devno);
495                 if(rbus->devno == devno){
496                         rdt = rbus->rdt;
497                         break;
498                 }
499         }
500         if(rdt == NULL){
501                 extern int mpisabusno;
502 printk("rdt is NULLLLLLLLLLLLLLLLLLLLLL\n");
503                 
504                 /*
505                  * First crack in the smooth exterior of the new code:
506                  * some BIOS make an MPS table where the PCI devices
507                  * are just defaulted to ISA.  Rewrite this to be
508                  * cleaner.
509                  * no MPS table in akaros.
510                 if((busno = mpisabusno) == -1)
511                         return -1;
512                  */
513                 devno = v->irq<<2;
514                 for(rbus = rdtbus[busno]; rbus != NULL; rbus = rbus->next)
515                         if(rbus->devno == devno){
516 printk("rbus->devno = %p, devno %p\n", rbus->devno, devno);
517                                 rdt = rbus->rdt;
518                                 break;
519                         }
520                 printk("isa: tbdf %#8.8ux busno %d devno %d %#p\n",
521                        v->tbdf, busno, devno, rdt);
522         }
523         if(rdt == NULL){
524                 printk("RDT Is STILL NULL!\n");
525                 return -1;
526         }
527         
528 printk("Second crack\n");
529         /*
530          * Second crack:
531          * what to do about devices that intrenable/intrdisable frequently?
532          * 1) there is no ioapicdisable yet;
533          * 2) it would be good to reuse freed vectors.
534          * Oh bugger.
535          */
536         /*
537          * This is a low-frequency event so just lock
538          * the whole IOAPIC to initialise the RDT entry
539          * rather than putting a Lock in each entry.
540          */
541         spin_lock(&rdt->apic->lock);
542         printk("%p: %ld/%d/%d (%d)\n", v->tbdf, rdt->apic - xioapic, rbus->devno, rdt->intin, devno);
543         if((rdt->lo & 0xff) == 0){
544                 vecno = nextvec();
545                 rdt->lo |= vecno;
546                 rdtvecno[vecno] = rdt;
547         }else
548                 printk("%p: mutiple irq bus %d dev %d\n", v->tbdf, busno, devno);
549
550         rdt->enabled++;
551         lo = (rdt->lo & ~Im);
552         ioapicintrdd(&hi, &lo);
553         rtblput(rdt->apic, rdt->intin, hi, lo);
554         vecno = lo & 0xff;
555         spin_unlock(&rdt->apic->lock);
556
557         printk("busno %d devno %d hi %#8.8p lo %#8.8p vecno %d\n",
558                busno, devno, hi, lo, vecno);
559         v->isr = apicisr;
560         v->eoi = apiceoi;
561         v->vno = vecno;
562         v->type = "ioapic";
563
564         return vecno;
565 }
566
567 int
568 ioapicintrdisable(int vecno)
569 {
570         struct Rdt *rdt;
571
572         /*
573          * FOV. Oh dear. This isn't very good.
574          * Fortunately rdtvecno[vecno] is static
575          * once assigned.
576          * Must do better.
577          *
578          * What about any pending interrupts?
579          */
580         if(vecno < 0 || vecno > MaxVectorAPIC){
581                 panic("ioapicintrdisable: vecno %d out of range", vecno);
582                 return -1;
583         }
584         if((rdt = rdtvecno[vecno]) == NULL){
585                 panic("ioapicintrdisable: vecno %d has no rdt", vecno);
586                 return -1;
587         }
588         
589         spin_lock(&rdt->apic->lock);
590         rdt->enabled--;
591         if(rdt->enabled == 0)
592                 rtblput(rdt->apic, rdt->intin, 0, rdt->lo);
593         spin_unlock(&rdt->apic->lock);
594         
595         return 0;
596 }
597
598 spinlock_t vctllock;
599
600 void*
601 intrenable(int irq, void (*f)(void*, void*), void* a, int tbdf)
602 {
603         int vno;
604         Vctl *v;
605         extern int ioapicintrenable(Vctl*);
606
607         if(f == NULL){
608                 printk("intrenable: nil handler for %d, tbdf %p\n",
609                        irq, tbdf);
610                 return NULL;
611         }
612
613         v = kzmalloc(sizeof(Vctl), KMALLOC_WAIT);
614         v->isintr = 1;
615         v->irq = irq;
616         v->tbdf = tbdf;
617         v->f = f;
618         v->a = a;
619
620         //spilock(&vctllock);
621         vno = ioapicintrenable(v);
622         printk("INTRENABLE, vno is %d\n", vno);
623         if(vno == -1){
624                 //iunlock(&vctllock);
625                 printk("intrenable: couldn't enable irq %d, tbdf %p for %s\n",
626                         irq, tbdf, v->name);
627                 kfree(v);
628                 return NULL;
629         }
630 #if 0
631         if(vctl[vno]){
632                 if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi)
633                         panic("intrenable: handler: %s %s %#p %#p %#p %#p",
634                                 vctl[v->vno]->name, v->name,
635                                 vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi);
636         }
637
638         v->vno = vno;
639         v->next = vctl[vno];
640         vctl[vno] = v;
641 #endif
642         //iunlock(&vctllock);
643
644         if(v->mask)
645                 v->mask(v, 0);
646
647         /*
648          * Return the assigned vector so intrdisable can find
649          * the handler; the IRQ is useless in the wonderful world
650          * of the IOAPIC.
651          */
652         printk("INTRNABLE returns %d\n", v);
653         return v;
654 }