| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: acpi_pci_link.c,v 1.17 2010/04/14 19:27:28 jruoho Exp $ */ | | 1 | /* $NetBSD: acpi_pci_link.c,v 1.18 2010/04/23 15:52:26 jruoho Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> | | 4 | * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -17,45 +17,46 @@ | | | @@ -17,45 +17,46 @@ |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: acpi_pci_link.c,v 1.17 2010/04/14 19:27:28 jruoho Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: acpi_pci_link.c,v 1.18 2010/04/23 15:52:26 jruoho Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/malloc.h> | | 33 | #include <sys/malloc.h> |
34 | #include <sys/queue.h> | | 34 | #include <sys/queue.h> |
35 | #include <sys/reboot.h> | | 35 | #include <sys/reboot.h> |
36 | #include <sys/systm.h> | | 36 | #include <sys/systm.h> |
37 | | | 37 | |
38 | #include <dev/acpi/acpireg.h> | | 38 | #include <dev/acpi/acpireg.h> |
39 | #include <dev/acpi/acpivar.h> | | 39 | #include <dev/acpi/acpivar.h> |
40 | | | 40 | |
41 | #include <dev/pci/pcireg.h> | | 41 | #include <dev/pci/pcireg.h> |
42 | | | 42 | |
43 | #include "opt_acpi.h" | | 43 | #include "opt_acpi.h" |
44 | | | 44 | |
45 | | | 45 | |
46 | #define _COMPONENT ACPI_BUS_COMPONENT | | 46 | #define _COMPONENT ACPI_BUS_COMPONENT |
47 | ACPI_MODULE_NAME ("acpi_pci_link") | | 47 | ACPI_MODULE_NAME ("acpi_pci_link") |
48 | | | 48 | |
| | | 49 | MALLOC_DECLARE(M_ACPI); |
49 | | | 50 | |
50 | #define NUM_ISA_INTERRUPTS 16 | | 51 | #define NUM_ISA_INTERRUPTS 16 |
51 | #define NUM_ACPI_INTERRUPTS 256 | | 52 | #define NUM_ACPI_INTERRUPTS 256 |
52 | | | 53 | |
53 | #define PCI_INVALID_IRQ 255 | | 54 | #define PCI_INVALID_IRQ 255 |
54 | #define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ && (x) != 0) | | 55 | #define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ && (x) != 0) |
55 | | | 56 | |
56 | #define ACPI_SERIAL_BEGIN(x) | | 57 | #define ACPI_SERIAL_BEGIN(x) |
57 | #define ACPI_SERIAL_END(x) | | 58 | #define ACPI_SERIAL_END(x) |
58 | | | 59 | |
59 | /* | | 60 | /* |
60 | * An ACPI PCI link device may contain multiple links. Each link has its | | 61 | * An ACPI PCI link device may contain multiple links. Each link has its |
61 | * own ACPI resource. _PRT entries specify which link is being used via | | 62 | * own ACPI resource. _PRT entries specify which link is being used via |
| @@ -122,28 +123,26 @@ struct link { | | | @@ -122,28 +123,26 @@ struct link { |
122 | | | 123 | |
123 | struct link_count_request { | | 124 | struct link_count_request { |
124 | int in_dpf; | | 125 | int in_dpf; |
125 | int count; | | 126 | int count; |
126 | }; | | 127 | }; |
127 | | | 128 | |
128 | struct link_res_request { | | 129 | struct link_res_request { |
129 | struct acpi_pci_link_softc *sc; | | 130 | struct acpi_pci_link_softc *sc; |
130 | int in_dpf; | | 131 | int in_dpf; |
131 | int res_index; | | 132 | int res_index; |
132 | int link_index; | | 133 | int link_index; |
133 | }; | | 134 | }; |
134 | | | 135 | |
135 | MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures"); | | | |
136 | | | | |
137 | static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS]; | | 136 | static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS]; |
138 | static int pci_link_bios_isa_irqs; | | 137 | static int pci_link_bios_isa_irqs; |
139 | | | 138 | |
140 | static ACPI_STATUS acpi_count_irq_resources(ACPI_RESOURCE *, void *); | | 139 | static ACPI_STATUS acpi_count_irq_resources(ACPI_RESOURCE *, void *); |
141 | static ACPI_STATUS link_add_crs(ACPI_RESOURCE *, void *); | | 140 | static ACPI_STATUS link_add_crs(ACPI_RESOURCE *, void *); |
142 | static ACPI_STATUS link_add_prs(ACPI_RESOURCE *, void *); | | 141 | static ACPI_STATUS link_add_prs(ACPI_RESOURCE *, void *); |
143 | static int link_valid_irq(struct link *, int); | | 142 | static int link_valid_irq(struct link *, int); |
144 | static void acpi_pci_link_dump(struct acpi_pci_link_softc *); | | 143 | static void acpi_pci_link_dump(struct acpi_pci_link_softc *); |
145 | static int acpi_pci_link_attach(struct acpi_pci_link_softc *); | | 144 | static int acpi_pci_link_attach(struct acpi_pci_link_softc *); |
146 | static uint8_t acpi_pci_link_search_irq(struct acpi_pci_link_softc *, int, int, | | 145 | static uint8_t acpi_pci_link_search_irq(struct acpi_pci_link_softc *, int, int, |
147 | int); | | 146 | int); |
148 | static struct link *acpi_pci_link_lookup(struct acpi_pci_link_softc *, int); | | 147 | static struct link *acpi_pci_link_lookup(struct acpi_pci_link_softc *, int); |
149 | static ACPI_STATUS acpi_pci_link_srs(struct acpi_pci_link_softc *, | | 148 | static ACPI_STATUS acpi_pci_link_srs(struct acpi_pci_link_softc *, |
| @@ -333,27 +332,27 @@ link_add_prs(ACPI_RESOURCE *res, void *c | | | @@ -333,27 +332,27 @@ link_add_prs(ACPI_RESOURCE *res, void *c |
333 | link->l_pol = res->Data.Irq.Polarity; | | 332 | link->l_pol = res->Data.Irq.Polarity; |
334 | irqs = res->Data.Irq.Interrupts; | | 333 | irqs = res->Data.Irq.Interrupts; |
335 | } | | 334 | } |
336 | if (link->l_num_irqs == 0) | | 335 | if (link->l_num_irqs == 0) |
337 | break; | | 336 | break; |
338 | | | 337 | |
339 | /* | | 338 | /* |
340 | * Save a list of the valid IRQs. Also, if all of the | | 339 | * Save a list of the valid IRQs. Also, if all of the |
341 | * valid IRQs are ISA IRQs, then mark this link as | | 340 | * valid IRQs are ISA IRQs, then mark this link as |
342 | * routed via an ISA interrupt. | | 341 | * routed via an ISA interrupt. |
343 | */ | | 342 | */ |
344 | link->l_isa_irq = TRUE; | | 343 | link->l_isa_irq = TRUE; |
345 | link->l_irqs = malloc(sizeof(int) * link->l_num_irqs, | | 344 | link->l_irqs = malloc(sizeof(int) * link->l_num_irqs, |
346 | M_PCI_LINK, M_WAITOK | M_ZERO); | | 345 | M_ACPI, M_WAITOK | M_ZERO); |
347 | for (i = 0; i < link->l_num_irqs; i++) { | | 346 | for (i = 0; i < link->l_num_irqs; i++) { |
348 | if (is_ext_irq) { | | 347 | if (is_ext_irq) { |
349 | link->l_irqs[i] = ext_irqs[i]; | | 348 | link->l_irqs[i] = ext_irqs[i]; |
350 | if (ext_irqs[i] >= NUM_ISA_INTERRUPTS) | | 349 | if (ext_irqs[i] >= NUM_ISA_INTERRUPTS) |
351 | link->l_isa_irq = FALSE; | | 350 | link->l_isa_irq = FALSE; |
352 | } else { | | 351 | } else { |
353 | link->l_irqs[i] = irqs[i]; | | 352 | link->l_irqs[i] = irqs[i]; |
354 | if (irqs[i] >= NUM_ISA_INTERRUPTS) | | 353 | if (irqs[i] >= NUM_ISA_INTERRUPTS) |
355 | link->l_isa_irq = FALSE; | | 354 | link->l_isa_irq = FALSE; |
356 | } | | 355 | } |
357 | } | | 356 | } |
358 | break; | | 357 | break; |
359 | default: | | 358 | default: |
| @@ -453,27 +452,27 @@ acpi_pci_link_attach(struct acpi_pci_lin | | | @@ -453,27 +452,27 @@ acpi_pci_link_attach(struct acpi_pci_lin |
453 | if (ACPI_FAILURE(status)) { | | 452 | if (ACPI_FAILURE(status)) { |
454 | aprint_error("%s: Unable to parse _CRS or _PRS: %s\n", | | 453 | aprint_error("%s: Unable to parse _CRS or _PRS: %s\n", |
455 | sc->pl_name, AcpiFormatException(status)); | | 454 | sc->pl_name, AcpiFormatException(status)); |
456 | ACPI_SERIAL_END(pci_link); | | 455 | ACPI_SERIAL_END(pci_link); |
457 | return (ENXIO); | | 456 | return (ENXIO); |
458 | } | | 457 | } |
459 | } | | 458 | } |
460 | sc->pl_num_links = creq.count; | | 459 | sc->pl_num_links = creq.count; |
461 | if (creq.count == 0) { | | 460 | if (creq.count == 0) { |
462 | ACPI_SERIAL_END(pci_link); | | 461 | ACPI_SERIAL_END(pci_link); |
463 | return (0); | | 462 | return (0); |
464 | } | | 463 | } |
465 | sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links, | | 464 | sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links, |
466 | M_PCI_LINK, M_WAITOK | M_ZERO); | | 465 | M_ACPI, M_WAITOK | M_ZERO); |
467 | | | 466 | |
468 | /* Initialize the child links. */ | | 467 | /* Initialize the child links. */ |
469 | for (i = 0; i < sc->pl_num_links; i++) { | | 468 | for (i = 0; i < sc->pl_num_links; i++) { |
470 | sc->pl_links[i].l_irq = PCI_INVALID_IRQ; | | 469 | sc->pl_links[i].l_irq = PCI_INVALID_IRQ; |
471 | sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ; | | 470 | sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ; |
472 | sc->pl_links[i].l_sc = sc; | | 471 | sc->pl_links[i].l_sc = sc; |
473 | sc->pl_links[i].l_isa_irq = FALSE; | | 472 | sc->pl_links[i].l_isa_irq = FALSE; |
474 | sc->pl_links[i].l_res_index = -1; | | 473 | sc->pl_links[i].l_res_index = -1; |
475 | sc->pl_links[i].l_dev_count = 0; | | 474 | sc->pl_links[i].l_dev_count = 0; |
476 | sc->pl_links[i].l_devices = NULL; | | 475 | sc->pl_links[i].l_devices = NULL; |
477 | } | | 476 | } |
478 | | | 477 | |
479 | /* Try to read the current settings from _CRS if it is valid. */ | | 478 | /* Try to read the current settings from _CRS if it is valid. */ |
| @@ -544,31 +543,31 @@ acpi_pci_link_attach(struct acpi_pci_lin | | | @@ -544,31 +543,31 @@ acpi_pci_link_attach(struct acpi_pci_lin |
544 | for (i = 0; i < sc->pl_num_links; i++) | | 543 | for (i = 0; i < sc->pl_num_links; i++) |
545 | if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq)) | | 544 | if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq)) |
546 | sc->pl_links[i].l_routed = TRUE; | | 545 | sc->pl_links[i].l_routed = TRUE; |
547 | if (boothowto & AB_VERBOSE) { | | 546 | if (boothowto & AB_VERBOSE) { |
548 | printf("%s: Links after disable:\n", sc->pl_name); | | 547 | printf("%s: Links after disable:\n", sc->pl_name); |
549 | acpi_pci_link_dump(sc); | | 548 | acpi_pci_link_dump(sc); |
550 | } | | 549 | } |
551 | ACPI_SERIAL_END(pci_link); | | 550 | ACPI_SERIAL_END(pci_link); |
552 | return (0); | | 551 | return (0); |
553 | fail: | | 552 | fail: |
554 | ACPI_SERIAL_END(pci_link); | | 553 | ACPI_SERIAL_END(pci_link); |
555 | for (i = 0; i < sc->pl_num_links; i++) { | | 554 | for (i = 0; i < sc->pl_num_links; i++) { |
556 | if (sc->pl_links[i].l_irqs != NULL) | | 555 | if (sc->pl_links[i].l_irqs != NULL) |
557 | free(sc->pl_links[i].l_irqs, M_PCI_LINK); | | 556 | free(sc->pl_links[i].l_irqs, M_ACPI); |
558 | if (sc->pl_links[i].l_devices != NULL) | | 557 | if (sc->pl_links[i].l_devices != NULL) |
559 | free(sc->pl_links[i].l_devices, M_PCI_LINK); | | 558 | free(sc->pl_links[i].l_devices, M_ACPI); |
560 | } | | 559 | } |
561 | free(sc->pl_links, M_PCI_LINK); | | 560 | free(sc->pl_links, M_ACPI); |
562 | return (ENXIO); | | 561 | return (ENXIO); |
563 | } | | 562 | } |
564 | | | 563 | |
565 | static void | | 564 | static void |
566 | acpi_pci_link_add_functions(struct acpi_pci_link_softc *sc, struct link *link, | | 565 | acpi_pci_link_add_functions(struct acpi_pci_link_softc *sc, struct link *link, |
567 | int bus, int device, int pin) | | 566 | int bus, int device, int pin) |
568 | { | | 567 | { |
569 | uint32_t value; | | 568 | uint32_t value; |
570 | uint8_t func, maxfunc, ipin; | | 569 | uint8_t func, maxfunc, ipin; |
571 | pcitag_t tag; | | 570 | pcitag_t tag; |
572 | | | 571 | |
573 | tag = pci_make_tag(acpi_softc->sc_pc, bus, device, 0); | | 572 | tag = pci_make_tag(acpi_softc->sc_pc, bus, device, 0); |
574 | /* See if we have a valid device at function 0. */ | | 573 | /* See if we have a valid device at function 0. */ |
| @@ -589,27 +588,27 @@ acpi_pci_link_add_functions(struct acpi_ | | | @@ -589,27 +588,27 @@ acpi_pci_link_add_functions(struct acpi_ |
589 | value = pci_conf_read(acpi_softc->sc_pc, tag, | | 588 | value = pci_conf_read(acpi_softc->sc_pc, tag, |
590 | PCI_INTERRUPT_REG); | | 589 | PCI_INTERRUPT_REG); |
591 | ipin = PCI_INTERRUPT_PIN(value); | | 590 | ipin = PCI_INTERRUPT_PIN(value); |
592 | /* | | 591 | /* |
593 | * See if it uses the pin in question. Note that the passed | | 592 | * See if it uses the pin in question. Note that the passed |
594 | * in pin uses 0 for A, .. 3 for D whereas the intpin | | 593 | * in pin uses 0 for A, .. 3 for D whereas the intpin |
595 | * register uses 0 for no interrupt, 1 for A, .. 4 for D. | | 594 | * register uses 0 for no interrupt, 1 for A, .. 4 for D. |
596 | */ | | 595 | */ |
597 | if (ipin != pin + 1) | | 596 | if (ipin != pin + 1) |
598 | continue; | | 597 | continue; |
599 | | | 598 | |
600 | link->l_devices = realloc(link->l_devices, | | 599 | link->l_devices = realloc(link->l_devices, |
601 | sizeof(pcitag_t) * (link->l_dev_count + 1), | | 600 | sizeof(pcitag_t) * (link->l_dev_count + 1), |
602 | M_PCI_LINK, M_WAITOK); | | 601 | M_ACPI, M_WAITOK); |
603 | link->l_devices[link->l_dev_count] = tag; | | 602 | link->l_devices[link->l_dev_count] = tag; |
604 | ++link->l_dev_count; | | 603 | ++link->l_dev_count; |
605 | } | | 604 | } |
606 | } | | 605 | } |
607 | | | 606 | |
608 | static uint8_t | | 607 | static uint8_t |
609 | acpi_pci_link_search_irq(struct acpi_pci_link_softc *sc, int bus, int device, | | 608 | acpi_pci_link_search_irq(struct acpi_pci_link_softc *sc, int bus, int device, |
610 | int pin) | | 609 | int pin) |
611 | { | | 610 | { |
612 | uint32_t value; | | 611 | uint32_t value; |
613 | uint8_t func, maxfunc, ipin, iline; | | 612 | uint8_t func, maxfunc, ipin, iline; |
614 | pcitag_t tag; | | 613 | pcitag_t tag; |
615 | | | 614 | |
| @@ -1134,30 +1133,30 @@ acpi_pci_link_init(struct acpi_pci_link_ | | | @@ -1134,30 +1133,30 @@ acpi_pci_link_init(struct acpi_pci_link_ |
1134 | snprintf(sc->pl_name, sizeof (sc->pl_name), "%s", | | 1133 | snprintf(sc->pl_name, sizeof (sc->pl_name), "%s", |
1135 | "ACPI link device"); | | 1134 | "ACPI link device"); |
1136 | | | 1135 | |
1137 | acpi_pci_link_attach(sc); | | 1136 | acpi_pci_link_attach(sc); |
1138 | } | | 1137 | } |
1139 | | | 1138 | |
1140 | void * | | 1139 | void * |
1141 | acpi_pci_link_devbyhandle(ACPI_HANDLE handle) | | 1140 | acpi_pci_link_devbyhandle(ACPI_HANDLE handle) |
1142 | { | | 1141 | { |
1143 | struct acpi_pci_link_softc *sc; | | 1142 | struct acpi_pci_link_softc *sc; |
1144 | | | 1143 | |
1145 | TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) { | | 1144 | TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) { |
1146 | if (sc->pl_handle == handle) | | 1145 | if (sc->pl_handle == handle) |
1147 | return sc; | | 1146 | return sc; |
1148 | } | | 1147 | } |
1149 | | | 1148 | |
1150 | sc = malloc(sizeof (*sc), M_PCI_LINK, M_NOWAIT|M_ZERO); | | 1149 | sc = malloc(sizeof (*sc), M_ACPI, M_NOWAIT | M_ZERO); |
1151 | if (sc == NULL) | | 1150 | if (sc == NULL) |
1152 | return NULL; | | 1151 | return NULL; |
1153 | | | 1152 | |
1154 | sc->pl_handle = handle; | | 1153 | sc->pl_handle = handle; |
1155 | | | 1154 | |
1156 | acpi_pci_link_init(sc); | | 1155 | acpi_pci_link_init(sc); |
1157 | | | 1156 | |
1158 | TAILQ_INSERT_TAIL(&acpi_pci_linkdevs, sc, pl_list); | | 1157 | TAILQ_INSERT_TAIL(&acpi_pci_linkdevs, sc, pl_list); |
1159 | | | 1158 | |
1160 | return (void *)sc; | | 1159 | return (void *)sc; |
1161 | } | | 1160 | } |
1162 | | | 1161 | |
1163 | void | | 1162 | void |