1 | /* $NetBSD: mpbios.c,v 1.65 2015/07/17 06:41:18 msaitoh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2000 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by RedBack Networks Inc. |
9 | * |
10 | * Author: Bill Sommerfeld |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | |
34 | /* |
35 | * Copyright (c) 1999 Stefan Grefen |
36 | * |
37 | * Redistribution and use in source and binary forms, with or without |
38 | * modification, are permitted provided that the following conditions |
39 | * are met: |
40 | * 1. Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. |
42 | * 2. Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in the |
44 | * documentation and/or other materials provided with the distribution. |
45 | * 3. All advertising materials mentioning features or use of this software |
46 | * must display the following acknowledgement: |
47 | * This product includes software developed by the NetBSD |
48 | * Foundation, Inc. and its contributors. |
49 | * 4. Neither the name of The NetBSD Foundation nor the names of its |
50 | * contributors may be used to endorse or promote products derived |
51 | * from this software without specific prior written permission. |
52 | * |
53 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY |
54 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE |
57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
63 | * SUCH DAMAGE. |
64 | */ |
65 | /* |
66 | * Derived from FreeBSD's mp_machdep.c |
67 | */ |
68 | /* |
69 | * Copyright (c) 1996, by Steve Passe |
70 | * All rights reserved. |
71 | * |
72 | * Redistribution and use in source and binary forms, with or without |
73 | * modification, are permitted provided that the following conditions |
74 | * are met: |
75 | * 1. Redistributions of source code must retain the above copyright |
76 | * notice, this list of conditions and the following disclaimer. |
77 | * 2. The name of the developer may NOT be used to endorse or promote products |
78 | * derived from this software without specific prior written permission. |
79 | * |
80 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
81 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
82 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
83 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
84 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
85 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
86 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
87 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
88 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
89 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
90 | * SUCH DAMAGE. |
91 | */ |
92 | |
93 | /* |
94 | * The Intel MP-stuff is just one way of x86 SMP systems |
95 | * so only Intel MP specific stuff is here. |
96 | */ |
97 | |
98 | #include <sys/cdefs.h> |
99 | __KERNEL_RCSID(0, "$NetBSD: mpbios.c,v 1.65 2015/07/17 06:41:18 msaitoh Exp $" ); |
100 | |
101 | #include "acpica.h" |
102 | #include "lapic.h" |
103 | #include "ioapic.h" |
104 | #include "opt_acpi.h" |
105 | #include "opt_mpbios.h" |
106 | |
107 | #include <sys/param.h> |
108 | #include <sys/systm.h> |
109 | #include <sys/kernel.h> |
110 | #include <sys/device.h> |
111 | #include <sys/kmem.h> |
112 | #include <sys/bus.h> |
113 | #include <sys/reboot.h> |
114 | |
115 | #include <uvm/uvm_extern.h> |
116 | |
117 | #include <machine/specialreg.h> |
118 | #include <machine/cpuvar.h> |
119 | #include <machine/mpbiosvar.h> |
120 | #include <machine/pio.h> |
121 | |
122 | #include <machine/i82093reg.h> |
123 | #include <machine/i82093var.h> |
124 | #include <machine/i82489reg.h> |
125 | #include <machine/i82489var.h> |
126 | |
127 | #include <dev/isa/isareg.h> |
128 | |
129 | #ifdef X86_MPBIOS_SUPPORT_EISA |
130 | #include <dev/eisa/eisavar.h> /* for ELCR* def'ns */ |
131 | #endif |
132 | |
133 | #if NACPICA > 0 |
134 | extern int mpacpi_ncpu; |
135 | extern int mpacpi_nioapic; |
136 | #endif |
137 | |
138 | int mpbios_ncpu; |
139 | int mpbios_nioapic; |
140 | |
141 | #include "pci.h" |
142 | |
143 | #if NPCI > 0 |
144 | #include <dev/pci/pcivar.h> |
145 | #include <dev/pci/pcireg.h> |
146 | #endif |
147 | |
148 | #include "locators.h" |
149 | |
150 | /* descriptions of MP basetable entries */ |
151 | struct mpbios_baseentry { |
152 | uint8_t type; |
153 | uint8_t length; |
154 | uint16_t count; |
155 | const char *name; |
156 | }; |
157 | |
158 | static const char *loc_where[] = { |
159 | "extended bios data area" , |
160 | "last page of base memory" , |
161 | "bios" |
162 | }; |
163 | |
164 | struct mp_map |
165 | { |
166 | vaddr_t baseva; |
167 | int vsize; |
168 | paddr_t pa; |
169 | paddr_t pg; |
170 | int psize; |
171 | }; |
172 | |
173 | struct dflt_conf_entry { |
174 | const char *bus_type[2]; |
175 | int flags; |
176 | }; |
177 | |
178 | int mp_cpuprint(void *, const char *); |
179 | int mp_ioapicprint(void *, const char *); |
180 | static const void *mpbios_search(device_t, paddr_t, int, |
181 | struct mp_map *); |
182 | static inline int mpbios_cksum(const void *,int); |
183 | |
184 | static void mp_cfg_special_intr(const struct mpbios_int *, uint32_t *); |
185 | static void mp_print_special_intr (int intr); |
186 | |
187 | static void mp_cfg_pci_intr(const struct mpbios_int *, uint32_t *); |
188 | static void mp_print_pci_intr (int intr); |
189 | |
190 | #ifdef X86_MPBIOS_SUPPORT_EISA |
191 | static void mp_print_eisa_intr (int intr); |
192 | static void mp_cfg_eisa_intr(const struct mpbios_int *, uint32_t *); |
193 | #endif |
194 | |
195 | static void mp_cfg_isa_intr(const struct mpbios_int *, uint32_t *); |
196 | static void mp_print_isa_intr(int intr); |
197 | |
198 | static void mpbios_dflt_conf_cpu(device_t); |
199 | static void mpbios_dflt_conf_bus(device_t, const struct dflt_conf_entry *); |
200 | static void mpbios_dflt_conf_ioapic(device_t); |
201 | static void mpbios_dflt_conf_int(device_t, const struct dflt_conf_entry *, |
202 | const int *); |
203 | |
204 | static void mpbios_cpu(const uint8_t *, device_t); |
205 | static void mpbios_bus(const uint8_t *, device_t); |
206 | static void mpbios_ioapic(const uint8_t *, device_t); |
207 | static void mpbios_int(const uint8_t *, int, struct mp_intr_map *); |
208 | |
209 | static const void *mpbios_map(paddr_t, int, struct mp_map *); |
210 | static void mpbios_unmap(struct mp_map *); |
211 | |
212 | /* |
213 | * globals to help us bounce our way through parsing the config table. |
214 | */ |
215 | |
216 | static struct mp_map mp_cfg_table_map; |
217 | static struct mp_map mp_fp_map; |
218 | const struct mpbios_cth *mp_cth; |
219 | const struct mpbios_fps *mp_fps; |
220 | |
221 | int mpbios_scanned; |
222 | |
223 | int |
224 | mp_cpuprint(void *aux, const char *pnp) |
225 | { |
226 | struct cpu_attach_args *caa = aux; |
227 | |
228 | if (pnp) |
229 | aprint_normal("cpu at %s" , pnp); |
230 | aprint_normal(" apid %d" , caa->cpu_number); |
231 | return (UNCONF); |
232 | } |
233 | |
234 | int |
235 | mp_ioapicprint(void *aux, const char *pnp) |
236 | { |
237 | struct apic_attach_args *aaa = aux; |
238 | |
239 | if (pnp) |
240 | aprint_normal("ioapic at %s" , pnp); |
241 | aprint_normal(" apid %d" , aaa->apic_id); |
242 | return (UNCONF); |
243 | } |
244 | |
245 | /* |
246 | * Map a chunk of memory read-only and return an appropriately |
247 | * const'ed pointer. |
248 | */ |
249 | |
250 | static const void * |
251 | mpbios_map(paddr_t pa, int len, struct mp_map *handle) |
252 | { |
253 | paddr_t pgpa = x86_trunc_page(pa); |
254 | paddr_t endpa = x86_round_page(pa + len); |
255 | vaddr_t va = uvm_km_alloc(kernel_map, endpa - pgpa, 0, UVM_KMF_VAONLY); |
256 | vaddr_t retva = va + (pa & PGOFSET); |
257 | |
258 | handle->pa = pa; |
259 | handle->pg = pgpa; |
260 | handle->psize = len; |
261 | handle->baseva = va; |
262 | handle->vsize = endpa-pgpa; |
263 | |
264 | do { |
265 | pmap_kenter_pa(va, pgpa, VM_PROT_READ, 0); |
266 | va += PAGE_SIZE; |
267 | pgpa += PAGE_SIZE; |
268 | } while (pgpa < endpa); |
269 | pmap_update(pmap_kernel()); |
270 | |
271 | return (const void *)retva; |
272 | } |
273 | |
274 | inline static void |
275 | mpbios_unmap(struct mp_map *handle) |
276 | { |
277 | pmap_kremove(handle->baseva, handle->vsize); |
278 | pmap_update(pmap_kernel()); |
279 | uvm_km_free(kernel_map, handle->baseva, handle->vsize, UVM_KMF_VAONLY); |
280 | } |
281 | |
282 | /* |
283 | * Look for an Intel MP spec table, indicating SMP capable hardware. |
284 | */ |
285 | int |
286 | mpbios_probe(device_t self) |
287 | { |
288 | paddr_t ebda, memtop; |
289 | |
290 | paddr_t cthpa; |
291 | int cthlen; |
292 | const uint8_t *mpbios_page; |
293 | int scan_loc; |
294 | |
295 | struct mp_map t; |
296 | |
297 | /* If MP is disabled, don't use MPBIOS or the ioapics. */ |
298 | if ((boothowto & RB_MD1) != 0) |
299 | return 0; |
300 | |
301 | /* see if EBDA exists */ |
302 | |
303 | mpbios_page = mpbios_map(0, PAGE_SIZE, &t); |
304 | |
305 | ebda = *(const uint16_t *)(&mpbios_page[0x40e]); |
306 | ebda <<= 4; |
307 | |
308 | memtop = *(const uint16_t *)(&mpbios_page[0x413]); |
309 | memtop <<= 10; |
310 | |
311 | mpbios_page = NULL; |
312 | mpbios_unmap(&t); |
313 | |
314 | scan_loc = 0; |
315 | |
316 | if (ebda && ebda < IOM_BEGIN ) { |
317 | mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map); |
318 | if (mp_fps != NULL) |
319 | goto found; |
320 | } |
321 | |
322 | scan_loc = 1; |
323 | |
324 | if (memtop && memtop <= IOM_BEGIN ) { |
325 | mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map); |
326 | if (mp_fps != NULL) |
327 | goto found; |
328 | } |
329 | |
330 | scan_loc = 2; |
331 | |
332 | mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map); |
333 | if (mp_fps != NULL) |
334 | goto found; |
335 | |
336 | /* nothing found */ |
337 | return 0; |
338 | |
339 | found: |
340 | if (mp_verbose) |
341 | aprint_verbose_dev(self, |
342 | "MP floating pointer found in %s at 0x%jx\n" , |
343 | loc_where[scan_loc], (uintmax_t)mp_fp_map.pa); |
344 | |
345 | if (mp_fps->pap == 0) { |
346 | if (mp_fps->mpfb1 == 0) { |
347 | aprint_error_dev(self, "MP fps invalid: " |
348 | "no default config and no configuration table\n" ); |
349 | |
350 | goto err; |
351 | } |
352 | return 10; |
353 | } |
354 | |
355 | cthpa = mp_fps->pap; |
356 | |
357 | mp_cth = mpbios_map (cthpa, sizeof (*mp_cth), &mp_cfg_table_map); |
358 | cthlen = mp_cth->base_len; |
359 | mpbios_unmap(&mp_cfg_table_map); |
360 | |
361 | mp_cth = mpbios_map (cthpa, cthlen, &mp_cfg_table_map); |
362 | |
363 | if (mp_verbose) |
364 | aprint_verbose_dev(self, |
365 | "MP config table at 0x%jx, %d bytes long\n" , |
366 | (uintmax_t)cthpa, cthlen); |
367 | |
368 | if (mp_cth->signature != MP_CT_SIG) { |
369 | aprint_error_dev(self, "MP signature mismatch (%x vs %x)\n" , |
370 | MP_CT_SIG, mp_cth->signature); |
371 | goto err; |
372 | } |
373 | |
374 | if (mpbios_cksum(mp_cth, cthlen)) { |
375 | aprint_error_dev(self, |
376 | "MP Configuration Table checksum mismatch\n" ); |
377 | goto err; |
378 | } |
379 | return 10; |
380 | err: |
381 | if (mp_fps) { |
382 | mp_fps = NULL; |
383 | mpbios_unmap(&mp_fp_map); |
384 | } |
385 | if (mp_cth) { |
386 | mp_cth = NULL; |
387 | mpbios_unmap(&mp_cfg_table_map); |
388 | } |
389 | return 0; |
390 | } |
391 | |
392 | |
393 | /* |
394 | * Simple byte checksum used on config tables. |
395 | */ |
396 | |
397 | inline static int |
398 | mpbios_cksum(const void *start, int len) |
399 | { |
400 | unsigned char res=0; |
401 | const char *p = start; |
402 | const char *end = p + len; |
403 | |
404 | while (p < end) |
405 | res += *p++; |
406 | |
407 | return res; |
408 | } |
409 | |
410 | |
411 | /* |
412 | * Look for the MP floating pointer signature in the given physical |
413 | * address range. |
414 | * |
415 | * We map the memory, scan through it, and unmap it. |
416 | * If we find it, remap the floating pointer structure and return it. |
417 | */ |
418 | |
419 | const void * |
420 | mpbios_search(device_t self, paddr_t start, int count, |
421 | struct mp_map *map) |
422 | { |
423 | struct mp_map t; |
424 | |
425 | int i, len; |
426 | const struct mpbios_fps *m; |
427 | int end = count - sizeof(*m); |
428 | const uint8_t *base = mpbios_map (start, count, &t); |
429 | |
430 | if (mp_verbose) |
431 | aprint_verbose_dev(self, |
432 | "scanning 0x%jx to 0x%jx for MP signature\n" , |
433 | (uintmax_t)start, (uintmax_t)(start+count-sizeof(*m))); |
434 | |
435 | for (i = 0; i <= end; i += 4) { |
436 | m = (const struct mpbios_fps *)&base[i]; |
437 | |
438 | if ((m->signature == MP_FP_SIG) && |
439 | ((len = m->length << 4) != 0) && |
440 | mpbios_cksum(m, (m->length << 4)) == 0) { |
441 | mpbios_unmap (&t); |
442 | |
443 | return mpbios_map(start + i, len, map); |
444 | } |
445 | } |
446 | mpbios_unmap(&t); |
447 | |
448 | return 0; |
449 | } |
450 | |
451 | /* |
452 | * MP configuration table parsing. |
453 | */ |
454 | |
455 | static struct mpbios_baseentry mp_conf[] = |
456 | { |
457 | {0, 20, 0, "cpu" }, |
458 | {1, 8, 0, "bus" }, |
459 | {2, 8, 0, "ioapic" }, |
460 | {3, 8, 0, "ioint" }, |
461 | {4, 8, 0, "lint" }, |
462 | }; |
463 | |
464 | static struct mp_bus extint_bus = { |
465 | "ExtINT" , |
466 | -1, |
467 | mp_print_special_intr, |
468 | mp_cfg_special_intr, |
469 | NULL, 0, 0, NULL, 0 |
470 | }; |
471 | static struct mp_bus smi_bus = { |
472 | "SMI" , |
473 | -1, |
474 | mp_print_special_intr, |
475 | mp_cfg_special_intr, |
476 | NULL, 0, 0, NULL, 0 |
477 | }; |
478 | static struct mp_bus nmi_bus = { |
479 | "NMI" , |
480 | -1, |
481 | mp_print_special_intr, |
482 | mp_cfg_special_intr, |
483 | NULL, 0, 0, NULL, 0 |
484 | }; |
485 | |
486 | /* |
487 | * MP default configuration tables (acc. MP Specification Version 1.4) |
488 | */ |
489 | |
490 | /* |
491 | * Default configurations always feature two processors and the local APIC IDs |
492 | * are assigned consecutively by hardware starting from zero (sec. 5). We set |
493 | * I/O APIC ID to 2. |
494 | */ |
495 | #define DFLT_IOAPIC_ID 2 |
496 | |
497 | #define ELCR_INV 0x1 |
498 | #define MCA_INV 0x2 |
499 | #define IRQ_VAR 0x4 |
500 | #define INTIN0_NC 0x8 |
501 | |
502 | static const struct dflt_conf_entry dflt_conf_tab[7] = { |
503 | /* |
504 | * Assume all systems with EISA and (modern) PCI chipsets have ELCRs |
505 | * (to control external interrupt-level inverters). MCA systems must |
506 | * use fixed inverters for INTIN1-INTIN15 (table 5-1; sec. 5.3.2). |
507 | */ |
508 | {{"ISA " , NULL }, 0 }, /* default config 1 */ |
509 | {{"EISA " , NULL }, ELCR_INV | IRQ_VAR }, /* default config 2 */ |
510 | {{"EISA " , NULL }, ELCR_INV }, /* default config 3 */ |
511 | {{"MCA " , NULL }, MCA_INV }, /* default config 4 */ |
512 | {{"ISA " , "PCI " }, ELCR_INV }, /* default config 5 */ |
513 | {{"EISA " , "PCI " }, ELCR_INV }, /* default config 6 */ |
514 | {{"MCA " , "PCI " }, MCA_INV | INTIN0_NC} /* default config 7 */ |
515 | }; |
516 | |
517 | #define _ (-1) /* INTINx not connected (to a bus interrupt) */ |
518 | |
519 | static const int dflt_bus_irq_tab[2][16] = { |
520 | /* Default configs 1,3-7 connect INTIN1-INTIN15 to bus interrupts. */ |
521 | {_, 1, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, |
522 | /* |
523 | * Default config 2 connects neither timer IRQ0 nor DMA chaining to |
524 | * INTIN2 and INTIN13 (sec. 5.3). |
525 | */ |
526 | {_, 1, _, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, _, 14, 15} |
527 | }; |
528 | |
529 | #undef _ |
530 | |
531 | static const uint8_t dflt_lint_tab[2] = { |
532 | MPS_INTTYPE_ExtINT, MPS_INTTYPE_NMI |
533 | }; |
534 | |
535 | |
536 | /* |
537 | * 1st pass on BIOS's Intel MP specification table. |
538 | * |
539 | * initializes: |
540 | * mp_ncpus = 1 |
541 | * |
542 | * determines: |
543 | * cpu_apic_address (common to all CPUs) |
544 | * ioapic_address[N] |
545 | * mp_naps |
546 | * mp_nbus |
547 | * mp_napics |
548 | * nintrs |
549 | */ |
550 | void |
551 | mpbios_scan(device_t self, int *ncpup) |
552 | { |
553 | const uint8_t *position, *end; |
554 | size_t i; |
555 | int count; |
556 | int type; |
557 | int intr_cnt, cur_intr; |
558 | #if NLAPIC > 0 |
559 | paddr_t lapic_base; |
560 | #endif |
561 | const struct dflt_conf_entry *dflt_conf; |
562 | const int *dflt_bus_irq; |
563 | const struct mpbios_int *iep; |
564 | struct mpbios_int ie; |
565 | |
566 | aprint_normal_dev(self, "Intel MP Specification " ); |
567 | |
568 | switch (mp_fps->spec_rev) { |
569 | case 1: |
570 | aprint_normal("(Version 1.1)" ); |
571 | break; |
572 | case 4: |
573 | aprint_normal("(Version 1.4)" ); |
574 | break; |
575 | default: |
576 | aprint_normal("(unrecognized rev %d)" , mp_fps->spec_rev); |
577 | } |
578 | |
579 | /* |
580 | * looks like we've got a MP system. start setting up |
581 | * infrastructure.. |
582 | * XXX is this the right place?? |
583 | */ |
584 | |
585 | #if NACPICA > 0 |
586 | if (mpacpi_ncpu == 0) { |
587 | #endif |
588 | #if NLAPIC > 0 |
589 | lapic_base = LAPIC_BASE; |
590 | if (mp_cth != NULL) |
591 | lapic_base = (paddr_t)mp_cth->apic_address; |
592 | |
593 | lapic_boot_init(lapic_base); |
594 | #endif |
595 | #if NACPICA > 0 |
596 | } |
597 | #endif |
598 | |
599 | /* check for use of 'default' configuration */ |
600 | if (mp_fps->mpfb1 != 0) { |
601 | |
602 | if (mp_fps->mpfb1 > __arraycount(dflt_conf_tab)) |
603 | panic("Unsupported MP default configuration %d\n" , |
604 | mp_fps->mpfb1); |
605 | |
606 | aprint_normal("\n" ); |
607 | aprint_normal_dev(self, "MP default configuration %d\n" , |
608 | mp_fps->mpfb1); |
609 | |
610 | dflt_conf = &dflt_conf_tab[mp_fps->mpfb1 - 1]; |
611 | dflt_bus_irq = |
612 | dflt_bus_irq_tab[(dflt_conf->flags & IRQ_VAR) != 0]; |
613 | |
614 | #if NACPICA > 0 |
615 | if (mpacpi_ncpu == 0) |
616 | #endif |
617 | mpbios_dflt_conf_cpu(self); |
618 | |
619 | #if NACPICA > 0 |
620 | if (mpacpi_nioapic == 0) |
621 | #endif |
622 | mpbios_dflt_conf_ioapic(self); |
623 | |
624 | /* |
625 | * Walk the table once, counting items. |
626 | */ |
627 | mp_nbus = 0; |
628 | for (i = 0; i < __arraycount(dflt_conf->bus_type); i++) { |
629 | if (dflt_conf->bus_type[i] != NULL) |
630 | mp_nbus++; |
631 | } |
632 | KASSERT(mp_nbus != 0); |
633 | |
634 | mp_busses = kmem_zalloc(sizeof(struct mp_bus) * mp_nbus, |
635 | KM_SLEEP); |
636 | KASSERT(mp_busses != NULL); |
637 | |
638 | /* INTIN0 */ |
639 | intr_cnt = (dflt_conf->flags & INTIN0_NC) ? 0 : 1; |
640 | /* INTINx */ |
641 | for (i = 0; i < __arraycount(dflt_bus_irq_tab[0]); i++) { |
642 | if (dflt_bus_irq[i] >= 0) |
643 | intr_cnt++; |
644 | } |
645 | KASSERT(intr_cnt != 0); |
646 | |
647 | /* LINTINx */ |
648 | for (i = 0; i < __arraycount(dflt_lint_tab); i++) |
649 | intr_cnt++; |
650 | |
651 | mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map) * intr_cnt, |
652 | KM_SLEEP); |
653 | KASSERT(mp_intrs != NULL); |
654 | mp_nintr = intr_cnt; |
655 | |
656 | /* |
657 | * Re-walk the table, recording info of interest. |
658 | */ |
659 | mpbios_dflt_conf_bus(self, dflt_conf); |
660 | mpbios_dflt_conf_int(self, dflt_conf, dflt_bus_irq); |
661 | } else { |
662 | /* |
663 | * should not happen; mp_probe returns 0 in this case, |
664 | * but.. |
665 | */ |
666 | if (mp_cth == NULL) |
667 | panic ("mpbios_scan: no config (can't happen?)" ); |
668 | |
669 | printf(" (%8.8s %12.12s)\n" , |
670 | mp_cth->oem_id, mp_cth->product_id); |
671 | |
672 | /* |
673 | * Walk the table once, counting items |
674 | */ |
675 | position = (const uint8_t *)(mp_cth); |
676 | end = position + mp_cth->base_len; |
677 | position += sizeof(*mp_cth); |
678 | |
679 | count = mp_cth->entry_count; |
680 | intr_cnt = 0; |
681 | |
682 | while ((count--) && (position < end)) { |
683 | type = *position; |
684 | if (type >= MPS_MCT_NTYPES) { |
685 | aprint_error_dev(self, "unknown entry type %x" |
686 | " in MP config table\n" , type); |
687 | break; |
688 | } |
689 | mp_conf[type].count++; |
690 | if (type == MPS_MCT_BUS) { |
691 | const struct mpbios_bus *bp = |
692 | (const struct mpbios_bus *)position; |
693 | if (bp->bus_id >= mp_nbus) |
694 | mp_nbus = bp->bus_id + 1; |
695 | } |
696 | /* |
697 | * Count actual interrupt instances. |
698 | * dst_apic_id of MPS_ALL_APICS means "wired to all |
699 | * apics of this type". |
700 | */ |
701 | if (type == MPS_MCT_IOINT) { |
702 | iep = (const struct mpbios_int *)position; |
703 | if (iep->dst_apic_id == MPS_ALL_APICS) |
704 | intr_cnt += |
705 | mp_conf[MPS_MCT_IOAPIC].count; |
706 | else |
707 | intr_cnt++; |
708 | } else if (type == MPS_MCT_LINT) |
709 | intr_cnt++; |
710 | position += mp_conf[type].length; |
711 | } |
712 | |
713 | mp_busses = kmem_zalloc(sizeof(struct mp_bus)*mp_nbus, |
714 | KM_SLEEP); |
715 | KASSERT(mp_busses != NULL); |
716 | mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map)*intr_cnt, |
717 | KM_SLEEP); |
718 | KASSERT(mp_intrs != NULL); |
719 | mp_nintr = intr_cnt; |
720 | |
721 | /* re-walk the table, recording info of interest */ |
722 | position = (const uint8_t *)mp_cth + sizeof(*mp_cth); |
723 | count = mp_cth->entry_count; |
724 | cur_intr = 0; |
725 | |
726 | while ((count--) && (position < end)) { |
727 | switch (type = *position) { |
728 | case MPS_MCT_CPU: |
729 | #if NACPICA > 0 |
730 | /* ACPI has done this for us */ |
731 | if (mpacpi_ncpu) |
732 | break; |
733 | #endif |
734 | mpbios_cpu(position, self); |
735 | break; |
736 | case MPS_MCT_BUS: |
737 | mpbios_bus(position, self); |
738 | break; |
739 | case MPS_MCT_IOAPIC: |
740 | #if NACPICA > 0 |
741 | /* ACPI has done this for us */ |
742 | if (mpacpi_nioapic) |
743 | break; |
744 | #endif |
745 | mpbios_ioapic(position, self); |
746 | break; |
747 | case MPS_MCT_IOINT: |
748 | iep = (const struct mpbios_int *)position; |
749 | ie = *iep; |
750 | if (iep->dst_apic_id == MPS_ALL_APICS) { |
751 | #if NIOAPIC > 0 |
752 | struct ioapic_softc *sc; |
753 | for (sc = ioapics ; sc != NULL; |
754 | sc = sc->sc_next) { |
755 | ie.dst_apic_id = sc->sc_apicid; |
756 | mpbios_int((char *)&ie, type, |
757 | &mp_intrs[cur_intr++]); |
758 | } |
759 | #endif |
760 | } else { |
761 | mpbios_int(position, type, |
762 | &mp_intrs[cur_intr++]); |
763 | } |
764 | break; |
765 | case MPS_MCT_LINT: |
766 | mpbios_int(position, type, |
767 | &mp_intrs[cur_intr]); |
768 | cur_intr++; |
769 | break; |
770 | default: |
771 | aprint_error_dev(self, "unknown entry type %x" |
772 | " in MP config table\n" , type); |
773 | /* NOTREACHED */ |
774 | return; |
775 | } |
776 | |
777 | position += mp_conf[type].length; |
778 | } |
779 | if (mp_verbose && mp_cth->ext_len) |
780 | aprint_verbose_dev(self, "MP WARNING: %d bytes of" |
781 | " extended entries not examined\n" , |
782 | mp_cth->ext_len); |
783 | } |
784 | /* Clean up. */ |
785 | mp_fps = NULL; |
786 | mpbios_unmap (&mp_fp_map); |
787 | if (mp_cth != NULL) { |
788 | mp_cth = NULL; |
789 | mpbios_unmap (&mp_cfg_table_map); |
790 | } |
791 | mpbios_scanned = 1; |
792 | |
793 | *ncpup = mpbios_ncpu; |
794 | } |
795 | |
796 | static void |
797 | mpbios_cpu(const uint8_t *ent, device_t self) |
798 | { |
799 | const struct mpbios_proc *entry = (const struct mpbios_proc *)ent; |
800 | struct cpu_attach_args caa; |
801 | int locs[CPUBUSCF_NLOCS]; |
802 | |
803 | /* XXX move this into the CPU attachment goo. */ |
804 | /* check for usability */ |
805 | if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) |
806 | return; |
807 | |
808 | mpbios_ncpu++; |
809 | |
810 | /* check for BSP flag */ |
811 | if (entry->cpu_flags & PROCENTRY_FLAG_BP) |
812 | caa.cpu_role = CPU_ROLE_BP; |
813 | else |
814 | caa.cpu_role = CPU_ROLE_AP; |
815 | |
816 | caa.cpu_id = entry->apic_id; |
817 | caa.cpu_number = entry->apic_id; |
818 | caa.cpu_func = &mp_cpu_funcs; |
819 | locs[CPUBUSCF_APID] = caa.cpu_number; |
820 | |
821 | config_found_sm_loc(self, "cpubus" , locs, &caa, mp_cpuprint, |
822 | config_stdsubmatch); |
823 | } |
824 | |
825 | static void |
826 | mpbios_dflt_conf_cpu(device_t self) |
827 | { |
828 | struct mpbios_proc mpp; |
829 | |
830 | /* mpp.type and mpp.apic_version are irrelevant for mpbios_cpu(). */ |
831 | /* |
832 | * Default configurations always feature two processors and the local |
833 | * APIC IDs are assigned consecutively by hardware starting from zero |
834 | * (sec. 5). Just determine the BSP (APIC ID). |
835 | */ |
836 | mpp.apic_id = cpu_info_primary.ci_cpuid; |
837 | mpp.cpu_flags = PROCENTRY_FLAG_EN | PROCENTRY_FLAG_BP; |
838 | mpbios_cpu((uint8_t *)&mpp, self); |
839 | |
840 | mpp.apic_id = 1 - cpu_info_primary.ci_cpuid; |
841 | mpp.cpu_flags = PROCENTRY_FLAG_EN; |
842 | mpbios_cpu((uint8_t *)&mpp, self); |
843 | } |
844 | |
845 | static void |
846 | mpbios_dflt_conf_bus(device_t self, const struct dflt_conf_entry *dflt_conf) |
847 | { |
848 | struct mpbios_bus mpb; |
849 | size_t i; |
850 | |
851 | /* mpb.type is irrelevant for mpbios_bus(). */ |
852 | mpb.bus_id = 0; |
853 | for (i = 0; i < __arraycount(dflt_conf->bus_type); i++) { |
854 | if (dflt_conf->bus_type[i] != NULL) { |
855 | memcpy(mpb.bus_type, dflt_conf->bus_type[i], 6); |
856 | mpbios_bus((u_int8_t *)&mpb, self); |
857 | mpb.bus_id++; |
858 | } |
859 | } |
860 | } |
861 | |
862 | static void |
863 | mpbios_dflt_conf_ioapic(device_t self) |
864 | { |
865 | struct mpbios_ioapic mpio; |
866 | |
867 | /* mpio.type is irrelevant for mpbios_ioapic(). */ |
868 | mpio.apic_id = DFLT_IOAPIC_ID; |
869 | /* XXX Let ioapic driver read real APIC version... */ |
870 | mpio.apic_version = 0; |
871 | mpio.apic_flags = IOAPICENTRY_FLAG_EN; |
872 | mpio.apic_address = (uint32_t)IOAPIC_BASE_DEFAULT; |
873 | mpbios_ioapic((uint8_t *)&mpio, self); |
874 | } |
875 | |
876 | static void |
877 | mpbios_dflt_conf_int(device_t self, const struct dflt_conf_entry *dflt_conf, |
878 | const int *dflt_bus_irq) |
879 | { |
880 | struct mpbios_int mpi; |
881 | size_t i; |
882 | int cur_intr; |
883 | uint16_t level_inv; |
884 | |
885 | cur_intr = 0; |
886 | /* |
887 | * INTIN0 |
888 | */ |
889 | /* |
890 | * 8259A INTR is connected to INTIN0 for default configs 1-6, but not |
891 | * for default config 7 (sec. 5.3). |
892 | */ |
893 | if ((dflt_conf->flags & INTIN0_NC) == 0) { |
894 | /* mpi.type is irrelevant for mpbios_int(). */ |
895 | mpi.int_type = MPS_INTTYPE_ExtINT; |
896 | mpi.int_flags = 0; |
897 | mpi.src_bus_id = 0; |
898 | mpi.src_bus_irq = 0; |
899 | mpi.dst_apic_id = DFLT_IOAPIC_ID; |
900 | mpi.dst_apic_int = 0; |
901 | mpbios_int((u_int8_t *)&mpi, MPS_MCT_IOINT, |
902 | &mp_intrs[cur_intr++]); |
903 | } |
904 | |
905 | /* |
906 | * INTINx |
907 | */ |
908 | /* mpi.type is irrelevant for mpbios_int(). */ |
909 | mpi.int_type = MPS_INTTYPE_INT; |
910 | /* |
911 | * PCI interrupt lines appear as (E)ISA interrupt lines/on bus 0 |
912 | * (sec. 5.2). |
913 | */ |
914 | mpi.src_bus_id = 0; |
915 | mpi.dst_apic_id = DFLT_IOAPIC_ID; |
916 | /* |
917 | * Compliant systems must convert active-low, level-triggered |
918 | * interrupts to active-high by external inverters before INTINx |
919 | *(table 5-1; sec. 5.3.2). |
920 | */ |
921 | if (dflt_conf->flags & ELCR_INV) { |
922 | #ifdef X86_MPBIOS_SUPPORT_EISA |
923 | /* Systems with ELCRs use them to control the inverters. */ |
924 | level_inv = ((uint16_t)inb(ELCR1) << 8) | inb(ELCR0); |
925 | #else |
926 | level_inv = 0; |
927 | #endif |
928 | } else if (dflt_conf->flags & MCA_INV) { |
929 | /* MCA systems have fixed inverters. */ |
930 | level_inv = 0xffffU; |
931 | } else |
932 | level_inv = 0; |
933 | |
934 | for (i = 0; i < __arraycount(dflt_bus_irq_tab[0]); i++) { |
935 | if (dflt_bus_irq[i] >= 0) { |
936 | mpi.src_bus_irq = (uint8_t)dflt_bus_irq[i]; |
937 | if (level_inv & (1U << mpi.src_bus_irq)) |
938 | mpi.int_flags = (MPS_INTTR_LEVEL << 2) |
939 | | MPS_INTPO_ACTHI; |
940 | else |
941 | mpi.int_flags = 0; /* conforms to bus spec. */ |
942 | mpi.dst_apic_int = (uint8_t)i; |
943 | mpbios_int((u_int8_t *)&mpi, MPS_MCT_IOINT, |
944 | &mp_intrs[cur_intr++]); |
945 | } |
946 | } |
947 | |
948 | /* |
949 | * LINTINx |
950 | */ |
951 | /* mpi.type is irrelevant for mpbios_int(). */ |
952 | mpi.int_flags = 0; |
953 | mpi.src_bus_id = 0; |
954 | mpi.src_bus_irq = 0; |
955 | mpi.dst_apic_id = MPS_ALL_APICS; |
956 | for (i = 0; i < __arraycount(dflt_lint_tab); i++) { |
957 | mpi.int_type = dflt_lint_tab[i]; |
958 | mpi.dst_apic_int = (uint8_t)i; |
959 | mpbios_int((u_int8_t *)&mpi, MPS_MCT_LINT, |
960 | &mp_intrs[cur_intr++]); |
961 | } |
962 | } |
963 | |
964 | /* |
965 | * The following functions conspire to compute base ioapic redirection |
966 | * table entry for a given interrupt line. |
967 | * |
968 | * Fill in: trigger mode, polarity, and possibly delivery mode. |
969 | */ |
970 | static void |
971 | mp_cfg_special_intr(const struct mpbios_int *entry, uint32_t *redir) |
972 | { |
973 | |
974 | /* |
975 | * All of these require edge triggered, zero vector, |
976 | * appropriate delivery mode. |
977 | * see page 13 of the 82093AA datasheet. |
978 | */ |
979 | *redir &= ~IOAPIC_REDLO_DEL_MASK; |
980 | *redir &= ~IOAPIC_REDLO_VECTOR_MASK; |
981 | *redir &= ~IOAPIC_REDLO_LEVEL; |
982 | |
983 | switch (entry->int_type) { |
984 | case MPS_INTTYPE_NMI: |
985 | *redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT); |
986 | break; |
987 | |
988 | case MPS_INTTYPE_SMI: |
989 | *redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT); |
990 | break; |
991 | |
992 | case MPS_INTTYPE_ExtINT: |
993 | /* |
994 | * We are using the ioapic in "native" mode. |
995 | * This indicates where the 8259 is wired to the ioapic |
996 | * and/or local apic.. |
997 | */ |
998 | *redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT); |
999 | *redir |= (IOAPIC_REDLO_MASK); |
1000 | break; |
1001 | } |
1002 | } |
1003 | |
1004 | /* XXX too much duplicated code here. */ |
1005 | |
1006 | static void |
1007 | mp_cfg_pci_intr(const struct mpbios_int *entry, uint32_t *redir) |
1008 | { |
1009 | int mpspo = entry->int_flags & 0x03; /* XXX magic */ |
1010 | int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ |
1011 | |
1012 | *redir &= ~IOAPIC_REDLO_DEL_MASK; |
1013 | switch (mpspo) { |
1014 | case MPS_INTPO_ACTHI: |
1015 | *redir &= ~IOAPIC_REDLO_ACTLO; |
1016 | break; |
1017 | case MPS_INTPO_DEF: |
1018 | case MPS_INTPO_ACTLO: |
1019 | *redir |= IOAPIC_REDLO_ACTLO; |
1020 | break; |
1021 | default: |
1022 | panic("unknown MPS interrupt polarity %d" , mpspo); |
1023 | } |
1024 | |
1025 | if (entry->int_type != MPS_INTTYPE_INT) { |
1026 | mp_cfg_special_intr(entry, redir); |
1027 | return; |
1028 | } |
1029 | *redir |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT); |
1030 | |
1031 | switch (mpstrig) { |
1032 | case MPS_INTTR_DEF: |
1033 | case MPS_INTTR_LEVEL: |
1034 | *redir |= IOAPIC_REDLO_LEVEL; |
1035 | break; |
1036 | case MPS_INTTR_EDGE: |
1037 | *redir &= ~IOAPIC_REDLO_LEVEL; |
1038 | break; |
1039 | default: |
1040 | panic("unknown MPS interrupt trigger %d" , mpstrig); |
1041 | } |
1042 | } |
1043 | |
1044 | #ifdef X86_MPBIOS_SUPPORT_EISA |
1045 | static void |
1046 | mp_cfg_eisa_intr(const struct mpbios_int *entry, uint32_t *redir) |
1047 | { |
1048 | int mpspo = entry->int_flags & 0x03; /* XXX magic */ |
1049 | int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ |
1050 | |
1051 | *redir &= ~IOAPIC_REDLO_DEL_MASK; |
1052 | switch (mpspo) { |
1053 | case MPS_INTPO_DEF: |
1054 | case MPS_INTPO_ACTHI: |
1055 | *redir &= ~IOAPIC_REDLO_ACTLO; |
1056 | break; |
1057 | case MPS_INTPO_ACTLO: |
1058 | *redir |= IOAPIC_REDLO_ACTLO; |
1059 | break; |
1060 | default: |
1061 | panic("unknown MPS interrupt polarity %d" , mpspo); |
1062 | } |
1063 | |
1064 | if (entry->int_type != MPS_INTTYPE_INT) { |
1065 | mp_cfg_special_intr(entry, redir); |
1066 | return; |
1067 | } |
1068 | *redir |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT); |
1069 | |
1070 | switch (mpstrig) { |
1071 | case MPS_INTTR_LEVEL: |
1072 | *redir |= IOAPIC_REDLO_LEVEL; |
1073 | break; |
1074 | case MPS_INTTR_EDGE: |
1075 | *redir &= ~IOAPIC_REDLO_LEVEL; |
1076 | break; |
1077 | case MPS_INTTR_DEF: |
1078 | /* |
1079 | * Set "default" setting based on ELCR value snagged |
1080 | * earlier. |
1081 | */ |
1082 | if (mp_busses[entry->src_bus_id].mb_data & |
1083 | (1 << entry->src_bus_irq)) { |
1084 | *redir |= IOAPIC_REDLO_LEVEL; |
1085 | } else { |
1086 | *redir &= ~IOAPIC_REDLO_LEVEL; |
1087 | } |
1088 | break; |
1089 | default: |
1090 | panic("unknown MPS interrupt trigger %d" , mpstrig); |
1091 | } |
1092 | } |
1093 | #endif |
1094 | |
1095 | |
1096 | static void |
1097 | mp_cfg_isa_intr(const struct mpbios_int *entry, uint32_t *redir) |
1098 | { |
1099 | int mpspo = entry->int_flags & 0x03; /* XXX magic */ |
1100 | int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ |
1101 | |
1102 | *redir &= ~IOAPIC_REDLO_DEL_MASK; |
1103 | switch (mpspo) { |
1104 | case MPS_INTPO_DEF: |
1105 | case MPS_INTPO_ACTHI: |
1106 | *redir &= ~IOAPIC_REDLO_ACTLO; |
1107 | break; |
1108 | case MPS_INTPO_ACTLO: |
1109 | *redir |= IOAPIC_REDLO_ACTLO; |
1110 | break; |
1111 | default: |
1112 | panic("unknown MPS interrupt polarity %d" , mpspo); |
1113 | } |
1114 | |
1115 | if (entry->int_type != MPS_INTTYPE_INT) { |
1116 | mp_cfg_special_intr(entry, redir); |
1117 | return; |
1118 | } |
1119 | *redir |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT); |
1120 | |
1121 | switch (mpstrig) { |
1122 | case MPS_INTTR_LEVEL: |
1123 | *redir |= IOAPIC_REDLO_LEVEL; |
1124 | break; |
1125 | case MPS_INTTR_DEF: |
1126 | case MPS_INTTR_EDGE: |
1127 | *redir &= ~IOAPIC_REDLO_LEVEL; |
1128 | break; |
1129 | default: |
1130 | panic("unknown MPS interrupt trigger %d" , mpstrig); |
1131 | } |
1132 | } |
1133 | |
1134 | |
1135 | static void |
1136 | mp_print_special_intr(int intr) |
1137 | { |
1138 | } |
1139 | |
1140 | static void |
1141 | mp_print_pci_intr(int intr) |
1142 | { |
1143 | printf(" device %d INT_%c" , (intr>>2)&0x1f, 'A' + (intr & 0x3)); |
1144 | } |
1145 | |
1146 | static void |
1147 | mp_print_isa_intr(int intr) |
1148 | { |
1149 | printf(" irq %d" , intr); |
1150 | } |
1151 | |
1152 | #ifdef X86_MPBIOS_SUPPORT_EISA |
1153 | static void |
1154 | mp_print_eisa_intr(int intr) |
1155 | { |
1156 | printf(" EISA irq %d" , intr); |
1157 | } |
1158 | #endif |
1159 | |
1160 | |
1161 | |
1162 | #define TAB_UNIT 4 |
1163 | #define TAB_ROUND(a) _TAB_ROUND(a, TAB_UNIT) |
1164 | |
1165 | #define _TAB_ROUND(a,u) (((a) + (u - 1)) & ~(u-1)) |
1166 | #define EXTEND_TAB(a,u) (!(_TAB_ROUND(a,u) == _TAB_ROUND((a+1),u))) |
1167 | |
1168 | static void |
1169 | mpbios_bus(const uint8_t *ent, device_t self) |
1170 | { |
1171 | const struct mpbios_bus *entry = (const struct mpbios_bus *)ent; |
1172 | int bus_id = entry->bus_id; |
1173 | |
1174 | aprint_verbose("mpbios: bus %d is type %6.6s\n" , bus_id, |
1175 | entry->bus_type); |
1176 | |
1177 | #ifdef DIAGNOSTIC |
1178 | /* |
1179 | * This "should not happen" unless the table changes out |
1180 | * from underneath us |
1181 | */ |
1182 | if (bus_id >= mp_nbus) { |
1183 | panic("mpbios: bus number %d out of range?? (type %6.6s)\n" , |
1184 | bus_id, entry->bus_type); |
1185 | } |
1186 | #endif |
1187 | |
1188 | mp_busses[bus_id].mb_intrs = NULL; |
1189 | |
1190 | if (memcmp(entry->bus_type, "PCI " , 6) == 0) { |
1191 | mp_busses[bus_id].mb_name = "pci" ; |
1192 | mp_busses[bus_id].mb_idx = bus_id; |
1193 | mp_busses[bus_id].mb_intr_print = mp_print_pci_intr; |
1194 | mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr; |
1195 | #ifdef X86_MPBIOS_SUPPORT_EISA |
1196 | } else if (memcmp(entry->bus_type, "EISA " , 6) == 0) { |
1197 | mp_busses[bus_id].mb_name = "eisa" ; |
1198 | mp_busses[bus_id].mb_idx = bus_id; |
1199 | mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr; |
1200 | mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr; |
1201 | |
1202 | mp_busses[bus_id].mb_data = inb(ELCR0) | (inb(ELCR1) << 8); |
1203 | |
1204 | if (mp_eisa_bus != -1) |
1205 | aprint_error("oops: multiple isa busses?\n" ); |
1206 | else |
1207 | mp_eisa_bus = bus_id; |
1208 | #endif |
1209 | |
1210 | } else if (memcmp(entry->bus_type, "ISA " , 6) == 0) { |
1211 | mp_busses[bus_id].mb_name = "isa" ; |
1212 | mp_busses[bus_id].mb_idx = 0; /* XXX */ |
1213 | mp_busses[bus_id].mb_intr_print = mp_print_isa_intr; |
1214 | mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr; |
1215 | if (mp_isa_bus != -1) |
1216 | printf("oops: multiple isa busses?\n" ); |
1217 | else |
1218 | mp_isa_bus = bus_id; |
1219 | } else |
1220 | aprint_error_dev(self, "unsupported bus type %6.6s\n" , |
1221 | entry->bus_type); |
1222 | } |
1223 | |
1224 | |
1225 | static void |
1226 | mpbios_ioapic(const uint8_t *ent, device_t self) |
1227 | { |
1228 | const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent; |
1229 | |
1230 | /* XXX let flags checking happen in ioapic driver.. */ |
1231 | if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN)) |
1232 | return; |
1233 | |
1234 | mpbios_nioapic++; |
1235 | |
1236 | #if NIOAPIC > 0 |
1237 | { |
1238 | int locs[IOAPICBUSCF_NLOCS]; |
1239 | struct apic_attach_args aaa; |
1240 | |
1241 | aaa.apic_id = entry->apic_id; |
1242 | aaa.apic_version = entry->apic_version; |
1243 | aaa.apic_address = (paddr_t)entry->apic_address; |
1244 | aaa.apic_vecbase = -1; |
1245 | aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE; |
1246 | locs[IOAPICBUSCF_APID] = aaa.apic_id; |
1247 | |
1248 | config_found_sm_loc(self, "ioapicbus" , locs, &aaa, mp_ioapicprint, |
1249 | config_stdsubmatch); |
1250 | } |
1251 | #endif |
1252 | } |
1253 | |
1254 | static const char inttype_fmt[] = "\177\020" |
1255 | "f\0\2type\0" "=\1NMI\0" "=\2SMI\0" "=\3ExtINT\0" ; |
1256 | |
1257 | static const char flagtype_fmt[] = "\177\020" |
1258 | "f\0\2pol\0" "=\1Act Hi\0" "=\3Act Lo\0" |
1259 | "f\2\2trig\0" "=\1Edge\0" "=\3Level\0" ; |
1260 | |
1261 | static void |
1262 | mpbios_int(const uint8_t *ent, int enttype, struct mp_intr_map *mpi) |
1263 | { |
1264 | const struct mpbios_int *entry = (const struct mpbios_int *)ent; |
1265 | struct ioapic_softc *sc = NULL; |
1266 | struct pic *sc2; |
1267 | |
1268 | struct mp_intr_map *altmpi; |
1269 | struct mp_bus *mpb; |
1270 | |
1271 | uint32_t id = entry->dst_apic_id; |
1272 | uint32_t pin = entry->dst_apic_int; |
1273 | uint32_t bus = entry->src_bus_id; |
1274 | uint32_t dev = entry->src_bus_irq; |
1275 | uint32_t type = entry->int_type; |
1276 | uint32_t flags = entry->int_flags; |
1277 | |
1278 | switch (type) { |
1279 | case MPS_INTTYPE_INT: |
1280 | mpb = &(mp_busses[bus]); |
1281 | break; |
1282 | case MPS_INTTYPE_ExtINT: |
1283 | mpb = &extint_bus; |
1284 | break; |
1285 | case MPS_INTTYPE_SMI: |
1286 | mpb = &smi_bus; |
1287 | break; |
1288 | case MPS_INTTYPE_NMI: |
1289 | mpb = &nmi_bus; |
1290 | break; |
1291 | default: |
1292 | panic("unknown MPS interrupt type %d" , entry->int_type); |
1293 | } |
1294 | |
1295 | mpi->next = mpb->mb_intrs; |
1296 | mpb->mb_intrs = mpi; |
1297 | mpi->bus = mpb; |
1298 | mpi->bus_pin = dev; |
1299 | mpi->global_int = -1; |
1300 | |
1301 | mpi->type = type; |
1302 | mpi->flags = flags; |
1303 | mpi->redir = 0; |
1304 | if (mpb->mb_intr_cfg == NULL) { |
1305 | printf("mpbios: can't find bus %d for apic %d pin %d\n" , |
1306 | bus, id, pin); |
1307 | return; |
1308 | } |
1309 | |
1310 | (*mpb->mb_intr_cfg)(entry, &mpi->redir); |
1311 | |
1312 | if (enttype == MPS_MCT_IOINT) { |
1313 | #if NIOAPIC > 0 |
1314 | sc = ioapic_find(id); |
1315 | #else |
1316 | sc = NULL; |
1317 | #endif |
1318 | if (sc == NULL) { |
1319 | #if NIOAPIC > 0 |
1320 | /* |
1321 | * If we couldn't find an ioapic by given id, retry to |
1322 | * get it by a pin number. |
1323 | */ |
1324 | sc = ioapic_find_bybase(pin); |
1325 | if (sc == NULL) { |
1326 | aprint_error("mpbios: can't find ioapic by" |
1327 | " neither apid(%d) nor pin number(%d)\n" , |
1328 | id, pin); |
1329 | return; |
1330 | } |
1331 | aprint_verbose("mpbios: use apid %d instead of %d\n" , |
1332 | sc->sc_pic.pic_apicid, id); |
1333 | id = sc->sc_pic.pic_apicid; |
1334 | #else |
1335 | aprint_error("mpbios: can't find ioapic %d\n" , id); |
1336 | return; |
1337 | #endif |
1338 | } |
1339 | |
1340 | /* |
1341 | * XXX workaround for broken BIOSs that put the ACPI global |
1342 | * interrupt number in the entry, not the pin number. |
1343 | */ |
1344 | if (pin >= sc->sc_apic_sz) { |
1345 | sc2 = intr_findpic(pin); |
1346 | if (sc2 && sc2->pic_ioapic != sc) { |
1347 | printf("mpbios: bad pin %d for apic %d\n" , |
1348 | pin, id); |
1349 | return; |
1350 | } |
1351 | printf("mpbios: WARNING: pin %d for apic %d too high; " |
1352 | "assuming ACPI global int value\n" , pin, id); |
1353 | pin -= sc->sc_apic_vecbase; |
1354 | } |
1355 | |
1356 | mpi->ioapic = (struct pic *)sc; |
1357 | mpi->ioapic_pin = pin; |
1358 | |
1359 | altmpi = sc->sc_pins[pin].ip_map; |
1360 | |
1361 | if (altmpi != NULL) { |
1362 | if ((altmpi->type != type) || |
1363 | (altmpi->flags != flags)) { |
1364 | printf("%s: conflicting map entries for pin %d\n" , |
1365 | device_xname(sc->sc_dev), pin); |
1366 | } |
1367 | } else |
1368 | sc->sc_pins[pin].ip_map = mpi; |
1369 | } else { |
1370 | if (pin >= 2) |
1371 | printf("pin %d of local apic doesn't exist!\n" , pin); |
1372 | else { |
1373 | mpi->ioapic = NULL; |
1374 | mpi->ioapic_pin = pin; |
1375 | mpi->cpu_id = id; |
1376 | } |
1377 | } |
1378 | |
1379 | mpi->ioapic_ih = APIC_INT_VIA_APIC | |
1380 | ((id << APIC_INT_APIC_SHIFT) | (pin << APIC_INT_PIN_SHIFT)); |
1381 | |
1382 | if (mp_verbose) { |
1383 | char buf[256]; |
1384 | |
1385 | printf("%s: int%d attached to %s" , |
1386 | sc ? device_xname(sc->sc_dev) : "local apic" , |
1387 | pin, mpb->mb_name); |
1388 | |
1389 | if (mpb->mb_idx != -1) |
1390 | printf("%d" , mpb->mb_idx); |
1391 | |
1392 | (*(mpb->mb_intr_print))(dev); |
1393 | |
1394 | snprintb(buf, sizeof(buf), inttype_fmt, type); |
1395 | printf(" (type %s" , buf); |
1396 | |
1397 | snprintb(buf, sizeof(buf), flagtype_fmt, flags); |
1398 | printf(" flags %s)\n" , buf); |
1399 | } |
1400 | } |
1401 | |
1402 | #if NPCI > 0 |
1403 | int |
1404 | mpbios_pci_attach_hook(device_t parent, device_t self, |
1405 | struct pcibus_attach_args *pba) |
1406 | { |
1407 | struct mp_bus *mpb; |
1408 | |
1409 | if (mpbios_scanned == 0) |
1410 | return ENOENT; |
1411 | |
1412 | if (pba->pba_bus >= mp_isa_bus) { |
1413 | intr_add_pcibus(pba); |
1414 | return 0; |
1415 | } |
1416 | |
1417 | mpb = &mp_busses[pba->pba_bus]; |
1418 | if (mpb->mb_name != NULL) { |
1419 | if (strcmp(mpb->mb_name, "pci" )) |
1420 | return EINVAL; |
1421 | } else |
1422 | mpb->mb_name = "pci" ; |
1423 | |
1424 | if (mp_verbose) |
1425 | printf("\n%s: added to list as bus %d" , device_xname(parent), |
1426 | pba->pba_bus); |
1427 | |
1428 | mpb->mb_dev = self; |
1429 | mpb->mb_pci_bridge_tag = pba->pba_bridgetag; |
1430 | mpb->mb_pci_chipset_tag = pba->pba_pc; |
1431 | return 0; |
1432 | } |
1433 | #endif |
1434 | |