This source file includes following definitions.
- ioapic_read
- ioapic_write
- ioapic_find
- ioapic_find_bybase
- ioapic_add
- ioapic_print_redir
- ioapic_match
- ioapic_set_id
- ioapic_attach
- apic_set_redir
- apic_vectorset
- ioapic_enable
- apic_intr_establish
- apic_intr_disestablish
- apic_stray
- ioapic_dump
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/device.h>
77 #include <sys/malloc.h>
78
79 #include <machine/bus.h>
80 #include <machine/psl.h>
81
82 #include <uvm/uvm_extern.h>
83
84 #include <machine/i82093reg.h>
85 #include <machine/i82093var.h>
86
87 #include <machine/i82489reg.h>
88 #include <machine/i82489var.h>
89
90 #include <machine/pmap.h>
91
92 #include <machine/mpbiosvar.h>
93
94 #include "isa.h"
95
96
97
98
99
100 int ioapic_match(struct device *, void *, void *);
101 void ioapic_attach(struct device *, struct device *, void *);
102
103
104 extern int bus_mem_add_mapping(bus_addr_t, bus_size_t, int,
105 bus_space_handle_t *);
106
107 void apic_set_redir(struct ioapic_softc *, int);
108 void apic_vectorset(struct ioapic_softc *, int, int, int);
109
110 void apic_stray(int);
111
112 int apic_verbose = 0;
113
114 int ioapic_bsp_id = 0;
115 int ioapic_cold = 1;
116
117 struct ioapic_softc *ioapics;
118 int nioapics = 0;
119 static int ioapic_vecbase;
120
121 void ioapic_set_id(struct ioapic_softc *);
122
123
124
125
126
127 u_int16_t ioapic_id_map = (1 << IOAPIC_ID_MAX) - 1;
128
129
130
131
132
133
134
135 u_int8_t ioapic_id_remap[IOAPIC_ID_MAX];
136
137
138
139
140 static __inline u_int32_t
141 ioapic_read(struct ioapic_softc *sc, int regid)
142 {
143 u_int32_t val;
144
145
146
147
148 *(sc->sc_reg) = regid;
149 val = *sc->sc_data;
150
151 return (val);
152
153 }
154
155 static __inline void
156 ioapic_write(struct ioapic_softc *sc, int regid, int val)
157 {
158
159
160
161 *(sc->sc_reg) = regid;
162 *(sc->sc_data) = val;
163 }
164
165 struct ioapic_softc *
166 ioapic_find(int apicid)
167 {
168 struct ioapic_softc *sc;
169
170 if (apicid == MPS_ALL_APICS) {
171
172
173
174
175 if (nioapics <= 1)
176 return (ioapics);
177 panic("unsupported: all-ioapics interrupt with >1 ioapic");
178 }
179
180 for (sc = ioapics; sc != NULL; sc = sc->sc_next)
181 if (sc->sc_apicid == apicid)
182 return (sc);
183
184 return (NULL);
185 }
186
187
188
189
190
191 struct ioapic_softc *
192 ioapic_find_bybase(int vec)
193 {
194 struct ioapic_softc *sc;
195
196 for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
197 if (vec >= sc->sc_apic_vecbase &&
198 vec < (sc->sc_apic_vecbase + sc->sc_apic_sz))
199 return sc;
200 }
201
202 return NULL;
203 }
204
205 static __inline void
206 ioapic_add(struct ioapic_softc *sc)
207 {
208 sc->sc_next = ioapics;
209 ioapics = sc;
210 nioapics++;
211 }
212
213 void
214 ioapic_print_redir(struct ioapic_softc *sc, char *why, int pin)
215 {
216 u_int32_t redirlo = ioapic_read(sc, IOAPIC_REDLO(pin));
217 u_int32_t redirhi = ioapic_read(sc, IOAPIC_REDHI(pin));
218
219 apic_format_redir(sc->sc_dev.dv_xname, why, pin, redirhi, redirlo);
220 }
221
222 struct cfattach ioapic_ca = {
223 sizeof(struct ioapic_softc), ioapic_match, ioapic_attach
224 };
225
226 struct cfdriver ioapic_cd = {
227 NULL, "ioapic", DV_DULL
228 };
229
230 int
231 ioapic_match(struct device *parent, void *matchv, void *aux)
232 {
233 struct cfdata *match = (struct cfdata *)matchv;
234 struct apic_attach_args * aaa = (struct apic_attach_args *)aux;
235
236 if (strcmp(aaa->aaa_name, match->cf_driver->cd_name) == 0)
237 return (1);
238 return (0);
239 }
240
241
242 void
243 ioapic_set_id(struct ioapic_softc *sc) {
244 u_int8_t apic_id;
245
246 ioapic_write(sc, IOAPIC_ID,
247 (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK) |
248 (sc->sc_apicid << IOAPIC_ID_SHIFT));
249
250 apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
251 IOAPIC_ID_SHIFT;
252
253 if (apic_id != sc->sc_apicid)
254 printf(", can't remap to apid %d\n", sc->sc_apicid);
255 else
256 printf(", remapped to apid %d\n", sc->sc_apicid);
257 }
258
259
260
261
262 void
263 ioapic_attach(struct device *parent, struct device *self, void *aux)
264 {
265 struct ioapic_softc *sc = (struct ioapic_softc *)self;
266 struct apic_attach_args *aaa = (struct apic_attach_args *)aux;
267 int apic_id;
268 int8_t new_id;
269 bus_space_handle_t bh;
270 u_int32_t ver_sz;
271 int i, ioapic_found;
272
273 sc->sc_flags = aaa->flags;
274 sc->sc_apicid = aaa->apic_id;
275
276 printf(": apid %d pa 0x%lx", aaa->apic_id, aaa->apic_address);
277
278 if (bus_mem_add_mapping(aaa->apic_address, PAGE_SIZE, 0, &bh) != 0) {
279 printf(", map failed\n");
280 return;
281 }
282 sc->sc_reg = (volatile u_int32_t *)(bh + IOAPIC_REG);
283 sc->sc_data = (volatile u_int32_t *)(bh + IOAPIC_DATA);
284
285 ver_sz = ioapic_read(sc, IOAPIC_VER);
286 sc->sc_apic_vers = (ver_sz & IOAPIC_VER_MASK) >> IOAPIC_VER_SHIFT;
287 sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT;
288 sc->sc_apic_sz++;
289
290 if (aaa->apic_vecbase != -1)
291 sc->sc_apic_vecbase = aaa->apic_vecbase;
292 else {
293
294
295
296
297 sc->sc_apic_vecbase = ioapic_vecbase;
298 ioapic_vecbase += sc->sc_apic_sz;
299 }
300
301 if (mp_verbose) {
302 printf(", %s mode",
303 aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire");
304 }
305
306 printf(", version %x, %d pins\n", sc->sc_apic_vers, sc->sc_apic_sz);
307
308
309
310
311
312
313
314 ioapic_found = ioapic_find(sc->sc_apicid) != NULL;
315 if (cpu_info[sc->sc_apicid] != NULL || ioapic_found) {
316 printf("%s: duplicate apic id", sc->sc_dev.dv_xname);
317 new_id = ffs(ioapic_id_map) - 1;
318 if (new_id == -1) {
319 printf(" (and none free, ignoring)\n");
320 return;
321 }
322
323
324
325
326
327
328 if (!ioapic_found && !IOAPIC_REMAPPED(sc->sc_apicid))
329 IOAPIC_REMAP(sc->sc_apicid, new_id);
330 sc->sc_apicid = new_id;
331 ioapic_set_id(sc);
332 }
333 ioapic_id_map &= ~(1 << sc->sc_apicid);
334
335 ioapic_add(sc);
336
337 apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
338 IOAPIC_ID_SHIFT;
339
340 sc->sc_pins = malloc(sizeof(struct ioapic_pin) * sc->sc_apic_sz,
341 M_DEVBUF, M_WAITOK);
342
343 for (i=0; i<sc->sc_apic_sz; i++) {
344 sc->sc_pins[i].ip_handler = NULL;
345 sc->sc_pins[i].ip_next = NULL;
346 sc->sc_pins[i].ip_map = NULL;
347 sc->sc_pins[i].ip_vector = 0;
348 sc->sc_pins[i].ip_type = 0;
349 sc->sc_pins[i].ip_minlevel = 0xff;
350 sc->sc_pins[i].ip_maxlevel = 0;
351 }
352
353
354
355
356
357 if (apic_id != sc->sc_apicid) {
358 printf("%s: misconfigured as apic %d", sc->sc_dev.dv_xname,
359 apic_id);
360 ioapic_set_id(sc);
361 }
362 #if 0
363
364 if (mp_verbose)
365 for (i=0; i<sc->sc_apic_sz; i++)
366 ioapic_print_redir(sc, "boot", i);
367 #endif
368 }
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387 struct intrhand *apic_intrhand[256];
388 int apic_intrcount[256];
389 int apic_maxlevel[256];
390
391
392
393 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < APIC_ICU_LEN && (x) != 2)
394
395 void
396 apic_set_redir(struct ioapic_softc *sc, int pin)
397 {
398 u_int32_t redlo;
399 u_int32_t redhi = 0;
400 int delmode;
401
402 struct ioapic_pin *pp;
403 struct mp_intr_map *map;
404
405 pp = &sc->sc_pins[pin];
406 map = pp->ip_map;
407 redlo = (map == NULL) ? IOAPIC_REDLO_MASK : map->redir;
408 delmode = (redlo & IOAPIC_REDLO_DEL_MASK) >> IOAPIC_REDLO_DEL_SHIFT;
409
410
411 if ((delmode != 0) && (delmode != 1))
412 ;
413 else if (pp->ip_handler == NULL) {
414 redlo |= IOAPIC_REDLO_MASK;
415 } else {
416 redlo |= (pp->ip_vector & 0xff);
417 redlo &= ~IOAPIC_REDLO_DEL_MASK;
418 redlo |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT);
419 redlo &= ~IOAPIC_REDLO_DSTMOD;
420
421
422
423
424
425
426
427
428
429
430 redhi |= (ioapic_bsp_id << IOAPIC_REDHI_DEST_SHIFT);
431
432
433 if (pp->ip_type == IST_LEVEL)
434 redlo |= IOAPIC_REDLO_LEVEL;
435 else
436 redlo &= ~IOAPIC_REDLO_LEVEL;
437 if (map != NULL && ((map->flags & 3) == MPS_INTPO_DEF)) {
438 if (pp->ip_type == IST_LEVEL)
439 redlo |= IOAPIC_REDLO_ACTLO;
440 else
441 redlo &= ~IOAPIC_REDLO_ACTLO;
442 }
443 }
444
445 ioapic_write(sc, IOAPIC_REDLO(pin), IOAPIC_REDLO_MASK);
446 ioapic_write(sc, IOAPIC_REDHI(pin), redhi);
447 ioapic_write(sc, IOAPIC_REDLO(pin), redlo);
448 if (mp_verbose)
449 ioapic_print_redir(sc, "int", pin);
450 }
451
452
453
454
455
456
457 extern int fakeintr(void *);
458 extern char *isa_intr_typename(int);
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476 void
477 apic_vectorset(struct ioapic_softc *sc, int pin, int minlevel, int maxlevel)
478 {
479 struct ioapic_pin *pp = &sc->sc_pins[pin];
480 int ovector = 0;
481 int nvector = 0;
482
483 ovector = pp->ip_vector;
484
485 if (maxlevel == 0) {
486
487 pp->ip_minlevel = 0xff;
488 pp->ip_maxlevel = 0;
489 pp->ip_vector = 0;
490 } else if (maxlevel != pp->ip_maxlevel) {
491 #ifdef MPVERBOSE
492 if (minlevel != maxlevel)
493 printf("%s: pin %d shares different IPL interrupts "
494 "(%x..%x)\n", sc->sc_dev.dv_xname, pin,
495 minlevel, maxlevel);
496 #endif
497
498
499
500
501
502
503
504
505 nvector = idt_vec_alloc(minlevel, minlevel+15);
506
507 if (nvector == 0) {
508
509
510
511
512
513 panic("%s: can't alloc vector for pin %d at level %x",
514 sc->sc_dev.dv_xname, pin, maxlevel);
515 }
516 apic_maxlevel[nvector] = maxlevel;
517
518
519
520
521 idt_vec_set(nvector, apichandler[nvector & 0xf]);
522 pp->ip_vector = nvector;
523 pp->ip_minlevel = minlevel;
524 pp->ip_maxlevel = maxlevel;
525 }
526 apic_intrhand[pp->ip_vector] = pp->ip_handler;
527
528 if (ovector) {
529
530
531
532
533
534
535
536
537
538
539
540
541
542 apic_intrhand[ovector] = NULL;
543 idt_vec_free(ovector);
544 printf("freed vector %x\n", ovector);
545 }
546
547 apic_set_redir(sc, pin);
548 }
549
550
551
552
553
554 void
555 ioapic_enable(void)
556 {
557 int p, maxlevel, minlevel;
558 struct ioapic_softc *sc;
559 struct intrhand *q;
560 extern void intr_calculatemasks(void);
561
562 intr_calculatemasks();
563
564 ioapic_cold = 0;
565
566 if (ioapics == NULL)
567 return;
568
569 #if 1
570 lapic_set_softvectors();
571 lapic_set_lvt();
572 #endif
573
574 if (ioapics->sc_flags & IOAPIC_PICMODE) {
575 printf("%s: writing to IMCR to disable pics\n",
576 ioapics->sc_dev.dv_xname);
577 outb(IMCR_ADDR, IMCR_REGISTER);
578 outb(IMCR_DATA, IMCR_APIC);
579 }
580
581 #if 0
582 isa_nodefaultirq();
583 #endif
584
585 for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
586 if (mp_verbose)
587 printf("%s: enabling\n", sc->sc_dev.dv_xname);
588
589 for (p=0; p<sc->sc_apic_sz; p++) {
590 maxlevel = 0;
591 minlevel = 0xff;
592
593 for (q = sc->sc_pins[p].ip_handler; q != NULL;
594 q = q->ih_next) {
595 if (q->ih_level > maxlevel)
596 maxlevel = q->ih_level;
597 if (q->ih_level < minlevel)
598 minlevel = q->ih_level;
599 }
600 apic_vectorset(sc, p, minlevel, maxlevel);
601 }
602 }
603 }
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 void *
626 apic_intr_establish(int irq, int type, int level, int (*ih_fun)(void *),
627 void *ih_arg, char *ih_what)
628 {
629 unsigned int ioapic = APIC_IRQ_APIC(irq);
630 unsigned int intr = APIC_IRQ_PIN(irq);
631 struct ioapic_softc *sc = ioapic_find(ioapic);
632 struct ioapic_pin *pin;
633 struct intrhand **p, *q, *ih;
634 static struct intrhand fakehand = {fakeintr};
635 extern int cold;
636 int minlevel, maxlevel;
637
638 if (sc == NULL)
639 panic("apic_intr_establish: unknown ioapic %d", ioapic);
640
641 if ((irq & APIC_INT_VIA_APIC) == 0)
642 panic("apic_intr_establish of non-apic interrupt 0x%x", irq);
643
644 if (intr >= sc->sc_apic_sz || type == IST_NONE)
645 panic("apic_intr_establish: bogus intr or type");
646
647
648 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
649 if (ih == NULL)
650 panic("apic_intr_establish: can't malloc handler info");
651
652 pin = &sc->sc_pins[intr];
653 switch (pin->ip_type) {
654 case IST_NONE:
655 pin->ip_type = type;
656 break;
657 case IST_EDGE:
658 case IST_LEVEL:
659 if (type == pin->ip_type)
660 break;
661 case IST_PULSE:
662 if (type != IST_NONE) {
663
664
665
666 free(ih, M_DEVBUF);
667 return (NULL);
668 }
669 break;
670 }
671
672
673
674
675
676
677 maxlevel = level;
678 minlevel = level;
679 for (p = &pin->ip_handler; (q = *p) != NULL; p = &q->ih_next) {
680 if (q->ih_level > maxlevel)
681 maxlevel = q->ih_level;
682 if (q->ih_level < minlevel)
683 minlevel = q->ih_level;
684 }
685
686
687
688
689
690
691 fakehand.ih_level = level;
692 *p = &fakehand;
693
694
695
696
697
698
699
700 if (!ioapic_cold)
701 apic_vectorset(sc, intr, minlevel, maxlevel);
702
703 #if 0
704 apic_calculatemasks();
705 #endif
706
707
708
709
710 ih->ih_fun = ih_fun;
711 ih->ih_arg = ih_arg;
712 ih->ih_next = NULL;
713 ih->ih_level = level;
714 ih->ih_irq = irq;
715 evcount_attach(&ih->ih_count, ih_what, (void *)&pin->ip_vector,
716 &evcount_intr);
717 *p = ih;
718
719 return (ih);
720 }
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738 void
739 apic_intr_disestablish(void *arg)
740 {
741 struct intrhand *ih = arg;
742 int irq = ih->ih_irq;
743 unsigned int ioapic = APIC_IRQ_APIC(irq);
744 unsigned int intr = APIC_IRQ_PIN(irq);
745 struct ioapic_softc *sc = ioapic_find(ioapic);
746 struct ioapic_pin *pin = &sc->sc_pins[intr];
747 struct intrhand **p, *q;
748 int minlevel, maxlevel;
749
750 if (sc == NULL)
751 panic("apic_intr_disestablish: unknown ioapic %d", ioapic);
752
753 if (intr >= sc->sc_apic_sz)
754 panic("apic_intr_disestablish: bogus irq");
755
756
757
758
759
760 maxlevel = 0;
761 minlevel = 0xff;
762 for (p = &pin->ip_handler; (q = *p) != NULL && q != ih;
763 p = &q->ih_next) {
764 if (q->ih_level > maxlevel)
765 maxlevel = q->ih_level;
766 if (q->ih_level < minlevel)
767 minlevel = q->ih_level;
768 }
769
770 if (q)
771 *p = q->ih_next;
772 else
773 panic("intr_disestablish: handler not registered");
774 for (; q != NULL; q = q->ih_next) {
775 if (q->ih_level > maxlevel)
776 maxlevel = q->ih_level;
777 if (q->ih_level < minlevel)
778 minlevel = q->ih_level;
779 }
780
781 if (!ioapic_cold)
782 apic_vectorset(sc, intr, minlevel, maxlevel);
783
784 evcount_detach(&ih->ih_count);
785 free(ih, M_DEVBUF);
786 }
787
788 void
789 apic_stray(int irqnum) {
790 unsigned int apicid;
791 struct ioapic_softc *sc;
792
793 apicid = APIC_IRQ_APIC(irqnum);
794 sc = ioapic_find(apicid);
795 if (sc == NULL)
796 return;
797 printf("%s: stray interrupt %d\n", sc->sc_dev.dv_xname, irqnum);
798 }
799
800 #ifdef DDB
801 void ioapic_dump(void);
802
803 void
804 ioapic_dump(void)
805 {
806 struct ioapic_softc *sc;
807 struct ioapic_pin *ip;
808 int p;
809
810 for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
811 for (p = 0; p < sc->sc_apic_sz; p++) {
812 ip = &sc->sc_pins[p];
813 if (ip->ip_type != IST_NONE)
814 ioapic_print_redir(sc, "dump", p);
815 }
816 }
817 }
818 #endif