1 | /* $NetBSD: mpacpi.c,v 1.102 2016/07/07 06:55:40 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2003 Wasabi Systems, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Written by Frank van der Linden for Wasabi Systems, Inc. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior |
23 | * written permission. |
24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ |
37 | |
38 | #include <sys/cdefs.h> |
39 | __KERNEL_RCSID(0, "$NetBSD: mpacpi.c,v 1.102 2016/07/07 06:55:40 msaitoh Exp $" ); |
40 | |
41 | #include "acpica.h" |
42 | #include "opt_acpi.h" |
43 | #include "opt_ddb.h" |
44 | #include "opt_mpbios.h" |
45 | #include "opt_multiprocessor.h" |
46 | #include "pchb.h" |
47 | |
48 | #include <sys/param.h> |
49 | #include <sys/systm.h> |
50 | #include <sys/kernel.h> |
51 | #include <sys/device.h> |
52 | #include <sys/kmem.h> |
53 | #include <sys/queue.h> |
54 | |
55 | #include <uvm/uvm_extern.h> |
56 | |
57 | #include <machine/specialreg.h> |
58 | #include <machine/cpuvar.h> |
59 | #include <sys/bus.h> |
60 | #include <machine/mpacpi.h> |
61 | #include <machine/mpbiosvar.h> |
62 | |
63 | #include <machine/i82093reg.h> |
64 | #include <machine/i82093var.h> |
65 | #include <machine/i82489reg.h> |
66 | #include <machine/i82489var.h> |
67 | #include <dev/isa/isareg.h> |
68 | #include <dev/pci/pcivar.h> |
69 | #include <dev/pci/pcidevs.h> |
70 | #include <dev/pci/ppbreg.h> |
71 | |
72 | #include <dev/acpi/acpica.h> |
73 | #include <dev/acpi/acpireg.h> |
74 | #include <dev/acpi/acpivar.h> |
75 | |
76 | #include <dev/cons.h> |
77 | |
78 | #define _COMPONENT ACPI_RESOURCE_COMPONENT |
79 | ACPI_MODULE_NAME ("mpacpi" ) |
80 | |
81 | #include "pci.h" |
82 | #include "ioapic.h" |
83 | #include "lapic.h" |
84 | |
85 | #include "locators.h" |
86 | |
87 | /* XXX room for PCI-to-PCI bus */ |
88 | #define BUS_BUFFER (16) |
89 | |
90 | #if NPCI > 0 |
91 | struct mpacpi_pcibus { |
92 | TAILQ_ENTRY(mpacpi_pcibus) mpr_list; |
93 | ACPI_HANDLE mpr_handle; /* Same thing really, but.. */ |
94 | ACPI_BUFFER mpr_buf; /* preserve _PRT */ |
95 | int mpr_seg; /* PCI segment number */ |
96 | int mpr_bus; /* PCI bus number */ |
97 | }; |
98 | |
99 | static TAILQ_HEAD(, mpacpi_pcibus) mpacpi_pcibusses; |
100 | |
101 | #endif |
102 | |
103 | static int mpacpi_cpuprint(void *, const char *); |
104 | static int mpacpi_ioapicprint(void *, const char *); |
105 | |
106 | /* acpi_madt_walk callbacks */ |
107 | static ACPI_STATUS mpacpi_count(ACPI_SUBTABLE_HEADER *, void *); |
108 | static ACPI_STATUS mpacpi_config_cpu(ACPI_SUBTABLE_HEADER *, void *); |
109 | static ACPI_STATUS mpacpi_config_ioapic(ACPI_SUBTABLE_HEADER *, void *); |
110 | static ACPI_STATUS mpacpi_nonpci_intr(ACPI_SUBTABLE_HEADER *, void *); |
111 | |
112 | #if NPCI > 0 |
113 | static int mpacpi_pcircount(struct mpacpi_pcibus *); |
114 | static int mpacpi_pciroute(struct mpacpi_pcibus *); |
115 | static int mpacpi_find_pcibusses(struct acpi_softc *); |
116 | |
117 | static void mpacpi_print_pci_intr(int); |
118 | #endif |
119 | |
120 | static void mpacpi_config_irouting(struct acpi_softc *); |
121 | |
122 | static void mpacpi_print_intr(struct mp_intr_map *); |
123 | static void mpacpi_print_isa_intr(int); |
124 | |
125 | static void mpacpi_user_continue(const char *fmt, ...); |
126 | |
127 | #ifdef DDB |
128 | void mpacpi_dump(void); |
129 | #endif |
130 | |
131 | int mpacpi_nioapic; /* number of ioapics */ |
132 | int mpacpi_ncpu; /* number of cpus */ |
133 | int mpacpi_nintsrc; /* number of non-device interrupts */ |
134 | |
135 | #if NPCI > 0 |
136 | static int mpacpi_npci; |
137 | static int mpacpi_maxpci; |
138 | static int mpacpi_npciroots; |
139 | #endif |
140 | |
141 | static int mpacpi_intr_index; |
142 | static paddr_t mpacpi_lapic_base = LAPIC_BASE; |
143 | |
144 | int mpacpi_step; |
145 | int mpacpi_force; |
146 | |
147 | static int |
148 | mpacpi_cpuprint(void *aux, const char *pnp) |
149 | { |
150 | struct cpu_attach_args *caa = aux; |
151 | |
152 | if (pnp) |
153 | aprint_normal("cpu at %s" , pnp); |
154 | aprint_normal(" apid %d" , caa->cpu_number); |
155 | return (UNCONF); |
156 | } |
157 | |
158 | static int |
159 | mpacpi_ioapicprint(void *aux, const char *pnp) |
160 | { |
161 | struct apic_attach_args *aaa = aux; |
162 | |
163 | if (pnp) |
164 | aprint_normal("ioapic at %s" , pnp); |
165 | aprint_normal(" apid %d" , aaa->apic_id); |
166 | return (UNCONF); |
167 | } |
168 | |
169 | /* |
170 | * Handle special interrupt sources and overrides from the MADT. |
171 | * This is a callback function for acpi_madt_walk() (see acpi.c). |
172 | */ |
173 | static ACPI_STATUS |
174 | mpacpi_nonpci_intr(ACPI_SUBTABLE_HEADER *hdrp, void *aux) |
175 | { |
176 | int *index = aux, pin, lindex; |
177 | struct mp_intr_map *mpi; |
178 | ACPI_MADT_NMI_SOURCE *ioapic_nmi; |
179 | ACPI_MADT_LOCAL_APIC_NMI *lapic_nmi; |
180 | ACPI_MADT_INTERRUPT_OVERRIDE *isa_ovr; |
181 | ACPI_MADT_LOCAL_X2APIC_NMI *x2apic_nmi; |
182 | struct pic *pic; |
183 | extern struct acpi_softc *acpi_softc; /* XXX */ |
184 | |
185 | switch (hdrp->Type) { |
186 | case ACPI_MADT_TYPE_NMI_SOURCE: |
187 | ioapic_nmi = (ACPI_MADT_NMI_SOURCE *)hdrp; |
188 | pic = intr_findpic(ioapic_nmi->GlobalIrq); |
189 | if (pic == NULL) |
190 | break; |
191 | #if NIOAPIC == 0 |
192 | if (pic->pic_type == PIC_IOAPIC) |
193 | break; |
194 | #endif |
195 | mpi = &mp_intrs[*index]; |
196 | (*index)++; |
197 | mpi->next = NULL; |
198 | mpi->bus = NULL; |
199 | mpi->type = MPS_INTTYPE_NMI; |
200 | mpi->ioapic = pic; |
201 | pin = ioapic_nmi->GlobalIrq - pic->pic_vecbase; |
202 | mpi->ioapic_pin = pin; |
203 | mpi->bus_pin = -1; |
204 | mpi->redir = (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT); |
205 | #if NIOAPIC > 0 |
206 | if (pic->pic_type == PIC_IOAPIC) { |
207 | pic->pic_ioapic->sc_pins[pin].ip_map = mpi; |
208 | mpi->ioapic_ih = APIC_INT_VIA_APIC | |
209 | (pic->pic_apicid << APIC_INT_APIC_SHIFT) | |
210 | (pin << APIC_INT_PIN_SHIFT); |
211 | } else |
212 | #endif |
213 | mpi->ioapic_ih = pin; |
214 | mpi->flags = ioapic_nmi->IntiFlags; |
215 | mpi->global_int = ioapic_nmi->GlobalIrq; |
216 | break; |
217 | case ACPI_MADT_TYPE_LOCAL_APIC_NMI: |
218 | lapic_nmi = (ACPI_MADT_LOCAL_APIC_NMI *)hdrp; |
219 | mpi = &mp_intrs[*index]; |
220 | (*index)++; |
221 | mpi->next = NULL; |
222 | mpi->bus = NULL; |
223 | mpi->ioapic = NULL; |
224 | mpi->type = MPS_INTTYPE_NMI; |
225 | mpi->ioapic_pin = lapic_nmi->Lint; |
226 | mpi->cpu_id = lapic_nmi->ProcessorId; |
227 | mpi->redir = (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT); |
228 | mpi->global_int = -1; |
229 | break; |
230 | case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: |
231 | isa_ovr = (ACPI_MADT_INTERRUPT_OVERRIDE *)hdrp; |
232 | if (mp_verbose) { |
233 | printf("mpacpi: ISA interrupt override %d -> %d (%d/%d)\n" , |
234 | isa_ovr->SourceIrq, isa_ovr->GlobalIrq, |
235 | isa_ovr->IntiFlags & ACPI_MADT_POLARITY_MASK, |
236 | (isa_ovr->IntiFlags & ACPI_MADT_TRIGGER_MASK) >>2); |
237 | } |
238 | if (isa_ovr->SourceIrq > 15 || isa_ovr->SourceIrq == 2 || |
239 | (isa_ovr->SourceIrq == 0 && isa_ovr->GlobalIrq == 2 && |
240 | (acpi_softc->sc_quirks & ACPI_QUIRK_IRQ0))) |
241 | break; |
242 | pic = intr_findpic(isa_ovr->GlobalIrq); |
243 | if (pic == NULL) |
244 | break; |
245 | #if NIOAPIC == 0 |
246 | if (pic->pic_type == PIC_IOAPIC) |
247 | break; |
248 | #endif |
249 | pin = isa_ovr->GlobalIrq - pic->pic_vecbase; |
250 | lindex = isa_ovr->SourceIrq; |
251 | /* |
252 | * IRQ 2 was skipped in the default setup. |
253 | */ |
254 | if (lindex > 2) |
255 | lindex--; |
256 | mpi = &mp_intrs[lindex]; |
257 | #if NIOAPIC > 0 |
258 | if (pic->pic_type == PIC_IOAPIC) { |
259 | mpi->ioapic_ih = APIC_INT_VIA_APIC | |
260 | (pic->pic_apicid << APIC_INT_APIC_SHIFT) | |
261 | (pin << APIC_INT_PIN_SHIFT); |
262 | } else |
263 | #endif |
264 | mpi->ioapic_ih = pin; |
265 | mpi->bus_pin = isa_ovr->SourceIrq; |
266 | mpi->ioapic = (struct pic *)pic; |
267 | mpi->ioapic_pin = pin; |
268 | mpi->sflags |= MPI_OVR; |
269 | mpi->redir = 0; |
270 | mpi->global_int = isa_ovr->GlobalIrq; |
271 | switch (isa_ovr->IntiFlags & ACPI_MADT_POLARITY_MASK) { |
272 | case ACPI_MADT_POLARITY_ACTIVE_HIGH: |
273 | mpi->redir &= ~IOAPIC_REDLO_ACTLO; |
274 | break; |
275 | case ACPI_MADT_POLARITY_ACTIVE_LOW: |
276 | mpi->redir |= IOAPIC_REDLO_ACTLO; |
277 | break; |
278 | case ACPI_MADT_POLARITY_CONFORMS: |
279 | if (isa_ovr->SourceIrq == AcpiGbl_FADT.SciInterrupt) |
280 | mpi->redir |= IOAPIC_REDLO_ACTLO; |
281 | else |
282 | mpi->redir &= ~IOAPIC_REDLO_ACTLO; |
283 | break; |
284 | } |
285 | mpi->redir |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT); |
286 | switch (isa_ovr->IntiFlags & ACPI_MADT_TRIGGER_MASK) { |
287 | case ACPI_MADT_TRIGGER_LEVEL: |
288 | mpi->redir |= IOAPIC_REDLO_LEVEL; |
289 | break; |
290 | case ACPI_MADT_TRIGGER_EDGE: |
291 | mpi->redir &= ~IOAPIC_REDLO_LEVEL; |
292 | break; |
293 | case ACPI_MADT_TRIGGER_CONFORMS: |
294 | if (isa_ovr->SourceIrq == AcpiGbl_FADT.SciInterrupt) |
295 | mpi->redir |= IOAPIC_REDLO_LEVEL; |
296 | else |
297 | mpi->redir &= ~IOAPIC_REDLO_LEVEL; |
298 | break; |
299 | } |
300 | mpi->flags = isa_ovr->IntiFlags; |
301 | #if NIOAPIC > 0 |
302 | if (pic->pic_type == PIC_IOAPIC) |
303 | pic->pic_ioapic->sc_pins[pin].ip_map = mpi; |
304 | #endif |
305 | break; |
306 | |
307 | case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: |
308 | x2apic_nmi = (ACPI_MADT_LOCAL_X2APIC_NMI *)hdrp; |
309 | |
310 | mpi = &mp_intrs[*index]; |
311 | (*index)++; |
312 | mpi->next = NULL; |
313 | mpi->bus = NULL; |
314 | mpi->ioapic = NULL; |
315 | mpi->type = MPS_INTTYPE_NMI; |
316 | mpi->ioapic_pin = x2apic_nmi->Lint; |
317 | mpi->cpu_id = x2apic_nmi->Uid; |
318 | mpi->redir = (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT); |
319 | mpi->global_int = -1; |
320 | break; |
321 | |
322 | default: |
323 | break; |
324 | } |
325 | return AE_OK; |
326 | } |
327 | |
328 | /* |
329 | * Count various MP resources present in the MADT. |
330 | * This is a callback function for acpi_madt_walk(). |
331 | */ |
332 | static ACPI_STATUS |
333 | mpacpi_count(ACPI_SUBTABLE_HEADER *hdrp, void *aux) |
334 | { |
335 | ACPI_MADT_LOCAL_APIC_OVERRIDE *lop; |
336 | |
337 | switch (hdrp->Type) { |
338 | case ACPI_MADT_TYPE_LOCAL_APIC: |
339 | case ACPI_MADT_TYPE_LOCAL_X2APIC: |
340 | mpacpi_ncpu++; |
341 | break; |
342 | case ACPI_MADT_TYPE_IO_APIC: |
343 | mpacpi_nioapic++; |
344 | break; |
345 | case ACPI_MADT_TYPE_NMI_SOURCE: |
346 | case ACPI_MADT_TYPE_LOCAL_APIC_NMI: |
347 | case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: |
348 | mpacpi_nintsrc++; |
349 | break; |
350 | case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: |
351 | lop = (ACPI_MADT_LOCAL_APIC_OVERRIDE *)hdrp; |
352 | mpacpi_lapic_base = lop->Address; |
353 | default: |
354 | break; |
355 | } |
356 | return AE_OK; |
357 | } |
358 | |
359 | static ACPI_STATUS |
360 | mpacpi_config_cpu(ACPI_SUBTABLE_HEADER *hdrp, void *aux) |
361 | { |
362 | device_t parent = aux; |
363 | ACPI_MADT_LOCAL_APIC *lapic; |
364 | ACPI_MADT_LOCAL_X2APIC *x2apic; |
365 | struct cpu_attach_args caa; |
366 | int cpunum = 0; |
367 | int locs[CPUBUSCF_NLOCS]; |
368 | |
369 | #if defined(MULTIPROCESSOR) || defined(IOAPIC) |
370 | if (mpacpi_ncpu > 1) |
371 | cpunum = lapic_cpu_number(); |
372 | #endif |
373 | |
374 | switch (hdrp->Type) { |
375 | case ACPI_MADT_TYPE_LOCAL_APIC: |
376 | lapic = (ACPI_MADT_LOCAL_APIC *)hdrp; |
377 | if (lapic->LapicFlags & ACPI_MADT_ENABLED) { |
378 | if (lapic->Id != cpunum) |
379 | caa.cpu_role = CPU_ROLE_AP; |
380 | else |
381 | caa.cpu_role = CPU_ROLE_BP; |
382 | caa.cpu_id = lapic->ProcessorId; |
383 | caa.cpu_number = lapic->Id; |
384 | caa.cpu_func = &mp_cpu_funcs; |
385 | locs[CPUBUSCF_APID] = caa.cpu_number; |
386 | config_found_sm_loc(parent, "cpubus" , locs, |
387 | &caa, mpacpi_cpuprint, config_stdsubmatch); |
388 | } |
389 | break; |
390 | |
391 | case ACPI_MADT_TYPE_LOCAL_X2APIC: |
392 | x2apic = (ACPI_MADT_LOCAL_X2APIC *)hdrp; |
393 | |
394 | /* ACPI spec: "Logical processors with APIC ID values |
395 | * less than 255 must use the Processor Local APIC |
396 | * structure to convey their APIC information to OSPM." |
397 | */ |
398 | if (x2apic->LocalApicId <= 0xff) { |
399 | printf("bogus MADT X2APIC entry (id = 0x%" PRIx32")\n" , |
400 | x2apic->LocalApicId); |
401 | break; |
402 | } |
403 | |
404 | if (x2apic->LapicFlags & ACPI_MADT_ENABLED) { |
405 | if (x2apic->LocalApicId != cpunum) |
406 | caa.cpu_role = CPU_ROLE_AP; |
407 | else |
408 | caa.cpu_role = CPU_ROLE_BP; |
409 | caa.cpu_id = x2apic->Uid; |
410 | caa.cpu_number = x2apic->LocalApicId; |
411 | caa.cpu_func = &mp_cpu_funcs; |
412 | locs[CPUBUSCF_APID] = caa.cpu_number; |
413 | config_found_sm_loc(parent, "cpubus" , locs, |
414 | &caa, mpacpi_cpuprint, config_stdsubmatch); |
415 | } |
416 | break; |
417 | |
418 | } |
419 | return AE_OK; |
420 | } |
421 | |
422 | static ACPI_STATUS |
423 | mpacpi_config_ioapic(ACPI_SUBTABLE_HEADER *hdrp, void *aux) |
424 | { |
425 | device_t parent = aux; |
426 | struct apic_attach_args aaa; |
427 | ACPI_MADT_IO_APIC *p; |
428 | int locs[IOAPICBUSCF_NLOCS]; |
429 | |
430 | if (hdrp->Type == ACPI_MADT_TYPE_IO_APIC) { |
431 | p = (ACPI_MADT_IO_APIC *)hdrp; |
432 | aaa.apic_id = p->Id; |
433 | aaa.apic_address = p->Address; |
434 | aaa.apic_version = -1; |
435 | aaa.flags = IOAPIC_VWIRE; |
436 | aaa.apic_vecbase = p->GlobalIrqBase; |
437 | locs[IOAPICBUSCF_APID] = aaa.apic_id; |
438 | config_found_sm_loc(parent, "ioapicbus" , locs, &aaa, |
439 | mpacpi_ioapicprint, config_stdsubmatch); |
440 | } |
441 | return AE_OK; |
442 | } |
443 | |
444 | int |
445 | mpacpi_scan_apics(device_t self, int *ncpup) |
446 | { |
447 | int rv = 0; |
448 | |
449 | if (acpi_madt_map() != AE_OK) |
450 | return 0; |
451 | |
452 | mpacpi_ncpu = mpacpi_nintsrc = mpacpi_nioapic = 0; |
453 | acpi_madt_walk(mpacpi_count, self); |
454 | |
455 | acpi_madt_walk(mpacpi_config_ioapic, self); |
456 | |
457 | #if NLAPIC > 0 |
458 | lapic_boot_init(mpacpi_lapic_base); |
459 | #endif |
460 | |
461 | acpi_madt_walk(mpacpi_config_cpu, self); |
462 | |
463 | if (mpacpi_ncpu == 0) |
464 | goto done; |
465 | |
466 | #if NPCI > 0 |
467 | /* |
468 | * If PCI routing tables can't be built we report failure |
469 | * and let MPBIOS do the work. |
470 | */ |
471 | if (!mpacpi_force && |
472 | (acpi_find_quirks() & (ACPI_QUIRK_BADPCI)) != 0) |
473 | goto done; |
474 | #endif |
475 | rv = 1; |
476 | done: |
477 | *ncpup = mpacpi_ncpu; |
478 | acpi_madt_unmap(); |
479 | return rv; |
480 | } |
481 | |
482 | #if NPCI > 0 |
483 | |
484 | static void |
485 | mpacpi_pci_foundbus(struct acpi_devnode *ad) |
486 | { |
487 | struct mpacpi_pcibus *mpr; |
488 | ACPI_BUFFER buf; |
489 | int rv; |
490 | |
491 | /* |
492 | * set mpr_buf from _PRT (if it exists). |
493 | * set mpr_seg and mpr_bus from previously cached info. |
494 | */ |
495 | |
496 | rv = acpi_get(ad->ad_handle, &buf, AcpiGetIrqRoutingTable); |
497 | if (ACPI_FAILURE(rv)) { |
498 | buf.Length = 0; |
499 | buf.Pointer = NULL; |
500 | } |
501 | |
502 | mpr = kmem_zalloc(sizeof(struct mpacpi_pcibus), KM_SLEEP); |
503 | mpr->mpr_handle = ad->ad_handle; |
504 | mpr->mpr_buf = buf; |
505 | mpr->mpr_seg = ad->ad_pciinfo->ap_segment; |
506 | mpr->mpr_bus = ad->ad_pciinfo->ap_downbus; |
507 | TAILQ_INSERT_TAIL(&mpacpi_pcibusses, mpr, mpr_list); |
508 | |
509 | if ((ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) { |
510 | if (mp_verbose) |
511 | printf("mpacpi: found root PCI bus %d\n" , |
512 | mpr->mpr_bus); |
513 | mpacpi_npciroots++; |
514 | } else { |
515 | if (mp_verbose) |
516 | printf("mpacpi: found subordinate bus %d\n" , |
517 | mpr->mpr_bus); |
518 | } |
519 | |
520 | /* |
521 | * XXX this wrongly assumes that bus numbers are unique |
522 | * even between segments. |
523 | */ |
524 | if (mpr->mpr_bus > mpacpi_maxpci) |
525 | mpacpi_maxpci = mpr->mpr_bus; |
526 | |
527 | mpacpi_npci++; |
528 | } |
529 | |
530 | |
531 | static void |
532 | mpacpi_pci_walk(struct acpi_devnode *ad) |
533 | { |
534 | struct acpi_devnode *child; |
535 | |
536 | if (ad->ad_pciinfo && |
537 | (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) != 0) { |
538 | mpacpi_pci_foundbus(ad); |
539 | } |
540 | SIMPLEQ_FOREACH(child, &ad->ad_child_head, ad_child_list) { |
541 | mpacpi_pci_walk(child); |
542 | } |
543 | } |
544 | |
545 | static int |
546 | mpacpi_find_pcibusses(struct acpi_softc *sc) |
547 | { |
548 | |
549 | TAILQ_INIT(&mpacpi_pcibusses); |
550 | mpacpi_pci_walk(sc->sc_root); |
551 | return 0; |
552 | } |
553 | |
554 | /* |
555 | * Find all static PRT entries for a PCI bus. |
556 | */ |
557 | static int |
558 | mpacpi_pciroute(struct mpacpi_pcibus *mpr) |
559 | { |
560 | ACPI_PCI_ROUTING_TABLE *ptrp; |
561 | ACPI_HANDLE linkdev; |
562 | char *p; |
563 | struct mp_intr_map *mpi, *iter; |
564 | struct mp_bus *mpb; |
565 | struct pic *pic; |
566 | unsigned dev; |
567 | int pin; |
568 | |
569 | if (mp_verbose) |
570 | printf("mpacpi: configuring PCI bus %d int routing\n" , |
571 | mpr->mpr_bus); |
572 | |
573 | mpb = &mp_busses[mpr->mpr_bus]; |
574 | |
575 | if (mpb->mb_name != NULL) |
576 | printf("mpacpi: PCI bus %d int routing already done!\n" , |
577 | mpr->mpr_bus); |
578 | |
579 | mpb->mb_intrs = NULL; |
580 | mpb->mb_name = "pci" ; |
581 | mpb->mb_idx = mpr->mpr_bus; |
582 | mpb->mb_intr_print = mpacpi_print_pci_intr; |
583 | mpb->mb_intr_cfg = NULL; |
584 | mpb->mb_data = 0; |
585 | |
586 | if (mpr->mpr_buf.Length == 0) { |
587 | goto out; |
588 | } |
589 | |
590 | for (p = mpr->mpr_buf.Pointer; ; p += ptrp->Length) { |
591 | ptrp = (ACPI_PCI_ROUTING_TABLE *)p; |
592 | if (ptrp->Length == 0) |
593 | break; |
594 | dev = ACPI_HIWORD(ptrp->Address); |
595 | |
596 | if (ptrp->Source[0] == 0 && |
597 | (ptrp->SourceIndex == 14 || ptrp->SourceIndex == 15)) { |
598 | printf("Skipping PCI routing entry for PCI IDE compat IRQ" ); |
599 | continue; |
600 | } |
601 | |
602 | mpi = &mp_intrs[mpacpi_intr_index]; |
603 | mpi->bus_pin = (dev << 2) | (ptrp->Pin & 3); |
604 | mpi->bus = mpb; |
605 | mpi->type = MPS_INTTYPE_INT; |
606 | |
607 | /* |
608 | * First check if an entry for this device/pin combination |
609 | * was already found. Some DSDTs have more than one entry |
610 | * and it seems that the first is generally the right one. |
611 | */ |
612 | for (iter = mpb->mb_intrs; iter != NULL; iter = iter->next) { |
613 | if (iter->bus_pin == mpi->bus_pin) |
614 | break; |
615 | } |
616 | if (iter != NULL) |
617 | continue; |
618 | |
619 | ++mpacpi_intr_index; |
620 | |
621 | if (ptrp->Source[0] != 0) { |
622 | if (mp_verbose > 1) |
623 | printf("pciroute: dev %d INT%c on lnkdev %s\n" , |
624 | dev, 'A' + (ptrp->Pin & 3), ptrp->Source); |
625 | mpi->global_int = -1; |
626 | mpi->sourceindex = ptrp->SourceIndex; |
627 | if (AcpiGetHandle(ACPI_ROOT_OBJECT, ptrp->Source, |
628 | &linkdev) != AE_OK) { |
629 | printf("AcpiGetHandle failed for '%s'\n" , |
630 | ptrp->Source); |
631 | continue; |
632 | } |
633 | /* acpi_allocate_resources(linkdev); */ |
634 | mpi->ioapic_pin = -1; |
635 | mpi->linkdev = acpi_pci_link_devbyhandle(linkdev); |
636 | acpi_pci_link_add_reference(mpi->linkdev, 0, |
637 | mpr->mpr_bus, dev, ptrp->Pin & 3); |
638 | mpi->ioapic = NULL; |
639 | mpi->flags = MPS_INTPO_ACTLO | (MPS_INTTR_LEVEL << 2); |
640 | if (mp_verbose > 1) |
641 | printf("pciroute: done adding entry\n" ); |
642 | } else { |
643 | if (mp_verbose > 1) |
644 | printf("pciroute: dev %d INT%c on globint %d\n" , |
645 | dev, 'A' + (ptrp->Pin & 3), |
646 | ptrp->SourceIndex); |
647 | mpi->sourceindex = 0; |
648 | mpi->global_int = ptrp->SourceIndex; |
649 | pic = intr_findpic(ptrp->SourceIndex); |
650 | if (pic == NULL) |
651 | continue; |
652 | /* Defaults for PCI (active low, level triggered) */ |
653 | mpi->redir = |
654 | (IOAPIC_REDLO_DEL_FIXED <<IOAPIC_REDLO_DEL_SHIFT) | |
655 | IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO; |
656 | mpi->ioapic = pic; |
657 | pin = ptrp->SourceIndex - pic->pic_vecbase; |
658 | if (pic->pic_type == PIC_I8259 && pin > 15) |
659 | panic("bad pin %d for legacy IRQ" , pin); |
660 | mpi->ioapic_pin = pin; |
661 | #if NIOAPIC > 0 |
662 | if (pic->pic_type == PIC_IOAPIC) { |
663 | pic->pic_ioapic->sc_pins[pin].ip_map = mpi; |
664 | mpi->ioapic_ih = APIC_INT_VIA_APIC | |
665 | (pic->pic_apicid << APIC_INT_APIC_SHIFT) | |
666 | (pin << APIC_INT_PIN_SHIFT); |
667 | } else |
668 | #endif |
669 | mpi->ioapic_ih = pin; |
670 | mpi->linkdev = NULL; |
671 | mpi->flags = MPS_INTPO_ACTLO | (MPS_INTTR_LEVEL << 2); |
672 | if (mp_verbose > 1) |
673 | printf("pciroute: done adding entry\n" ); |
674 | } |
675 | |
676 | mpi->cpu_id = 0; |
677 | |
678 | mpi->next = mpb->mb_intrs; |
679 | mpb->mb_intrs = mpi; |
680 | } |
681 | |
682 | ACPI_FREE(mpr->mpr_buf.Pointer); |
683 | mpr->mpr_buf.Pointer = NULL; /* be preventive to bugs */ |
684 | |
685 | out: |
686 | if (mp_verbose > 1) |
687 | printf("pciroute: done\n" ); |
688 | |
689 | return 0; |
690 | } |
691 | |
692 | /* |
693 | * Count number of elements in _PRT |
694 | */ |
695 | static int |
696 | mpacpi_pcircount(struct mpacpi_pcibus *mpr) |
697 | { |
698 | int count = 0; |
699 | ACPI_PCI_ROUTING_TABLE *PrtElement; |
700 | uint8_t *Buffer; |
701 | |
702 | if (mpr->mpr_buf.Length == 0) { |
703 | return 0; |
704 | } |
705 | |
706 | for (Buffer = mpr->mpr_buf.Pointer;; Buffer += PrtElement->Length) { |
707 | PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer; |
708 | if (PrtElement->Length == 0) |
709 | break; |
710 | count++; |
711 | } |
712 | |
713 | return count; |
714 | } |
715 | #endif |
716 | |
717 | /* |
718 | * Set up the interrupt config lists, in the same format as the mpbios does. |
719 | */ |
720 | static void |
721 | mpacpi_config_irouting(struct acpi_softc *acpi) |
722 | { |
723 | #if NPCI > 0 |
724 | struct mpacpi_pcibus *mpr; |
725 | #endif |
726 | int nintr; |
727 | int i; |
728 | struct mp_bus *mbp; |
729 | struct mp_intr_map *mpi; |
730 | struct pic *pic; |
731 | |
732 | nintr = mpacpi_nintsrc + NUM_LEGACY_IRQS - 1; |
733 | #if NPCI > 0 |
734 | TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) { |
735 | nintr += mpacpi_pcircount(mpr); |
736 | } |
737 | |
738 | mp_isa_bus = mpacpi_maxpci + BUS_BUFFER; /* XXX */ |
739 | #else |
740 | mp_isa_bus = 0; |
741 | #endif |
742 | mp_nbus = mp_isa_bus + 1; |
743 | mp_nintr = nintr; |
744 | |
745 | mp_busses = kmem_zalloc(sizeof(struct mp_bus) * mp_nbus, KM_SLEEP); |
746 | if (mp_busses == NULL) |
747 | panic("can't allocate mp_busses" ); |
748 | |
749 | mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map) * mp_nintr, KM_SLEEP); |
750 | if (mp_intrs == NULL) |
751 | panic("can't allocate mp_intrs" ); |
752 | |
753 | mbp = &mp_busses[mp_isa_bus]; |
754 | mbp->mb_name = "isa" ; |
755 | mbp->mb_idx = 0; |
756 | mbp->mb_intr_print = mpacpi_print_isa_intr; |
757 | mbp->mb_intr_cfg = NULL; |
758 | mbp->mb_intrs = &mp_intrs[0]; |
759 | mbp->mb_data = 0; |
760 | |
761 | pic = intr_findpic(0); |
762 | if (pic == NULL) |
763 | panic("mpacpi: can't find first PIC" ); |
764 | #if NIOAPIC == 0 |
765 | if (pic->pic_type == PIC_IOAPIC) |
766 | panic("mpacpi: ioapic but no i8259?" ); |
767 | #endif |
768 | |
769 | /* |
770 | * Set up default identity mapping for ISA irqs to first ioapic. |
771 | */ |
772 | for (i = mpacpi_intr_index = 0; i < NUM_LEGACY_IRQS; i++) { |
773 | if (i == 2) |
774 | continue; |
775 | mpi = &mp_intrs[mpacpi_intr_index]; |
776 | if (mpacpi_intr_index < (NUM_LEGACY_IRQS - 2)) |
777 | mpi->next = &mp_intrs[mpacpi_intr_index + 1]; |
778 | else |
779 | mpi->next = NULL; |
780 | mpi->bus = mbp; |
781 | mpi->bus_pin = i; |
782 | mpi->ioapic_pin = i; |
783 | mpi->ioapic = pic; |
784 | mpi->type = MPS_INTTYPE_INT; |
785 | mpi->cpu_id = 0; |
786 | mpi->redir = 0; |
787 | #if NIOAPIC > 0 |
788 | if (pic->pic_type == PIC_IOAPIC) { |
789 | mpi->ioapic_ih = APIC_INT_VIA_APIC | |
790 | (pic->pic_apicid << APIC_INT_APIC_SHIFT) | |
791 | (i << APIC_INT_PIN_SHIFT); |
792 | mpi->redir = |
793 | (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT); |
794 | pic->pic_ioapic->sc_pins[i].ip_map = mpi; |
795 | } else |
796 | #endif |
797 | mpi->ioapic_ih = i; |
798 | |
799 | mpi->flags = MPS_INTPO_DEF | (MPS_INTTR_DEF << 2); |
800 | mpi->global_int = i; |
801 | mpacpi_intr_index++; |
802 | } |
803 | |
804 | mpacpi_user_continue("done setting up mp_bus array and ISA maps" ); |
805 | |
806 | if (acpi_madt_map() == AE_OK) { |
807 | acpi_madt_walk(mpacpi_nonpci_intr, &mpacpi_intr_index); |
808 | acpi_madt_unmap(); |
809 | } |
810 | |
811 | mpacpi_user_continue("done with non-PCI interrupts" ); |
812 | |
813 | #if NPCI > 0 |
814 | TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) { |
815 | mpacpi_pciroute(mpr); |
816 | } |
817 | #endif |
818 | |
819 | mpacpi_user_continue("done routing PCI interrupts" ); |
820 | |
821 | mp_nintr = mpacpi_intr_index; |
822 | } |
823 | |
824 | /* |
825 | * XXX code duplication with mpbios.c |
826 | */ |
827 | |
828 | #if NPCI > 0 |
829 | static void |
830 | mpacpi_print_pci_intr(int intr) |
831 | { |
832 | printf(" device %d INT_%c" , (intr >> 2) & 0x1f, 'A' + (intr & 0x3)); |
833 | } |
834 | #endif |
835 | |
836 | static void |
837 | mpacpi_print_isa_intr(int intr) |
838 | { |
839 | printf(" irq %d" , intr); |
840 | } |
841 | |
842 | static const char inttype_fmt[] = "\177\020" |
843 | "f\0\2type\0" "=\1NMI\0" "=\2SMI\0" "=\3ExtINT\0" ; |
844 | |
845 | static const char flagtype_fmt[] = "\177\020" |
846 | "f\0\2pol\0" "=\1Act Hi\0" "=\3Act Lo\0" |
847 | "f\2\2trig\0" "=\1Edge\0" "=\3Level\0" ; |
848 | |
849 | static void |
850 | mpacpi_print_intr(struct mp_intr_map *mpi) |
851 | { |
852 | char buf[256]; |
853 | int pin; |
854 | struct pic *sc; |
855 | const char *busname; |
856 | |
857 | sc = mpi->ioapic; |
858 | pin = mpi->ioapic_pin; |
859 | if (mpi->bus != NULL) |
860 | busname = mpi->bus->mb_name; |
861 | else { |
862 | switch (mpi->type) { |
863 | case MPS_INTTYPE_NMI: |
864 | busname = "NMI" ; |
865 | break; |
866 | case MPS_INTTYPE_SMI: |
867 | busname = "SMI" ; |
868 | break; |
869 | case MPS_INTTYPE_ExtINT: |
870 | busname = "ExtINT" ; |
871 | break; |
872 | default: |
873 | busname = "<unknown>" ; |
874 | break; |
875 | } |
876 | } |
877 | |
878 | if (mpi->linkdev != NULL) |
879 | printf("linkdev %s attached to %s" , |
880 | acpi_pci_link_name(mpi->linkdev), busname); |
881 | else |
882 | printf("%s: pin %d attached to %s" , |
883 | sc ? sc->pic_name : "local apic" , |
884 | pin, busname); |
885 | |
886 | if (mpi->bus != NULL) { |
887 | if (mpi->bus->mb_idx != -1) |
888 | printf("%d" , mpi->bus->mb_idx); |
889 | (*(mpi->bus->mb_intr_print))(mpi->bus_pin); |
890 | } |
891 | snprintb(buf, sizeof(buf), inttype_fmt, mpi->type); |
892 | printf(" (type %s" , buf); |
893 | |
894 | snprintb(buf, sizeof(buf), flagtype_fmt, mpi->flags); |
895 | printf(" flags %s)\n" , buf); |
896 | |
897 | } |
898 | |
899 | |
900 | int |
901 | mpacpi_find_interrupts(void *self) |
902 | { |
903 | #if NIOAPIC > 0 |
904 | ACPI_STATUS rv; |
905 | #endif |
906 | struct acpi_softc *acpi = self; |
907 | int i; |
908 | |
909 | #ifdef MPBIOS |
910 | /* |
911 | * If MPBIOS was enabled, and did the work (because the initial |
912 | * MADT scan failed for some reason), there's nothing left to |
913 | * do here. Same goes for the case where no I/O APICS were found. |
914 | */ |
915 | if (mpbios_scanned) |
916 | return 0; |
917 | #endif |
918 | |
919 | #if NIOAPIC > 0 |
920 | if (mpacpi_nioapic != 0) { |
921 | /* |
922 | * Switch us into APIC mode by evaluating _PIC(1). |
923 | * Needs to be done now, since it has an effect on |
924 | * the interrupt information we're about to retrieve. |
925 | * |
926 | * ACPI 3.0 (section 5.8.1): |
927 | * 0 = PIC mode, 1 = APIC mode, 2 = SAPIC mode. |
928 | */ |
929 | rv = acpi_eval_set_integer(NULL, "\\_PIC" , 1); |
930 | if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) { |
931 | if (mp_verbose) |
932 | printf("mpacpi: switch to APIC mode failed\n" ); |
933 | return 0; |
934 | } |
935 | } |
936 | #endif |
937 | |
938 | #if NPCI > 0 |
939 | mpacpi_user_continue("finding PCI busses " ); |
940 | mpacpi_find_pcibusses(acpi); |
941 | if (mp_verbose) |
942 | printf("mpacpi: %d PCI busses\n" , mpacpi_npci); |
943 | #endif |
944 | mpacpi_config_irouting(acpi); |
945 | if (mp_verbose) |
946 | for (i = 0; i < mp_nintr; i++) |
947 | mpacpi_print_intr(&mp_intrs[i]); |
948 | return 0; |
949 | } |
950 | |
951 | #if NPCI > 0 |
952 | |
953 | int |
954 | mpacpi_pci_attach_hook(device_t parent, device_t self, |
955 | struct pcibus_attach_args *pba) |
956 | { |
957 | struct mp_bus *mpb; |
958 | |
959 | #ifdef MPBIOS |
960 | if (mpbios_scanned != 0) |
961 | return ENOENT; |
962 | #endif |
963 | |
964 | if (TAILQ_EMPTY(&mpacpi_pcibusses)) |
965 | return 0; |
966 | |
967 | /* |
968 | * If this bus is not found in mpacpi_find_pcibusses |
969 | * (i.e. behind PCI-to-PCI bridge), register as an extra bus. |
970 | * |
971 | * at this point, mp_busses[] are as follows: |
972 | * mp_busses[0 .. mpacpi_maxpci] : PCI |
973 | * mp_busses[mpacpi_maxpci + BUS_BUFFER] : ISA |
974 | */ |
975 | if (pba->pba_bus >= mp_isa_bus) { |
976 | intr_add_pcibus(pba); |
977 | return 0; |
978 | } |
979 | |
980 | mpb = &mp_busses[pba->pba_bus]; |
981 | if (mpb->mb_name != NULL) { |
982 | if (strcmp(mpb->mb_name, "pci" )) |
983 | return EINVAL; |
984 | } else |
985 | /* |
986 | * As we cannot find all PCI-to-PCI bridge in |
987 | * mpacpi_find_pcibusses, some of the MP_busses may remain |
988 | * uninitialized. |
989 | */ |
990 | mpb->mb_name = "pci" ; |
991 | |
992 | mpb->mb_dev = self; |
993 | mpb->mb_pci_bridge_tag = pba->pba_bridgetag; |
994 | mpb->mb_pci_chipset_tag = pba->pba_pc; |
995 | |
996 | if (mp_verbose) |
997 | printf("\n%s: added to list as bus %d" , device_xname(parent), |
998 | pba->pba_bus); |
999 | |
1000 | |
1001 | if (pba->pba_bus > mpacpi_maxpci) |
1002 | mpacpi_maxpci = pba->pba_bus; |
1003 | |
1004 | return 0; |
1005 | } |
1006 | #endif |
1007 | |
1008 | int |
1009 | mpacpi_findintr_linkdev(struct mp_intr_map *mip) |
1010 | { |
1011 | int irq, line, pol, trig; |
1012 | struct pic *pic; |
1013 | int pin; |
1014 | |
1015 | if (mip->linkdev == NULL) |
1016 | return ENOENT; |
1017 | |
1018 | irq = acpi_pci_link_route_interrupt(mip->linkdev, mip->sourceindex, |
1019 | &line, &pol, &trig); |
1020 | if (mp_verbose) |
1021 | printf("linkdev %s returned ACPI global irq %d, line %d\n" , |
1022 | acpi_pci_link_name(mip->linkdev), irq, line); |
1023 | if (irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) |
1024 | return ENOENT; |
1025 | if (irq != line) { |
1026 | aprint_error("%s: mpacpi_findintr_linkdev:" |
1027 | " irq mismatch (%d vs %d)\n" , |
1028 | acpi_pci_link_name(mip->linkdev), irq, line); |
1029 | return ENOENT; |
1030 | } |
1031 | |
1032 | /* |
1033 | * Convert ACPICA values to MPS values |
1034 | */ |
1035 | if (pol == ACPI_ACTIVE_LOW) |
1036 | pol = MPS_INTPO_ACTLO; |
1037 | else |
1038 | pol = MPS_INTPO_ACTHI; |
1039 | |
1040 | if (trig == ACPI_EDGE_SENSITIVE) |
1041 | trig = MPS_INTTR_EDGE; |
1042 | else |
1043 | trig = MPS_INTTR_LEVEL; |
1044 | |
1045 | mip->flags = pol | (trig << 2); |
1046 | mip->global_int = irq; |
1047 | pic = intr_findpic(irq); |
1048 | if (pic == NULL) |
1049 | return ENOENT; |
1050 | mip->ioapic = pic; |
1051 | pin = irq - pic->pic_vecbase; |
1052 | |
1053 | if (pic->pic_type == PIC_IOAPIC) { |
1054 | #if NIOAPIC > 0 |
1055 | mip->redir = (IOAPIC_REDLO_DEL_FIXED <<IOAPIC_REDLO_DEL_SHIFT); |
1056 | if (pol == MPS_INTPO_ACTLO) |
1057 | mip->redir |= IOAPIC_REDLO_ACTLO; |
1058 | if (trig == MPS_INTTR_LEVEL) |
1059 | mip->redir |= IOAPIC_REDLO_LEVEL; |
1060 | mip->ioapic_ih = APIC_INT_VIA_APIC | |
1061 | (pic->pic_apicid << APIC_INT_APIC_SHIFT) | |
1062 | (pin << APIC_INT_PIN_SHIFT); |
1063 | pic->pic_ioapic->sc_pins[pin].ip_map = mip; |
1064 | mip->ioapic_pin = pin; |
1065 | #else |
1066 | return ENOENT; |
1067 | #endif |
1068 | } else |
1069 | mip->ioapic_ih = pin; |
1070 | return 0; |
1071 | } |
1072 | |
1073 | static void |
1074 | mpacpi_user_continue(const char *fmt, ...) |
1075 | { |
1076 | va_list ap; |
1077 | |
1078 | if (!mpacpi_step) |
1079 | return; |
1080 | |
1081 | printf("mpacpi: " ); |
1082 | va_start(ap, fmt); |
1083 | vprintf(fmt, ap); |
1084 | va_end(ap); |
1085 | printf("<press any key to continue>\n>" ); |
1086 | cngetc(); |
1087 | } |
1088 | |
1089 | #ifdef DDB |
1090 | void |
1091 | mpacpi_dump(void) |
1092 | { |
1093 | int i; |
1094 | for (i = 0; i < mp_nintr; i++) |
1095 | mpacpi_print_intr(&mp_intrs[i]); |
1096 | } |
1097 | #endif |
1098 | |