acpi_pci_link.c revision 1.7 1 /* $NetBSD: acpi_pci_link.c,v 1.7 2006/09/24 06:03:20 dogcow Exp $ */
2
3 /*-
4 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki (at) jp.freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: acpi_pci_link.c,v 1.7 2006/09/24 06:03:20 dogcow Exp $");
31
32 #include "opt_acpi.h"
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/queue.h>
37 #include <sys/reboot.h>
38
39 #include <dev/acpi/acpica.h>
40 #include <dev/acpi/acpireg.h>
41 #include <dev/acpi/acpivar.h>
42
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcivar.h>
45
46 #define NUM_ISA_INTERRUPTS 16
47 #define NUM_ACPI_INTERRUPTS 256
48
49 #define PCI_INVALID_IRQ 255
50 #define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ && (x) != 0)
51
52 #define ACPI_SERIAL_BEGIN(x)
53 #define ACPI_SERIAL_END(x)
54
55 /*
56 * An ACPI PCI link device may contain multiple links. Each link has its
57 * own ACPI resource. _PRT entries specify which link is being used via
58 * the Source Index.
59 *
60 * XXX: A note about Source Indices and DPFs: Currently we assume that
61 * the DPF start and end tags are not counted towards the index that
62 * Source Index corresponds to. Also, we assume that when DPFs are in use
63 * they various sets overlap in terms of Indices. Here's an example
64 * resource list indicating these assumptions:
65 *
66 * Resource Index
67 * -------- -----
68 * I/O Port 0
69 * Start DPF -
70 * IRQ 1
71 * MemIO 2
72 * Start DPF -
73 * IRQ 1
74 * MemIO 2
75 * End DPF -
76 * DMA Channel 3
77 *
78 * The XXX is because I'm not sure if this is a valid assumption to make.
79 */
80
81 /* States during DPF processing. */
82 #define DPF_OUTSIDE 0
83 #define DPF_FIRST 1
84 #define DPF_IGNORE 2
85
86 struct link;
87
88 struct acpi_pci_link_softc {
89 int pl_num_links;
90 int pl_crs_bad;
91 struct link *pl_links;
92 char pl_name[32];
93 ACPI_HANDLE pl_handle;
94 void *pl_powerhook;
95 TAILQ_ENTRY(acpi_pci_link_softc) pl_list;
96 };
97
98 static TAILQ_HEAD(, acpi_pci_link_softc) acpi_pci_linkdevs =
99 TAILQ_HEAD_INITIALIZER(acpi_pci_linkdevs);
100
101
102 struct link {
103 struct acpi_pci_link_softc *l_sc;
104 uint8_t l_bios_irq;
105 uint8_t l_irq;
106 uint8_t l_trig;
107 uint8_t l_pol;
108 uint8_t l_initial_irq;
109 int l_res_index;
110 int l_num_irqs;
111 int *l_irqs;
112 int l_references;
113 int l_routed:1;
114 int l_isa_irq:1;
115 ACPI_RESOURCE l_prs_template;
116 };
117
118 struct link_count_request {
119 int in_dpf;
120 int count;
121 };
122
123 struct link_res_request {
124 struct acpi_pci_link_softc *sc;
125 int in_dpf;
126 int res_index;
127 int link_index;
128 };
129
130 MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures");
131
132 static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS];
133 static int pci_link_bios_isa_irqs;
134
135 static ACPI_STATUS acpi_count_irq_resources(ACPI_RESOURCE *, void *);
136 static ACPI_STATUS link_add_crs(ACPI_RESOURCE *, void *);
137 static ACPI_STATUS link_add_prs(ACPI_RESOURCE *, void *);
138 static int link_valid_irq(struct link *, int);
139 static void acpi_pci_link_dump(struct acpi_pci_link_softc *);
140 static int acpi_pci_link_attach(struct acpi_pci_link_softc *);
141 static uint8_t acpi_pci_link_search_irq(struct acpi_pci_link_softc *, int, int,
142 int);
143 static void acpi_pci_link_resume(int, void *);
144 static struct link *acpi_pci_link_lookup(struct acpi_pci_link_softc *, int);
145 static ACPI_STATUS acpi_pci_link_srs(struct acpi_pci_link_softc *,
146 ACPI_BUFFER *);
147 static ACPI_STATUS acpi_AppendBufferResource(ACPI_BUFFER *, ACPI_RESOURCE *);
148
149 static ACPI_STATUS
150 acpi_count_irq_resources(ACPI_RESOURCE *res, void *context)
151 {
152 struct link_count_request *req;
153
154 req = (struct link_count_request *)context;
155 switch (res->Type) {
156 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
157 switch (req->in_dpf) {
158 case DPF_OUTSIDE:
159 /* We've started the first DPF. */
160 req->in_dpf = DPF_FIRST;
161 break;
162 case DPF_FIRST:
163 /* We've started the second DPF. */
164 req->in_dpf = DPF_IGNORE;
165 break;
166 }
167 break;
168 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
169 /* We are finished with DPF parsing. */
170 KASSERT(req->in_dpf != DPF_OUTSIDE);
171 req->in_dpf = DPF_OUTSIDE;
172 break;
173 case ACPI_RESOURCE_TYPE_IRQ:
174 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
175 /*
176 * Don't count resources if we are in a DPF set that we are
177 * ignoring.
178 */
179 if (req->in_dpf != DPF_IGNORE)
180 req->count++;
181 }
182 return (AE_OK);
183 }
184
185 static ACPI_STATUS
186 link_add_crs(ACPI_RESOURCE *res, void *context)
187 {
188 struct link_res_request *req;
189 struct link *link;
190
191 req = (struct link_res_request *)context;
192 switch (res->Type) {
193 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
194 switch (req->in_dpf) {
195 case DPF_OUTSIDE:
196 /* We've started the first DPF. */
197 req->in_dpf = DPF_FIRST;
198 break;
199 case DPF_FIRST:
200 /* We've started the second DPF. */
201 panic(
202 "%s: Multiple dependent functions within a current resource",
203 __func__);
204 break;
205 }
206 break;
207 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
208 /* We are finished with DPF parsing. */
209 KASSERT(req->in_dpf != DPF_OUTSIDE);
210 req->in_dpf = DPF_OUTSIDE;
211 break;
212 case ACPI_RESOURCE_TYPE_IRQ:
213 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
214 KASSERT(req->link_index < req->sc->pl_num_links);
215 link = &req->sc->pl_links[req->link_index];
216 link->l_res_index = req->res_index;
217 req->link_index++;
218 req->res_index++;
219
220 /*
221 * Only use the current value if there's one IRQ. Some
222 * systems return multiple IRQs (which is nonsense for _CRS)
223 * when the link hasn't been programmed.
224 */
225 if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
226 if (res->Data.Irq.InterruptCount == 1) {
227 link->l_irq = res->Data.Irq.Interrupts[0];
228 link->l_trig = res->Data.Irq.Triggering;
229 link->l_pol = res->Data.Irq.Polarity;
230 }
231 } else if (res->Data.ExtendedIrq.InterruptCount == 1) {
232 link->l_irq = res->Data.ExtendedIrq.Interrupts[0];
233 link->l_trig = res->Data.ExtendedIrq.Triggering;
234 link->l_pol = res->Data.ExtendedIrq.Polarity;
235 }
236
237 /*
238 * An IRQ of zero means that the link isn't routed.
239 */
240 if (link->l_irq == 0)
241 link->l_irq = PCI_INVALID_IRQ;
242 break;
243 default:
244 req->res_index++;
245 }
246 return (AE_OK);
247 }
248
249 /*
250 * Populate the set of possible IRQs for each device.
251 */
252 static ACPI_STATUS
253 link_add_prs(ACPI_RESOURCE *res, void *context)
254 {
255 struct link_res_request *req;
256 struct link *link;
257 UINT8 *irqs = NULL;
258 UINT32 *ext_irqs = NULL;
259 int i, is_ext_irq = 1;
260
261 req = (struct link_res_request *)context;
262 switch (res->Type) {
263 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
264 switch (req->in_dpf) {
265 case DPF_OUTSIDE:
266 /* We've started the first DPF. */
267 req->in_dpf = DPF_FIRST;
268 break;
269 case DPF_FIRST:
270 /* We've started the second DPF. */
271 req->in_dpf = DPF_IGNORE;
272 break;
273 }
274 break;
275 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
276 /* We are finished with DPF parsing. */
277 KASSERT(req->in_dpf != DPF_OUTSIDE);
278 req->in_dpf = DPF_OUTSIDE;
279 break;
280 case ACPI_RESOURCE_TYPE_IRQ:
281 is_ext_irq = 0;
282 /* fall through */
283 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
284 /*
285 * Don't parse resources if we are in a DPF set that we are
286 * ignoring.
287 */
288 if (req->in_dpf == DPF_IGNORE)
289 break;
290
291 KASSERT(req->link_index < req->sc->pl_num_links);
292 link = &req->sc->pl_links[req->link_index];
293 if (link->l_res_index == -1) {
294 KASSERT(req->sc->pl_crs_bad);
295 link->l_res_index = req->res_index;
296 }
297 req->link_index++;
298 req->res_index++;
299
300 /*
301 * Stash a copy of the resource for later use when
302 * doing _SRS.
303 *
304 * Note that in theory res->Length may exceed the size
305 * of ACPI_RESOURCE, due to variable length lists in
306 * subtypes. However, all uses of l_prs_template only
307 * rely on lists lengths of zero or one, for which
308 * sizeof(ACPI_RESOURCE) is sufficient space anyway.
309 * We cannot read longer than Length bytes, in case we
310 * read off the end of mapped memory. So we read
311 * whichever length is shortest, Length or
312 * sizeof(ACPI_RESOURCE).
313 */
314 KASSERT(res->Length >= ACPI_RS_SIZE_MIN);
315
316 memset(&link->l_prs_template, 0, sizeof(link->l_prs_template));
317 memcpy(&link->l_prs_template, res,
318 MIN(res->Length, sizeof(link->l_prs_template)));
319
320 if (is_ext_irq) {
321 link->l_num_irqs =
322 res->Data.ExtendedIrq.InterruptCount;
323 link->l_trig = res->Data.ExtendedIrq.Triggering;
324 link->l_pol = res->Data.ExtendedIrq.Polarity;
325 ext_irqs = res->Data.ExtendedIrq.Interrupts;
326 } else {
327 link->l_num_irqs = res->Data.Irq.InterruptCount;
328 link->l_trig = res->Data.Irq.Triggering;
329 link->l_pol = res->Data.Irq.Polarity;
330 irqs = res->Data.Irq.Interrupts;
331 }
332 if (link->l_num_irqs == 0)
333 break;
334
335 /*
336 * Save a list of the valid IRQs. Also, if all of the
337 * valid IRQs are ISA IRQs, then mark this link as
338 * routed via an ISA interrupt.
339 */
340 link->l_isa_irq = TRUE;
341 link->l_irqs = malloc(sizeof(int) * link->l_num_irqs,
342 M_PCI_LINK, M_WAITOK | M_ZERO);
343 for (i = 0; i < link->l_num_irqs; i++) {
344 if (is_ext_irq) {
345 link->l_irqs[i] = ext_irqs[i];
346 if (ext_irqs[i] >= NUM_ISA_INTERRUPTS)
347 link->l_isa_irq = FALSE;
348 } else {
349 link->l_irqs[i] = irqs[i];
350 if (irqs[i] >= NUM_ISA_INTERRUPTS)
351 link->l_isa_irq = FALSE;
352 }
353 }
354 break;
355 default:
356 if (req->in_dpf == DPF_IGNORE)
357 break;
358 if (req->sc->pl_crs_bad)
359 aprint_normal("%s: Warning: possible resource %d "
360 "will be lost during _SRS\n", req->sc->pl_name,
361 req->res_index);
362 req->res_index++;
363 }
364 return (AE_OK);
365 }
366
367 static int
368 link_valid_irq(struct link *link, int irq)
369 {
370 int i;
371
372 /* Invalid interrupts are never valid. */
373 if (!PCI_INTERRUPT_VALID(irq))
374 return (FALSE);
375
376 /* Any interrupt in the list of possible interrupts is valid. */
377 for (i = 0; i < link->l_num_irqs; i++)
378 if (link->l_irqs[i] == irq)
379 return (TRUE);
380
381 /*
382 * For links routed via an ISA interrupt, if the SCI is routed via
383 * an ISA interrupt, the SCI is always treated as a valid IRQ.
384 */
385 if (link->l_isa_irq && AcpiGbl_FADT->SciInt == irq &&
386 irq < NUM_ISA_INTERRUPTS)
387 return (TRUE);
388
389 /* If the interrupt wasn't found in the list it is not valid. */
390 return (FALSE);
391 }
392
393 void
394 acpi_pci_link_state(void)
395 {
396 struct acpi_pci_link_softc *sc;
397
398 TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) {
399 acpi_pci_link_dump(sc);
400 }
401 }
402
403 static void
404 acpi_pci_link_dump(struct acpi_pci_link_softc *sc)
405 {
406 struct link *link;
407 int i, j;
408
409 printf("Link Device %s:\n", sc->pl_name);
410 printf("Index IRQ Rtd Ref IRQs\n");
411 for (i = 0; i < sc->pl_num_links; i++) {
412 link = &sc->pl_links[i];
413 printf("%5d %3d %c %3d ", i, link->l_irq,
414 link->l_routed ? 'Y' : 'N', link->l_references);
415 if (link->l_num_irqs == 0)
416 printf(" none");
417 else for (j = 0; j < link->l_num_irqs; j++)
418 printf(" %d", link->l_irqs[j]);
419 printf(" polarity %u trigger %u\n", link->l_pol, link->l_trig);
420 }
421 printf("\n");
422 }
423
424 static int
425 acpi_pci_link_attach(struct acpi_pci_link_softc *sc)
426 {
427 struct link_count_request creq;
428 struct link_res_request rreq;
429 ACPI_STATUS status;
430 int i;
431
432 ACPI_SERIAL_BEGIN(pci_link);
433
434 /*
435 * Count the number of current resources so we know how big of
436 * a link array to allocate. On some systems, _CRS is broken,
437 * so for those systems try to derive the count from _PRS instead.
438 */
439 creq.in_dpf = DPF_OUTSIDE;
440 creq.count = 0;
441 status = AcpiWalkResources(sc->pl_handle, "_CRS",
442 acpi_count_irq_resources, &creq);
443 sc->pl_crs_bad = ACPI_FAILURE(status);
444 if (sc->pl_crs_bad) {
445 creq.in_dpf = DPF_OUTSIDE;
446 creq.count = 0;
447 status = AcpiWalkResources(sc->pl_handle, "_PRS",
448 acpi_count_irq_resources, &creq);
449 if (ACPI_FAILURE(status)) {
450 aprint_error("%s: Unable to parse _CRS or _PRS: %s\n",
451 sc->pl_name, AcpiFormatException(status));
452 ACPI_SERIAL_END(pci_link);
453 return (ENXIO);
454 }
455 }
456 sc->pl_num_links = creq.count;
457 if (creq.count == 0) {
458 ACPI_SERIAL_END(pci_link);
459 return (0);
460 }
461 sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links,
462 M_PCI_LINK, M_WAITOK | M_ZERO);
463
464 /* Initialize the child links. */
465 for (i = 0; i < sc->pl_num_links; i++) {
466 sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
467 sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ;
468 sc->pl_links[i].l_sc = sc;
469 sc->pl_links[i].l_isa_irq = FALSE;
470 sc->pl_links[i].l_res_index = -1;
471 }
472
473 /* Try to read the current settings from _CRS if it is valid. */
474 if (!sc->pl_crs_bad) {
475 rreq.in_dpf = DPF_OUTSIDE;
476 rreq.link_index = 0;
477 rreq.res_index = 0;
478 rreq.sc = sc;
479 status = AcpiWalkResources(sc->pl_handle, "_CRS",
480 link_add_crs, &rreq);
481 if (ACPI_FAILURE(status)) {
482 aprint_error("%s: Unable to parse _CRS: %s\n",
483 sc->pl_name, AcpiFormatException(status));
484 goto fail;
485 }
486 }
487
488 /*
489 * Try to read the possible settings from _PRS. Note that if the
490 * _CRS is toast, we depend on having a working _PRS. However, if
491 * _CRS works, then it is ok for _PRS to be missing.
492 */
493 rreq.in_dpf = DPF_OUTSIDE;
494 rreq.link_index = 0;
495 rreq.res_index = 0;
496 rreq.sc = sc;
497 status = AcpiWalkResources(sc->pl_handle, "_PRS",
498 link_add_prs, &rreq);
499 if (ACPI_FAILURE(status) &&
500 (status != AE_NOT_FOUND || sc->pl_crs_bad)) {
501 aprint_error("%s: Unable to parse _PRS: %s\n",
502 sc->pl_name, AcpiFormatException(status));
503 goto fail;
504 }
505 if (boothowto & AB_VERBOSE) {
506 aprint_normal("%s: Links after initial probe:\n", sc->pl_name);
507 acpi_pci_link_dump(sc);
508 }
509
510 /* Verify initial IRQs if we have _PRS. */
511 if (status != AE_NOT_FOUND)
512 for (i = 0; i < sc->pl_num_links; i++)
513 if (!link_valid_irq(&sc->pl_links[i],
514 sc->pl_links[i].l_irq))
515 sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
516 if (boothowto & AB_VERBOSE) {
517 printf("%s: Links after initial validation:\n", sc->pl_name);
518 acpi_pci_link_dump(sc);
519 }
520
521 /* Save initial IRQs. */
522 for (i = 0; i < sc->pl_num_links; i++)
523 sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq;
524
525 /*
526 * Try to disable this link. If successful, set the current IRQ to
527 * zero and flags to indicate this link is not routed. If we can't
528 * run _DIS (i.e., the method doesn't exist), assume the initial
529 * IRQ was routed by the BIOS.
530 */
531 #if 0 /* XXX causes spontaneaous resets on some systems. Disabled for now. */
532 if (ACPI_SUCCESS(AcpiEvaluateObject(sc->pl_handle, "_DIS", NULL,
533 NULL)))
534 for (i = 0; i < sc->pl_num_links; i++)
535 sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
536 else
537 #endif
538 for (i = 0; i < sc->pl_num_links; i++)
539 if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq))
540 sc->pl_links[i].l_routed = TRUE;
541 if (boothowto & AB_VERBOSE) {
542 printf("%s: Links after disable:\n", sc->pl_name);
543 acpi_pci_link_dump(sc);
544 }
545 ACPI_SERIAL_END(pci_link);
546 return (0);
547 fail:
548 ACPI_SERIAL_END(pci_link);
549 for (i = 0; i < sc->pl_num_links; i++)
550 if (sc->pl_links[i].l_irqs != NULL)
551 free(sc->pl_links[i].l_irqs, M_PCI_LINK);
552 free(sc->pl_links, M_PCI_LINK);
553 return (ENXIO);
554 }
555
556 static uint8_t
557 acpi_pci_link_search_irq(struct acpi_pci_link_softc *sc, int bus, int device,
558 int pin)
559 {
560 uint32_t value;
561 uint8_t func, maxfunc, ipin, iline;
562 pcitag_t tag;
563
564 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, 0);
565 /* See if we have a valid device at function 0. */
566 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_BHLC_REG);
567 if (PCI_HDRTYPE_TYPE(value) > PCI_HDRTYPE_PCB)
568 return (PCI_INVALID_IRQ);
569 if (PCI_HDRTYPE_MULTIFN(value))
570 maxfunc = 7;
571 else
572 maxfunc = 0;
573
574 /* Scan all possible functions at this device. */
575 for (func = 0; func <= maxfunc; func++) {
576 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, func);
577 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_ID_REG);
578 if (PCI_VENDOR(value) == 0xffff)
579 continue;
580 value = pci_conf_read(acpi_softc->sc_pc, tag,
581 PCI_INTERRUPT_REG);
582 ipin = PCI_INTERRUPT_PIN(value);
583 iline = PCI_INTERRUPT_LINE(value);
584
585 /*
586 * See if it uses the pin in question. Note that the passed
587 * in pin uses 0 for A, .. 3 for D whereas the intpin
588 * register uses 0 for no interrupt, 1 for A, .. 4 for D.
589 */
590 if (ipin != pin + 1)
591 continue;
592 aprint_verbose(
593 "%s: ACPI: Found matching pin for %d.%d.INT%c"
594 " at func %d: %d\n",
595 sc->pl_name, bus, device, pin + 'A', func, iline);
596 if (PCI_INTERRUPT_VALID(iline))
597 return (iline);
598 }
599 return (PCI_INVALID_IRQ);
600 }
601
602 /*
603 * Find the link structure that corresponds to the resource index passed in
604 * via 'source_index'.
605 */
606 static struct link *
607 acpi_pci_link_lookup(struct acpi_pci_link_softc *sc, int source_index)
608 {
609 int i;
610
611 for (i = 0; i < sc->pl_num_links; i++)
612 if (sc->pl_links[i].l_res_index == source_index)
613 return (&sc->pl_links[i]);
614 return (NULL);
615 }
616
617 void
618 acpi_pci_link_add_reference(void *v, int index, int bus, int slot, int pin)
619 {
620 struct acpi_pci_link_softc *sc = v;
621 struct link *link;
622 uint8_t bios_irq;
623
624 /* Bump the reference count. */
625 ACPI_SERIAL_BEGIN(pci_link);
626 link = acpi_pci_link_lookup(sc, index);
627 if (link == NULL) {
628 printf("%s: apparently invalid index %d\n", sc->pl_name, index);
629 ACPI_SERIAL_END(pci_link);
630 return;
631 }
632 link->l_references++;
633 if (link->l_routed)
634 pci_link_interrupt_weights[link->l_irq]++;
635
636 /*
637 * The BIOS only routes interrupts via ISA IRQs using the ATPICs
638 * (8259As). Thus, if this link is routed via an ISA IRQ, go
639 * look to see if the BIOS routed an IRQ for this link at the
640 * indicated (bus, slot, pin). If so, we prefer that IRQ for
641 * this link and add that IRQ to our list of known-good IRQs.
642 * This provides a good work-around for link devices whose _CRS
643 * method is either broken or bogus. We only use the value
644 * returned by _CRS if we can't find a valid IRQ via this method
645 * in fact.
646 *
647 * If this link is not routed via an ISA IRQ (because we are using
648 * APIC for example), then don't bother looking up the BIOS IRQ
649 * as if we find one it won't be valid anyway.
650 */
651 if (!link->l_isa_irq) {
652 ACPI_SERIAL_END(pci_link);
653 return;
654 }
655
656 /* Try to find a BIOS IRQ setting from any matching devices. */
657 bios_irq = acpi_pci_link_search_irq(sc, bus, slot, pin);
658 if (!PCI_INTERRUPT_VALID(bios_irq)) {
659 ACPI_SERIAL_END(pci_link);
660 return;
661 }
662
663 /* Validate the BIOS IRQ. */
664 if (!link_valid_irq(link, bios_irq)) {
665 printf("%s: BIOS IRQ %u for %d.%d.INT%c is invalid\n",
666 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A');
667 } else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
668 link->l_bios_irq = bios_irq;
669 if (bios_irq < NUM_ISA_INTERRUPTS)
670 pci_link_bios_isa_irqs |= (1 << bios_irq);
671 if (bios_irq != link->l_initial_irq &&
672 PCI_INTERRUPT_VALID(link->l_initial_irq))
673 printf(
674 "%s: BIOS IRQ %u does not match initial IRQ %u\n",
675 sc->pl_name, bios_irq, link->l_initial_irq);
676 } else if (bios_irq != link->l_bios_irq)
677 printf(
678 "%s: BIOS IRQ %u for %d.%d.INT%c does not match "
679 "previous BIOS IRQ %u\n",
680 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A',
681 link->l_bios_irq);
682 ACPI_SERIAL_END(pci_link);
683 }
684
685 static ACPI_STATUS
686 acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf)
687 {
688 ACPI_RESOURCE *resource, *end, newres, *resptr;
689 ACPI_BUFFER crsbuf;
690 ACPI_STATUS status;
691 struct link *link;
692 int i, in_dpf;
693
694 /* Fetch the _CRS. */
695 crsbuf.Pointer = NULL;
696 crsbuf.Length = ACPI_ALLOCATE_BUFFER;
697 status = AcpiGetCurrentResources(sc->pl_handle, &crsbuf);
698 if (ACPI_SUCCESS(status) && crsbuf.Pointer == NULL)
699 status = AE_NO_MEMORY;
700 if (ACPI_FAILURE(status)) {
701 aprint_verbose("%s: Unable to fetch current resources: %s\n",
702 sc->pl_name, AcpiFormatException(status));
703 return (status);
704 }
705
706 /* Fill in IRQ resources via link structures. */
707 srsbuf->Pointer = NULL;
708 link = sc->pl_links;
709 i = 0;
710 in_dpf = DPF_OUTSIDE;
711 resource = (ACPI_RESOURCE *)crsbuf.Pointer;
712 end = (ACPI_RESOURCE *)((char *)crsbuf.Pointer + crsbuf.Length);
713 for (;;) {
714 switch (resource->Type) {
715 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
716 switch (in_dpf) {
717 case DPF_OUTSIDE:
718 /* We've started the first DPF. */
719 in_dpf = DPF_FIRST;
720 break;
721 case DPF_FIRST:
722 /* We've started the second DPF. */
723 panic(
724 "%s: Multiple dependent functions within a current resource",
725 __func__);
726 break;
727 }
728 resptr = NULL;
729 break;
730 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
731 /* We are finished with DPF parsing. */
732 KASSERT(in_dpf != DPF_OUTSIDE);
733 in_dpf = DPF_OUTSIDE;
734 resptr = NULL;
735 break;
736 case ACPI_RESOURCE_TYPE_IRQ:
737 newres = link->l_prs_template;
738 resptr = &newres;
739 resptr->Data.Irq.InterruptCount = 1;
740 if (PCI_INTERRUPT_VALID(link->l_irq)) {
741 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS);
742 resptr->Data.Irq.Interrupts[0] = link->l_irq;
743 resptr->Data.Irq.Triggering = link->l_trig;
744 resptr->Data.Irq.Polarity = link->l_pol;
745 } else
746 resptr->Data.Irq.Interrupts[0] = 0;
747 link++;
748 i++;
749 break;
750 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
751 newres = link->l_prs_template;
752 resptr = &newres;
753 resptr->Data.ExtendedIrq.InterruptCount = 1;
754 if (PCI_INTERRUPT_VALID(link->l_irq)) {
755 resptr->Data.ExtendedIrq.Interrupts[0] =
756 link->l_irq;
757 resptr->Data.ExtendedIrq.Triggering =
758 link->l_trig;
759 resptr->Data.ExtendedIrq.Polarity = link->l_pol;
760 } else
761 resptr->Data.ExtendedIrq.Interrupts[0] = 0;
762 link++;
763 i++;
764 break;
765 default:
766 resptr = resource;
767 }
768 if (resptr != NULL) {
769 status = acpi_AppendBufferResource(srsbuf, resptr);
770 if (ACPI_FAILURE(status)) {
771 printf("%s: Unable to build resources: %s\n",
772 sc->pl_name, AcpiFormatException(status));
773 if (srsbuf->Pointer != NULL)
774 AcpiOsFree(srsbuf->Pointer);
775 AcpiOsFree(crsbuf.Pointer);
776 return (status);
777 }
778 }
779 if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
780 break;
781 resource = ACPI_NEXT_RESOURCE(resource);
782 if (resource >= end)
783 break;
784 }
785 AcpiOsFree(crsbuf.Pointer);
786 return (AE_OK);
787 }
788
789 static ACPI_STATUS
790 acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc,
791 ACPI_BUFFER *srsbuf)
792 {
793 ACPI_RESOURCE newres;
794 ACPI_STATUS status;
795 struct link *link;
796 int i;
797
798 /* Start off with an empty buffer. */
799 srsbuf->Pointer = NULL;
800 link = sc->pl_links;
801 for (i = 0; i < sc->pl_num_links; i++) {
802
803 /* Add a new IRQ resource from each link. */
804 link = &sc->pl_links[i];
805 newres = link->l_prs_template;
806 if (newres.Type == ACPI_RESOURCE_TYPE_IRQ) {
807
808 /* Build an IRQ resource. */
809 newres.Data.Irq.InterruptCount = 1;
810 if (PCI_INTERRUPT_VALID(link->l_irq)) {
811 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS);
812 newres.Data.Irq.Interrupts[0] = link->l_irq;
813 newres.Data.Irq.Triggering = link->l_trig;
814 newres.Data.Irq.Polarity = link->l_pol;
815 } else
816 newres.Data.Irq.Interrupts[0] = 0;
817 } else {
818
819 /* Build an ExtIRQ resuorce. */
820 newres.Data.ExtendedIrq.InterruptCount = 1;
821 if (PCI_INTERRUPT_VALID(link->l_irq)) {
822 newres.Data.ExtendedIrq.Interrupts[0] =
823 link->l_irq;
824 newres.Data.ExtendedIrq.Triggering =
825 link->l_trig;
826 newres.Data.ExtendedIrq.Polarity =
827 link->l_pol;
828 } else {
829 newres.Data.ExtendedIrq.Interrupts[0] = 0;
830 }
831 }
832
833 /* Add the new resource to the end of the _SRS buffer. */
834 status = acpi_AppendBufferResource(srsbuf, &newres);
835 if (ACPI_FAILURE(status)) {
836 printf("%s: Unable to build resources: %s\n",
837 sc->pl_name, AcpiFormatException(status));
838 if (srsbuf->Pointer != NULL)
839 AcpiOsFree(srsbuf->Pointer);
840 return (status);
841 }
842 }
843 return (AE_OK);
844 }
845
846 static ACPI_STATUS
847 acpi_pci_link_srs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf)
848 {
849 ACPI_STATUS status;
850
851 if (sc->pl_crs_bad)
852 status = acpi_pci_link_srs_from_links(sc, srsbuf);
853 else
854 status = acpi_pci_link_srs_from_crs(sc, srsbuf);
855
856 /* Write out new resources via _SRS. */
857 return AcpiSetCurrentResources(sc->pl_handle, srsbuf);
858 }
859
860 static ACPI_STATUS
861 acpi_pci_link_route_irqs(struct acpi_pci_link_softc *sc, int *irq, int *pol,
862 int *trig)
863 {
864 ACPI_RESOURCE *resource, *end;
865 ACPI_BUFFER srsbuf;
866 ACPI_STATUS status;
867 struct link *link;
868 int i, is_ext = 0;
869
870 status = acpi_pci_link_srs(sc, &srsbuf);
871 if (ACPI_FAILURE(status)) {
872 printf("%s: _SRS failed: %s\n",
873 sc->pl_name, AcpiFormatException(status));
874 return (status);
875 }
876 /*
877 * Perform acpi_config_intr() on each IRQ resource if it was just
878 * routed for the first time.
879 */
880 link = sc->pl_links;
881 i = 0;
882 resource = (ACPI_RESOURCE *)srsbuf.Pointer;
883 end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length);
884 for (;;) {
885 if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
886 break;
887 switch (resource->Type) {
888 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
889 is_ext = 1;
890 /* FALLTHROUGH */
891 case ACPI_RESOURCE_TYPE_IRQ:
892 /*
893 * Only configure the interrupt and update the
894 * weights if this link has a valid IRQ and was
895 * previously unrouted.
896 */
897 if (!link->l_routed &&
898 PCI_INTERRUPT_VALID(link->l_irq)) {
899 *trig = is_ext ?
900 resource->Data.ExtendedIrq.Triggering :
901 resource->Data.Irq.Triggering;
902 *pol = is_ext ?
903 resource->Data.ExtendedIrq.Polarity :
904 resource->Data.Irq.Polarity;
905 *irq = is_ext ?
906 resource->Data.ExtendedIrq.Interrupts[0] :
907 resource->Data.Irq.Interrupts[0];
908 link->l_routed = TRUE;
909 pci_link_interrupt_weights[link->l_irq] +=
910 link->l_references;
911 }
912 link++;
913 i++;
914 break;
915 }
916 resource = ACPI_NEXT_RESOURCE(resource);
917 if (resource >= end)
918 break;
919 }
920 AcpiOsFree(srsbuf.Pointer);
921 return (AE_OK);
922 }
923
924 static void
925 acpi_pci_link_resume(int why, void *arg)
926 {
927 struct acpi_pci_link_softc *sc = arg;
928 ACPI_BUFFER srsbuf;
929
930 switch (why) {
931 case PWR_RESUME:
932 ACPI_SERIAL_BEGIN(pci_link);
933 if (ACPI_SUCCESS(acpi_pci_link_srs(sc, &srsbuf)))
934 AcpiOsFree(srsbuf.Pointer);
935 ACPI_SERIAL_END(pci_link);
936 default:
937 break;
938 }
939 }
940
941 /*
942 * Pick an IRQ to use for this unrouted link.
943 */
944 static uint8_t
945 acpi_pci_link_choose_irq(struct acpi_pci_link_softc *sc, struct link *link)
946 {
947 u_int8_t best_irq, pos_irq;
948 int best_weight, pos_weight, i;
949
950 KASSERT(!link->l_routed);
951 KASSERT(!PCI_INTERRUPT_VALID(link->l_irq));
952
953 /*
954 * If we have a valid BIOS IRQ, use that. We trust what the BIOS
955 * says it routed over what _CRS says the link thinks is routed.
956 */
957 if (PCI_INTERRUPT_VALID(link->l_bios_irq))
958 return (link->l_bios_irq);
959
960 /*
961 * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS,
962 * then use that.
963 */
964 if (PCI_INTERRUPT_VALID(link->l_initial_irq))
965 return (link->l_initial_irq);
966
967 /*
968 * Ok, we have no useful hints, so we have to pick from the
969 * possible IRQs. For ISA IRQs we only use interrupts that
970 * have already been used by the BIOS.
971 */
972 best_irq = PCI_INVALID_IRQ;
973 best_weight = INT_MAX;
974 for (i = 0; i < link->l_num_irqs; i++) {
975 pos_irq = link->l_irqs[i];
976 if (pos_irq < NUM_ISA_INTERRUPTS &&
977 (pci_link_bios_isa_irqs & 1 << pos_irq) == 0)
978 continue;
979 pos_weight = pci_link_interrupt_weights[pos_irq];
980 if (pos_weight < best_weight) {
981 best_weight = pos_weight;
982 best_irq = pos_irq;
983 }
984 }
985
986 /*
987 * If this is an ISA IRQ, try using the SCI if it is also an ISA
988 * interrupt as a fallback.
989 */
990 if (link->l_isa_irq) {
991 pos_irq = AcpiGbl_FADT->SciInt;
992 pos_weight = pci_link_interrupt_weights[pos_irq];
993 if (pos_weight < best_weight) {
994 best_weight = pos_weight;
995 best_irq = pos_irq;
996 }
997 }
998
999 if (PCI_INTERRUPT_VALID(best_irq)) {
1000 aprint_verbose("%s: Picked IRQ %u with weight %d\n",
1001 sc->pl_name, best_irq, best_weight);
1002 } else
1003 printf("%s: Unable to choose an IRQ\n", sc->pl_name);
1004 return (best_irq);
1005 }
1006
1007 int
1008 acpi_pci_link_route_interrupt(void *v, int index, int *irq, int *pol, int *trig)
1009 {
1010 struct acpi_pci_link_softc *sc = v;
1011 struct link *link;
1012
1013 ACPI_SERIAL_BEGIN(pci_link);
1014 link = acpi_pci_link_lookup(sc, index);
1015 if (link == NULL)
1016 panic("%s: apparently invalid index %d", __func__, index);
1017
1018 /*
1019 * If this link device is already routed to an interrupt, just return
1020 * the interrupt it is routed to.
1021 */
1022 if (link->l_routed) {
1023 KASSERT(PCI_INTERRUPT_VALID(link->l_irq));
1024 ACPI_SERIAL_END(pci_link);
1025 *irq = link->l_irq;
1026 *pol = link->l_pol;
1027 *trig = link->l_trig;
1028 return (link->l_irq);
1029 }
1030
1031 /* Choose an IRQ if we need one. */
1032 if (!PCI_INTERRUPT_VALID(link->l_irq)) {
1033 link->l_irq = acpi_pci_link_choose_irq(sc, link);
1034
1035 /*
1036 * Try to route the interrupt we picked. If it fails, then
1037 * assume the interrupt is not routed.
1038 */
1039 if (PCI_INTERRUPT_VALID(link->l_irq)) {
1040 acpi_pci_link_route_irqs(sc, irq, pol, trig);
1041 if (!link->l_routed)
1042 link->l_irq = PCI_INVALID_IRQ;
1043 else {
1044 link->l_pol = *pol;
1045 link->l_trig = *trig;
1046 }
1047 }
1048 }
1049 ACPI_SERIAL_END(pci_link);
1050
1051 return (link->l_irq);
1052 }
1053
1054 /*
1055 * This is gross, but we abuse the identify routine to perform one-time
1056 * SYSINIT() style initialization for the driver.
1057 */
1058 static void
1059 acpi_pci_link_init(struct acpi_pci_link_softc *sc)
1060 {
1061 ACPI_BUFFER buf;
1062 char acpipcilinkname[] = "acpi_pci_link";
1063
1064 /*
1065 * If the SCI is an ISA IRQ, add it to the bitmask of known good
1066 * ISA IRQs.
1067 *
1068 * XXX: If we are using the APIC, the SCI might have been
1069 * rerouted to an APIC pin in which case this is invalid. However,
1070 * if we are using the APIC, we also shouldn't be having any PCI
1071 * interrupts routed via ISA IRQs, so this is probably ok.
1072 */
1073 if (AcpiGbl_FADT->SciInt < NUM_ISA_INTERRUPTS)
1074 pci_link_bios_isa_irqs |= (1 << AcpiGbl_FADT->SciInt);
1075
1076 sc->pl_powerhook = powerhook_establish(acpipcilinkname,
1077 acpi_pci_link_resume, sc);
1078 if (sc->pl_powerhook == NULL)
1079 aprint_normal("can't establish powerhook\n");
1080
1081 buf.Length = sizeof (sc->pl_name);
1082 buf.Pointer = sc->pl_name;
1083
1084 if (ACPI_FAILURE(AcpiGetName(sc->pl_handle, ACPI_SINGLE_NAME, &buf)))
1085 snprintf(sc->pl_name, sizeof (sc->pl_name), "%s",
1086 "ACPI link device");
1087
1088 acpi_pci_link_attach(sc);
1089 }
1090
1091 void *
1092 acpi_pci_link_devbyhandle(ACPI_HANDLE handle)
1093 {
1094 struct acpi_pci_link_softc *sc;
1095
1096 TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) {
1097 if (sc->pl_handle == handle)
1098 return sc;
1099 }
1100
1101 sc = malloc(sizeof (*sc), M_PCI_LINK, M_NOWAIT|M_ZERO);
1102 if (sc == NULL)
1103 return NULL;
1104
1105 sc->pl_handle = handle;
1106
1107 acpi_pci_link_init(sc);
1108
1109 TAILQ_INSERT_TAIL(&acpi_pci_linkdevs, sc, pl_list);
1110
1111 return (void *)sc;
1112 }
1113
1114 ACPI_HANDLE
1115 acpi_pci_link_handle(void *v)
1116 {
1117 struct acpi_pci_link_softc *sc = v;
1118
1119 return sc->pl_handle;
1120 }
1121
1122 char *
1123 acpi_pci_link_name(void *v)
1124 {
1125 struct acpi_pci_link_softc *sc = v;
1126
1127 return sc->pl_name;
1128 }
1129
1130
1131 /*
1132 * Append an ACPI_RESOURCE to an ACPI_BUFFER.
1133 *
1134 * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER
1135 * provided to contain it. If the ACPI_BUFFER is empty, allocate a sensible
1136 * backing block. If the ACPI_RESOURCE is NULL, return an empty set of
1137 * resources.
1138 */
1139 #define ACPI_INITIAL_RESOURCE_BUFFER_SIZE 512
1140
1141 static ACPI_STATUS
1142 acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
1143 {
1144 ACPI_RESOURCE *rp;
1145 void *newp;
1146
1147 /* Initialise the buffer if necessary. */
1148 if (buf->Pointer == NULL) {
1149 buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE;
1150 if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL)
1151 return (AE_NO_MEMORY);
1152 rp = (ACPI_RESOURCE *)buf->Pointer;
1153 rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
1154 rp->Length = 0;
1155 }
1156
1157 if (res == NULL)
1158 return (AE_OK);
1159
1160 /*
1161 * Scan the current buffer looking for the terminator.
1162 * This will either find the terminator or hit the end
1163 * of the buffer and return an error.
1164 */
1165 rp = (ACPI_RESOURCE *)buf->Pointer;
1166 for (;;) {
1167 /* Range check, don't go outside the buffer */
1168 if (rp >= (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer +
1169 buf->Length))
1170 return (AE_BAD_PARAMETER);
1171 if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0)
1172 break;
1173 rp = ACPI_NEXT_RESOURCE(rp);
1174 }
1175
1176 /*
1177 * Check the size of the buffer and expand if required.
1178 *
1179 * Required size is:
1180 * size of existing resources before terminator +
1181 * size of new resource and header +
1182 * size of terminator.
1183 *
1184 * Note that this loop should really only run once, unless
1185 * for some reason we are stuffing a *really* huge resource.
1186 */
1187 while ((((u_int8_t *)rp - (u_int8_t *)buf->Pointer) +
1188 res->Length + ACPI_RS_SIZE_NO_DATA +
1189 ACPI_RS_SIZE_MIN) >= buf->Length) {
1190 if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL)
1191 return (AE_NO_MEMORY);
1192 memcpy(newp, buf->Pointer, buf->Length);
1193 rp = (ACPI_RESOURCE *)((u_int8_t *)newp +
1194 ((u_int8_t *)rp - (u_int8_t *)buf->Pointer));
1195 AcpiOsFree(buf->Pointer);
1196 buf->Pointer = newp;
1197 buf->Length += buf->Length;
1198 }
1199
1200 /* Insert the new resource. */
1201 memcpy(rp, res, res->Length + ACPI_RS_SIZE_NO_DATA);
1202
1203 /* And add the terminator. */
1204 rp = ACPI_NEXT_RESOURCE(rp);
1205 rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
1206 rp->Length = 0;
1207
1208 return (AE_OK);
1209 }
1210