190638023SMitsuru IWASAKI /*- 290638023SMitsuru IWASAKI * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 390638023SMitsuru IWASAKI * All rights reserved. 490638023SMitsuru IWASAKI * 590638023SMitsuru IWASAKI * Redistribution and use in source and binary forms, with or without 690638023SMitsuru IWASAKI * modification, are permitted provided that the following conditions 790638023SMitsuru IWASAKI * are met: 890638023SMitsuru IWASAKI * 1. Redistributions of source code must retain the above copyright 990638023SMitsuru IWASAKI * notice, this list of conditions and the following disclaimer. 1090638023SMitsuru IWASAKI * 2. Redistributions in binary form must reproduce the above copyright 1190638023SMitsuru IWASAKI * notice, this list of conditions and the following disclaimer in the 1290638023SMitsuru IWASAKI * documentation and/or other materials provided with the distribution. 1390638023SMitsuru IWASAKI * 1490638023SMitsuru IWASAKI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1590638023SMitsuru IWASAKI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1690638023SMitsuru IWASAKI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1790638023SMitsuru IWASAKI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1890638023SMitsuru IWASAKI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1990638023SMitsuru IWASAKI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2090638023SMitsuru IWASAKI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2190638023SMitsuru IWASAKI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2290638023SMitsuru IWASAKI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2390638023SMitsuru IWASAKI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2490638023SMitsuru IWASAKI * SUCH DAMAGE. 2590638023SMitsuru IWASAKI */ 2690638023SMitsuru IWASAKI 27aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 2890638023SMitsuru IWASAKI #include "opt_acpi.h" 2990638023SMitsuru IWASAKI #include <sys/param.h> 3090638023SMitsuru IWASAKI #include <sys/bus.h> 315e1ba6d4SJohn Baldwin #include <sys/kernel.h> 325e1ba6d4SJohn Baldwin #include <sys/limits.h> 335e1ba6d4SJohn Baldwin #include <sys/malloc.h> 345e1ba6d4SJohn Baldwin #include <sys/module.h> 3590638023SMitsuru IWASAKI 36129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h> 37129d3046SJung-uk Kim 3890638023SMitsuru IWASAKI #include <dev/acpica/acpivar.h> 3990638023SMitsuru IWASAKI #include <dev/acpica/acpi_pcibvar.h> 4090638023SMitsuru IWASAKI 415e1ba6d4SJohn Baldwin #include <machine/pci_cfgreg.h> 425e1ba6d4SJohn Baldwin #include <dev/pci/pcireg.h> 43e4116e93SNate Lawson #include <dev/pci/pcivar.h> 44e4116e93SNate Lawson #include "pcib_if.h" 45e4116e93SNate Lawson 46ea6b2bc9SNate Lawson /* Hooks for the ACPI CA debugging infrastructure. */ 4790638023SMitsuru IWASAKI #define _COMPONENT ACPI_BUS 4890638023SMitsuru IWASAKI ACPI_MODULE_NAME("PCI_LINK") 4990638023SMitsuru IWASAKI 5086b697a7SNate Lawson ACPI_SERIAL_DECL(pci_link, "ACPI PCI link"); 5190638023SMitsuru IWASAKI 525e1ba6d4SJohn Baldwin #define NUM_ISA_INTERRUPTS 16 535e1ba6d4SJohn Baldwin #define NUM_ACPI_INTERRUPTS 256 54e4116e93SNate Lawson 5590638023SMitsuru IWASAKI /* 565e1ba6d4SJohn Baldwin * An ACPI PCI link device may contain multiple links. Each link has its 575e1ba6d4SJohn Baldwin * own ACPI resource. _PRT entries specify which link is being used via 585e1ba6d4SJohn Baldwin * the Source Index. 597e1f562eSJohn Baldwin * 607e1f562eSJohn Baldwin * XXX: A note about Source Indices and DPFs: Currently we assume that 617e1f562eSJohn Baldwin * the DPF start and end tags are not counted towards the index that 627e1f562eSJohn Baldwin * Source Index corresponds to. Also, we assume that when DPFs are in use 637e1f562eSJohn Baldwin * they various sets overlap in terms of Indices. Here's an example 647e1f562eSJohn Baldwin * resource list indicating these assumptions: 657e1f562eSJohn Baldwin * 667e1f562eSJohn Baldwin * Resource Index 677e1f562eSJohn Baldwin * -------- ----- 687e1f562eSJohn Baldwin * I/O Port 0 697e1f562eSJohn Baldwin * Start DPF - 707e1f562eSJohn Baldwin * IRQ 1 717e1f562eSJohn Baldwin * MemIO 2 727e1f562eSJohn Baldwin * Start DPF - 737e1f562eSJohn Baldwin * IRQ 1 747e1f562eSJohn Baldwin * MemIO 2 757e1f562eSJohn Baldwin * End DPF - 767e1f562eSJohn Baldwin * DMA Channel 3 777e1f562eSJohn Baldwin * 787e1f562eSJohn Baldwin * The XXX is because I'm not sure if this is a valid assumption to make. 7990638023SMitsuru IWASAKI */ 8090638023SMitsuru IWASAKI 817e1f562eSJohn Baldwin /* States during DPF processing. */ 827e1f562eSJohn Baldwin #define DPF_OUTSIDE 0 837e1f562eSJohn Baldwin #define DPF_FIRST 1 847e1f562eSJohn Baldwin #define DPF_IGNORE 2 857e1f562eSJohn Baldwin 865e1ba6d4SJohn Baldwin struct link; 875e1ba6d4SJohn Baldwin 885e1ba6d4SJohn Baldwin struct acpi_pci_link_softc { 895e1ba6d4SJohn Baldwin int pl_num_links; 9094b3af82SJohn Baldwin int pl_crs_bad; 915e1ba6d4SJohn Baldwin struct link *pl_links; 9294b3af82SJohn Baldwin device_t pl_dev; 935e1ba6d4SJohn Baldwin }; 945e1ba6d4SJohn Baldwin 955e1ba6d4SJohn Baldwin struct link { 965e1ba6d4SJohn Baldwin struct acpi_pci_link_softc *l_sc; 975e1ba6d4SJohn Baldwin uint8_t l_bios_irq; 985e1ba6d4SJohn Baldwin uint8_t l_irq; 995e1ba6d4SJohn Baldwin uint8_t l_initial_irq; 10060d306f0SJohn Baldwin UINT32 l_crs_type; 1015e1ba6d4SJohn Baldwin int l_res_index; 1025e1ba6d4SJohn Baldwin int l_num_irqs; 1035e1ba6d4SJohn Baldwin int *l_irqs; 1045e1ba6d4SJohn Baldwin int l_references; 105bab8274cSDimitry Andric bool l_routed:1; 106bab8274cSDimitry Andric bool l_isa_irq:1; 1075e1ba6d4SJohn Baldwin ACPI_RESOURCE l_prs_template; 1085e1ba6d4SJohn Baldwin }; 1095e1ba6d4SJohn Baldwin 1107e1f562eSJohn Baldwin struct link_count_request { 1117e1f562eSJohn Baldwin int in_dpf; 1127e1f562eSJohn Baldwin int count; 1137e1f562eSJohn Baldwin }; 1147e1f562eSJohn Baldwin 1155e1ba6d4SJohn Baldwin struct link_res_request { 1165e1ba6d4SJohn Baldwin struct acpi_pci_link_softc *sc; 1177e1f562eSJohn Baldwin int in_dpf; 1187e1f562eSJohn Baldwin int res_index; 1197e1f562eSJohn Baldwin int link_index; 1205e1ba6d4SJohn Baldwin }; 1215e1ba6d4SJohn Baldwin 122d745c852SEd Schouten static MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures"); 1235e1ba6d4SJohn Baldwin 1245e1ba6d4SJohn Baldwin static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS]; 1255e1ba6d4SJohn Baldwin static int pci_link_bios_isa_irqs; 1265e1ba6d4SJohn Baldwin 1275e1ba6d4SJohn Baldwin static char *pci_link_ids[] = { "PNP0C0F", NULL }; 1285e1ba6d4SJohn Baldwin 1295e1ba6d4SJohn Baldwin /* 1305e1ba6d4SJohn Baldwin * Fetch the short name associated with an ACPI handle and save it in the 1315e1ba6d4SJohn Baldwin * passed in buffer. 1325e1ba6d4SJohn Baldwin */ 1335e1ba6d4SJohn Baldwin static ACPI_STATUS 1345e1ba6d4SJohn Baldwin acpi_short_name(ACPI_HANDLE handle, char *buffer, size_t buflen) 1353d9644efSJohn Baldwin { 1365e1ba6d4SJohn Baldwin ACPI_BUFFER buf; 1373d9644efSJohn Baldwin 1385e1ba6d4SJohn Baldwin buf.Length = buflen; 1395e1ba6d4SJohn Baldwin buf.Pointer = buffer; 1405e1ba6d4SJohn Baldwin return (AcpiGetName(handle, ACPI_SINGLE_NAME, &buf)); 1413d9644efSJohn Baldwin } 1423d9644efSJohn Baldwin 1435e1ba6d4SJohn Baldwin static int 1445e1ba6d4SJohn Baldwin acpi_pci_link_probe(device_t dev) 1453d9644efSJohn Baldwin { 146*bad36a49SMark Johnston char name[12]; 1475efca36fSTakanori Watanabe int rv; 1483d9644efSJohn Baldwin 1495e1ba6d4SJohn Baldwin /* 1505e1ba6d4SJohn Baldwin * We explicitly do not check _STA since not all systems set it to 1515e1ba6d4SJohn Baldwin * sensible values. 1525e1ba6d4SJohn Baldwin */ 1535efca36fSTakanori Watanabe if (acpi_disabled("pci_link")) 1545e1ba6d4SJohn Baldwin return (ENXIO); 1555efca36fSTakanori Watanabe rv = ACPI_ID_PROBE(device_get_parent(dev), dev, pci_link_ids, NULL); 1565efca36fSTakanori Watanabe if (rv > 0) 1575efca36fSTakanori Watanabe return (rv); 1582f3f3112SNate Lawson 1592f3f3112SNate Lawson if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), name, 160*bad36a49SMark Johnston sizeof(name)))) 161*bad36a49SMark Johnston device_set_descf(dev, "ACPI PCI Link %s", name); 162*bad36a49SMark Johnston else 1632f3f3112SNate Lawson device_set_desc(dev, "ACPI PCI Link"); 164ef2cda76SJohn Baldwin device_quiet(dev); 1655efca36fSTakanori Watanabe return (rv); 16690638023SMitsuru IWASAKI } 16790638023SMitsuru IWASAKI 16890638023SMitsuru IWASAKI static ACPI_STATUS 169ad71daf0SNate Lawson acpi_count_irq_resources(ACPI_RESOURCE *res, void *context) 17090638023SMitsuru IWASAKI { 1717e1f562eSJohn Baldwin struct link_count_request *req; 17290638023SMitsuru IWASAKI 1737e1f562eSJohn Baldwin req = (struct link_count_request *)context; 174e8d472a7SJung-uk Kim switch (res->Type) { 175e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_START_DEPENDENT: 1767e1f562eSJohn Baldwin switch (req->in_dpf) { 1777e1f562eSJohn Baldwin case DPF_OUTSIDE: 1787e1f562eSJohn Baldwin /* We've started the first DPF. */ 1797e1f562eSJohn Baldwin req->in_dpf = DPF_FIRST; 1807e1f562eSJohn Baldwin break; 1817e1f562eSJohn Baldwin case DPF_FIRST: 1827e1f562eSJohn Baldwin /* We've started the second DPF. */ 1837e1f562eSJohn Baldwin req->in_dpf = DPF_IGNORE; 1847e1f562eSJohn Baldwin break; 1857e1f562eSJohn Baldwin } 1867e1f562eSJohn Baldwin break; 187e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_END_DEPENDENT: 1887e1f562eSJohn Baldwin /* We are finished with DPF parsing. */ 1897e1f562eSJohn Baldwin KASSERT(req->in_dpf != DPF_OUTSIDE, 1907e1f562eSJohn Baldwin ("%s: end dpf when not parsing a dpf", __func__)); 1917e1f562eSJohn Baldwin req->in_dpf = DPF_OUTSIDE; 1927e1f562eSJohn Baldwin break; 193e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_IRQ: 194e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 1957e1f562eSJohn Baldwin /* 1967e1f562eSJohn Baldwin * Don't count resources if we are in a DPF set that we are 1977e1f562eSJohn Baldwin * ignoring. 1987e1f562eSJohn Baldwin */ 1997e1f562eSJohn Baldwin if (req->in_dpf != DPF_IGNORE) 2007e1f562eSJohn Baldwin req->count++; 201ad71daf0SNate Lawson } 2025e1ba6d4SJohn Baldwin return (AE_OK); 20390638023SMitsuru IWASAKI } 20490638023SMitsuru IWASAKI 2055e1ba6d4SJohn Baldwin static ACPI_STATUS 2065e1ba6d4SJohn Baldwin link_add_crs(ACPI_RESOURCE *res, void *context) 2075e1ba6d4SJohn Baldwin { 2085e1ba6d4SJohn Baldwin struct link_res_request *req; 2095e1ba6d4SJohn Baldwin struct link *link; 2105e1ba6d4SJohn Baldwin 2115e1ba6d4SJohn Baldwin ACPI_SERIAL_ASSERT(pci_link); 2125e1ba6d4SJohn Baldwin req = (struct link_res_request *)context; 213e8d472a7SJung-uk Kim switch (res->Type) { 214e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_START_DEPENDENT: 2157e1f562eSJohn Baldwin switch (req->in_dpf) { 2167e1f562eSJohn Baldwin case DPF_OUTSIDE: 2177e1f562eSJohn Baldwin /* We've started the first DPF. */ 2187e1f562eSJohn Baldwin req->in_dpf = DPF_FIRST; 2197e1f562eSJohn Baldwin break; 2207e1f562eSJohn Baldwin case DPF_FIRST: 2217e1f562eSJohn Baldwin /* We've started the second DPF. */ 2227e1f562eSJohn Baldwin panic( 2237e1f562eSJohn Baldwin "%s: Multiple dependent functions within a current resource", 2247e1f562eSJohn Baldwin __func__); 2257e1f562eSJohn Baldwin break; 2267e1f562eSJohn Baldwin } 2277e1f562eSJohn Baldwin break; 228e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_END_DEPENDENT: 2297e1f562eSJohn Baldwin /* We are finished with DPF parsing. */ 2307e1f562eSJohn Baldwin KASSERT(req->in_dpf != DPF_OUTSIDE, 2317e1f562eSJohn Baldwin ("%s: end dpf when not parsing a dpf", __func__)); 2327e1f562eSJohn Baldwin req->in_dpf = DPF_OUTSIDE; 2337e1f562eSJohn Baldwin break; 234e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_IRQ: 235e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 2367e1f562eSJohn Baldwin KASSERT(req->link_index < req->sc->pl_num_links, 2377e1f562eSJohn Baldwin ("%s: array boundary violation", __func__)); 2387e1f562eSJohn Baldwin link = &req->sc->pl_links[req->link_index]; 2397e1f562eSJohn Baldwin link->l_res_index = req->res_index; 24060d306f0SJohn Baldwin link->l_crs_type = res->Type; 2417e1f562eSJohn Baldwin req->link_index++; 2427e1f562eSJohn Baldwin req->res_index++; 2438c702862SNate Lawson 2448c702862SNate Lawson /* 2458c702862SNate Lawson * Only use the current value if there's one IRQ. Some 2468c702862SNate Lawson * systems return multiple IRQs (which is nonsense for _CRS) 2478c702862SNate Lawson * when the link hasn't been programmed. 2488c702862SNate Lawson */ 249e8d472a7SJung-uk Kim if (res->Type == ACPI_RESOURCE_TYPE_IRQ) { 250e8d472a7SJung-uk Kim if (res->Data.Irq.InterruptCount == 1) 2515e1ba6d4SJohn Baldwin link->l_irq = res->Data.Irq.Interrupts[0]; 252e8d472a7SJung-uk Kim } else if (res->Data.ExtendedIrq.InterruptCount == 1) 2535e1ba6d4SJohn Baldwin link->l_irq = res->Data.ExtendedIrq.Interrupts[0]; 25490638023SMitsuru IWASAKI 2555e1ba6d4SJohn Baldwin /* 2565e1ba6d4SJohn Baldwin * An IRQ of zero means that the link isn't routed. 2575e1ba6d4SJohn Baldwin */ 2585e1ba6d4SJohn Baldwin if (link->l_irq == 0) 2595e1ba6d4SJohn Baldwin link->l_irq = PCI_INVALID_IRQ; 2605e1ba6d4SJohn Baldwin break; 2617e1f562eSJohn Baldwin default: 2627e1f562eSJohn Baldwin req->res_index++; 2635e1ba6d4SJohn Baldwin } 2645e1ba6d4SJohn Baldwin return (AE_OK); 26590638023SMitsuru IWASAKI } 26690638023SMitsuru IWASAKI 2675e1ba6d4SJohn Baldwin /* 2685e1ba6d4SJohn Baldwin * Populate the set of possible IRQs for each device. 2695e1ba6d4SJohn Baldwin */ 2705e1ba6d4SJohn Baldwin static ACPI_STATUS 2715e1ba6d4SJohn Baldwin link_add_prs(ACPI_RESOURCE *res, void *context) 2725e1ba6d4SJohn Baldwin { 2739fe3e6c0SJung-uk Kim ACPI_RESOURCE *tmp; 2745e1ba6d4SJohn Baldwin struct link_res_request *req; 2755e1ba6d4SJohn Baldwin struct link *link; 276e8d472a7SJung-uk Kim UINT8 *irqs = NULL; 277e8d472a7SJung-uk Kim UINT32 *ext_irqs = NULL; 278e8d472a7SJung-uk Kim int i, is_ext_irq = 1; 2795e1ba6d4SJohn Baldwin 2805e1ba6d4SJohn Baldwin ACPI_SERIAL_ASSERT(pci_link); 2815e1ba6d4SJohn Baldwin req = (struct link_res_request *)context; 282e8d472a7SJung-uk Kim switch (res->Type) { 283e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_START_DEPENDENT: 2847e1f562eSJohn Baldwin switch (req->in_dpf) { 2857e1f562eSJohn Baldwin case DPF_OUTSIDE: 2867e1f562eSJohn Baldwin /* We've started the first DPF. */ 2877e1f562eSJohn Baldwin req->in_dpf = DPF_FIRST; 2887e1f562eSJohn Baldwin break; 2897e1f562eSJohn Baldwin case DPF_FIRST: 2907e1f562eSJohn Baldwin /* We've started the second DPF. */ 2917e1f562eSJohn Baldwin req->in_dpf = DPF_IGNORE; 2927e1f562eSJohn Baldwin break; 2937e1f562eSJohn Baldwin } 2947e1f562eSJohn Baldwin break; 295e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_END_DEPENDENT: 2967e1f562eSJohn Baldwin /* We are finished with DPF parsing. */ 2977e1f562eSJohn Baldwin KASSERT(req->in_dpf != DPF_OUTSIDE, 2987e1f562eSJohn Baldwin ("%s: end dpf when not parsing a dpf", __func__)); 2997e1f562eSJohn Baldwin req->in_dpf = DPF_OUTSIDE; 3007e1f562eSJohn Baldwin break; 301e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_IRQ: 302e8d472a7SJung-uk Kim is_ext_irq = 0; 303e8d472a7SJung-uk Kim /* fall through */ 304e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 3057e1f562eSJohn Baldwin /* 3067e1f562eSJohn Baldwin * Don't parse resources if we are in a DPF set that we are 3077e1f562eSJohn Baldwin * ignoring. 3087e1f562eSJohn Baldwin */ 3097e1f562eSJohn Baldwin if (req->in_dpf == DPF_IGNORE) 3107e1f562eSJohn Baldwin break; 3117e1f562eSJohn Baldwin 3127e1f562eSJohn Baldwin KASSERT(req->link_index < req->sc->pl_num_links, 3137e1f562eSJohn Baldwin ("%s: array boundary violation", __func__)); 3147e1f562eSJohn Baldwin link = &req->sc->pl_links[req->link_index]; 31594b3af82SJohn Baldwin if (link->l_res_index == -1) { 31694b3af82SJohn Baldwin KASSERT(req->sc->pl_crs_bad, 31794b3af82SJohn Baldwin ("res_index should be set")); 31894b3af82SJohn Baldwin link->l_res_index = req->res_index; 31994b3af82SJohn Baldwin } 3207e1f562eSJohn Baldwin req->link_index++; 32194b3af82SJohn Baldwin req->res_index++; 3225e1ba6d4SJohn Baldwin 3235e1ba6d4SJohn Baldwin /* 3245e1ba6d4SJohn Baldwin * Stash a copy of the resource for later use when doing 3255e1ba6d4SJohn Baldwin * _SRS. 3265e1ba6d4SJohn Baldwin */ 3279fe3e6c0SJung-uk Kim tmp = &link->l_prs_template; 328e8d472a7SJung-uk Kim if (is_ext_irq) { 3299fe3e6c0SJung-uk Kim bcopy(res, tmp, ACPI_RS_SIZE(tmp->Data.ExtendedIrq)); 3309fe3e6c0SJung-uk Kim 3319fe3e6c0SJung-uk Kim /* 3329fe3e6c0SJung-uk Kim * XXX acpi_AppendBufferResource() cannot handle 3339fe3e6c0SJung-uk Kim * optional data. 3349fe3e6c0SJung-uk Kim */ 3359fe3e6c0SJung-uk Kim bzero(&tmp->Data.ExtendedIrq.ResourceSource, 3369fe3e6c0SJung-uk Kim sizeof(tmp->Data.ExtendedIrq.ResourceSource)); 3379fe3e6c0SJung-uk Kim tmp->Length = ACPI_RS_SIZE(tmp->Data.ExtendedIrq); 3389fe3e6c0SJung-uk Kim 3395e1ba6d4SJohn Baldwin link->l_num_irqs = 340e8d472a7SJung-uk Kim res->Data.ExtendedIrq.InterruptCount; 341e8d472a7SJung-uk Kim ext_irqs = res->Data.ExtendedIrq.Interrupts; 342e8d472a7SJung-uk Kim } else { 3439fe3e6c0SJung-uk Kim bcopy(res, tmp, ACPI_RS_SIZE(tmp->Data.Irq)); 344e8d472a7SJung-uk Kim link->l_num_irqs = res->Data.Irq.InterruptCount; 345e8d472a7SJung-uk Kim irqs = res->Data.Irq.Interrupts; 34690638023SMitsuru IWASAKI } 3475e1ba6d4SJohn Baldwin if (link->l_num_irqs == 0) 34890638023SMitsuru IWASAKI break; 3495e1ba6d4SJohn Baldwin 3505e1ba6d4SJohn Baldwin /* 3515e1ba6d4SJohn Baldwin * Save a list of the valid IRQs. Also, if all of the 3525e1ba6d4SJohn Baldwin * valid IRQs are ISA IRQs, then mark this link as 3535e1ba6d4SJohn Baldwin * routed via an ISA interrupt. 3545e1ba6d4SJohn Baldwin */ 355bab8274cSDimitry Andric link->l_isa_irq = true; 3565e1ba6d4SJohn Baldwin link->l_irqs = malloc(sizeof(int) * link->l_num_irqs, 3575e1ba6d4SJohn Baldwin M_PCI_LINK, M_WAITOK | M_ZERO); 3585e1ba6d4SJohn Baldwin for (i = 0; i < link->l_num_irqs; i++) { 359e8d472a7SJung-uk Kim if (is_ext_irq) { 360e8d472a7SJung-uk Kim link->l_irqs[i] = ext_irqs[i]; 361e8d472a7SJung-uk Kim if (ext_irqs[i] >= NUM_ISA_INTERRUPTS) 362bab8274cSDimitry Andric link->l_isa_irq = false; 363e8d472a7SJung-uk Kim } else { 3645e1ba6d4SJohn Baldwin link->l_irqs[i] = irqs[i]; 365ad71daf0SNate Lawson if (irqs[i] >= NUM_ISA_INTERRUPTS) 366bab8274cSDimitry Andric link->l_isa_irq = false; 3675e1ba6d4SJohn Baldwin } 368e8d472a7SJung-uk Kim } 36960d306f0SJohn Baldwin 37060d306f0SJohn Baldwin /* 37160d306f0SJohn Baldwin * If this is not an ISA IRQ but _CRS used a non-extended 37260d306f0SJohn Baldwin * IRQ descriptor, don't use _CRS as a template for _SRS. 37360d306f0SJohn Baldwin */ 37460d306f0SJohn Baldwin if (!req->sc->pl_crs_bad && !link->l_isa_irq && 37560d306f0SJohn Baldwin link->l_crs_type == ACPI_RESOURCE_TYPE_IRQ) 376bab8274cSDimitry Andric req->sc->pl_crs_bad = true; 37790638023SMitsuru IWASAKI break; 37894b3af82SJohn Baldwin default: 37994b3af82SJohn Baldwin if (req->in_dpf == DPF_IGNORE) 38094b3af82SJohn Baldwin break; 38194b3af82SJohn Baldwin if (req->sc->pl_crs_bad) 38294b3af82SJohn Baldwin device_printf(req->sc->pl_dev, 38394b3af82SJohn Baldwin "Warning: possible resource %d will be lost during _SRS\n", 38494b3af82SJohn Baldwin req->res_index); 38594b3af82SJohn Baldwin req->res_index++; 38690638023SMitsuru IWASAKI } 3875e1ba6d4SJohn Baldwin return (AE_OK); 38890638023SMitsuru IWASAKI } 38990638023SMitsuru IWASAKI 390bab8274cSDimitry Andric static bool 3915e1ba6d4SJohn Baldwin link_valid_irq(struct link *link, int irq) 39290638023SMitsuru IWASAKI { 3935e1ba6d4SJohn Baldwin int i; 39490638023SMitsuru IWASAKI 39586b697a7SNate Lawson ACPI_SERIAL_ASSERT(pci_link); 39690638023SMitsuru IWASAKI 3975e1ba6d4SJohn Baldwin /* Invalid interrupts are never valid. */ 3985e1ba6d4SJohn Baldwin if (!PCI_INTERRUPT_VALID(irq)) 399bab8274cSDimitry Andric return (false); 40090638023SMitsuru IWASAKI 4015e1ba6d4SJohn Baldwin /* Any interrupt in the list of possible interrupts is valid. */ 4025e1ba6d4SJohn Baldwin for (i = 0; i < link->l_num_irqs; i++) 4035e1ba6d4SJohn Baldwin if (link->l_irqs[i] == irq) 404bab8274cSDimitry Andric return (true); 40590638023SMitsuru IWASAKI 406e4116e93SNate Lawson /* 4075e1ba6d4SJohn Baldwin * For links routed via an ISA interrupt, if the SCI is routed via 4085e1ba6d4SJohn Baldwin * an ISA interrupt, the SCI is always treated as a valid IRQ. 409e4116e93SNate Lawson */ 4102be4e471SJung-uk Kim if (link->l_isa_irq && AcpiGbl_FADT.SciInterrupt == irq && 4115e1ba6d4SJohn Baldwin irq < NUM_ISA_INTERRUPTS) 412bab8274cSDimitry Andric return (true); 4135e1ba6d4SJohn Baldwin 4145e1ba6d4SJohn Baldwin /* If the interrupt wasn't found in the list it is not valid. */ 415bab8274cSDimitry Andric return (false); 41690638023SMitsuru IWASAKI } 41790638023SMitsuru IWASAKI 4185e1ba6d4SJohn Baldwin static void 41967b712deSJohn Baldwin acpi_pci_link_dump(struct acpi_pci_link_softc *sc, int header, const char *tag) 4205e1ba6d4SJohn Baldwin { 4215e1ba6d4SJohn Baldwin struct link *link; 42267b712deSJohn Baldwin char buf[16]; 4235e1ba6d4SJohn Baldwin int i, j; 4245e1ba6d4SJohn Baldwin 4250297d51eSDavid E. O'Brien ACPI_SERIAL_ASSERT(pci_link); 42667b712deSJohn Baldwin if (header) { 42767b712deSJohn Baldwin snprintf(buf, sizeof(buf), "%s:", 42867b712deSJohn Baldwin device_get_nameunit(sc->pl_dev)); 42967b712deSJohn Baldwin printf("%-16.16s Index IRQ Rtd Ref IRQs\n", buf); 43067b712deSJohn Baldwin } 4315e1ba6d4SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) { 4325e1ba6d4SJohn Baldwin link = &sc->pl_links[i]; 43367b712deSJohn Baldwin printf(" %-14.14s %5d %3d %c %3d ", i == 0 ? tag : "", i, 43467b712deSJohn Baldwin link->l_irq, link->l_routed ? 'Y' : 'N', 43567b712deSJohn Baldwin link->l_references); 4365e1ba6d4SJohn Baldwin if (link->l_num_irqs == 0) 4375e1ba6d4SJohn Baldwin printf(" none"); 4385e1ba6d4SJohn Baldwin else for (j = 0; j < link->l_num_irqs; j++) 4395e1ba6d4SJohn Baldwin printf(" %d", link->l_irqs[j]); 4405e1ba6d4SJohn Baldwin printf("\n"); 44190638023SMitsuru IWASAKI } 44290638023SMitsuru IWASAKI } 44390638023SMitsuru IWASAKI 4445e1ba6d4SJohn Baldwin static int 4455e1ba6d4SJohn Baldwin acpi_pci_link_attach(device_t dev) 4465e1ba6d4SJohn Baldwin { 4475e1ba6d4SJohn Baldwin struct acpi_pci_link_softc *sc; 4487e1f562eSJohn Baldwin struct link_count_request creq; 4497e1f562eSJohn Baldwin struct link_res_request rreq; 4505e1ba6d4SJohn Baldwin ACPI_STATUS status; 4515e1ba6d4SJohn Baldwin int i; 45256a7639bSNate Lawson 4535e1ba6d4SJohn Baldwin sc = device_get_softc(dev); 45494b3af82SJohn Baldwin sc->pl_dev = dev; 4550297d51eSDavid E. O'Brien ACPI_SERIAL_BEGIN(pci_link); 45690638023SMitsuru IWASAKI 4575e1ba6d4SJohn Baldwin /* 4585e1ba6d4SJohn Baldwin * Count the number of current resources so we know how big of 45994b3af82SJohn Baldwin * a link array to allocate. On some systems, _CRS is broken, 46094b3af82SJohn Baldwin * so for those systems try to derive the count from _PRS instead. 4615e1ba6d4SJohn Baldwin */ 4627e1f562eSJohn Baldwin creq.in_dpf = DPF_OUTSIDE; 4637e1f562eSJohn Baldwin creq.count = 0; 4645e1ba6d4SJohn Baldwin status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", 4657e1f562eSJohn Baldwin acpi_count_irq_resources, &creq); 46694b3af82SJohn Baldwin sc->pl_crs_bad = ACPI_FAILURE(status); 46794b3af82SJohn Baldwin if (sc->pl_crs_bad) { 46894b3af82SJohn Baldwin creq.in_dpf = DPF_OUTSIDE; 46994b3af82SJohn Baldwin creq.count = 0; 47094b3af82SJohn Baldwin status = AcpiWalkResources(acpi_get_handle(dev), "_PRS", 47194b3af82SJohn Baldwin acpi_count_irq_resources, &creq); 47294b3af82SJohn Baldwin if (ACPI_FAILURE(status)) { 47394b3af82SJohn Baldwin device_printf(dev, 47494b3af82SJohn Baldwin "Unable to parse _CRS or _PRS: %s\n", 47594b3af82SJohn Baldwin AcpiFormatException(status)); 47694b3af82SJohn Baldwin ACPI_SERIAL_END(pci_link); 4775e1ba6d4SJohn Baldwin return (ENXIO); 47894b3af82SJohn Baldwin } 47994b3af82SJohn Baldwin } 48094b3af82SJohn Baldwin sc->pl_num_links = creq.count; 48182946891SJohn Baldwin if (creq.count == 0) { 48282946891SJohn Baldwin ACPI_SERIAL_END(pci_link); 4835e1ba6d4SJohn Baldwin return (0); 48482946891SJohn Baldwin } 4855e1ba6d4SJohn Baldwin sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links, 4865e1ba6d4SJohn Baldwin M_PCI_LINK, M_WAITOK | M_ZERO); 4875e1ba6d4SJohn Baldwin 4885e1ba6d4SJohn Baldwin /* Initialize the child links. */ 4895e1ba6d4SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) { 4905e1ba6d4SJohn Baldwin sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 4915e1ba6d4SJohn Baldwin sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ; 4925e1ba6d4SJohn Baldwin sc->pl_links[i].l_sc = sc; 493bab8274cSDimitry Andric sc->pl_links[i].l_isa_irq = false; 49494b3af82SJohn Baldwin sc->pl_links[i].l_res_index = -1; 4955e1ba6d4SJohn Baldwin } 49694b3af82SJohn Baldwin 49794b3af82SJohn Baldwin /* Try to read the current settings from _CRS if it is valid. */ 49894b3af82SJohn Baldwin if (!sc->pl_crs_bad) { 4997e1f562eSJohn Baldwin rreq.in_dpf = DPF_OUTSIDE; 5007e1f562eSJohn Baldwin rreq.link_index = 0; 5017e1f562eSJohn Baldwin rreq.res_index = 0; 5027e1f562eSJohn Baldwin rreq.sc = sc; 5035e1ba6d4SJohn Baldwin status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", 5047e1f562eSJohn Baldwin link_add_crs, &rreq); 50594b3af82SJohn Baldwin if (ACPI_FAILURE(status)) { 50694b3af82SJohn Baldwin device_printf(dev, "Unable to parse _CRS: %s\n", 50794b3af82SJohn Baldwin AcpiFormatException(status)); 5085e1ba6d4SJohn Baldwin goto fail; 50994b3af82SJohn Baldwin } 51094b3af82SJohn Baldwin } 51194b3af82SJohn Baldwin 51294b3af82SJohn Baldwin /* 51394b3af82SJohn Baldwin * Try to read the possible settings from _PRS. Note that if the 51494b3af82SJohn Baldwin * _CRS is toast, we depend on having a working _PRS. However, if 51594b3af82SJohn Baldwin * _CRS works, then it is ok for _PRS to be missing. 51694b3af82SJohn Baldwin */ 5177e1f562eSJohn Baldwin rreq.in_dpf = DPF_OUTSIDE; 5187e1f562eSJohn Baldwin rreq.link_index = 0; 5197e1f562eSJohn Baldwin rreq.res_index = 0; 52094b3af82SJohn Baldwin rreq.sc = sc; 5215e1ba6d4SJohn Baldwin status = AcpiWalkResources(acpi_get_handle(dev), "_PRS", 5227e1f562eSJohn Baldwin link_add_prs, &rreq); 52394b3af82SJohn Baldwin if (ACPI_FAILURE(status) && 52494b3af82SJohn Baldwin (status != AE_NOT_FOUND || sc->pl_crs_bad)) { 52594b3af82SJohn Baldwin device_printf(dev, "Unable to parse _PRS: %s\n", 52694b3af82SJohn Baldwin AcpiFormatException(status)); 5275e1ba6d4SJohn Baldwin goto fail; 52894b3af82SJohn Baldwin } 52967b712deSJohn Baldwin if (bootverbose) 53067b712deSJohn Baldwin acpi_pci_link_dump(sc, 1, "Initial Probe"); 53190638023SMitsuru IWASAKI 5325e1ba6d4SJohn Baldwin /* Verify initial IRQs if we have _PRS. */ 5335e1ba6d4SJohn Baldwin if (status != AE_NOT_FOUND) 5345e1ba6d4SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) 5355e1ba6d4SJohn Baldwin if (!link_valid_irq(&sc->pl_links[i], 5365e1ba6d4SJohn Baldwin sc->pl_links[i].l_irq)) 5375e1ba6d4SJohn Baldwin sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 53867b712deSJohn Baldwin if (bootverbose) 53967b712deSJohn Baldwin acpi_pci_link_dump(sc, 0, "Validation"); 54090638023SMitsuru IWASAKI 5415e1ba6d4SJohn Baldwin /* Save initial IRQs. */ 5425e1ba6d4SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) 5435e1ba6d4SJohn Baldwin sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq; 5445e1ba6d4SJohn Baldwin 545e4116e93SNate Lawson /* 5460c601400SNate Lawson * Try to disable this link. If successful, set the current IRQ to 5470c601400SNate Lawson * zero and flags to indicate this link is not routed. If we can't 5480c601400SNate Lawson * run _DIS (i.e., the method doesn't exist), assume the initial 5490c601400SNate Lawson * IRQ was routed by the BIOS. 5500c601400SNate Lawson */ 5515e1ba6d4SJohn Baldwin if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL, 5525e1ba6d4SJohn Baldwin NULL))) 5535e1ba6d4SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) 5545e1ba6d4SJohn Baldwin sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 5555e1ba6d4SJohn Baldwin else 5565e1ba6d4SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) 5575e1ba6d4SJohn Baldwin if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq)) 558bab8274cSDimitry Andric sc->pl_links[i].l_routed = true; 55967b712deSJohn Baldwin if (bootverbose) 56067b712deSJohn Baldwin acpi_pci_link_dump(sc, 0, "After Disable"); 5610297d51eSDavid E. O'Brien ACPI_SERIAL_END(pci_link); 5625e1ba6d4SJohn Baldwin return (0); 5635e1ba6d4SJohn Baldwin fail: 5640297d51eSDavid E. O'Brien ACPI_SERIAL_END(pci_link); 5655e1ba6d4SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) 5665e1ba6d4SJohn Baldwin if (sc->pl_links[i].l_irqs != NULL) 5675e1ba6d4SJohn Baldwin free(sc->pl_links[i].l_irqs, M_PCI_LINK); 5685e1ba6d4SJohn Baldwin free(sc->pl_links, M_PCI_LINK); 5695e1ba6d4SJohn Baldwin return (ENXIO); 570e4116e93SNate Lawson } 571e4116e93SNate Lawson 5725e1ba6d4SJohn Baldwin /* XXX: Note that this is identical to pci_pir_search_irq(). */ 5735e1ba6d4SJohn Baldwin static uint8_t 5741587a9dbSJohn Baldwin acpi_pci_link_search_irq(int domain, int bus, int device, int pin) 5755e1ba6d4SJohn Baldwin { 5765e1ba6d4SJohn Baldwin uint32_t value; 5775e1ba6d4SJohn Baldwin uint8_t func, maxfunc; 57890638023SMitsuru IWASAKI 5795e1ba6d4SJohn Baldwin /* See if we have a valid device at function 0. */ 5801587a9dbSJohn Baldwin value = pci_cfgregread(domain, bus, device, 0, PCIR_VENDOR, 2); 581a04725cdSJohn Baldwin if (value == PCIV_INVALID) 582a04725cdSJohn Baldwin return (PCI_INVALID_IRQ); 5831587a9dbSJohn Baldwin value = pci_cfgregread(domain, bus, device, 0, PCIR_HDRTYPE, 1); 5845e1ba6d4SJohn Baldwin if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 5855e1ba6d4SJohn Baldwin return (PCI_INVALID_IRQ); 5865e1ba6d4SJohn Baldwin if (value & PCIM_MFDEV) 5875e1ba6d4SJohn Baldwin maxfunc = PCI_FUNCMAX; 5885e1ba6d4SJohn Baldwin else 5895e1ba6d4SJohn Baldwin maxfunc = 0; 59090638023SMitsuru IWASAKI 5915e1ba6d4SJohn Baldwin /* Scan all possible functions at this device. */ 5925e1ba6d4SJohn Baldwin for (func = 0; func <= maxfunc; func++) { 5931587a9dbSJohn Baldwin value = pci_cfgregread(domain, bus, device, func, PCIR_VENDOR, 5941587a9dbSJohn Baldwin 2); 595a04725cdSJohn Baldwin if (value == PCIV_INVALID) 5965e1ba6d4SJohn Baldwin continue; 5971587a9dbSJohn Baldwin value = pci_cfgregread(domain, bus, device, func, PCIR_INTPIN, 5981587a9dbSJohn Baldwin 1); 5995e1ba6d4SJohn Baldwin 6005e1ba6d4SJohn Baldwin /* 6015e1ba6d4SJohn Baldwin * See if it uses the pin in question. Note that the passed 6025e1ba6d4SJohn Baldwin * in pin uses 0 for A, .. 3 for D whereas the intpin 6035e1ba6d4SJohn Baldwin * register uses 0 for no interrupt, 1 for A, .. 4 for D. 6045e1ba6d4SJohn Baldwin */ 6055e1ba6d4SJohn Baldwin if (value != pin + 1) 6065e1ba6d4SJohn Baldwin continue; 6071587a9dbSJohn Baldwin value = pci_cfgregread(domain, bus, device, func, PCIR_INTLINE, 6081587a9dbSJohn Baldwin 1); 6095e1ba6d4SJohn Baldwin if (bootverbose) 6105e1ba6d4SJohn Baldwin printf( 6115e1ba6d4SJohn Baldwin "ACPI: Found matching pin for %d.%d.INT%c at func %d: %d\n", 6125e1ba6d4SJohn Baldwin bus, device, pin + 'A', func, value); 6135e1ba6d4SJohn Baldwin if (value != PCI_INVALID_IRQ) 6145e1ba6d4SJohn Baldwin return (value); 6155e1ba6d4SJohn Baldwin } 6165e1ba6d4SJohn Baldwin return (PCI_INVALID_IRQ); 6175e1ba6d4SJohn Baldwin } 6185e1ba6d4SJohn Baldwin 6197e1f562eSJohn Baldwin /* 6207e1f562eSJohn Baldwin * Find the link structure that corresponds to the resource index passed in 6217e1f562eSJohn Baldwin * via 'source_index'. 6227e1f562eSJohn Baldwin */ 6237e1f562eSJohn Baldwin static struct link * 6247e1f562eSJohn Baldwin acpi_pci_link_lookup(device_t dev, int source_index) 6257e1f562eSJohn Baldwin { 6267e1f562eSJohn Baldwin struct acpi_pci_link_softc *sc; 6277e1f562eSJohn Baldwin int i; 6287e1f562eSJohn Baldwin 6297e1f562eSJohn Baldwin ACPI_SERIAL_ASSERT(pci_link); 6307e1f562eSJohn Baldwin sc = device_get_softc(dev); 6317e1f562eSJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) 6327e1f562eSJohn Baldwin if (sc->pl_links[i].l_res_index == source_index) 6337e1f562eSJohn Baldwin return (&sc->pl_links[i]); 6347e1f562eSJohn Baldwin return (NULL); 6357e1f562eSJohn Baldwin } 6367e1f562eSJohn Baldwin 6375e1ba6d4SJohn Baldwin void 6385e1ba6d4SJohn Baldwin acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot, 6395e1ba6d4SJohn Baldwin int pin) 6405e1ba6d4SJohn Baldwin { 6415e1ba6d4SJohn Baldwin struct link *link; 6425e1ba6d4SJohn Baldwin uint8_t bios_irq; 6431587a9dbSJohn Baldwin uintptr_t bus, domain; 644a4104d1cSJohn Baldwin 645a4104d1cSJohn Baldwin /* 6461587a9dbSJohn Baldwin * Look up the PCI domain and bus for the specified PCI bridge 6471587a9dbSJohn Baldwin * device. Note that the PCI bridge device might not have any 6481587a9dbSJohn Baldwin * children yet. However, looking up these IVARs doesn't 6491587a9dbSJohn Baldwin * require a valid child device, so we just pass NULL. 650a4104d1cSJohn Baldwin */ 651a4104d1cSJohn Baldwin if (BUS_READ_IVAR(pcib, NULL, PCIB_IVAR_BUS, &bus) != 0) { 652a4104d1cSJohn Baldwin device_printf(pcib, "Unable to read PCI bus number"); 653ef2cda76SJohn Baldwin panic("PCI bridge without a bus number"); 654a4104d1cSJohn Baldwin } 6551587a9dbSJohn Baldwin if (BUS_READ_IVAR(pcib, NULL, PCIB_IVAR_DOMAIN, &domain) != 0) { 6561587a9dbSJohn Baldwin device_printf(pcib, "Unable to read PCI domain number"); 6571587a9dbSJohn Baldwin panic("PCI bridge without a domain number"); 6581587a9dbSJohn Baldwin } 6595e1ba6d4SJohn Baldwin 6605e1ba6d4SJohn Baldwin /* Bump the reference count. */ 6615e1ba6d4SJohn Baldwin ACPI_SERIAL_BEGIN(pci_link); 6627e1f562eSJohn Baldwin link = acpi_pci_link_lookup(dev, index); 6638dc0e020SJohn Baldwin if (link == NULL) { 6648dc0e020SJohn Baldwin device_printf(dev, "apparently invalid index %d\n", index); 6658dc0e020SJohn Baldwin ACPI_SERIAL_END(pci_link); 6668dc0e020SJohn Baldwin return; 6678dc0e020SJohn Baldwin } 6685e1ba6d4SJohn Baldwin link->l_references++; 6695e1ba6d4SJohn Baldwin if (link->l_routed) 6705e1ba6d4SJohn Baldwin pci_link_interrupt_weights[link->l_irq]++; 6715e1ba6d4SJohn Baldwin 672ef2cda76SJohn Baldwin /* 673ef2cda76SJohn Baldwin * The BIOS only routes interrupts via ISA IRQs using the ATPICs 674ef2cda76SJohn Baldwin * (8259As). Thus, if this link is routed via an ISA IRQ, go 675ef2cda76SJohn Baldwin * look to see if the BIOS routed an IRQ for this link at the 6761587a9dbSJohn Baldwin * indicated (domain, bus, slot, pin). If so, we prefer that IRQ for 677ef2cda76SJohn Baldwin * this link and add that IRQ to our list of known-good IRQs. 678ef2cda76SJohn Baldwin * This provides a good work-around for link devices whose _CRS 679ef2cda76SJohn Baldwin * method is either broken or bogus. We only use the value 680ef2cda76SJohn Baldwin * returned by _CRS if we can't find a valid IRQ via this method 681ef2cda76SJohn Baldwin * in fact. 682ef2cda76SJohn Baldwin * 683ef2cda76SJohn Baldwin * If this link is not routed via an ISA IRQ (because we are using 684ef2cda76SJohn Baldwin * APIC for example), then don't bother looking up the BIOS IRQ 685ef2cda76SJohn Baldwin * as if we find one it won't be valid anyway. 686ef2cda76SJohn Baldwin */ 687ef2cda76SJohn Baldwin if (!link->l_isa_irq) { 688ef2cda76SJohn Baldwin ACPI_SERIAL_END(pci_link); 689ef2cda76SJohn Baldwin return; 690ef2cda76SJohn Baldwin } 691ef2cda76SJohn Baldwin 6925e1ba6d4SJohn Baldwin /* Try to find a BIOS IRQ setting from any matching devices. */ 6931587a9dbSJohn Baldwin bios_irq = acpi_pci_link_search_irq(domain, bus, slot, pin); 6945e1ba6d4SJohn Baldwin if (!PCI_INTERRUPT_VALID(bios_irq)) { 6955e1ba6d4SJohn Baldwin ACPI_SERIAL_END(pci_link); 6965e1ba6d4SJohn Baldwin return; 6975e1ba6d4SJohn Baldwin } 6985e1ba6d4SJohn Baldwin 6995e1ba6d4SJohn Baldwin /* Validate the BIOS IRQ. */ 7005e1ba6d4SJohn Baldwin if (!link_valid_irq(link, bios_irq)) { 7015e1ba6d4SJohn Baldwin device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n", 702a4104d1cSJohn Baldwin bios_irq, (int)bus, slot, pin + 'A'); 7035e1ba6d4SJohn Baldwin } else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) { 7045e1ba6d4SJohn Baldwin link->l_bios_irq = bios_irq; 7055e1ba6d4SJohn Baldwin if (bios_irq < NUM_ISA_INTERRUPTS) 7065e1ba6d4SJohn Baldwin pci_link_bios_isa_irqs |= (1 << bios_irq); 7075e1ba6d4SJohn Baldwin if (bios_irq != link->l_initial_irq && 7085e1ba6d4SJohn Baldwin PCI_INTERRUPT_VALID(link->l_initial_irq)) 7095e1ba6d4SJohn Baldwin device_printf(dev, 7105e1ba6d4SJohn Baldwin "BIOS IRQ %u does not match initial IRQ %u\n", 7115e1ba6d4SJohn Baldwin bios_irq, link->l_initial_irq); 7125e1ba6d4SJohn Baldwin } else if (bios_irq != link->l_bios_irq) 7135e1ba6d4SJohn Baldwin device_printf(dev, 7145e1ba6d4SJohn Baldwin "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n", 715a4104d1cSJohn Baldwin bios_irq, (int)bus, slot, pin + 'A', 7165e1ba6d4SJohn Baldwin link->l_bios_irq); 7175e1ba6d4SJohn Baldwin ACPI_SERIAL_END(pci_link); 71890638023SMitsuru IWASAKI } 71990638023SMitsuru IWASAKI 72090638023SMitsuru IWASAKI static ACPI_STATUS 72194b3af82SJohn Baldwin acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf) 72290638023SMitsuru IWASAKI { 7239fe3e6c0SJung-uk Kim ACPI_RESOURCE *end, *res; 7245e1ba6d4SJohn Baldwin ACPI_STATUS status; 7255e1ba6d4SJohn Baldwin struct link *link; 7260fd8d358SEd Maste int i __diagused, in_dpf; 72790638023SMitsuru IWASAKI 7285e1ba6d4SJohn Baldwin /* Fetch the _CRS. */ 72986b697a7SNate Lawson ACPI_SERIAL_ASSERT(pci_link); 7309fe3e6c0SJung-uk Kim srsbuf->Pointer = NULL; 7319fe3e6c0SJung-uk Kim srsbuf->Length = ACPI_ALLOCATE_BUFFER; 7329fe3e6c0SJung-uk Kim status = AcpiGetCurrentResources(acpi_get_handle(sc->pl_dev), srsbuf); 7339fe3e6c0SJung-uk Kim if (ACPI_SUCCESS(status) && srsbuf->Pointer == NULL) 7345e1ba6d4SJohn Baldwin status = AE_NO_MEMORY; 7355e1ba6d4SJohn Baldwin if (ACPI_FAILURE(status)) { 7365e1ba6d4SJohn Baldwin if (bootverbose) 73794b3af82SJohn Baldwin device_printf(sc->pl_dev, 7385e1ba6d4SJohn Baldwin "Unable to fetch current resources: %s\n", 7395e1ba6d4SJohn Baldwin AcpiFormatException(status)); 7405e1ba6d4SJohn Baldwin return (status); 7415e1ba6d4SJohn Baldwin } 74290638023SMitsuru IWASAKI 7435e1ba6d4SJohn Baldwin /* Fill in IRQ resources via link structures. */ 7445e1ba6d4SJohn Baldwin link = sc->pl_links; 7455e1ba6d4SJohn Baldwin i = 0; 7467e1f562eSJohn Baldwin in_dpf = DPF_OUTSIDE; 7479fe3e6c0SJung-uk Kim res = (ACPI_RESOURCE *)srsbuf->Pointer; 7489fe3e6c0SJung-uk Kim end = (ACPI_RESOURCE *)((char *)srsbuf->Pointer + srsbuf->Length); 7495e1ba6d4SJohn Baldwin for (;;) { 7509fe3e6c0SJung-uk Kim switch (res->Type) { 751e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_START_DEPENDENT: 7527e1f562eSJohn Baldwin switch (in_dpf) { 7537e1f562eSJohn Baldwin case DPF_OUTSIDE: 7547e1f562eSJohn Baldwin /* We've started the first DPF. */ 7557e1f562eSJohn Baldwin in_dpf = DPF_FIRST; 7567e1f562eSJohn Baldwin break; 7577e1f562eSJohn Baldwin case DPF_FIRST: 7587e1f562eSJohn Baldwin /* We've started the second DPF. */ 7597e1f562eSJohn Baldwin panic( 7607e1f562eSJohn Baldwin "%s: Multiple dependent functions within a current resource", 7617e1f562eSJohn Baldwin __func__); 7627e1f562eSJohn Baldwin break; 7637e1f562eSJohn Baldwin } 7647e1f562eSJohn Baldwin break; 765e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_END_DEPENDENT: 7667e1f562eSJohn Baldwin /* We are finished with DPF parsing. */ 7677e1f562eSJohn Baldwin KASSERT(in_dpf != DPF_OUTSIDE, 7687e1f562eSJohn Baldwin ("%s: end dpf when not parsing a dpf", __func__)); 7697e1f562eSJohn Baldwin in_dpf = DPF_OUTSIDE; 7707e1f562eSJohn Baldwin break; 771e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_IRQ: 7725e1ba6d4SJohn Baldwin MPASS(i < sc->pl_num_links); 7739fe3e6c0SJung-uk Kim res->Data.Irq.InterruptCount = 1; 7747e1f562eSJohn Baldwin if (PCI_INTERRUPT_VALID(link->l_irq)) { 7757e1f562eSJohn Baldwin KASSERT(link->l_irq < NUM_ISA_INTERRUPTS, 7767e1f562eSJohn Baldwin ("%s: can't put non-ISA IRQ %d in legacy IRQ resource type", 7777e1f562eSJohn Baldwin __func__, link->l_irq)); 7789fe3e6c0SJung-uk Kim res->Data.Irq.Interrupts[0] = link->l_irq; 7797e1f562eSJohn Baldwin } else 7809fe3e6c0SJung-uk Kim res->Data.Irq.Interrupts[0] = 0; 7817e1f562eSJohn Baldwin link++; 7827e1f562eSJohn Baldwin i++; 78390638023SMitsuru IWASAKI break; 784e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 7855e1ba6d4SJohn Baldwin MPASS(i < sc->pl_num_links); 7869fe3e6c0SJung-uk Kim res->Data.ExtendedIrq.InterruptCount = 1; 7875e1ba6d4SJohn Baldwin if (PCI_INTERRUPT_VALID(link->l_irq)) 7889fe3e6c0SJung-uk Kim res->Data.ExtendedIrq.Interrupts[0] = 7895e1ba6d4SJohn Baldwin link->l_irq; 7905e1ba6d4SJohn Baldwin else 7919fe3e6c0SJung-uk Kim res->Data.ExtendedIrq.Interrupts[0] = 0; 7927e1f562eSJohn Baldwin link++; 7937e1f562eSJohn Baldwin i++; 79490638023SMitsuru IWASAKI break; 79590638023SMitsuru IWASAKI } 7969fe3e6c0SJung-uk Kim if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) 7975e1ba6d4SJohn Baldwin break; 7989fe3e6c0SJung-uk Kim res = ACPI_NEXT_RESOURCE(res); 7999fe3e6c0SJung-uk Kim if (res >= end) 8005e1ba6d4SJohn Baldwin break; 80190638023SMitsuru IWASAKI } 80294b3af82SJohn Baldwin return (AE_OK); 80394b3af82SJohn Baldwin } 80494b3af82SJohn Baldwin 80594b3af82SJohn Baldwin static ACPI_STATUS 80694b3af82SJohn Baldwin acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc, 80794b3af82SJohn Baldwin ACPI_BUFFER *srsbuf) 80894b3af82SJohn Baldwin { 80994b3af82SJohn Baldwin ACPI_RESOURCE newres; 81094b3af82SJohn Baldwin ACPI_STATUS status; 81194b3af82SJohn Baldwin struct link *link; 81294b3af82SJohn Baldwin int i; 81394b3af82SJohn Baldwin 81494b3af82SJohn Baldwin /* Start off with an empty buffer. */ 81594b3af82SJohn Baldwin srsbuf->Pointer = NULL; 81694b3af82SJohn Baldwin link = sc->pl_links; 81794b3af82SJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) { 81894b3af82SJohn Baldwin /* Add a new IRQ resource from each link. */ 81994b3af82SJohn Baldwin link = &sc->pl_links[i]; 820e7bb9ab6SJung-uk Kim if (link->l_prs_template.Type == ACPI_RESOURCE_TYPE_IRQ) { 82194b3af82SJohn Baldwin /* Build an IRQ resource. */ 8229fe3e6c0SJung-uk Kim bcopy(&link->l_prs_template, &newres, 8239fe3e6c0SJung-uk Kim ACPI_RS_SIZE(newres.Data.Irq)); 824e8d472a7SJung-uk Kim newres.Data.Irq.InterruptCount = 1; 82594b3af82SJohn Baldwin if (PCI_INTERRUPT_VALID(link->l_irq)) { 82694b3af82SJohn Baldwin KASSERT(link->l_irq < NUM_ISA_INTERRUPTS, 82794b3af82SJohn Baldwin ("%s: can't put non-ISA IRQ %d in legacy IRQ resource type", 82894b3af82SJohn Baldwin __func__, link->l_irq)); 82994b3af82SJohn Baldwin newres.Data.Irq.Interrupts[0] = link->l_irq; 83094b3af82SJohn Baldwin } else 83194b3af82SJohn Baldwin newres.Data.Irq.Interrupts[0] = 0; 83294b3af82SJohn Baldwin } else { 83394b3af82SJohn Baldwin /* Build an ExtIRQ resuorce. */ 8349fe3e6c0SJung-uk Kim bcopy(&link->l_prs_template, &newres, 8359fe3e6c0SJung-uk Kim ACPI_RS_SIZE(newres.Data.ExtendedIrq)); 836e8d472a7SJung-uk Kim newres.Data.ExtendedIrq.InterruptCount = 1; 83794b3af82SJohn Baldwin if (PCI_INTERRUPT_VALID(link->l_irq)) 83894b3af82SJohn Baldwin newres.Data.ExtendedIrq.Interrupts[0] = 83994b3af82SJohn Baldwin link->l_irq; 84094b3af82SJohn Baldwin else 84194b3af82SJohn Baldwin newres.Data.ExtendedIrq.Interrupts[0] = 0; 84294b3af82SJohn Baldwin } 84394b3af82SJohn Baldwin 84494b3af82SJohn Baldwin /* Add the new resource to the end of the _SRS buffer. */ 84594b3af82SJohn Baldwin status = acpi_AppendBufferResource(srsbuf, &newres); 84694b3af82SJohn Baldwin if (ACPI_FAILURE(status)) { 84794b3af82SJohn Baldwin device_printf(sc->pl_dev, 84894b3af82SJohn Baldwin "Unable to build resources: %s\n", 84994b3af82SJohn Baldwin AcpiFormatException(status)); 8504cf33275SMark Johnston if (srsbuf->Pointer != NULL) { 85194b3af82SJohn Baldwin AcpiOsFree(srsbuf->Pointer); 8524cf33275SMark Johnston srsbuf->Pointer = NULL; 8534cf33275SMark Johnston } 85494b3af82SJohn Baldwin return (status); 85594b3af82SJohn Baldwin } 85694b3af82SJohn Baldwin } 85794b3af82SJohn Baldwin return (AE_OK); 85894b3af82SJohn Baldwin } 85994b3af82SJohn Baldwin 86094b3af82SJohn Baldwin static ACPI_STATUS 86194b3af82SJohn Baldwin acpi_pci_link_route_irqs(device_t dev) 86294b3af82SJohn Baldwin { 86394b3af82SJohn Baldwin struct acpi_pci_link_softc *sc; 86494b3af82SJohn Baldwin ACPI_RESOURCE *resource, *end; 86594b3af82SJohn Baldwin ACPI_BUFFER srsbuf; 86694b3af82SJohn Baldwin ACPI_STATUS status; 86794b3af82SJohn Baldwin struct link *link; 8680fd8d358SEd Maste int i __diagused; 86994b3af82SJohn Baldwin 87094b3af82SJohn Baldwin ACPI_SERIAL_ASSERT(pci_link); 87194b3af82SJohn Baldwin sc = device_get_softc(dev); 87294b3af82SJohn Baldwin if (sc->pl_crs_bad) 87394b3af82SJohn Baldwin status = acpi_pci_link_srs_from_links(sc, &srsbuf); 87494b3af82SJohn Baldwin else 87594b3af82SJohn Baldwin status = acpi_pci_link_srs_from_crs(sc, &srsbuf); 8764cf33275SMark Johnston if (ACPI_FAILURE(status)) 8774cf33275SMark Johnston return (status); 87890638023SMitsuru IWASAKI 8795e1ba6d4SJohn Baldwin /* Write out new resources via _SRS. */ 8805e1ba6d4SJohn Baldwin status = AcpiSetCurrentResources(acpi_get_handle(dev), &srsbuf); 8815e1ba6d4SJohn Baldwin if (ACPI_FAILURE(status)) { 8825e1ba6d4SJohn Baldwin device_printf(dev, "Unable to route IRQs: %s\n", 8835e1ba6d4SJohn Baldwin AcpiFormatException(status)); 8845e1ba6d4SJohn Baldwin AcpiOsFree(srsbuf.Pointer); 8855e1ba6d4SJohn Baldwin return (status); 8865e1ba6d4SJohn Baldwin } 8875e1ba6d4SJohn Baldwin 88890638023SMitsuru IWASAKI /* 8895e1ba6d4SJohn Baldwin * Perform acpi_config_intr() on each IRQ resource if it was just 8905e1ba6d4SJohn Baldwin * routed for the first time. 89190638023SMitsuru IWASAKI */ 8925e1ba6d4SJohn Baldwin link = sc->pl_links; 8935e1ba6d4SJohn Baldwin i = 0; 8945e1ba6d4SJohn Baldwin resource = (ACPI_RESOURCE *)srsbuf.Pointer; 89594b3af82SJohn Baldwin end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length); 8965e1ba6d4SJohn Baldwin for (;;) { 897e8d472a7SJung-uk Kim if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG) 8985e1ba6d4SJohn Baldwin break; 899e8d472a7SJung-uk Kim switch (resource->Type) { 900e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_IRQ: 901e8d472a7SJung-uk Kim case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 9027e1f562eSJohn Baldwin MPASS(i < sc->pl_num_links); 9037e1f562eSJohn Baldwin 9047e1f562eSJohn Baldwin /* 9057e1f562eSJohn Baldwin * Only configure the interrupt and update the 9067e1f562eSJohn Baldwin * weights if this link has a valid IRQ and was 9077e1f562eSJohn Baldwin * previously unrouted. 9087e1f562eSJohn Baldwin */ 9097e1f562eSJohn Baldwin if (!link->l_routed && 9107e1f562eSJohn Baldwin PCI_INTERRUPT_VALID(link->l_irq)) { 911bab8274cSDimitry Andric link->l_routed = true; 9125e1ba6d4SJohn Baldwin acpi_config_intr(dev, resource); 9135e1ba6d4SJohn Baldwin pci_link_interrupt_weights[link->l_irq] += 9145e1ba6d4SJohn Baldwin link->l_references; 9157e1f562eSJohn Baldwin } 9167e1f562eSJohn Baldwin link++; 9177e1f562eSJohn Baldwin i++; 9185e1ba6d4SJohn Baldwin break; 91990638023SMitsuru IWASAKI } 9205e1ba6d4SJohn Baldwin resource = ACPI_NEXT_RESOURCE(resource); 9215e1ba6d4SJohn Baldwin if (resource >= end) 9225e1ba6d4SJohn Baldwin break; 92390638023SMitsuru IWASAKI } 9245e1ba6d4SJohn Baldwin AcpiOsFree(srsbuf.Pointer); 9255e1ba6d4SJohn Baldwin return (AE_OK); 92690638023SMitsuru IWASAKI } 92790638023SMitsuru IWASAKI 92890638023SMitsuru IWASAKI static int 929e4116e93SNate Lawson acpi_pci_link_resume(device_t dev) 93090638023SMitsuru IWASAKI { 9312445af1aSJohn Baldwin struct acpi_pci_link_softc *sc; 932e4116e93SNate Lawson ACPI_STATUS status; 9332445af1aSJohn Baldwin int i, routed; 934e4116e93SNate Lawson 9352445af1aSJohn Baldwin /* 9362445af1aSJohn Baldwin * If all of our links are routed, then restore the link via _SRS, 9372445af1aSJohn Baldwin * otherwise, disable the link via _DIS. 9382445af1aSJohn Baldwin */ 93986b697a7SNate Lawson ACPI_SERIAL_BEGIN(pci_link); 9402445af1aSJohn Baldwin sc = device_get_softc(dev); 9412445af1aSJohn Baldwin routed = 0; 9422445af1aSJohn Baldwin for (i = 0; i < sc->pl_num_links; i++) 9432445af1aSJohn Baldwin if (sc->pl_links[i].l_routed) 9442445af1aSJohn Baldwin routed++; 9452445af1aSJohn Baldwin if (routed == sc->pl_num_links) 9465e1ba6d4SJohn Baldwin status = acpi_pci_link_route_irqs(dev); 947e71f249bSJohn Baldwin else { 948e71f249bSJohn Baldwin AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL, NULL); 949e71f249bSJohn Baldwin status = AE_OK; 950e71f249bSJohn Baldwin } 9515e1ba6d4SJohn Baldwin ACPI_SERIAL_END(pci_link); 9525e1ba6d4SJohn Baldwin if (ACPI_FAILURE(status)) 9535e1ba6d4SJohn Baldwin return (ENXIO); 9545e1ba6d4SJohn Baldwin else 9555e1ba6d4SJohn Baldwin return (0); 956e4116e93SNate Lawson } 957e4116e93SNate Lawson 958e4116e93SNate Lawson /* 9595e1ba6d4SJohn Baldwin * Pick an IRQ to use for this unrouted link. 960e4116e93SNate Lawson */ 9615e1ba6d4SJohn Baldwin static uint8_t 9625e1ba6d4SJohn Baldwin acpi_pci_link_choose_irq(device_t dev, struct link *link) 9635e1ba6d4SJohn Baldwin { 9645e1ba6d4SJohn Baldwin char tunable_buffer[64], link_name[5]; 9655e1ba6d4SJohn Baldwin u_int8_t best_irq, pos_irq; 9665e1ba6d4SJohn Baldwin int best_weight, pos_weight, i; 9675e1ba6d4SJohn Baldwin 9682f3f3112SNate Lawson KASSERT(!link->l_routed, ("%s: link already routed", __func__)); 9695e1ba6d4SJohn Baldwin KASSERT(!PCI_INTERRUPT_VALID(link->l_irq), 9705e1ba6d4SJohn Baldwin ("%s: link already has an IRQ", __func__)); 9715e1ba6d4SJohn Baldwin 9720cdba3b7SJohn Baldwin /* Check for a tunable override. */ 9735e1ba6d4SJohn Baldwin if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), link_name, 9745e1ba6d4SJohn Baldwin sizeof(link_name)))) { 9755e1ba6d4SJohn Baldwin snprintf(tunable_buffer, sizeof(tunable_buffer), 9765e1ba6d4SJohn Baldwin "hw.pci.link.%s.%d.irq", link_name, link->l_res_index); 9770cdba3b7SJohn Baldwin if (getenv_int(tunable_buffer, &i) && PCI_INTERRUPT_VALID(i)) { 9780cdba3b7SJohn Baldwin if (!link_valid_irq(link, i)) 9790cdba3b7SJohn Baldwin device_printf(dev, 9800cdba3b7SJohn Baldwin "Warning, IRQ %d is not listed as valid\n", 9810cdba3b7SJohn Baldwin i); 9825e1ba6d4SJohn Baldwin return (i); 9830cdba3b7SJohn Baldwin } 9845e1ba6d4SJohn Baldwin snprintf(tunable_buffer, sizeof(tunable_buffer), 9855e1ba6d4SJohn Baldwin "hw.pci.link.%s.irq", link_name); 9860cdba3b7SJohn Baldwin if (getenv_int(tunable_buffer, &i) && PCI_INTERRUPT_VALID(i)) { 9870cdba3b7SJohn Baldwin if (!link_valid_irq(link, i)) 9880cdba3b7SJohn Baldwin device_printf(dev, 9890cdba3b7SJohn Baldwin "Warning, IRQ %d is not listed as valid\n", 9900cdba3b7SJohn Baldwin i); 9915e1ba6d4SJohn Baldwin return (i); 992e4116e93SNate Lawson } 9930cdba3b7SJohn Baldwin } 994e4116e93SNate Lawson 9955e1ba6d4SJohn Baldwin /* 9965e1ba6d4SJohn Baldwin * If we have a valid BIOS IRQ, use that. We trust what the BIOS 9975e1ba6d4SJohn Baldwin * says it routed over what _CRS says the link thinks is routed. 9985e1ba6d4SJohn Baldwin */ 9995e1ba6d4SJohn Baldwin if (PCI_INTERRUPT_VALID(link->l_bios_irq)) 10005e1ba6d4SJohn Baldwin return (link->l_bios_irq); 1001e4116e93SNate Lawson 10025e1ba6d4SJohn Baldwin /* 10035e1ba6d4SJohn Baldwin * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS, 10045e1ba6d4SJohn Baldwin * then use that. 10055e1ba6d4SJohn Baldwin */ 10065e1ba6d4SJohn Baldwin if (PCI_INTERRUPT_VALID(link->l_initial_irq)) 10075e1ba6d4SJohn Baldwin return (link->l_initial_irq); 10085e1ba6d4SJohn Baldwin 10095e1ba6d4SJohn Baldwin /* 10105e1ba6d4SJohn Baldwin * Ok, we have no useful hints, so we have to pick from the 10115e1ba6d4SJohn Baldwin * possible IRQs. For ISA IRQs we only use interrupts that 10125e1ba6d4SJohn Baldwin * have already been used by the BIOS. 10135e1ba6d4SJohn Baldwin */ 10145e1ba6d4SJohn Baldwin best_irq = PCI_INVALID_IRQ; 10155e1ba6d4SJohn Baldwin best_weight = INT_MAX; 10165e1ba6d4SJohn Baldwin for (i = 0; i < link->l_num_irqs; i++) { 10175e1ba6d4SJohn Baldwin pos_irq = link->l_irqs[i]; 10185e1ba6d4SJohn Baldwin if (pos_irq < NUM_ISA_INTERRUPTS && 10195e1ba6d4SJohn Baldwin (pci_link_bios_isa_irqs & 1 << pos_irq) == 0) 10205e1ba6d4SJohn Baldwin continue; 10215e1ba6d4SJohn Baldwin pos_weight = pci_link_interrupt_weights[pos_irq]; 10225e1ba6d4SJohn Baldwin if (pos_weight < best_weight) { 10235e1ba6d4SJohn Baldwin best_weight = pos_weight; 10245e1ba6d4SJohn Baldwin best_irq = pos_irq; 1025e4116e93SNate Lawson } 10265e1ba6d4SJohn Baldwin } 1027e4116e93SNate Lawson 10285e1ba6d4SJohn Baldwin /* 10295e1ba6d4SJohn Baldwin * If this is an ISA IRQ, try using the SCI if it is also an ISA 10305e1ba6d4SJohn Baldwin * interrupt as a fallback. 10315e1ba6d4SJohn Baldwin */ 10325e1ba6d4SJohn Baldwin if (link->l_isa_irq) { 10332be4e471SJung-uk Kim pos_irq = AcpiGbl_FADT.SciInterrupt; 10345e1ba6d4SJohn Baldwin pos_weight = pci_link_interrupt_weights[pos_irq]; 10355e1ba6d4SJohn Baldwin if (pos_weight < best_weight) { 10365e1ba6d4SJohn Baldwin best_weight = pos_weight; 10375e1ba6d4SJohn Baldwin best_irq = pos_irq; 10385e1ba6d4SJohn Baldwin } 10395e1ba6d4SJohn Baldwin } 10405e1ba6d4SJohn Baldwin 1041b88076feSJohn Baldwin if (PCI_INTERRUPT_VALID(best_irq)) { 1042b88076feSJohn Baldwin if (bootverbose) 10435e1ba6d4SJohn Baldwin device_printf(dev, "Picked IRQ %u with weight %d\n", 10445e1ba6d4SJohn Baldwin best_irq, best_weight); 10455e1ba6d4SJohn Baldwin } else 10465e1ba6d4SJohn Baldwin device_printf(dev, "Unable to choose an IRQ\n"); 10475e1ba6d4SJohn Baldwin return (best_irq); 10485e1ba6d4SJohn Baldwin } 10495e1ba6d4SJohn Baldwin 10505e1ba6d4SJohn Baldwin int 10515e1ba6d4SJohn Baldwin acpi_pci_link_route_interrupt(device_t dev, int index) 10525e1ba6d4SJohn Baldwin { 10535e1ba6d4SJohn Baldwin struct link *link; 10545e1ba6d4SJohn Baldwin 1055f9959468SJohn Baldwin if (acpi_disabled("pci_link")) 1056f9959468SJohn Baldwin return (PCI_INVALID_IRQ); 1057f9959468SJohn Baldwin 10585e1ba6d4SJohn Baldwin ACPI_SERIAL_BEGIN(pci_link); 10597e1f562eSJohn Baldwin link = acpi_pci_link_lookup(dev, index); 10607e1f562eSJohn Baldwin if (link == NULL) 10617e1f562eSJohn Baldwin panic("%s: apparently invalid index %d", __func__, index); 10625e1ba6d4SJohn Baldwin 10635e1ba6d4SJohn Baldwin /* 10645e1ba6d4SJohn Baldwin * If this link device is already routed to an interrupt, just return 10655e1ba6d4SJohn Baldwin * the interrupt it is routed to. 10665e1ba6d4SJohn Baldwin */ 10675e1ba6d4SJohn Baldwin if (link->l_routed) { 10685e1ba6d4SJohn Baldwin KASSERT(PCI_INTERRUPT_VALID(link->l_irq), 10695e1ba6d4SJohn Baldwin ("%s: link is routed but has an invalid IRQ", __func__)); 107086b697a7SNate Lawson ACPI_SERIAL_END(pci_link); 10715e1ba6d4SJohn Baldwin return (link->l_irq); 1072e4116e93SNate Lawson } 10735e1ba6d4SJohn Baldwin 10745e1ba6d4SJohn Baldwin /* Choose an IRQ if we need one. */ 10755e1ba6d4SJohn Baldwin if (!PCI_INTERRUPT_VALID(link->l_irq)) { 10765e1ba6d4SJohn Baldwin link->l_irq = acpi_pci_link_choose_irq(dev, link); 10775e1ba6d4SJohn Baldwin 10785e1ba6d4SJohn Baldwin /* 10795e1ba6d4SJohn Baldwin * Try to route the interrupt we picked. If it fails, then 10805e1ba6d4SJohn Baldwin * assume the interrupt is not routed. 10815e1ba6d4SJohn Baldwin */ 10825e1ba6d4SJohn Baldwin if (PCI_INTERRUPT_VALID(link->l_irq)) { 10835e1ba6d4SJohn Baldwin acpi_pci_link_route_irqs(dev); 10845e1ba6d4SJohn Baldwin if (!link->l_routed) 10855e1ba6d4SJohn Baldwin link->l_irq = PCI_INVALID_IRQ; 10865e1ba6d4SJohn Baldwin } 10875e1ba6d4SJohn Baldwin } 10885e1ba6d4SJohn Baldwin ACPI_SERIAL_END(pci_link); 10895e1ba6d4SJohn Baldwin 10905e1ba6d4SJohn Baldwin return (link->l_irq); 10915e1ba6d4SJohn Baldwin } 10925e1ba6d4SJohn Baldwin 10935e1ba6d4SJohn Baldwin /* 10945e1ba6d4SJohn Baldwin * This is gross, but we abuse the identify routine to perform one-time 10955e1ba6d4SJohn Baldwin * SYSINIT() style initialization for the driver. 10965e1ba6d4SJohn Baldwin */ 10975e1ba6d4SJohn Baldwin static void 10985e1ba6d4SJohn Baldwin acpi_pci_link_identify(driver_t *driver, device_t parent) 10995e1ba6d4SJohn Baldwin { 11005e1ba6d4SJohn Baldwin 11015e1ba6d4SJohn Baldwin /* 11025e1ba6d4SJohn Baldwin * If the SCI is an ISA IRQ, add it to the bitmask of known good 11035e1ba6d4SJohn Baldwin * ISA IRQs. 11045e1ba6d4SJohn Baldwin * 11055e1ba6d4SJohn Baldwin * XXX: If we are using the APIC, the SCI might have been 11065e1ba6d4SJohn Baldwin * rerouted to an APIC pin in which case this is invalid. However, 11075e1ba6d4SJohn Baldwin * if we are using the APIC, we also shouldn't be having any PCI 11085e1ba6d4SJohn Baldwin * interrupts routed via ISA IRQs, so this is probably ok. 11095e1ba6d4SJohn Baldwin */ 11102be4e471SJung-uk Kim if (AcpiGbl_FADT.SciInterrupt < NUM_ISA_INTERRUPTS) 11112be4e471SJung-uk Kim pci_link_bios_isa_irqs |= (1 << AcpiGbl_FADT.SciInterrupt); 11125e1ba6d4SJohn Baldwin } 11135e1ba6d4SJohn Baldwin 11145e1ba6d4SJohn Baldwin static device_method_t acpi_pci_link_methods[] = { 11155e1ba6d4SJohn Baldwin /* Device interface */ 11165e1ba6d4SJohn Baldwin DEVMETHOD(device_identify, acpi_pci_link_identify), 11175e1ba6d4SJohn Baldwin DEVMETHOD(device_probe, acpi_pci_link_probe), 11185e1ba6d4SJohn Baldwin DEVMETHOD(device_attach, acpi_pci_link_attach), 11195e1ba6d4SJohn Baldwin DEVMETHOD(device_resume, acpi_pci_link_resume), 11205e1ba6d4SJohn Baldwin 112161bfd867SSofian Brabez DEVMETHOD_END 11225e1ba6d4SJohn Baldwin }; 11235e1ba6d4SJohn Baldwin 11245e1ba6d4SJohn Baldwin static driver_t acpi_pci_link_driver = { 11255e1ba6d4SJohn Baldwin "pci_link", 11265e1ba6d4SJohn Baldwin acpi_pci_link_methods, 11275e1ba6d4SJohn Baldwin sizeof(struct acpi_pci_link_softc), 11285e1ba6d4SJohn Baldwin }; 11295e1ba6d4SJohn Baldwin 1130916a5d8aSJohn Baldwin DRIVER_MODULE(acpi_pci_link, acpi, acpi_pci_link_driver, 0, 0); 11315e1ba6d4SJohn Baldwin MODULE_DEPEND(acpi_pci_link, acpi, 1, 1, 1); 1132