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