1 /* $NetBSD: acpi_pci_link.c,v 1.14 2008/11/17 23:29:49 joerg Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@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.14 2008/11/17 23:29:49 joerg 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 TAILQ_ENTRY(acpi_pci_link_softc) pl_list; 95 }; 96 97 static TAILQ_HEAD(, acpi_pci_link_softc) acpi_pci_linkdevs = 98 TAILQ_HEAD_INITIALIZER(acpi_pci_linkdevs); 99 100 101 struct link { 102 struct acpi_pci_link_softc *l_sc; 103 uint8_t l_bios_irq; 104 uint8_t l_irq; 105 uint8_t l_trig; 106 uint8_t l_pol; 107 uint8_t l_initial_irq; 108 int l_res_index; 109 int l_num_irqs; 110 int *l_irqs; 111 int l_references; 112 int l_dev_count; 113 pcitag_t *l_devices; 114 int l_routed:1; 115 int l_isa_irq:1; 116 ACPI_RESOURCE l_prs_template; 117 }; 118 119 struct link_count_request { 120 int in_dpf; 121 int count; 122 }; 123 124 struct link_res_request { 125 struct acpi_pci_link_softc *sc; 126 int in_dpf; 127 int res_index; 128 int link_index; 129 }; 130 131 MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures"); 132 133 static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS]; 134 static int pci_link_bios_isa_irqs; 135 136 static ACPI_STATUS acpi_count_irq_resources(ACPI_RESOURCE *, void *); 137 static ACPI_STATUS link_add_crs(ACPI_RESOURCE *, void *); 138 static ACPI_STATUS link_add_prs(ACPI_RESOURCE *, void *); 139 static int link_valid_irq(struct link *, int); 140 static void acpi_pci_link_dump(struct acpi_pci_link_softc *); 141 static int acpi_pci_link_attach(struct acpi_pci_link_softc *); 142 static uint8_t acpi_pci_link_search_irq(struct acpi_pci_link_softc *, int, int, 143 int); 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.SciInterrupt == 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 sc->pl_links[i].l_dev_count = 0; 472 sc->pl_links[i].l_devices = NULL; 473 } 474 475 /* Try to read the current settings from _CRS if it is valid. */ 476 if (!sc->pl_crs_bad) { 477 rreq.in_dpf = DPF_OUTSIDE; 478 rreq.link_index = 0; 479 rreq.res_index = 0; 480 rreq.sc = sc; 481 status = AcpiWalkResources(sc->pl_handle, "_CRS", 482 link_add_crs, &rreq); 483 if (ACPI_FAILURE(status)) { 484 aprint_error("%s: Unable to parse _CRS: %s\n", 485 sc->pl_name, AcpiFormatException(status)); 486 goto fail; 487 } 488 } 489 490 /* 491 * Try to read the possible settings from _PRS. Note that if the 492 * _CRS is toast, we depend on having a working _PRS. However, if 493 * _CRS works, then it is ok for _PRS to be missing. 494 */ 495 rreq.in_dpf = DPF_OUTSIDE; 496 rreq.link_index = 0; 497 rreq.res_index = 0; 498 rreq.sc = sc; 499 status = AcpiWalkResources(sc->pl_handle, "_PRS", 500 link_add_prs, &rreq); 501 if (ACPI_FAILURE(status) && 502 (status != AE_NOT_FOUND || sc->pl_crs_bad)) { 503 aprint_error("%s: Unable to parse _PRS: %s\n", 504 sc->pl_name, AcpiFormatException(status)); 505 goto fail; 506 } 507 if (boothowto & AB_VERBOSE) { 508 aprint_normal("%s: Links after initial probe:\n", sc->pl_name); 509 acpi_pci_link_dump(sc); 510 } 511 512 /* Verify initial IRQs if we have _PRS. */ 513 if (status != AE_NOT_FOUND) 514 for (i = 0; i < sc->pl_num_links; i++) 515 if (!link_valid_irq(&sc->pl_links[i], 516 sc->pl_links[i].l_irq)) 517 sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 518 if (boothowto & AB_VERBOSE) { 519 printf("%s: Links after initial validation:\n", sc->pl_name); 520 acpi_pci_link_dump(sc); 521 } 522 523 /* Save initial IRQs. */ 524 for (i = 0; i < sc->pl_num_links; i++) 525 sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq; 526 527 /* 528 * Try to disable this link. If successful, set the current IRQ to 529 * zero and flags to indicate this link is not routed. If we can't 530 * run _DIS (i.e., the method doesn't exist), assume the initial 531 * IRQ was routed by the BIOS. 532 */ 533 #if 0 /* XXX causes spontaneaous resets on some systems. Disabled for now. */ 534 if (ACPI_SUCCESS(AcpiEvaluateObject(sc->pl_handle, "_DIS", NULL, 535 NULL))) 536 for (i = 0; i < sc->pl_num_links; i++) 537 sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 538 else 539 #endif 540 for (i = 0; i < sc->pl_num_links; i++) 541 if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq)) 542 sc->pl_links[i].l_routed = TRUE; 543 if (boothowto & AB_VERBOSE) { 544 printf("%s: Links after disable:\n", sc->pl_name); 545 acpi_pci_link_dump(sc); 546 } 547 ACPI_SERIAL_END(pci_link); 548 return (0); 549 fail: 550 ACPI_SERIAL_END(pci_link); 551 for (i = 0; i < sc->pl_num_links; i++) { 552 if (sc->pl_links[i].l_irqs != NULL) 553 free(sc->pl_links[i].l_irqs, M_PCI_LINK); 554 if (sc->pl_links[i].l_devices != NULL) 555 free(sc->pl_links[i].l_devices, M_PCI_LINK); 556 } 557 free(sc->pl_links, M_PCI_LINK); 558 return (ENXIO); 559 } 560 561 static void 562 acpi_pci_link_add_functions(struct acpi_pci_link_softc *sc, struct link *link, 563 int bus, int device, int pin) 564 { 565 uint32_t value; 566 uint8_t func, maxfunc, ipin; 567 pcitag_t tag; 568 569 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, 0); 570 /* See if we have a valid device at function 0. */ 571 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_BHLC_REG); 572 if (PCI_HDRTYPE_TYPE(value) > PCI_HDRTYPE_PCB) 573 return; 574 if (PCI_HDRTYPE_MULTIFN(value)) 575 maxfunc = 7; 576 else 577 maxfunc = 0; 578 579 /* Scan all possible functions at this device. */ 580 for (func = 0; func <= maxfunc; func++) { 581 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, func); 582 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_ID_REG); 583 if (PCI_VENDOR(value) == 0xffff) 584 continue; 585 value = pci_conf_read(acpi_softc->sc_pc, tag, 586 PCI_INTERRUPT_REG); 587 ipin = PCI_INTERRUPT_PIN(value); 588 /* 589 * See if it uses the pin in question. Note that the passed 590 * in pin uses 0 for A, .. 3 for D whereas the intpin 591 * register uses 0 for no interrupt, 1 for A, .. 4 for D. 592 */ 593 if (ipin != pin + 1) 594 continue; 595 596 link->l_devices = realloc(link->l_devices, 597 sizeof(pcitag_t) * (link->l_dev_count + 1), 598 M_PCI_LINK, M_WAITOK); 599 link->l_devices[link->l_dev_count] = tag; 600 ++link->l_dev_count; 601 } 602 } 603 604 static uint8_t 605 acpi_pci_link_search_irq(struct acpi_pci_link_softc *sc, int bus, int device, 606 int pin) 607 { 608 uint32_t value; 609 uint8_t func, maxfunc, ipin, iline; 610 pcitag_t tag; 611 612 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, 0); 613 /* See if we have a valid device at function 0. */ 614 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_BHLC_REG); 615 if (PCI_HDRTYPE_TYPE(value) > PCI_HDRTYPE_PCB) 616 return (PCI_INVALID_IRQ); 617 if (PCI_HDRTYPE_MULTIFN(value)) 618 maxfunc = 7; 619 else 620 maxfunc = 0; 621 622 /* Scan all possible functions at this device. */ 623 for (func = 0; func <= maxfunc; func++) { 624 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, func); 625 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_ID_REG); 626 if (PCI_VENDOR(value) == 0xffff) 627 continue; 628 value = pci_conf_read(acpi_softc->sc_pc, tag, 629 PCI_INTERRUPT_REG); 630 ipin = PCI_INTERRUPT_PIN(value); 631 iline = PCI_INTERRUPT_LINE(value); 632 633 /* 634 * See if it uses the pin in question. Note that the passed 635 * in pin uses 0 for A, .. 3 for D whereas the intpin 636 * register uses 0 for no interrupt, 1 for A, .. 4 for D. 637 */ 638 if (ipin != pin + 1) 639 continue; 640 aprint_verbose( 641 "%s: ACPI: Found matching pin for %d.%d.INT%c" 642 " at func %d: %d\n", 643 sc->pl_name, bus, device, pin + 'A', func, iline); 644 if (PCI_INTERRUPT_VALID(iline)) 645 return (iline); 646 } 647 return (PCI_INVALID_IRQ); 648 } 649 650 /* 651 * Find the link structure that corresponds to the resource index passed in 652 * via 'source_index'. 653 */ 654 static struct link * 655 acpi_pci_link_lookup(struct acpi_pci_link_softc *sc, int source_index) 656 { 657 int i; 658 659 for (i = 0; i < sc->pl_num_links; i++) 660 if (sc->pl_links[i].l_res_index == source_index) 661 return (&sc->pl_links[i]); 662 return (NULL); 663 } 664 665 void 666 acpi_pci_link_add_reference(void *v, int index, int bus, int slot, int pin) 667 { 668 struct acpi_pci_link_softc *sc = v; 669 struct link *link; 670 uint8_t bios_irq; 671 672 /* Bump the reference count. */ 673 ACPI_SERIAL_BEGIN(pci_link); 674 link = acpi_pci_link_lookup(sc, index); 675 if (link == NULL) { 676 printf("%s: apparently invalid index %d\n", sc->pl_name, index); 677 ACPI_SERIAL_END(pci_link); 678 return; 679 } 680 link->l_references++; 681 acpi_pci_link_add_functions(sc, link, bus, slot, pin); 682 if (link->l_routed) 683 pci_link_interrupt_weights[link->l_irq]++; 684 685 /* 686 * The BIOS only routes interrupts via ISA IRQs using the ATPICs 687 * (8259As). Thus, if this link is routed via an ISA IRQ, go 688 * look to see if the BIOS routed an IRQ for this link at the 689 * indicated (bus, slot, pin). If so, we prefer that IRQ for 690 * this link and add that IRQ to our list of known-good IRQs. 691 * This provides a good work-around for link devices whose _CRS 692 * method is either broken or bogus. We only use the value 693 * returned by _CRS if we can't find a valid IRQ via this method 694 * in fact. 695 * 696 * If this link is not routed via an ISA IRQ (because we are using 697 * APIC for example), then don't bother looking up the BIOS IRQ 698 * as if we find one it won't be valid anyway. 699 */ 700 if (!link->l_isa_irq) { 701 ACPI_SERIAL_END(pci_link); 702 return; 703 } 704 705 /* Try to find a BIOS IRQ setting from any matching devices. */ 706 bios_irq = acpi_pci_link_search_irq(sc, bus, slot, pin); 707 if (!PCI_INTERRUPT_VALID(bios_irq)) { 708 ACPI_SERIAL_END(pci_link); 709 return; 710 } 711 712 /* Validate the BIOS IRQ. */ 713 if (!link_valid_irq(link, bios_irq)) { 714 printf("%s: BIOS IRQ %u for %d.%d.INT%c is invalid\n", 715 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A'); 716 } else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) { 717 link->l_bios_irq = bios_irq; 718 if (bios_irq < NUM_ISA_INTERRUPTS) 719 pci_link_bios_isa_irqs |= (1 << bios_irq); 720 if (bios_irq != link->l_initial_irq && 721 PCI_INTERRUPT_VALID(link->l_initial_irq)) 722 printf( 723 "%s: BIOS IRQ %u does not match initial IRQ %u\n", 724 sc->pl_name, bios_irq, link->l_initial_irq); 725 } else if (bios_irq != link->l_bios_irq) 726 printf( 727 "%s: BIOS IRQ %u for %d.%d.INT%c does not match " 728 "previous BIOS IRQ %u\n", 729 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A', 730 link->l_bios_irq); 731 ACPI_SERIAL_END(pci_link); 732 } 733 734 static ACPI_STATUS 735 acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf) 736 { 737 ACPI_RESOURCE *resource, *end, newres, *resptr; 738 ACPI_BUFFER crsbuf; 739 ACPI_STATUS status; 740 struct link *link; 741 int i, in_dpf; 742 743 /* Fetch the _CRS. */ 744 crsbuf.Pointer = NULL; 745 crsbuf.Length = ACPI_ALLOCATE_BUFFER; 746 status = AcpiGetCurrentResources(sc->pl_handle, &crsbuf); 747 if (ACPI_SUCCESS(status) && crsbuf.Pointer == NULL) 748 status = AE_NO_MEMORY; 749 if (ACPI_FAILURE(status)) { 750 aprint_verbose("%s: Unable to fetch current resources: %s\n", 751 sc->pl_name, AcpiFormatException(status)); 752 return (status); 753 } 754 755 /* Fill in IRQ resources via link structures. */ 756 srsbuf->Pointer = NULL; 757 link = sc->pl_links; 758 i = 0; 759 in_dpf = DPF_OUTSIDE; 760 resource = (ACPI_RESOURCE *)crsbuf.Pointer; 761 end = (ACPI_RESOURCE *)((char *)crsbuf.Pointer + crsbuf.Length); 762 for (;;) { 763 switch (resource->Type) { 764 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 765 switch (in_dpf) { 766 case DPF_OUTSIDE: 767 /* We've started the first DPF. */ 768 in_dpf = DPF_FIRST; 769 break; 770 case DPF_FIRST: 771 /* We've started the second DPF. */ 772 panic( 773 "%s: Multiple dependent functions within a current resource", 774 __func__); 775 break; 776 } 777 resptr = NULL; 778 break; 779 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 780 /* We are finished with DPF parsing. */ 781 KASSERT(in_dpf != DPF_OUTSIDE); 782 in_dpf = DPF_OUTSIDE; 783 resptr = NULL; 784 break; 785 case ACPI_RESOURCE_TYPE_IRQ: 786 newres = link->l_prs_template; 787 resptr = &newres; 788 resptr->Data.Irq.InterruptCount = 1; 789 if (PCI_INTERRUPT_VALID(link->l_irq)) { 790 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS); 791 resptr->Data.Irq.Interrupts[0] = link->l_irq; 792 resptr->Data.Irq.Triggering = link->l_trig; 793 resptr->Data.Irq.Polarity = link->l_pol; 794 } else 795 resptr->Data.Irq.Interrupts[0] = 0; 796 link++; 797 i++; 798 break; 799 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 800 newres = link->l_prs_template; 801 resptr = &newres; 802 resptr->Data.ExtendedIrq.InterruptCount = 1; 803 if (PCI_INTERRUPT_VALID(link->l_irq)) { 804 resptr->Data.ExtendedIrq.Interrupts[0] = 805 link->l_irq; 806 resptr->Data.ExtendedIrq.Triggering = 807 link->l_trig; 808 resptr->Data.ExtendedIrq.Polarity = link->l_pol; 809 } else 810 resptr->Data.ExtendedIrq.Interrupts[0] = 0; 811 link++; 812 i++; 813 break; 814 default: 815 resptr = resource; 816 } 817 if (resptr != NULL) { 818 status = acpi_AppendBufferResource(srsbuf, resptr); 819 if (ACPI_FAILURE(status)) { 820 printf("%s: Unable to build resources: %s\n", 821 sc->pl_name, AcpiFormatException(status)); 822 if (srsbuf->Pointer != NULL) 823 AcpiOsFree(srsbuf->Pointer); 824 AcpiOsFree(crsbuf.Pointer); 825 return (status); 826 } 827 } 828 if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG) 829 break; 830 resource = ACPI_NEXT_RESOURCE(resource); 831 if (resource >= end) 832 break; 833 } 834 AcpiOsFree(crsbuf.Pointer); 835 return (AE_OK); 836 } 837 838 static ACPI_STATUS 839 acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc, 840 ACPI_BUFFER *srsbuf) 841 { 842 ACPI_RESOURCE newres; 843 ACPI_STATUS status; 844 struct link *link; 845 int i; 846 847 /* Start off with an empty buffer. */ 848 srsbuf->Pointer = NULL; 849 link = sc->pl_links; 850 for (i = 0; i < sc->pl_num_links; i++) { 851 852 /* Add a new IRQ resource from each link. */ 853 link = &sc->pl_links[i]; 854 newres = link->l_prs_template; 855 if (newres.Type == ACPI_RESOURCE_TYPE_IRQ) { 856 857 /* Build an IRQ resource. */ 858 newres.Data.Irq.InterruptCount = 1; 859 if (PCI_INTERRUPT_VALID(link->l_irq)) { 860 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS); 861 newres.Data.Irq.Interrupts[0] = link->l_irq; 862 newres.Data.Irq.Triggering = link->l_trig; 863 newres.Data.Irq.Polarity = link->l_pol; 864 } else 865 newres.Data.Irq.Interrupts[0] = 0; 866 } else { 867 868 /* Build an ExtIRQ resuorce. */ 869 newres.Data.ExtendedIrq.InterruptCount = 1; 870 if (PCI_INTERRUPT_VALID(link->l_irq)) { 871 newres.Data.ExtendedIrq.Interrupts[0] = 872 link->l_irq; 873 newres.Data.ExtendedIrq.Triggering = 874 link->l_trig; 875 newres.Data.ExtendedIrq.Polarity = 876 link->l_pol; 877 } else { 878 newres.Data.ExtendedIrq.Interrupts[0] = 0; 879 } 880 } 881 882 /* Add the new resource to the end of the _SRS buffer. */ 883 status = acpi_AppendBufferResource(srsbuf, &newres); 884 if (ACPI_FAILURE(status)) { 885 printf("%s: Unable to build resources: %s\n", 886 sc->pl_name, AcpiFormatException(status)); 887 if (srsbuf->Pointer != NULL) 888 AcpiOsFree(srsbuf->Pointer); 889 return (status); 890 } 891 } 892 return (AE_OK); 893 } 894 895 static ACPI_STATUS 896 acpi_pci_link_srs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf) 897 { 898 ACPI_STATUS status; 899 900 if (sc->pl_crs_bad) 901 status = acpi_pci_link_srs_from_links(sc, srsbuf); 902 else 903 status = acpi_pci_link_srs_from_crs(sc, srsbuf); 904 905 /* Write out new resources via _SRS. */ 906 return AcpiSetCurrentResources(sc->pl_handle, srsbuf); 907 } 908 909 static ACPI_STATUS 910 acpi_pci_link_route_irqs(struct acpi_pci_link_softc *sc, int *irq, int *pol, 911 int *trig) 912 { 913 ACPI_RESOURCE *resource, *end; 914 ACPI_BUFFER srsbuf; 915 ACPI_STATUS status; 916 struct link *link; 917 int i, is_ext = 0; 918 919 status = acpi_pci_link_srs(sc, &srsbuf); 920 if (ACPI_FAILURE(status)) { 921 printf("%s: _SRS failed: %s\n", 922 sc->pl_name, AcpiFormatException(status)); 923 return (status); 924 } 925 /* 926 * Perform acpi_config_intr() on each IRQ resource if it was just 927 * routed for the first time. 928 */ 929 link = sc->pl_links; 930 i = 0; 931 resource = (ACPI_RESOURCE *)srsbuf.Pointer; 932 end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length); 933 for (;;) { 934 if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG) 935 break; 936 switch (resource->Type) { 937 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 938 is_ext = 1; 939 /* FALLTHROUGH */ 940 case ACPI_RESOURCE_TYPE_IRQ: 941 /* 942 * Only configure the interrupt and update the 943 * weights if this link has a valid IRQ and was 944 * previously unrouted. 945 */ 946 if (!link->l_routed && 947 PCI_INTERRUPT_VALID(link->l_irq)) { 948 *trig = is_ext ? 949 resource->Data.ExtendedIrq.Triggering : 950 resource->Data.Irq.Triggering; 951 *pol = is_ext ? 952 resource->Data.ExtendedIrq.Polarity : 953 resource->Data.Irq.Polarity; 954 *irq = is_ext ? 955 resource->Data.ExtendedIrq.Interrupts[0] : 956 resource->Data.Irq.Interrupts[0]; 957 link->l_routed = TRUE; 958 pci_link_interrupt_weights[link->l_irq] += 959 link->l_references; 960 } 961 link++; 962 i++; 963 break; 964 } 965 resource = ACPI_NEXT_RESOURCE(resource); 966 if (resource >= end) 967 break; 968 } 969 AcpiOsFree(srsbuf.Pointer); 970 return (AE_OK); 971 } 972 973 /* 974 * Pick an IRQ to use for this unrouted link. 975 */ 976 static uint8_t 977 acpi_pci_link_choose_irq(struct acpi_pci_link_softc *sc, struct link *link) 978 { 979 u_int8_t best_irq, pos_irq; 980 int best_weight, pos_weight, i; 981 982 KASSERT(!link->l_routed); 983 KASSERT(!PCI_INTERRUPT_VALID(link->l_irq)); 984 985 /* 986 * If we have a valid BIOS IRQ, use that. We trust what the BIOS 987 * says it routed over what _CRS says the link thinks is routed. 988 */ 989 if (PCI_INTERRUPT_VALID(link->l_bios_irq)) 990 return (link->l_bios_irq); 991 992 /* 993 * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS, 994 * then use that. 995 */ 996 if (PCI_INTERRUPT_VALID(link->l_initial_irq)) 997 return (link->l_initial_irq); 998 999 /* 1000 * Ok, we have no useful hints, so we have to pick from the 1001 * possible IRQs. For ISA IRQs we only use interrupts that 1002 * have already been used by the BIOS. 1003 */ 1004 best_irq = PCI_INVALID_IRQ; 1005 best_weight = INT_MAX; 1006 for (i = 0; i < link->l_num_irqs; i++) { 1007 pos_irq = link->l_irqs[i]; 1008 if (pos_irq < NUM_ISA_INTERRUPTS && 1009 (pci_link_bios_isa_irqs & 1 << pos_irq) == 0) 1010 continue; 1011 pos_weight = pci_link_interrupt_weights[pos_irq]; 1012 if (pos_weight < best_weight) { 1013 best_weight = pos_weight; 1014 best_irq = pos_irq; 1015 } 1016 } 1017 1018 /* 1019 * If this is an ISA IRQ, try using the SCI if it is also an ISA 1020 * interrupt as a fallback. 1021 */ 1022 if (link->l_isa_irq && !PCI_INTERRUPT_VALID(best_irq)) { 1023 pos_irq = AcpiGbl_FADT.SciInterrupt; 1024 pos_weight = pci_link_interrupt_weights[pos_irq]; 1025 if (pos_weight < best_weight) { 1026 best_weight = pos_weight; 1027 best_irq = pos_irq; 1028 } 1029 } 1030 1031 if (PCI_INTERRUPT_VALID(best_irq)) { 1032 aprint_verbose("%s: Picked IRQ %u with weight %d\n", 1033 sc->pl_name, best_irq, best_weight); 1034 } else 1035 printf("%s: Unable to choose an IRQ\n", sc->pl_name); 1036 return (best_irq); 1037 } 1038 1039 int 1040 acpi_pci_link_route_interrupt(void *v, int index, int *irq, int *pol, int *trig) 1041 { 1042 struct acpi_pci_link_softc *sc = v; 1043 struct link *link; 1044 int i; 1045 pcireg_t reg; 1046 1047 ACPI_SERIAL_BEGIN(pci_link); 1048 link = acpi_pci_link_lookup(sc, index); 1049 if (link == NULL) 1050 panic("%s: apparently invalid index %d", __func__, index); 1051 1052 /* 1053 * If this link device is already routed to an interrupt, just return 1054 * the interrupt it is routed to. 1055 */ 1056 if (link->l_routed) { 1057 KASSERT(PCI_INTERRUPT_VALID(link->l_irq)); 1058 ACPI_SERIAL_END(pci_link); 1059 *irq = link->l_irq; 1060 *pol = link->l_pol; 1061 *trig = link->l_trig; 1062 return (link->l_irq); 1063 } 1064 1065 /* Choose an IRQ if we need one. */ 1066 if (PCI_INTERRUPT_VALID(link->l_irq)) { 1067 *irq = link->l_irq; 1068 *pol = link->l_pol; 1069 *trig = link->l_trig; 1070 goto done; 1071 } 1072 1073 link->l_irq = acpi_pci_link_choose_irq(sc, link); 1074 1075 /* 1076 * Try to route the interrupt we picked. If it fails, then 1077 * assume the interrupt is not routed. 1078 */ 1079 if (!PCI_INTERRUPT_VALID(link->l_irq)) 1080 goto done; 1081 1082 acpi_pci_link_route_irqs(sc, irq, pol, trig); 1083 if (!link->l_routed) { 1084 link->l_irq = PCI_INVALID_IRQ; 1085 goto done; 1086 } 1087 1088 link->l_pol = *pol; 1089 link->l_trig = *trig; 1090 for (i = 0; i < link->l_dev_count; ++i) { 1091 reg = pci_conf_read(acpi_softc->sc_pc, link->l_devices[i], 1092 PCI_INTERRUPT_REG); 1093 reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 1094 reg |= link->l_irq << PCI_INTERRUPT_LINE_SHIFT; 1095 pci_conf_write(acpi_softc->sc_pc, link->l_devices[i], 1096 PCI_INTERRUPT_REG, reg); 1097 } 1098 1099 done: 1100 ACPI_SERIAL_END(pci_link); 1101 1102 return (link->l_irq); 1103 } 1104 1105 /* 1106 * This is gross, but we abuse the identify routine to perform one-time 1107 * SYSINIT() style initialization for the driver. 1108 */ 1109 static void 1110 acpi_pci_link_init(struct acpi_pci_link_softc *sc) 1111 { 1112 ACPI_BUFFER buf; 1113 1114 /* 1115 * If the SCI is an ISA IRQ, add it to the bitmask of known good 1116 * ISA IRQs. 1117 * 1118 * XXX: If we are using the APIC, the SCI might have been 1119 * rerouted to an APIC pin in which case this is invalid. However, 1120 * if we are using the APIC, we also shouldn't be having any PCI 1121 * interrupts routed via ISA IRQs, so this is probably ok. 1122 */ 1123 if (AcpiGbl_FADT.SciInterrupt < NUM_ISA_INTERRUPTS) 1124 pci_link_bios_isa_irqs |= (1 << AcpiGbl_FADT.SciInterrupt); 1125 1126 buf.Length = sizeof (sc->pl_name); 1127 buf.Pointer = sc->pl_name; 1128 1129 if (ACPI_FAILURE(AcpiGetName(sc->pl_handle, ACPI_SINGLE_NAME, &buf))) 1130 snprintf(sc->pl_name, sizeof (sc->pl_name), "%s", 1131 "ACPI link device"); 1132 1133 acpi_pci_link_attach(sc); 1134 } 1135 1136 void * 1137 acpi_pci_link_devbyhandle(ACPI_HANDLE handle) 1138 { 1139 struct acpi_pci_link_softc *sc; 1140 1141 TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) { 1142 if (sc->pl_handle == handle) 1143 return sc; 1144 } 1145 1146 sc = malloc(sizeof (*sc), M_PCI_LINK, M_NOWAIT|M_ZERO); 1147 if (sc == NULL) 1148 return NULL; 1149 1150 sc->pl_handle = handle; 1151 1152 acpi_pci_link_init(sc); 1153 1154 TAILQ_INSERT_TAIL(&acpi_pci_linkdevs, sc, pl_list); 1155 1156 return (void *)sc; 1157 } 1158 1159 void 1160 acpi_pci_link_resume(void) 1161 { 1162 struct acpi_pci_link_softc *sc; 1163 ACPI_BUFFER srsbuf; 1164 1165 TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) { 1166 ACPI_SERIAL_BEGIN(pci_link); 1167 if (ACPI_SUCCESS(acpi_pci_link_srs(sc, &srsbuf))) 1168 AcpiOsFree(srsbuf.Pointer); 1169 ACPI_SERIAL_END(pci_link); 1170 } 1171 } 1172 1173 ACPI_HANDLE 1174 acpi_pci_link_handle(void *v) 1175 { 1176 struct acpi_pci_link_softc *sc = v; 1177 1178 return sc->pl_handle; 1179 } 1180 1181 char * 1182 acpi_pci_link_name(void *v) 1183 { 1184 struct acpi_pci_link_softc *sc = v; 1185 1186 return sc->pl_name; 1187 } 1188 1189 1190 /* 1191 * Append an ACPI_RESOURCE to an ACPI_BUFFER. 1192 * 1193 * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER 1194 * provided to contain it. If the ACPI_BUFFER is empty, allocate a sensible 1195 * backing block. If the ACPI_RESOURCE is NULL, return an empty set of 1196 * resources. 1197 */ 1198 #define ACPI_INITIAL_RESOURCE_BUFFER_SIZE 512 1199 1200 static ACPI_STATUS 1201 acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res) 1202 { 1203 ACPI_RESOURCE *rp; 1204 void *newp; 1205 1206 /* Initialise the buffer if necessary. */ 1207 if (buf->Pointer == NULL) { 1208 buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE; 1209 if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL) 1210 return (AE_NO_MEMORY); 1211 rp = (ACPI_RESOURCE *)buf->Pointer; 1212 rp->Type = ACPI_RESOURCE_TYPE_END_TAG; 1213 rp->Length = 0; 1214 } 1215 1216 if (res == NULL) 1217 return (AE_OK); 1218 1219 /* 1220 * Scan the current buffer looking for the terminator. 1221 * This will either find the terminator or hit the end 1222 * of the buffer and return an error. 1223 */ 1224 rp = (ACPI_RESOURCE *)buf->Pointer; 1225 for (;;) { 1226 /* Range check, don't go outside the buffer */ 1227 if (rp >= (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + 1228 buf->Length)) 1229 return (AE_BAD_PARAMETER); 1230 if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0) 1231 break; 1232 rp = ACPI_NEXT_RESOURCE(rp); 1233 } 1234 1235 /* 1236 * Check the size of the buffer and expand if required. 1237 * 1238 * Required size is: 1239 * size of existing resources before terminator + 1240 * size of new resource and header + 1241 * size of terminator. 1242 * 1243 * Note that this loop should really only run once, unless 1244 * for some reason we are stuffing a *really* huge resource. 1245 */ 1246 while ((((u_int8_t *)rp - (u_int8_t *)buf->Pointer) + 1247 res->Length + ACPI_RS_SIZE_NO_DATA + 1248 ACPI_RS_SIZE_MIN) >= buf->Length) { 1249 if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL) 1250 return (AE_NO_MEMORY); 1251 memcpy(newp, buf->Pointer, buf->Length); 1252 rp = (ACPI_RESOURCE *)((u_int8_t *)newp + 1253 ((u_int8_t *)rp - (u_int8_t *)buf->Pointer)); 1254 AcpiOsFree(buf->Pointer); 1255 buf->Pointer = newp; 1256 buf->Length += buf->Length; 1257 } 1258 1259 /* Insert the new resource. */ 1260 memcpy(rp, res, res->Length + ACPI_RS_SIZE_NO_DATA); 1261 1262 /* And add the terminator. */ 1263 rp = ACPI_NEXT_RESOURCE(rp); 1264 rp->Type = ACPI_RESOURCE_TYPE_END_TAG; 1265 rp->Length = 0; 1266 1267 return (AE_OK); 1268 } 1269