115e32d5dSMike Smith /*- 215e32d5dSMike Smith * Copyright (c) 2000 Michael Smith 315e32d5dSMike Smith * Copyright (c) 2000 BSDi 415e32d5dSMike Smith * All rights reserved. 515e32d5dSMike Smith * 615e32d5dSMike Smith * Redistribution and use in source and binary forms, with or without 715e32d5dSMike Smith * modification, are permitted provided that the following conditions 815e32d5dSMike Smith * are met: 915e32d5dSMike Smith * 1. Redistributions of source code must retain the above copyright 1015e32d5dSMike Smith * notice, this list of conditions and the following disclaimer. 1115e32d5dSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1215e32d5dSMike Smith * notice, this list of conditions and the following disclaimer in the 1315e32d5dSMike Smith * documentation and/or other materials provided with the distribution. 1415e32d5dSMike Smith * 1515e32d5dSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1615e32d5dSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1715e32d5dSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1815e32d5dSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1915e32d5dSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2015e32d5dSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2115e32d5dSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2215e32d5dSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2315e32d5dSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2415e32d5dSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2515e32d5dSMike Smith * SUCH DAMAGE. 2615e32d5dSMike Smith */ 27dad97feeSDavid E. O'Brien 28dad97feeSDavid E. O'Brien #include <sys/cdefs.h> 29dad97feeSDavid E. O'Brien __FBSDID("$FreeBSD$"); 30dad97feeSDavid E. O'Brien 3115e32d5dSMike Smith #include "opt_acpi.h" 3215e32d5dSMike Smith #include <sys/param.h> 3315e32d5dSMike Smith #include <sys/bus.h> 344fa387b6SMike Smith #include <sys/kernel.h> 3534ff71eeSJohn Baldwin #include <sys/limits.h> 36e3aa81b8SNate Lawson #include <sys/malloc.h> 37fe12f24bSPoul-Henning Kamp #include <sys/module.h> 3883c41143SJohn Baldwin #include <sys/rman.h> 39fd492ee0SWarner Losh #include <sys/sysctl.h> 4015e32d5dSMike Smith 41129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h> 42129d3046SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h> 43129d3046SJung-uk Kim 4415e32d5dSMike Smith #include <dev/acpica/acpivar.h> 4515e32d5dSMike Smith 4615e32d5dSMike Smith #include <machine/pci_cfgreg.h> 47cace7a2aSWarner Losh #include <dev/pci/pcivar.h> 48cace7a2aSWarner Losh #include <dev/pci/pcib_private.h> 4915e32d5dSMike Smith #include "pcib_if.h" 5015e32d5dSMike Smith 512ccfc932SJohn Baldwin #include <dev/acpica/acpi_pcibvar.h> 522ccfc932SJohn Baldwin 53e3aa81b8SNate Lawson /* Hooks for the ACPI CA debugging infrastructure. */ 54e71b6381SMike Smith #define _COMPONENT ACPI_BUS 552ccfc932SJohn Baldwin ACPI_MODULE_NAME("PCI_ACPI") 560ae55423SMike Smith 572ccfc932SJohn Baldwin struct acpi_hpcib_softc { 5815e32d5dSMike Smith device_t ap_dev; 5915e32d5dSMike Smith ACPI_HANDLE ap_handle; 60d4b9ff91SNate Lawson int ap_flags; 6115e32d5dSMike Smith 6215e32d5dSMike Smith int ap_segment; /* analagous to Alpha 'hose' */ 6315e32d5dSMike Smith int ap_bus; /* bios-assigned bus number */ 644fa387b6SMike Smith 654fa387b6SMike Smith ACPI_BUFFER ap_prt; /* interrupt routing table */ 6634ff71eeSJohn Baldwin #ifdef NEW_PCIB 6734ff71eeSJohn Baldwin struct pcib_host_resources ap_host_res; 6834ff71eeSJohn Baldwin #endif 6915e32d5dSMike Smith }; 7015e32d5dSMike Smith 712ccfc932SJohn Baldwin static int acpi_pcib_acpi_probe(device_t bus); 722ccfc932SJohn Baldwin static int acpi_pcib_acpi_attach(device_t bus); 73e3aa81b8SNate Lawson static int acpi_pcib_read_ivar(device_t dev, device_t child, 74e3aa81b8SNate Lawson int which, uintptr_t *result); 75e3aa81b8SNate Lawson static int acpi_pcib_write_ivar(device_t dev, device_t child, 76e3aa81b8SNate Lawson int which, uintptr_t value); 771496d4a9SWarner Losh static uint32_t acpi_pcib_read_config(device_t dev, u_int bus, 781496d4a9SWarner Losh u_int slot, u_int func, u_int reg, int bytes); 791496d4a9SWarner Losh static void acpi_pcib_write_config(device_t dev, u_int bus, 801496d4a9SWarner Losh u_int slot, u_int func, u_int reg, uint32_t data, 811496d4a9SWarner Losh int bytes); 822ccfc932SJohn Baldwin static int acpi_pcib_acpi_route_interrupt(device_t pcib, 832ccfc932SJohn Baldwin device_t dev, int pin); 848964299aSJohn Baldwin static int acpi_pcib_alloc_msi(device_t pcib, device_t dev, 858964299aSJohn Baldwin int count, int maxcount, int *irqs); 86e706f7f0SJohn Baldwin static int acpi_pcib_map_msi(device_t pcib, device_t dev, 87e706f7f0SJohn Baldwin int irq, uint64_t *addr, uint32_t *data); 888964299aSJohn Baldwin static int acpi_pcib_alloc_msix(device_t pcib, device_t dev, 89e706f7f0SJohn Baldwin int *irq); 90cd8b53edSWarner Losh static struct resource *acpi_pcib_acpi_alloc_resource(device_t dev, 91cd8b53edSWarner Losh device_t child, int type, int *rid, 92cd8b53edSWarner Losh u_long start, u_long end, u_long count, 93cd8b53edSWarner Losh u_int flags); 9434ff71eeSJohn Baldwin #ifdef NEW_PCIB 9534ff71eeSJohn Baldwin static int acpi_pcib_acpi_adjust_resource(device_t dev, 9634ff71eeSJohn Baldwin device_t child, int type, struct resource *r, 9734ff71eeSJohn Baldwin u_long start, u_long end); 9834ff71eeSJohn Baldwin #endif 9915e32d5dSMike Smith 1002ccfc932SJohn Baldwin static device_method_t acpi_pcib_acpi_methods[] = { 10115e32d5dSMike Smith /* Device interface */ 1022ccfc932SJohn Baldwin DEVMETHOD(device_probe, acpi_pcib_acpi_probe), 1032ccfc932SJohn Baldwin DEVMETHOD(device_attach, acpi_pcib_acpi_attach), 10415e32d5dSMike Smith DEVMETHOD(device_shutdown, bus_generic_shutdown), 10515e32d5dSMike Smith DEVMETHOD(device_suspend, bus_generic_suspend), 1067d23a9b3SJohn Baldwin DEVMETHOD(device_resume, bus_generic_resume), 10715e32d5dSMike Smith 10815e32d5dSMike Smith /* Bus interface */ 10915e32d5dSMike Smith DEVMETHOD(bus_print_child, bus_generic_print_child), 11015e32d5dSMike Smith DEVMETHOD(bus_read_ivar, acpi_pcib_read_ivar), 11115e32d5dSMike Smith DEVMETHOD(bus_write_ivar, acpi_pcib_write_ivar), 112cd8b53edSWarner Losh DEVMETHOD(bus_alloc_resource, acpi_pcib_acpi_alloc_resource), 11334ff71eeSJohn Baldwin #ifdef NEW_PCIB 11434ff71eeSJohn Baldwin DEVMETHOD(bus_adjust_resource, acpi_pcib_acpi_adjust_resource), 11534ff71eeSJohn Baldwin #else 116d2c9344fSJohn Baldwin DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 11734ff71eeSJohn Baldwin #endif 11815e32d5dSMike Smith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 11915e32d5dSMike Smith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 12015e32d5dSMike Smith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 12115e32d5dSMike Smith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 12215e32d5dSMike Smith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 12315e32d5dSMike Smith 12415e32d5dSMike Smith /* pcib interface */ 1252ccfc932SJohn Baldwin DEVMETHOD(pcib_maxslots, pcib_maxslots), 12615e32d5dSMike Smith DEVMETHOD(pcib_read_config, acpi_pcib_read_config), 12715e32d5dSMike Smith DEVMETHOD(pcib_write_config, acpi_pcib_write_config), 1282ccfc932SJohn Baldwin DEVMETHOD(pcib_route_interrupt, acpi_pcib_acpi_route_interrupt), 1298964299aSJohn Baldwin DEVMETHOD(pcib_alloc_msi, acpi_pcib_alloc_msi), 1309bf4c9c1SJohn Baldwin DEVMETHOD(pcib_release_msi, pcib_release_msi), 1318964299aSJohn Baldwin DEVMETHOD(pcib_alloc_msix, acpi_pcib_alloc_msix), 1329bf4c9c1SJohn Baldwin DEVMETHOD(pcib_release_msix, pcib_release_msix), 133e706f7f0SJohn Baldwin DEVMETHOD(pcib_map_msi, acpi_pcib_map_msi), 13462508c53SJohn Baldwin DEVMETHOD(pcib_power_for_sleep, acpi_pcib_power_for_sleep), 13515e32d5dSMike Smith 13615e32d5dSMike Smith {0, 0} 13715e32d5dSMike Smith }; 13815e32d5dSMike Smith 13904dda605SJohn Baldwin static devclass_t pcib_devclass; 14015e32d5dSMike Smith 14104dda605SJohn Baldwin DEFINE_CLASS_0(pcib, acpi_pcib_acpi_driver, acpi_pcib_acpi_methods, 14204dda605SJohn Baldwin sizeof(struct acpi_hpcib_softc)); 1432ccfc932SJohn Baldwin DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_acpi_driver, pcib_devclass, 0, 0); 14464278df5SNate Lawson MODULE_DEPEND(acpi_pcib, acpi, 1, 1, 1); 14515e32d5dSMike Smith 14615e32d5dSMike Smith static int 1472ccfc932SJohn Baldwin acpi_pcib_acpi_probe(device_t dev) 14815e32d5dSMike Smith { 14992488a57SJung-uk Kim ACPI_DEVICE_INFO *devinfo; 15092488a57SJung-uk Kim ACPI_HANDLE h; 15192488a57SJung-uk Kim int root; 15215e32d5dSMike Smith 15392488a57SJung-uk Kim if (acpi_disabled("pcib") || (h = acpi_get_handle(dev)) == NULL || 15492488a57SJung-uk Kim ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) 15592488a57SJung-uk Kim return (ENXIO); 15692488a57SJung-uk Kim root = (devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0; 15792488a57SJung-uk Kim AcpiOsFree(devinfo); 15892488a57SJung-uk Kim if (!root || pci_cfgregopen() == 0) 1595fcc8a58SNate Lawson return (ENXIO); 16015e32d5dSMike Smith 1612ccfc932SJohn Baldwin device_set_desc(dev, "ACPI Host-PCI bridge"); 16215e32d5dSMike Smith return (0); 16315e32d5dSMike Smith } 16415e32d5dSMike Smith 16534ff71eeSJohn Baldwin #ifdef NEW_PCIB 16634ff71eeSJohn Baldwin static ACPI_STATUS 16734ff71eeSJohn Baldwin acpi_pcib_producer_handler(ACPI_RESOURCE *res, void *context) 16834ff71eeSJohn Baldwin { 16934ff71eeSJohn Baldwin struct acpi_hpcib_softc *sc; 17034ff71eeSJohn Baldwin UINT64 length, min, max; 17134ff71eeSJohn Baldwin u_int flags; 17234ff71eeSJohn Baldwin int error, type; 17334ff71eeSJohn Baldwin 17434ff71eeSJohn Baldwin sc = context; 17534ff71eeSJohn Baldwin switch (res->Type) { 17634ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_START_DEPENDENT: 17734ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_END_DEPENDENT: 17834ff71eeSJohn Baldwin panic("host bridge has depenedent resources"); 17934ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_ADDRESS16: 18034ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_ADDRESS32: 18134ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_ADDRESS64: 18234ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 18334ff71eeSJohn Baldwin if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER) 18434ff71eeSJohn Baldwin break; 18534ff71eeSJohn Baldwin switch (res->Type) { 18634ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_ADDRESS16: 18734ff71eeSJohn Baldwin min = res->Data.Address16.Minimum; 18834ff71eeSJohn Baldwin max = res->Data.Address16.Maximum; 18934ff71eeSJohn Baldwin length = res->Data.Address16.AddressLength; 19034ff71eeSJohn Baldwin break; 19134ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_ADDRESS32: 19234ff71eeSJohn Baldwin min = res->Data.Address32.Minimum; 19334ff71eeSJohn Baldwin max = res->Data.Address32.Maximum; 19434ff71eeSJohn Baldwin length = res->Data.Address32.AddressLength; 19534ff71eeSJohn Baldwin break; 19634ff71eeSJohn Baldwin case ACPI_RESOURCE_TYPE_ADDRESS64: 19734ff71eeSJohn Baldwin min = res->Data.Address64.Minimum; 19834ff71eeSJohn Baldwin max = res->Data.Address64.Maximum; 19934ff71eeSJohn Baldwin length = res->Data.Address64.AddressLength; 20034ff71eeSJohn Baldwin break; 20134ff71eeSJohn Baldwin default: 20234ff71eeSJohn Baldwin KASSERT(res->Type == 20334ff71eeSJohn Baldwin ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64, 20434ff71eeSJohn Baldwin ("should never happen")); 20534ff71eeSJohn Baldwin min = res->Data.ExtAddress64.Minimum; 20634ff71eeSJohn Baldwin max = res->Data.ExtAddress64.Maximum; 20734ff71eeSJohn Baldwin length = res->Data.ExtAddress64.AddressLength; 20834ff71eeSJohn Baldwin break; 20934ff71eeSJohn Baldwin } 210e9f91b2bSJohn Baldwin if (length == 0) 211e9f91b2bSJohn Baldwin break; 212e9f91b2bSJohn Baldwin if (min + length - 1 != max && 213e9f91b2bSJohn Baldwin (res->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED || 214e9f91b2bSJohn Baldwin res->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED)) 21534ff71eeSJohn Baldwin break; 21634ff71eeSJohn Baldwin flags = 0; 21734ff71eeSJohn Baldwin switch (res->Data.Address.ResourceType) { 21834ff71eeSJohn Baldwin case ACPI_MEMORY_RANGE: 21934ff71eeSJohn Baldwin type = SYS_RES_MEMORY; 22034ff71eeSJohn Baldwin if (res->Type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) { 22134ff71eeSJohn Baldwin if (res->Data.Address.Info.Mem.Caching == 22234ff71eeSJohn Baldwin ACPI_PREFETCHABLE_MEMORY) 22334ff71eeSJohn Baldwin flags |= RF_PREFETCHABLE; 22434ff71eeSJohn Baldwin } else { 22534ff71eeSJohn Baldwin /* 22634ff71eeSJohn Baldwin * XXX: Parse prefetch flag out of 22734ff71eeSJohn Baldwin * TypeSpecific. 22834ff71eeSJohn Baldwin */ 22934ff71eeSJohn Baldwin } 23034ff71eeSJohn Baldwin break; 23134ff71eeSJohn Baldwin case ACPI_IO_RANGE: 23234ff71eeSJohn Baldwin type = SYS_RES_IOPORT; 23334ff71eeSJohn Baldwin break; 23434ff71eeSJohn Baldwin #ifdef PCI_RES_BUS 23534ff71eeSJohn Baldwin case ACPI_BUS_NUMBER_RANGE: 23634ff71eeSJohn Baldwin type = PCI_RES_BUS; 23734ff71eeSJohn Baldwin break; 23834ff71eeSJohn Baldwin #endif 23934ff71eeSJohn Baldwin default: 24034ff71eeSJohn Baldwin return (AE_OK); 24134ff71eeSJohn Baldwin } 24234ff71eeSJohn Baldwin 24334ff71eeSJohn Baldwin if (min + length - 1 != max) 24434ff71eeSJohn Baldwin device_printf(sc->ap_dev, 24534ff71eeSJohn Baldwin "Length mismatch for %d range: %jx vs %jx\n", type, 24634ff71eeSJohn Baldwin (uintmax_t)max - min + 1, (uintmax_t)length); 24734ff71eeSJohn Baldwin #ifdef __i386__ 24834ff71eeSJohn Baldwin if (min > ULONG_MAX) { 24934ff71eeSJohn Baldwin device_printf(sc->ap_dev, 25034ff71eeSJohn Baldwin "Ignoring %d range above 4GB (%#jx-%#jx)\n", 25134ff71eeSJohn Baldwin type, (uintmax_t)min, (uintmax_t)max); 25234ff71eeSJohn Baldwin break; 25334ff71eeSJohn Baldwin } 25434ff71eeSJohn Baldwin if (max > ULONG_MAX) { 25534ff71eeSJohn Baldwin device_printf(sc->ap_dev, 25634ff71eeSJohn Baldwin "Truncating end of %d range above 4GB (%#jx-%#jx)\n", 25734ff71eeSJohn Baldwin type, (uintmax_t)min, (uintmax_t)max); 25834ff71eeSJohn Baldwin max = ULONG_MAX; 25934ff71eeSJohn Baldwin } 26034ff71eeSJohn Baldwin #endif 26134ff71eeSJohn Baldwin error = pcib_host_res_decodes(&sc->ap_host_res, type, min, max, 26234ff71eeSJohn Baldwin flags); 26334ff71eeSJohn Baldwin if (error) 26434ff71eeSJohn Baldwin panic("Failed to manage %d range (%#jx-%#jx): %d", 26534ff71eeSJohn Baldwin type, (uintmax_t)min, (uintmax_t)max, error); 26634ff71eeSJohn Baldwin break; 26734ff71eeSJohn Baldwin default: 26834ff71eeSJohn Baldwin break; 26934ff71eeSJohn Baldwin } 27034ff71eeSJohn Baldwin return (AE_OK); 27134ff71eeSJohn Baldwin } 27234ff71eeSJohn Baldwin #endif 27334ff71eeSJohn Baldwin 27415e32d5dSMike Smith static int 2752ccfc932SJohn Baldwin acpi_pcib_acpi_attach(device_t dev) 27615e32d5dSMike Smith { 2772ccfc932SJohn Baldwin struct acpi_hpcib_softc *sc; 27815e32d5dSMike Smith ACPI_STATUS status; 2790668724bSJohn Baldwin static int bus0_seen = 0; 2808b149b51SJohn Baldwin u_int addr, slot, func, busok; 2819debb532SJohn Baldwin uint8_t busno; 2820ae55423SMike Smith 283b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 28415e32d5dSMike Smith 28515e32d5dSMike Smith sc = device_get_softc(dev); 28615e32d5dSMike Smith sc->ap_dev = dev; 28715e32d5dSMike Smith sc->ap_handle = acpi_get_handle(dev); 28815e32d5dSMike Smith 28915e32d5dSMike Smith /* 2900668724bSJohn Baldwin * Get our segment number by evaluating _SEG 2910668724bSJohn Baldwin * It's OK for this to not exist. 2920668724bSJohn Baldwin */ 2930668724bSJohn Baldwin status = acpi_GetInteger(sc->ap_handle, "_SEG", &sc->ap_segment); 2940668724bSJohn Baldwin if (ACPI_FAILURE(status)) { 2950668724bSJohn Baldwin if (status != AE_NOT_FOUND) { 2960668724bSJohn Baldwin device_printf(dev, "could not evaluate _SEG - %s\n", 2970668724bSJohn Baldwin AcpiFormatException(status)); 2980668724bSJohn Baldwin return_VALUE (ENXIO); 2990668724bSJohn Baldwin } 3000668724bSJohn Baldwin /* If it's not found, assume 0. */ 3010668724bSJohn Baldwin sc->ap_segment = 0; 3020668724bSJohn Baldwin } 3030668724bSJohn Baldwin 30434ff71eeSJohn Baldwin #ifdef NEW_PCIB 30534ff71eeSJohn Baldwin /* 30634ff71eeSJohn Baldwin * Determine which address ranges this bridge decodes and setup 30734ff71eeSJohn Baldwin * resource managers for those ranges. 30834ff71eeSJohn Baldwin */ 30934ff71eeSJohn Baldwin if (pcib_host_res_init(sc->ap_dev, &sc->ap_host_res) != 0) 31034ff71eeSJohn Baldwin panic("failed to init hostb resources"); 31134ff71eeSJohn Baldwin if (!acpi_disabled("hostres")) { 31234ff71eeSJohn Baldwin status = AcpiWalkResources(sc->ap_handle, "_CRS", 31334ff71eeSJohn Baldwin acpi_pcib_producer_handler, sc); 31434ff71eeSJohn Baldwin if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) 31534ff71eeSJohn Baldwin device_printf(sc->ap_dev, "failed to parse resources: %s\n", 31634ff71eeSJohn Baldwin AcpiFormatException(status)); 31734ff71eeSJohn Baldwin } 31834ff71eeSJohn Baldwin #endif 31934ff71eeSJohn Baldwin 3200668724bSJohn Baldwin /* 3219debb532SJohn Baldwin * Get our base bus number by evaluating _BBN. 322c1b1f787SMike Smith * If this doesn't work, we assume we're bus number 0. 32315e32d5dSMike Smith * 32415e32d5dSMike Smith * XXX note that it may also not exist in the case where we are 32515e32d5dSMike Smith * meant to use a private configuration space mechanism for this bus, 32615e32d5dSMike Smith * so we should dig out our resources and check to see if we have 32715e32d5dSMike Smith * anything like that. How do we do this? 328042283a6SMike Smith * XXX If we have the requisite information, and if we don't think the 329042283a6SMike Smith * default PCI configuration space handlers can deal with this bus, 330042283a6SMike Smith * we should attach our own handler. 331042283a6SMike Smith * XXX invoke _REG on this for the PCI config space address space? 3329debb532SJohn Baldwin * XXX It seems many BIOS's with multiple Host-PCI bridges do not set 3339debb532SJohn Baldwin * _BBN correctly. They set _BBN to zero for all bridges. Thus, 3340668724bSJohn Baldwin * if _BBN is zero and PCI bus 0 already exists, we try to read our 3359debb532SJohn Baldwin * bus number from the configuration registers at address _ADR. 3360668724bSJohn Baldwin * We only do this for domain/segment 0 in the hopes that this is 3370668724bSJohn Baldwin * only needed for old single-domain machines. 33815e32d5dSMike Smith */ 339c310653eSNate Lawson status = acpi_GetInteger(sc->ap_handle, "_BBN", &sc->ap_bus); 3409debb532SJohn Baldwin if (ACPI_FAILURE(status)) { 34115e32d5dSMike Smith if (status != AE_NOT_FOUND) { 3429debb532SJohn Baldwin device_printf(dev, "could not evaluate _BBN - %s\n", 3439debb532SJohn Baldwin AcpiFormatException(status)); 344c1b1f787SMike Smith return_VALUE (ENXIO); 345c1b1f787SMike Smith } else { 346e3aa81b8SNate Lawson /* If it's not found, assume 0. */ 34715e32d5dSMike Smith sc->ap_bus = 0; 34815e32d5dSMike Smith } 3498745ec57SJohn Baldwin } 3509debb532SJohn Baldwin 3519debb532SJohn Baldwin /* 3520668724bSJohn Baldwin * If this is segment 0, the bus is zero, and PCI bus 0 already 3530668724bSJohn Baldwin * exists, read the bus number via PCI config space. 3549debb532SJohn Baldwin */ 3559debb532SJohn Baldwin busok = 1; 3560668724bSJohn Baldwin if (sc->ap_segment == 0 && sc->ap_bus == 0 && bus0_seen) { 3578745ec57SJohn Baldwin busok = 0; 358c310653eSNate Lawson status = acpi_GetInteger(sc->ap_handle, "_ADR", &addr); 3599debb532SJohn Baldwin if (ACPI_FAILURE(status)) { 3609debb532SJohn Baldwin if (status != AE_NOT_FOUND) { 3619debb532SJohn Baldwin device_printf(dev, "could not evaluate _ADR - %s\n", 3629debb532SJohn Baldwin AcpiFormatException(status)); 3639debb532SJohn Baldwin return_VALUE (ENXIO); 3648745ec57SJohn Baldwin } else 365e3aa81b8SNate Lawson device_printf(dev, "couldn't find _ADR\n"); 3669debb532SJohn Baldwin } else { 3679debb532SJohn Baldwin /* XXX: We assume bus 0. */ 368e0a93586SJohn Baldwin slot = ACPI_ADR_PCI_SLOT(addr); 369e0a93586SJohn Baldwin func = ACPI_ADR_PCI_FUNC(addr); 3709debb532SJohn Baldwin if (bootverbose) 3719debb532SJohn Baldwin device_printf(dev, "reading config registers from 0:%d:%d\n", 3729debb532SJohn Baldwin slot, func); 3738745ec57SJohn Baldwin if (host_pcib_get_busno(pci_cfgregread, 0, slot, func, &busno) == 0) 374e3aa81b8SNate Lawson device_printf(dev, "couldn't read bus number from cfg space\n"); 3758745ec57SJohn Baldwin else { 3769debb532SJohn Baldwin sc->ap_bus = busno; 3778745ec57SJohn Baldwin busok = 1; 3789debb532SJohn Baldwin } 3799debb532SJohn Baldwin } 3809debb532SJohn Baldwin } 3819debb532SJohn Baldwin 3829debb532SJohn Baldwin /* 3839debb532SJohn Baldwin * If nothing else worked, hope that ACPI at least lays out the 3849debb532SJohn Baldwin * host-PCI bridges in order and that as a result our unit number 3859debb532SJohn Baldwin * is actually our bus number. There are several reasons this 3869debb532SJohn Baldwin * might not be true. 3879debb532SJohn Baldwin */ 3889debb532SJohn Baldwin if (busok == 0) { 3899debb532SJohn Baldwin sc->ap_bus = device_get_unit(dev); 3909debb532SJohn Baldwin device_printf(dev, "trying bus number %d\n", sc->ap_bus); 391c1b1f787SMike Smith } 39215e32d5dSMike Smith 3930668724bSJohn Baldwin /* If this is bus 0 on segment 0, note that it has been seen already. */ 3940668724bSJohn Baldwin if (sc->ap_segment == 0 && sc->ap_bus == 0) 3950668724bSJohn Baldwin bus0_seen = 1; 39615e32d5dSMike Smith 3972ccfc932SJohn Baldwin return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_bus)); 39815e32d5dSMike Smith } 39915e32d5dSMike Smith 4004fa387b6SMike Smith /* 4014fa387b6SMike Smith * Support for standard PCI bridge ivars. 4024fa387b6SMike Smith */ 40315e32d5dSMike Smith static int 40415e32d5dSMike Smith acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 40515e32d5dSMike Smith { 4062ccfc932SJohn Baldwin struct acpi_hpcib_softc *sc = device_get_softc(dev); 40715e32d5dSMike Smith 40815e32d5dSMike Smith switch (which) { 40955aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 41024c93a6fSJohn Baldwin *result = sc->ap_segment; 41155aaf894SMarius Strobl return (0); 41215e32d5dSMike Smith case PCIB_IVAR_BUS: 41315e32d5dSMike Smith *result = sc->ap_bus; 41415e32d5dSMike Smith return (0); 4152ccfc932SJohn Baldwin case ACPI_IVAR_HANDLE: 4162ccfc932SJohn Baldwin *result = (uintptr_t)sc->ap_handle; 4172ccfc932SJohn Baldwin return (0); 418d4b9ff91SNate Lawson case ACPI_IVAR_FLAGS: 419d4b9ff91SNate Lawson *result = (uintptr_t)sc->ap_flags; 420d4b9ff91SNate Lawson return (0); 42115e32d5dSMike Smith } 42215e32d5dSMike Smith return (ENOENT); 42315e32d5dSMike Smith } 42415e32d5dSMike Smith 42515e32d5dSMike Smith static int 42615e32d5dSMike Smith acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 42715e32d5dSMike Smith { 4282ccfc932SJohn Baldwin struct acpi_hpcib_softc *sc = device_get_softc(dev); 42915e32d5dSMike Smith 43015e32d5dSMike Smith switch (which) { 43155aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 43255aaf894SMarius Strobl return (EINVAL); 43315e32d5dSMike Smith case PCIB_IVAR_BUS: 43415e32d5dSMike Smith sc->ap_bus = value; 43515e32d5dSMike Smith return (0); 436d4b9ff91SNate Lawson case ACPI_IVAR_HANDLE: 437d4b9ff91SNate Lawson sc->ap_handle = (ACPI_HANDLE)value; 438d4b9ff91SNate Lawson return (0); 439d4b9ff91SNate Lawson case ACPI_IVAR_FLAGS: 440d4b9ff91SNate Lawson sc->ap_flags = (int)value; 441d4b9ff91SNate Lawson return (0); 44215e32d5dSMike Smith } 44315e32d5dSMike Smith return (ENOENT); 44415e32d5dSMike Smith } 44515e32d5dSMike Smith 446e3aa81b8SNate Lawson static uint32_t 4471496d4a9SWarner Losh acpi_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 4481496d4a9SWarner Losh u_int reg, int bytes) 44915e32d5dSMike Smith { 45015e32d5dSMike Smith return (pci_cfgregread(bus, slot, func, reg, bytes)); 45115e32d5dSMike Smith } 45215e32d5dSMike Smith 45315e32d5dSMike Smith static void 4541496d4a9SWarner Losh acpi_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 4551496d4a9SWarner Losh u_int reg, uint32_t data, int bytes) 45615e32d5dSMike Smith { 45715e32d5dSMike Smith pci_cfgregwrite(bus, slot, func, reg, data, bytes); 45815e32d5dSMike Smith } 45915e32d5dSMike Smith 46015e32d5dSMike Smith static int 4612ccfc932SJohn Baldwin acpi_pcib_acpi_route_interrupt(device_t pcib, device_t dev, int pin) 46215e32d5dSMike Smith { 4635e1ba6d4SJohn Baldwin struct acpi_hpcib_softc *sc = device_get_softc(pcib); 4644fa387b6SMike Smith 4655e1ba6d4SJohn Baldwin return (acpi_pcib_route_interrupt(pcib, dev, pin, &sc->ap_prt)); 46615e32d5dSMike Smith } 467cd8b53edSWarner Losh 4688964299aSJohn Baldwin static int 4698964299aSJohn Baldwin acpi_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, 4708964299aSJohn Baldwin int *irqs) 4718964299aSJohn Baldwin { 4728964299aSJohn Baldwin device_t bus; 4738964299aSJohn Baldwin 4748964299aSJohn Baldwin bus = device_get_parent(pcib); 4758964299aSJohn Baldwin return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 4768964299aSJohn Baldwin irqs)); 4778964299aSJohn Baldwin } 4788964299aSJohn Baldwin 4798964299aSJohn Baldwin static int 480e706f7f0SJohn Baldwin acpi_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 4818964299aSJohn Baldwin { 4828964299aSJohn Baldwin device_t bus; 4838964299aSJohn Baldwin 4848964299aSJohn Baldwin bus = device_get_parent(pcib); 485e706f7f0SJohn Baldwin return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 486e706f7f0SJohn Baldwin } 487e706f7f0SJohn Baldwin 488e706f7f0SJohn Baldwin static int 489e706f7f0SJohn Baldwin acpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 490e706f7f0SJohn Baldwin uint32_t *data) 491e706f7f0SJohn Baldwin { 492e706f7f0SJohn Baldwin device_t bus; 493e706f7f0SJohn Baldwin 494e706f7f0SJohn Baldwin bus = device_get_parent(pcib); 495e706f7f0SJohn Baldwin return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); 4968964299aSJohn Baldwin } 4978964299aSJohn Baldwin 498cd8b53edSWarner Losh struct resource * 499cd8b53edSWarner Losh acpi_pcib_acpi_alloc_resource(device_t dev, device_t child, int type, int *rid, 500cd8b53edSWarner Losh u_long start, u_long end, u_long count, u_int flags) 501cd8b53edSWarner Losh { 50234ff71eeSJohn Baldwin #ifdef NEW_PCIB 50334ff71eeSJohn Baldwin struct acpi_hpcib_softc *sc; 504*5d0d779bSJohn Baldwin struct resource *res; 50534ff71eeSJohn Baldwin #endif 50638d7a61bSJohn Baldwin 50738d7a61bSJohn Baldwin #if defined(__i386__) || defined(__amd64__) 50838d7a61bSJohn Baldwin start = hostb_alloc_start(type, start, end, count); 50938d7a61bSJohn Baldwin #endif 51034ff71eeSJohn Baldwin 51134ff71eeSJohn Baldwin #ifdef NEW_PCIB 51234ff71eeSJohn Baldwin sc = device_get_softc(dev); 513*5d0d779bSJohn Baldwin res = pcib_host_res_alloc(&sc->ap_host_res, child, type, rid, start, end, 514*5d0d779bSJohn Baldwin count, flags); 515*5d0d779bSJohn Baldwin if (res == NULL && start + count - 1 == end) 516*5d0d779bSJohn Baldwin res = acpi_alloc_sysres(child, type, rid, start, end, count, flags); 517*5d0d779bSJohn Baldwin return (res); 51834ff71eeSJohn Baldwin #else 519cd8b53edSWarner Losh return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 520cd8b53edSWarner Losh count, flags)); 52134ff71eeSJohn Baldwin #endif 522cd8b53edSWarner Losh } 52334ff71eeSJohn Baldwin 52434ff71eeSJohn Baldwin #ifdef NEW_PCIB 52534ff71eeSJohn Baldwin int 52634ff71eeSJohn Baldwin acpi_pcib_acpi_adjust_resource(device_t dev, device_t child, int type, 52734ff71eeSJohn Baldwin struct resource *r, u_long start, u_long end) 52834ff71eeSJohn Baldwin { 52934ff71eeSJohn Baldwin struct acpi_hpcib_softc *sc; 53034ff71eeSJohn Baldwin 53134ff71eeSJohn Baldwin sc = device_get_softc(dev); 53234ff71eeSJohn Baldwin return (pcib_host_res_adjust(&sc->ap_host_res, child, type, r, start, 53334ff71eeSJohn Baldwin end)); 53434ff71eeSJohn Baldwin } 53534ff71eeSJohn Baldwin #endif 536