Annotation of sys/arch/i386/i386/mpbios.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mpbios.c,v 1.22 2007/04/24 13:00:59 tom Exp $ */
2: /* $NetBSD: mpbios.c,v 1.2 2002/10/01 12:56:57 fvdl Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by RedBack Networks Inc.
10: *
11: * Author: Bill Sommerfeld
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by the NetBSD
24: * Foundation, Inc. and its contributors.
25: * 4. Neither the name of The NetBSD Foundation nor the names of its
26: * contributors may be used to endorse or promote products derived
27: * from this software without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39: * POSSIBILITY OF SUCH DAMAGE.
40: */
41:
42: /*
43: * Copyright (c) 1999 Stefan Grefen
44: *
45: * Redistribution and use in source and binary forms, with or without
46: * modification, are permitted provided that the following conditions
47: * are met:
48: * 1. Redistributions of source code must retain the above copyright
49: * notice, this list of conditions and the following disclaimer.
50: * 2. Redistributions in binary form must reproduce the above copyright
51: * notice, this list of conditions and the following disclaimer in the
52: * documentation and/or other materials provided with the distribution.
53: * 3. All advertising materials mentioning features or use of this software
54: * must display the following acknowledgement:
55: * This product includes software developed by the NetBSD
56: * Foundation, Inc. and its contributors.
57: * 4. Neither the name of The NetBSD Foundation nor the names of its
58: * contributors may be used to endorse or promote products derived
59: * from this software without specific prior written permission.
60: *
61: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
62: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
65: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71: * SUCH DAMAGE.
72: */
73: /*
74: * Derived from FreeBSD's mp_machdep.c
75: */
76: /*
77: * Copyright (c) 1996, by Steve Passe
78: * All rights reserved.
79: *
80: * Redistribution and use in source and binary forms, with or without
81: * modification, are permitted provided that the following conditions
82: * are met:
83: * 1. Redistributions of source code must retain the above copyright
84: * notice, this list of conditions and the following disclaimer.
85: * 2. The name of the developer may NOT be used to endorse or promote products
86: * derived from this software without specific prior written permission.
87: *
88: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
89: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
92: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98: * SUCH DAMAGE.
99: */
100:
101: /*
102: * The Intel MP-stuff is just one way of x86 SMP systems
103: * so only Intel MP specific stuff is here.
104: */
105:
106: #include "mpbios.h"
107:
108: #include <sys/param.h>
109: #include <sys/systm.h>
110: #include <sys/kernel.h>
111: #include <sys/device.h>
112: #include <sys/malloc.h>
113:
114: #include <uvm/uvm_extern.h>
115:
116: #include <machine/specialreg.h>
117: #include <machine/cputypes.h>
118: #include <machine/cpuvar.h>
119: #include <machine/bus.h>
120: #include <machine/mpbiosreg.h>
121: #include <machine/mpbiosvar.h>
122:
123: #include <machine/i82093reg.h>
124: #include <machine/i82093var.h>
125: #include <machine/i82489reg.h>
126: #include <machine/i82489var.h>
127:
128: #include <dev/isa/isareg.h>
129: #include <dev/pci/pcivar.h>
130:
131: #include <dev/eisa/eisavar.h> /* for ELCR* def'ns */
132:
133: #include "pci.h"
134:
135:
136: static struct mpbios_ioapic default_ioapic = {
137: 2, 0, 1, IOAPICENTRY_FLAG_EN, (caddr_t)IOAPIC_BASE_DEFAULT
138: };
139:
140: /* descriptions of MP basetable entries */
141: struct mpbios_baseentry {
142: u_int8_t type;
143: u_int8_t length;
144: u_int16_t count;
145: const char *name;
146: };
147:
148: static const char *loc_where[] = {
149: "extended bios data area",
150: "last page of base memory",
151: "bios"
152: };
153:
154: struct mp_map
155: {
156: vaddr_t baseva;
157: int vsize;
158: paddr_t pa;
159: paddr_t pg;
160: int psize;
161: };
162:
163: int mp_print(void *, const char *);
164: int mp_match(struct device *, void *, void *);
165: int mpbios_cpu_start(struct cpu_info *);
166: const void *mpbios_search(struct device *, paddr_t, int,
167: struct mp_map *);
168: static __inline int mpbios_cksum(const void *, int);
169:
170: void mp_cfg_special_intr(const struct mpbios_int *, u_int32_t *);
171: void mp_cfg_pci_intr(const struct mpbios_int *, u_int32_t *);
172: void mp_cfg_eisa_intr(const struct mpbios_int *, u_int32_t *);
173: void mp_cfg_isa_intr(const struct mpbios_int *, u_int32_t *);
174: void mp_print_special_intr (int);
175: void mp_print_pci_intr (int);
176: void mp_print_eisa_intr (int);
177: void mp_print_isa_intr (int);
178:
179: void mpbios_cpu(const u_int8_t *, struct device *);
180: void mpbios_bus(const u_int8_t *, struct device *);
181: void mpbios_ioapic(const u_int8_t *, struct device *);
182: int mpbios_int(const u_int8_t *, struct mp_intr_map *);
183:
184: const void *mpbios_map(paddr_t, int, struct mp_map *);
185: static __inline void mpbios_unmap(struct mp_map *);
186:
187: /*
188: * globals to help us bounce our way through parsing the config table.
189: */
190:
191: static struct mp_map mp_cfg_table_map;
192: static struct mp_map mp_fp_map;
193: const struct mpbios_cth *mp_cth;
194: const struct mpbios_fps *mp_fps;
195:
196: #ifdef MPVERBOSE
197: int mp_verbose = 1;
198: #else
199: int mp_verbose = 0;
200: #endif
201:
202: int
203: mp_print(void *aux, const char *pnp)
204: {
205: struct cpu_attach_args * caa = (struct cpu_attach_args *) aux;
206: if (pnp)
207: printf("%s at %s:", caa->caa_name, pnp);
208: return (UNCONF);
209: }
210:
211: int
212: mp_match(struct device *parent, void *cfv, void *aux)
213: {
214: struct cfdata *cf = (struct cfdata *)cfv;
215: struct cpu_attach_args * caa = (struct cpu_attach_args *) aux;
216: if (strcmp(caa->caa_name, cf->cf_driver->cd_name))
217: return 0;
218:
219: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
220: }
221:
222: /*
223: * Map a chunk of memory read-only and return an appropriately
224: * const'ed pointer.
225: */
226: const void *
227: mpbios_map(paddr_t pa, int len, struct mp_map *handle)
228: {
229: paddr_t pgpa = trunc_page(pa);
230: paddr_t endpa = round_page(pa + len);
231: vaddr_t va = uvm_km_valloc(kernel_map, endpa - pgpa);
232: vaddr_t retva = va + (pa & PGOFSET);
233:
234: handle->pa = pa;
235: handle->pg = pgpa;
236: handle->psize = len;
237: handle->baseva = va;
238: handle->vsize = endpa-pgpa;
239:
240: do {
241: #if 1
242: pmap_kenter_pa(va, pgpa, VM_PROT_READ);
243: #else
244: pmap_enter(pmap_kernel(), va, pgpa, VM_PROT_READ, TRUE,
245: VM_PROT_READ);
246: #endif
247: va += NBPG;
248: pgpa += NBPG;
249: } while (pgpa < endpa);
250:
251: return ((const void *)retva);
252: }
253:
254: static __inline void
255: mpbios_unmap(struct mp_map *handle)
256: {
257: #if 1
258: pmap_kremove(handle->baseva, handle->vsize);
259: #else
260: pmap_extract(pmap_kernel(), handle->baseva, NULL);
261: #endif
262: uvm_km_free(kernel_map, handle->baseva, handle->vsize);
263: }
264:
265: /*
266: * Look for an Intel MP spec table, indicating SMP capable hardware.
267: */
268: int
269: mpbios_probe(struct device *self)
270: {
271: paddr_t ebda, memtop;
272:
273: paddr_t cthpa;
274: int cthlen;
275: const u_int8_t *mpbios_page;
276: int scan_loc;
277:
278: struct mp_map t;
279:
280: /*
281: * Skip probe if someone else (e.g. acpi) already provided the
282: * necessary details.
283: */
284: if (mp_busses)
285: return (0);
286:
287: /* see if EBDA exists */
288:
289: mpbios_page = mpbios_map(0, NBPG, &t);
290:
291: /* XXX Ugly magic constants below. */
292: ebda = *(const u_int16_t *)(&mpbios_page[0x40e]);
293: ebda <<= 4;
294:
295: memtop = *(const u_int16_t *)(&mpbios_page[0x413]);
296: memtop <<= 10;
297:
298: mpbios_page = NULL;
299: mpbios_unmap(&t);
300:
301: scan_loc = 0;
302:
303: if (ebda && ebda < IOM_BEGIN ) {
304: mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map);
305: if (mp_fps != NULL)
306: goto found;
307: }
308:
309: scan_loc = 1;
310:
311: if (memtop && memtop <= IOM_BEGIN ) {
312: mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map);
313: if (mp_fps != NULL)
314: goto found;
315: }
316:
317: scan_loc = 2;
318:
319: mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map);
320: if (mp_fps != NULL)
321: goto found;
322:
323: /* nothing found */
324: return (0);
325:
326: found:
327: if (mp_verbose)
328: printf("%s: MP floating pointer found in %s at 0x%lx\n",
329: self->dv_xname, loc_where[scan_loc], mp_fp_map.pa);
330:
331: if (mp_fps->pap == 0) {
332: if (mp_fps->mpfb1 == 0) {
333: printf("%s: MP fps invalid: "
334: "no default config and no configuration table\n",
335: self->dv_xname);
336:
337: goto err;
338: }
339: printf("%s: MP default configuration %d\n",
340: self->dv_xname, mp_fps->mpfb1);
341: return (10);
342: }
343:
344: cthpa = mp_fps->pap;
345:
346: mp_cth = mpbios_map(cthpa, sizeof (*mp_cth), &mp_cfg_table_map);
347: cthlen = mp_cth->base_len;
348: mpbios_unmap(&mp_cfg_table_map);
349:
350: mp_cth = mpbios_map(cthpa, cthlen, &mp_cfg_table_map);
351:
352: if (mp_verbose)
353: printf("%s: MP config table at 0x%lx, %d bytes long\n",
354: self->dv_xname, cthpa, cthlen);
355:
356: if (mp_cth->signature != MP_CT_SIG) {
357: printf("%s: MP signature mismatch (%x vs %x)\n",
358: self->dv_xname,
359: MP_CT_SIG, mp_cth->signature);
360: goto err;
361: }
362:
363: if (mpbios_cksum(mp_cth, cthlen)) {
364: printf ("%s: MP Configuration Table checksum mismatch\n",
365: self->dv_xname);
366: goto err;
367: }
368: return (10);
369:
370: err:
371: if (mp_fps) {
372: mp_fps = NULL;
373: mpbios_unmap(&mp_fp_map);
374: }
375: if (mp_cth) {
376: mp_cth = NULL;
377: mpbios_unmap(&mp_cfg_table_map);
378: }
379: return (0);
380: }
381:
382:
383: /*
384: * Simple byte checksum used on config tables.
385: */
386:
387: static __inline int
388: mpbios_cksum(const void *start, int len)
389: {
390: unsigned char res=0;
391: const char *p = start;
392: const char *end = p + len;
393:
394: while (p < end)
395: res += *p++;
396:
397: return res;
398: }
399:
400:
401: /*
402: * Look for the MP floating pointer signature in the given physical
403: * address range.
404: *
405: * We map the memory, scan through it, and unmap it.
406: * If we find it, remap the floating pointer structure and return it.
407: */
408:
409: const void *
410: mpbios_search(struct device *self, paddr_t start, int count, struct mp_map *map)
411: {
412: struct mp_map t;
413:
414: int i, len;
415: const struct mpbios_fps *m;
416: int end = count - sizeof(*m);
417: const u_int8_t *base = mpbios_map(start, count, &t);
418:
419: if (mp_verbose)
420: printf("%s: scanning 0x%lx to 0x%lx for MP signature\n",
421: self->dv_xname, start, start + count - sizeof(*m));
422:
423: for (i = 0; i <= end; i += 4) {
424: m = (struct mpbios_fps *)&base[i];
425:
426: if ((m->signature == MP_FP_SIG) &&
427: ((len = m->length << 4) != 0) &&
428: mpbios_cksum(m, (m->length << 4)) == 0) {
429: mpbios_unmap(&t);
430:
431: return (mpbios_map(start + i, len, map));
432: }
433: }
434: mpbios_unmap(&t);
435:
436: return (0);
437: }
438:
439: /*
440: * MP configuration table parsing.
441: */
442:
443: static struct mpbios_baseentry mp_conf[] =
444: {
445: {0, 20, 0, "cpu"},
446: {1, 8, 0, "bus"},
447: {2, 8, 0, "ioapic"},
448: {3, 8, 0, "ioint"},
449: {4, 8, 0, "lint"},
450: };
451:
452: struct mp_bus *mp_busses;
453: int mp_nbus;
454: struct mp_intr_map *mp_intrs;
455: int mp_nintrs;
456:
457: struct mp_bus *mp_isa_bus;
458: struct mp_bus *mp_eisa_bus;
459:
460: static struct mp_bus extint_bus = {
461: "ExtINT",
462: -1,
463: mp_print_special_intr,
464: mp_cfg_special_intr,
465: 0
466: };
467: static struct mp_bus smi_bus = {
468: "SMI",
469: -1,
470: mp_print_special_intr,
471: mp_cfg_special_intr,
472: 0
473: };
474: static struct mp_bus nmi_bus = {
475: "NMI",
476: -1,
477: mp_print_special_intr,
478: mp_cfg_special_intr,
479: 0
480: };
481:
482:
483: /*
484: * 1st pass on BIOS's Intel MP specification table.
485: *
486: * initializes:
487: * mp_ncpus = 1
488: *
489: * determines:
490: * cpu_apic_address (common to all CPUs)
491: * ioapic_address[N]
492: * mp_naps
493: * mp_nbusses
494: * mp_napics
495: * nintrs
496: */
497: void
498: mpbios_scan(struct device *self)
499: {
500: const u_int8_t *position, *end;
501: int count;
502: int type;
503: int intr_cnt;
504: paddr_t lapic_base;
505:
506: printf("%s: Intel MP Specification ", self->dv_xname);
507:
508: switch (mp_fps->spec_rev) {
509: case 1:
510: printf("(Version 1.1)\n");
511: break;
512: case 4:
513: printf("(Version 1.4)\n");
514: break;
515: default:
516: printf("(unrecognized rev %d)\n", mp_fps->spec_rev);
517: }
518:
519: /*
520: * looks like we've got a MP system. start setting up
521: * infrastructure..
522: * XXX is this the right place??
523: */
524:
525: lapic_base = LAPIC_BASE;
526: if (mp_cth != NULL)
527: lapic_base = (paddr_t)mp_cth->apic_address;
528:
529: lapic_boot_init(lapic_base);
530:
531: /* check for use of 'default' configuration */
532: if (mp_fps->mpfb1 != 0) {
533: struct mpbios_proc pe;
534:
535: printf("\n%s: MP default configuration %d\n",
536: self->dv_xname, mp_fps->mpfb1);
537:
538: /* use default addresses */
539: pe.apic_id = cpu_number();
540: pe.cpu_flags = PROCENTRY_FLAG_EN|PROCENTRY_FLAG_BP;
541: pe.cpu_signature = cpu_info_primary.ci_signature;
542: pe.feature_flags = cpu_info_primary.ci_feature_flags;
543:
544: mpbios_cpu((u_int8_t *)&pe, self);
545:
546: pe.apic_id = 1 - cpu_number();
547: pe.cpu_flags = PROCENTRY_FLAG_EN;
548:
549: mpbios_cpu((u_int8_t *)&pe, self);
550:
551: mpbios_ioapic((u_int8_t *)&default_ioapic, self);
552:
553: /* XXX */
554: printf("%s: WARNING: interrupts not configured\n",
555: self->dv_xname);
556: panic("lazy bum");
557: return;
558: } else {
559: /*
560: * should not happen; mp_probe returns 0 in this case,
561: * but..
562: */
563: if (mp_cth == NULL)
564: panic("mpbios_scan: no config (can't happen?)");
565:
566: /*
567: * Walk the table once, counting items
568: */
569: for (count = mp_cth->entry_count,
570: position = (const u_int8_t *)mp_cth + sizeof(*mp_cth),
571: end = position + mp_cth->base_len;
572: count-- && position < end;
573: position += mp_conf[type].length) {
574:
575: type = *position;
576: if (type >= MPS_MCT_NTYPES) {
577: printf("%s: unknown entry type %x"
578: " in MP config table\n",
579: self->dv_xname, type);
580: end = position;
581: break;
582: }
583: mp_conf[type].count++;
584: }
585:
586: /*
587: * Walk the table twice, counting int and bus entries
588: */
589: for (count = mp_cth->entry_count,
590: intr_cnt = 15, /* presume all isa irqs missing */
591: position = (const u_int8_t *)mp_cth + sizeof(*mp_cth);
592: count-- && position < end;
593: position += mp_conf[type].length) {
594: type = *position;
595: if (type == MPS_MCT_BUS) {
596: const struct mpbios_bus *bp =
597: (const struct mpbios_bus *)position;
598: if (bp->bus_id >= mp_nbus)
599: mp_nbus = bp->bus_id + 1;
600: }
601:
602: /*
603: * Count actual interrupt instances.
604: * dst_apic_id of MPS_ALL_APICS means "wired to all
605: * apics of this type".
606: */
607: if ((type == MPS_MCT_IOINT) ||
608: (type == MPS_MCT_LINT)) {
609: const struct mpbios_int *ie =
610: (const struct mpbios_int *)position;
611: if (ie->dst_apic_id != MPS_ALL_APICS)
612: intr_cnt++;
613: else if (type == MPS_MCT_IOINT)
614: intr_cnt +=
615: mp_conf[MPS_MCT_IOAPIC].count;
616: else
617: intr_cnt += mp_conf[MPS_MCT_CPU].count;
618: }
619: }
620:
621: mp_busses = malloc(sizeof(struct mp_bus) * mp_nbus,
622: M_DEVBUF, M_NOWAIT);
623: memset(mp_busses, 0, sizeof(struct mp_bus) * mp_nbus);
624: mp_intrs = malloc(sizeof(struct mp_intr_map) * intr_cnt,
625: M_DEVBUF, M_NOWAIT);
626:
627: /* re-walk the table, recording info of interest */
628: position = (const u_int8_t *)mp_cth + sizeof(*mp_cth);
629: count = mp_cth->entry_count;
630: mp_nintrs = 0;
631:
632: while ((count--) && (position < end)) {
633: switch (type = *(u_char *)position) {
634: case MPS_MCT_CPU:
635: mpbios_cpu(position, self);
636: break;
637: case MPS_MCT_BUS:
638: mpbios_bus(position, self);
639: break;
640: case MPS_MCT_IOAPIC:
641: mpbios_ioapic(position, self);
642: break;
643: case MPS_MCT_IOINT:
644: case MPS_MCT_LINT:
645: if (mpbios_int(position,
646: &mp_intrs[mp_nintrs]) == 0)
647: mp_nintrs++;
648: break;
649: default:
650: printf("%s: unknown entry type %x "
651: "in MP config table\n",
652: self->dv_xname, type);
653: /* NOTREACHED */
654: return;
655: }
656:
657: (u_char*)position += mp_conf[type].length;
658: }
659: if (mp_verbose && mp_cth->ext_len)
660: printf("%s: MP WARNING: %d "
661: "bytes of extended entries not examined\n",
662: self->dv_xname, mp_cth->ext_len);
663: }
664: /* Clean up. */
665: mp_fps = NULL;
666: mpbios_unmap(&mp_fp_map);
667: if (mp_cth != NULL) {
668: mp_cth = NULL;
669: mpbios_unmap(&mp_cfg_table_map);
670: }
671:
672: #if NPCI > 0
673: if (pci_mode_detect() != 0)
674: mpbios_intr_fixup();
675: #endif
676: }
677:
678: int
679: mpbios_invent(int irq, int type, int bus)
680: {
681: struct mp_intr_map *mip;
682: struct mpbios_int e;
683:
684: e.type = MPS_MCT_IOINT;
685: e.int_type = MPS_INTTYPE_INT;
686: switch (type) {
687: case IST_EDGE:
688: e.int_flags = MPS_INT(MPS_INTPO_ACTHI, MPS_INTTR_EDGE);
689: break;
690:
691: case IST_LEVEL:
692: e.int_flags = MPS_INT(MPS_INTPO_ACTLO, MPS_INTTR_LEVEL);
693: break;
694:
695: case IST_NONE:
696: case IST_PULSE:
697: e.int_flags = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF);
698: break;
699: }
700: e.src_bus_id = bus;
701: e.src_bus_irq = irq;
702: e.dst_apic_id = mp_busses[bus].mb_intrs->ioapic->sc_apicid;
703: e.dst_apic_int = irq;
704:
705: if (mpbios_int((const u_int8_t *)&e, &mp_intrs[mp_nintrs]) == 0) {
706: mip = &mp_intrs[mp_nintrs++];
707: return (mip->ioapic_ih | irq);
708: }
709:
710: return irq;
711: }
712:
713: void
714: mpbios_cpu(const u_int8_t *ent, struct device *self)
715: {
716: const struct mpbios_proc *entry = (const struct mpbios_proc *)ent;
717: struct cpu_attach_args caa;
718:
719: /* XXX move this into the CPU attachment goo. */
720: /* check for usability */
721: if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
722: return;
723:
724: /* check for BSP flag */
725: if (entry->cpu_flags & PROCENTRY_FLAG_BP)
726: caa.cpu_role = CPU_ROLE_BP;
727: else
728: caa.cpu_role = CPU_ROLE_AP;
729:
730: caa.caa_name = "cpu";
731: caa.cpu_number = entry->apic_id;
732: caa.cpu_func = &mp_cpu_funcs;
733: #if 1 /* XXX Will be removed when the real stuff is probed */
734: caa.cpu_signature = entry->cpu_signature;
735:
736: /*
737: * XXX this is truncated to just contain the low-order 16 bits
738: * of the flags on at least some MP bioses
739: */
740: caa.feature_flags = entry->feature_flags;
741:
742: /*
743: * XXX some MP bioses don't specify a valid CPU signature; use
744: * the result of the 'cpuid' instruction for the processor
745: * we're running on
746: */
747: if ((caa.cpu_signature & 0x00000fff) == 0) {
748: caa.cpu_signature = cpu_id;
749: caa.feature_flags = cpu_feature;
750: }
751: #endif
752:
753: config_found_sm(self, &caa, mp_print, mp_match);
754: }
755:
756: /*
757: * The following functions conspire to compute base ioapic redirection
758: * table entry for a given interrupt line.
759: *
760: * Fill in: trigger mode, polarity, and possibly delivery mode.
761: */
762: void
763: mp_cfg_special_intr(const struct mpbios_int *entry, u_int32_t *redir)
764: {
765:
766: /*
767: * All of these require edge triggered, zero vector,
768: * appropriate delivery mode.
769: * see page 13 of the 82093AA datasheet.
770: */
771: *redir &= ~IOAPIC_REDLO_DEL_MASK;
772: *redir &= ~IOAPIC_REDLO_VECTOR_MASK;
773: *redir &= ~IOAPIC_REDLO_LEVEL;
774:
775: switch (entry->int_type) {
776: case MPS_INTTYPE_NMI:
777: *redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT);
778: break;
779:
780: case MPS_INTTYPE_SMI:
781: *redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT);
782: break;
783: case MPS_INTTYPE_ExtINT:
784: /*
785: * We are using the ioapic in "native" mode.
786: * This indicates where the 8259 is wired to the ioapic
787: * and/or local apic..
788: */
789: *redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT);
790: *redir |= (IOAPIC_REDLO_MASK);
791: break;
792: default:
793: panic("unknown MPS interrupt type %d", entry->int_type);
794: }
795: }
796:
797: /* XXX too much duplicated code here. */
798:
799: void
800: mp_cfg_pci_intr(const struct mpbios_int *entry, u_int32_t *redir)
801: {
802: int mpspo = entry->int_flags & 0x03; /* XXX magic */
803: int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
804:
805: *redir &= ~IOAPIC_REDLO_DEL_MASK;
806: switch (mpspo) {
807: case MPS_INTPO_ACTHI:
808: *redir &= ~IOAPIC_REDLO_ACTLO;
809: break;
810: case MPS_INTPO_DEF:
811: case MPS_INTPO_ACTLO:
812: *redir |= IOAPIC_REDLO_ACTLO;
813: break;
814: default:
815: panic("unknown MPS interrupt polarity %d", mpspo);
816: }
817:
818: if (entry->int_type != MPS_INTTYPE_INT) {
819: mp_cfg_special_intr(entry, redir);
820: return;
821: }
822: *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
823:
824: switch (mpstrig) {
825: case MPS_INTTR_DEF:
826: case MPS_INTTR_LEVEL:
827: *redir |= IOAPIC_REDLO_LEVEL;
828: break;
829: case MPS_INTTR_EDGE:
830: *redir &= ~IOAPIC_REDLO_LEVEL;
831: break;
832: default:
833: panic("unknown MPS interrupt trigger %d", mpstrig);
834: }
835: }
836:
837: void
838: mp_cfg_eisa_intr (const struct mpbios_int *entry, u_int32_t *redir)
839: {
840: int mpspo = entry->int_flags & 0x03; /* XXX magic */
841: int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
842:
843: *redir &= ~IOAPIC_REDLO_DEL_MASK;
844: switch (mpspo) {
845: case MPS_INTPO_DEF:
846: case MPS_INTPO_ACTHI:
847: *redir &= ~IOAPIC_REDLO_ACTLO;
848: break;
849: case MPS_INTPO_ACTLO:
850: *redir |= IOAPIC_REDLO_ACTLO;
851: break;
852: default:
853: panic("unknown MPS interrupt polarity %d", mpspo);
854: }
855:
856: if (entry->int_type != MPS_INTTYPE_INT) {
857: mp_cfg_special_intr(entry, redir);
858: return;
859: }
860: *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
861:
862: switch (mpstrig) {
863: case MPS_INTTR_LEVEL:
864: *redir |= IOAPIC_REDLO_LEVEL;
865: break;
866: case MPS_INTTR_EDGE:
867: *redir &= ~IOAPIC_REDLO_LEVEL;
868: break;
869: case MPS_INTTR_DEF:
870: /*
871: * Set "default" setting based on ELCR value snagged
872: * earlier.
873: */
874: if (mp_busses[entry->src_bus_id].mb_data &
875: (1<<entry->src_bus_irq)) {
876: *redir |= IOAPIC_REDLO_LEVEL;
877: } else {
878: *redir &= ~IOAPIC_REDLO_LEVEL;
879: }
880: break;
881: default:
882: panic("unknown MPS interrupt trigger %d", mpstrig);
883: }
884: }
885:
886:
887: void
888: mp_cfg_isa_intr(const struct mpbios_int *entry, u_int32_t *redir)
889: {
890: int mpspo = entry->int_flags & 0x03; /* XXX magic */
891: int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
892:
893: *redir &= ~IOAPIC_REDLO_DEL_MASK;
894: switch (mpspo) {
895: case MPS_INTPO_DEF:
896: case MPS_INTPO_ACTHI:
897: *redir &= ~IOAPIC_REDLO_ACTLO;
898: break;
899: case MPS_INTPO_ACTLO:
900: *redir |= IOAPIC_REDLO_ACTLO;
901: break;
902: default:
903: panic("unknown MPS interrupt polarity %d", mpspo);
904: }
905:
906: if (entry->int_type != MPS_INTTYPE_INT) {
907: mp_cfg_special_intr(entry, redir);
908: return;
909: }
910: *redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
911:
912: switch (mpstrig) {
913: case MPS_INTTR_LEVEL:
914: *redir |= IOAPIC_REDLO_LEVEL;
915: break;
916: case MPS_INTTR_DEF:
917: case MPS_INTTR_EDGE:
918: *redir &= ~IOAPIC_REDLO_LEVEL;
919: break;
920: default:
921: panic("unknown MPS interrupt trigger %d", mpstrig);
922: }
923: }
924:
925:
926: void
927: mp_print_special_intr(int intr)
928: {
929: }
930:
931: void
932: mp_print_pci_intr(int intr)
933: {
934: printf(" device %d INT_%c", (intr >> 2) & 0x1f, 'A' + (intr & 0x3));
935: }
936:
937: void
938: mp_print_isa_intr(int intr)
939: {
940: printf(" irq %d", intr);
941: }
942:
943: void
944: mp_print_eisa_intr(int intr)
945: {
946: printf(" EISA irq %d", intr);
947: }
948:
949:
950:
951: #define TAB_UNIT 4
952: #define TAB_ROUND(a) _TAB_ROUND(a, TAB_UNIT)
953:
954: #define _TAB_ROUND(a,u) (((a) + (u - 1)) & ~(u - 1))
955: #define EXTEND_TAB(a,u) (!(_TAB_ROUND(a, u) == _TAB_ROUND((a + 1), u)))
956:
957: void
958: mpbios_bus(const u_int8_t *ent, struct device *self)
959: {
960: const struct mpbios_bus *entry = (const struct mpbios_bus *)ent;
961: int bus_id = entry->bus_id;
962:
963: printf("%s: bus %d is type %6.6s\n", self->dv_xname,
964: bus_id, entry->bus_type);
965:
966: #ifdef DIAGNOSTIC
967: /*
968: * This "should not happen" unless the table changes out
969: * from underneath us
970: */
971: if (bus_id >= mp_nbus) {
972: panic("%s: bus number %d out of range?? (type %6.6s)",
973: self->dv_xname, bus_id, entry->bus_type);
974: }
975: #endif
976:
977: mp_busses[bus_id].mb_intrs = NULL;
978:
979: if (memcmp(entry->bus_type, "PCI ", 6) == 0) {
980: mp_busses[bus_id].mb_name = "pci";
981: mp_busses[bus_id].mb_idx = bus_id;
982: mp_busses[bus_id].mb_intr_print = mp_print_pci_intr;
983: mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr;
984: } else if (memcmp(entry->bus_type, "EISA ", 6) == 0) {
985: mp_busses[bus_id].mb_name = "eisa";
986: mp_busses[bus_id].mb_idx = bus_id;
987: mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr;
988: mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr;
989:
990: mp_busses[bus_id].mb_data = inb(ELCR0) | (inb(ELCR1) << 8);
991:
992: if (mp_eisa_bus)
993: printf("%s: multiple eisa busses?\n",
994: self->dv_xname);
995: else
996: mp_eisa_bus = &mp_busses[bus_id];
997: } else if (memcmp(entry->bus_type, "ISA ", 6) == 0) {
998: mp_busses[bus_id].mb_name = "isa";
999: mp_busses[bus_id].mb_idx = bus_id;
1000: mp_busses[bus_id].mb_intr_print = mp_print_isa_intr;
1001: mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr;
1002: if (mp_isa_bus)
1003: printf("%s: multiple isa busses?\n",
1004: self->dv_xname);
1005: else
1006: mp_isa_bus = &mp_busses[bus_id];
1007: } else {
1008: printf("%s: unsupported bus type %6.6s\n", self->dv_xname,
1009: entry->bus_type);
1010: }
1011: }
1012:
1013:
1014: void
1015: mpbios_ioapic(const u_int8_t *ent, struct device *self)
1016: {
1017: const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent;
1018: struct apic_attach_args aaa;
1019:
1020: /* XXX let flags checking happen in ioapic driver.. */
1021: if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN))
1022: return;
1023:
1024: aaa.aaa_name = "ioapic";
1025: aaa.apic_id = entry->apic_id;
1026: aaa.apic_version = entry->apic_version;
1027: aaa.apic_address = (u_int32_t)entry->apic_address;
1028: aaa.apic_vecbase = -1;
1029: aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE;
1030:
1031: config_found_sm(self, &aaa, mp_print, mp_match);
1032: }
1033:
1034: int
1035: mpbios_int(const u_int8_t *ent, struct mp_intr_map *mpi)
1036: {
1037: const struct mpbios_int *entry = (const struct mpbios_int *)ent;
1038: struct mpbios_int rw_entry = *entry;
1039: struct ioapic_softc *sc = NULL, *sc2;
1040:
1041: struct mp_intr_map *altmpi;
1042: struct mp_bus *mpb;
1043:
1044: u_int32_t id = IOAPIC_REMAPPED_ID(entry->dst_apic_id);
1045: u_int32_t pin = entry->dst_apic_int;
1046: u_int32_t bus = entry->src_bus_id;
1047: u_int32_t dev = entry->src_bus_irq;
1048: u_int32_t type = entry->int_type;
1049: u_int32_t flags = entry->int_flags;
1050:
1051: rw_entry.dst_apic_id = id;
1052:
1053: switch (type) {
1054: case MPS_INTTYPE_INT:
1055: mpb = &(mp_busses[bus]);
1056: break;
1057: case MPS_INTTYPE_ExtINT:
1058: mpb = &extint_bus;
1059: break;
1060: case MPS_INTTYPE_SMI:
1061: mpb = &smi_bus;
1062: break;
1063: case MPS_INTTYPE_NMI:
1064: mpb = &nmi_bus;
1065: break;
1066: }
1067: mpi->bus = mpb;
1068: mpi->bus_pin = dev;
1069:
1070: mpi->ioapic_ih = APIC_INT_VIA_APIC |
1071: ((id << APIC_INT_APIC_SHIFT) | ((pin << APIC_INT_PIN_SHIFT)));
1072:
1073: mpi->type = type;
1074: mpi->flags = flags;
1075: mpi->redir = 0;
1076: if (mpb->mb_intr_cfg == NULL) {
1077: printf("mpbios: can't find bus %d for apic %d pin %d\n",
1078: bus, id, pin);
1079: return (1);
1080: }
1081:
1082: (*mpb->mb_intr_cfg)(&rw_entry, &mpi->redir);
1083:
1084: if (entry->type == MPS_MCT_IOINT) {
1085: sc = ioapic_find(id);
1086: if (sc == NULL) {
1087: printf("mpbios: can't find ioapic %d\n", id);
1088: return (1);
1089: }
1090:
1091: /*
1092: * XXX workaround for broken BIOSs that put the ACPI
1093: * global interrupt number in the entry, not the pin
1094: * number.
1095: */
1096: if (pin >= sc->sc_apic_sz) {
1097: sc2 = ioapic_find_bybase(pin);
1098: if (sc2 != sc) {
1099: printf("mpbios: bad pin %d for apic %d\n",
1100: pin, id);
1101: return (1);
1102: }
1103: printf("mpbios: WARNING: pin %d for apic %d too high; "
1104: "assuming ACPI global int value\n", pin, id);
1105: pin -= sc->sc_apic_vecbase;
1106: }
1107:
1108: mpi->ioapic = sc;
1109: mpi->ioapic_pin = pin;
1110:
1111: altmpi = sc->sc_pins[pin].ip_map;
1112:
1113: if (altmpi != NULL) {
1114: if ((altmpi->type != type) ||
1115: (altmpi->flags != flags)) {
1116: printf(
1117: "%s: conflicting map entries for pin %d\n",
1118: sc->sc_dev.dv_xname, pin);
1119: }
1120: } else {
1121: sc->sc_pins[pin].ip_map = mpi;
1122: }
1123: } else {
1124: if (pin >= 2)
1125: printf("pin %d of local apic doesn't exist!\n", pin);
1126: else {
1127: mpi->ioapic = NULL;
1128: mpi->ioapic_pin = pin;
1129: mpi->cpu_id = id;
1130: }
1131: }
1132:
1133: if (mp_verbose) {
1134: printf("%s: int%d attached to %s",
1135: sc ? sc->sc_dev.dv_xname : "local apic", pin,
1136: mpb->mb_name);
1137: if (mpb->mb_idx != -1)
1138: printf("%d", mpb->mb_idx);
1139:
1140: (*(mpb->mb_intr_print))(dev);
1141:
1142: printf(" (type 0x%x flags 0x%x)\n", type, flags);
1143: }
1144:
1145: mpi->next = mpb->mb_intrs;
1146: mpb->mb_intrs = mpi;
1147:
1148: return (0);
1149: }
CVSweb