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