1bb0d0a8eSMike Smith /*- 2bb0d0a8eSMike Smith * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier 3bb0d0a8eSMike Smith * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 4bb0d0a8eSMike Smith * Copyright (c) 2000 BSDi 5bb0d0a8eSMike Smith * All rights reserved. 6bb0d0a8eSMike Smith * 7bb0d0a8eSMike Smith * Redistribution and use in source and binary forms, with or without 8bb0d0a8eSMike Smith * modification, are permitted provided that the following conditions 9bb0d0a8eSMike Smith * are met: 10bb0d0a8eSMike Smith * 1. Redistributions of source code must retain the above copyright 11bb0d0a8eSMike Smith * notice, this list of conditions and the following disclaimer. 12bb0d0a8eSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 13bb0d0a8eSMike Smith * notice, this list of conditions and the following disclaimer in the 14bb0d0a8eSMike Smith * documentation and/or other materials provided with the distribution. 15bb0d0a8eSMike Smith * 3. The name of the author may not be used to endorse or promote products 16bb0d0a8eSMike Smith * derived from this software without specific prior written permission. 17bb0d0a8eSMike Smith * 18bb0d0a8eSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19bb0d0a8eSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20bb0d0a8eSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21bb0d0a8eSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22bb0d0a8eSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23bb0d0a8eSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24bb0d0a8eSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25bb0d0a8eSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26bb0d0a8eSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27bb0d0a8eSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28bb0d0a8eSMike Smith * SUCH DAMAGE. 29bb0d0a8eSMike Smith */ 30bb0d0a8eSMike Smith 31aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 33aad970f1SDavid E. O'Brien 34bb0d0a8eSMike Smith /* 35bb0d0a8eSMike Smith * PCI:PCI bridge support. 36bb0d0a8eSMike Smith */ 37bb0d0a8eSMike Smith 38bb0d0a8eSMike Smith #include <sys/param.h> 39bb0d0a8eSMike Smith #include <sys/bus.h> 4083c41143SJohn Baldwin #include <sys/kernel.h> 4183c41143SJohn Baldwin #include <sys/malloc.h> 4283c41143SJohn Baldwin #include <sys/module.h> 43a8b354a8SWarner Losh #include <sys/rman.h> 441c54ff33SMatthew N. Dodd #include <sys/sysctl.h> 4583c41143SJohn Baldwin #include <sys/systm.h> 46bb0d0a8eSMike Smith 4738d8c994SWarner Losh #include <dev/pci/pcivar.h> 4838d8c994SWarner Losh #include <dev/pci/pcireg.h> 4962508c53SJohn Baldwin #include <dev/pci/pci_private.h> 5038d8c994SWarner Losh #include <dev/pci/pcib_private.h> 51bb0d0a8eSMike Smith 52bb0d0a8eSMike Smith #include "pcib_if.h" 53bb0d0a8eSMike Smith 54bb0d0a8eSMike Smith static int pcib_probe(device_t dev); 55e36af292SJung-uk Kim static int pcib_suspend(device_t dev); 56e36af292SJung-uk Kim static int pcib_resume(device_t dev); 5762508c53SJohn Baldwin static int pcib_power_for_sleep(device_t pcib, device_t dev, 5862508c53SJohn Baldwin int *pstate); 59bb0d0a8eSMike Smith 60bb0d0a8eSMike Smith static device_method_t pcib_methods[] = { 61bb0d0a8eSMike Smith /* Device interface */ 62bb0d0a8eSMike Smith DEVMETHOD(device_probe, pcib_probe), 63bb0d0a8eSMike Smith DEVMETHOD(device_attach, pcib_attach), 644e30440dSWarner Losh DEVMETHOD(device_detach, bus_generic_detach), 65bb0d0a8eSMike Smith DEVMETHOD(device_shutdown, bus_generic_shutdown), 66e36af292SJung-uk Kim DEVMETHOD(device_suspend, pcib_suspend), 67e36af292SJung-uk Kim DEVMETHOD(device_resume, pcib_resume), 68bb0d0a8eSMike Smith 69bb0d0a8eSMike Smith /* Bus interface */ 70bb0d0a8eSMike Smith DEVMETHOD(bus_read_ivar, pcib_read_ivar), 71bb0d0a8eSMike Smith DEVMETHOD(bus_write_ivar, pcib_write_ivar), 72bb0d0a8eSMike Smith DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), 7383c41143SJohn Baldwin #ifdef NEW_PCIB 7483c41143SJohn Baldwin DEVMETHOD(bus_adjust_resource, pcib_adjust_resource), 7583c41143SJohn Baldwin DEVMETHOD(bus_release_resource, pcib_release_resource), 7683c41143SJohn Baldwin #else 77d2c9344fSJohn Baldwin DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 78bb0d0a8eSMike Smith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 7983c41143SJohn Baldwin #endif 80bb0d0a8eSMike Smith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 81bb0d0a8eSMike Smith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 82bb0d0a8eSMike Smith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 83bb0d0a8eSMike Smith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 84bb0d0a8eSMike Smith 85bb0d0a8eSMike Smith /* pcib interface */ 86bb0d0a8eSMike Smith DEVMETHOD(pcib_maxslots, pcib_maxslots), 87bb0d0a8eSMike Smith DEVMETHOD(pcib_read_config, pcib_read_config), 88bb0d0a8eSMike Smith DEVMETHOD(pcib_write_config, pcib_write_config), 89bb0d0a8eSMike Smith DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 909bf4c9c1SJohn Baldwin DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), 919bf4c9c1SJohn Baldwin DEVMETHOD(pcib_release_msi, pcib_release_msi), 929bf4c9c1SJohn Baldwin DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), 939bf4c9c1SJohn Baldwin DEVMETHOD(pcib_release_msix, pcib_release_msix), 94e706f7f0SJohn Baldwin DEVMETHOD(pcib_map_msi, pcib_map_msi), 9562508c53SJohn Baldwin DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep), 96bb0d0a8eSMike Smith 97*4b7ec270SMarius Strobl DEVMETHOD_END 98bb0d0a8eSMike Smith }; 99bb0d0a8eSMike Smith 10004dda605SJohn Baldwin static devclass_t pcib_devclass; 101bb0d0a8eSMike Smith 10204dda605SJohn Baldwin DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); 103bb0d0a8eSMike Smith DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); 104bb0d0a8eSMike Smith 10583c41143SJohn Baldwin #ifdef NEW_PCIB 10683c41143SJohn Baldwin /* 10783c41143SJohn Baldwin * XXX Todo: 10883c41143SJohn Baldwin * - properly handle the ISA enable bit. If it is set, we should change 10983c41143SJohn Baldwin * the behavior of the I/O window resource and rman to not allocate the 11083c41143SJohn Baldwin * blocked ranges (upper 768 bytes of each 1K in the first 64k of the 11183c41143SJohn Baldwin * I/O port address space). 11283c41143SJohn Baldwin */ 11383c41143SJohn Baldwin 11483c41143SJohn Baldwin /* 11583c41143SJohn Baldwin * Is a resource from a child device sub-allocated from one of our 11683c41143SJohn Baldwin * resource managers? 11783c41143SJohn Baldwin */ 11883c41143SJohn Baldwin static int 11983c41143SJohn Baldwin pcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r) 12083c41143SJohn Baldwin { 12183c41143SJohn Baldwin 12283c41143SJohn Baldwin switch (type) { 12383c41143SJohn Baldwin case SYS_RES_IOPORT: 12483c41143SJohn Baldwin return (rman_is_region_manager(r, &sc->io.rman)); 12583c41143SJohn Baldwin case SYS_RES_MEMORY: 12683c41143SJohn Baldwin /* Prefetchable resources may live in either memory rman. */ 12783c41143SJohn Baldwin if (rman_get_flags(r) & RF_PREFETCHABLE && 12883c41143SJohn Baldwin rman_is_region_manager(r, &sc->pmem.rman)) 12983c41143SJohn Baldwin return (1); 13083c41143SJohn Baldwin return (rman_is_region_manager(r, &sc->mem.rman)); 13183c41143SJohn Baldwin } 13283c41143SJohn Baldwin return (0); 13383c41143SJohn Baldwin } 13483c41143SJohn Baldwin 13583c41143SJohn Baldwin static int 13683c41143SJohn Baldwin pcib_is_window_open(struct pcib_window *pw) 13783c41143SJohn Baldwin { 13883c41143SJohn Baldwin 13983c41143SJohn Baldwin return (pw->valid && pw->base < pw->limit); 14083c41143SJohn Baldwin } 14183c41143SJohn Baldwin 14283c41143SJohn Baldwin /* 14383c41143SJohn Baldwin * XXX: If RF_ACTIVE did not also imply allocating a bus space tag and 14483c41143SJohn Baldwin * handle for the resource, we could pass RF_ACTIVE up to the PCI bus 14583c41143SJohn Baldwin * when allocating the resource windows and rely on the PCI bus driver 14683c41143SJohn Baldwin * to do this for us. 14783c41143SJohn Baldwin */ 14883c41143SJohn Baldwin static void 14983c41143SJohn Baldwin pcib_activate_window(struct pcib_softc *sc, int type) 15083c41143SJohn Baldwin { 15183c41143SJohn Baldwin 15283c41143SJohn Baldwin PCI_ENABLE_IO(device_get_parent(sc->dev), sc->dev, type); 15383c41143SJohn Baldwin } 15483c41143SJohn Baldwin 15583c41143SJohn Baldwin static void 15683c41143SJohn Baldwin pcib_write_windows(struct pcib_softc *sc, int mask) 15783c41143SJohn Baldwin { 15883c41143SJohn Baldwin device_t dev; 15983c41143SJohn Baldwin uint32_t val; 16083c41143SJohn Baldwin 16183c41143SJohn Baldwin dev = sc->dev; 16283c41143SJohn Baldwin if (sc->io.valid && mask & WIN_IO) { 16383c41143SJohn Baldwin val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 16483c41143SJohn Baldwin if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 16583c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEH_1, 16683c41143SJohn Baldwin sc->io.base >> 16, 2); 16783c41143SJohn Baldwin pci_write_config(dev, PCIR_IOLIMITH_1, 16883c41143SJohn Baldwin sc->io.limit >> 16, 2); 16983c41143SJohn Baldwin } 17083c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEL_1, sc->io.base >> 8, 1); 17183c41143SJohn Baldwin pci_write_config(dev, PCIR_IOLIMITL_1, sc->io.limit >> 8, 1); 17283c41143SJohn Baldwin } 17383c41143SJohn Baldwin 17483c41143SJohn Baldwin if (mask & WIN_MEM) { 17583c41143SJohn Baldwin pci_write_config(dev, PCIR_MEMBASE_1, sc->mem.base >> 16, 2); 17683c41143SJohn Baldwin pci_write_config(dev, PCIR_MEMLIMIT_1, sc->mem.limit >> 16, 2); 17783c41143SJohn Baldwin } 17883c41143SJohn Baldwin 17983c41143SJohn Baldwin if (sc->pmem.valid && mask & WIN_PMEM) { 18083c41143SJohn Baldwin val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 18183c41143SJohn Baldwin if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 18283c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEH_1, 18383c41143SJohn Baldwin sc->pmem.base >> 32, 4); 18483c41143SJohn Baldwin pci_write_config(dev, PCIR_PMLIMITH_1, 18583c41143SJohn Baldwin sc->pmem.limit >> 32, 4); 18683c41143SJohn Baldwin } 18783c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEL_1, sc->pmem.base >> 16, 2); 18883c41143SJohn Baldwin pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmem.limit >> 16, 2); 18983c41143SJohn Baldwin } 19083c41143SJohn Baldwin } 19183c41143SJohn Baldwin 19283c41143SJohn Baldwin static void 19383c41143SJohn Baldwin pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, 19483c41143SJohn Baldwin int flags, pci_addr_t max_address) 19583c41143SJohn Baldwin { 19683c41143SJohn Baldwin char buf[64]; 19783c41143SJohn Baldwin int error, rid; 19883c41143SJohn Baldwin 19983c41143SJohn Baldwin if (max_address != (u_long)max_address) 20083c41143SJohn Baldwin max_address = ~0ul; 20183c41143SJohn Baldwin w->rman.rm_start = 0; 20283c41143SJohn Baldwin w->rman.rm_end = max_address; 20383c41143SJohn Baldwin w->rman.rm_type = RMAN_ARRAY; 20483c41143SJohn Baldwin snprintf(buf, sizeof(buf), "%s %s window", 20583c41143SJohn Baldwin device_get_nameunit(sc->dev), w->name); 20683c41143SJohn Baldwin w->rman.rm_descr = strdup(buf, M_DEVBUF); 20783c41143SJohn Baldwin error = rman_init(&w->rman); 20883c41143SJohn Baldwin if (error) 20983c41143SJohn Baldwin panic("Failed to initialize %s %s rman", 21083c41143SJohn Baldwin device_get_nameunit(sc->dev), w->name); 21183c41143SJohn Baldwin 21283c41143SJohn Baldwin if (!pcib_is_window_open(w)) 21383c41143SJohn Baldwin return; 21483c41143SJohn Baldwin 21583c41143SJohn Baldwin if (w->base > max_address || w->limit > max_address) { 21683c41143SJohn Baldwin device_printf(sc->dev, 21783c41143SJohn Baldwin "initial %s window has too many bits, ignoring\n", w->name); 21883c41143SJohn Baldwin return; 21983c41143SJohn Baldwin } 22083c41143SJohn Baldwin rid = w->reg; 22183c41143SJohn Baldwin w->res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit, 22283c41143SJohn Baldwin w->limit - w->base + 1, flags); 22383c41143SJohn Baldwin if (w->res == NULL) { 22483c41143SJohn Baldwin device_printf(sc->dev, 22583c41143SJohn Baldwin "failed to allocate initial %s window: %#jx-%#jx\n", 22683c41143SJohn Baldwin w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 22783c41143SJohn Baldwin w->base = max_address; 22883c41143SJohn Baldwin w->limit = 0; 22983c41143SJohn Baldwin pcib_write_windows(sc, w->mask); 23083c41143SJohn Baldwin return; 23183c41143SJohn Baldwin } 23283c41143SJohn Baldwin pcib_activate_window(sc, type); 23383c41143SJohn Baldwin 23483c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 23583c41143SJohn Baldwin rman_get_end(w->res)); 23683c41143SJohn Baldwin if (error) 23783c41143SJohn Baldwin panic("Failed to initialize rman with resource"); 23883c41143SJohn Baldwin } 23983c41143SJohn Baldwin 24083c41143SJohn Baldwin /* 24183c41143SJohn Baldwin * Initialize I/O windows. 24283c41143SJohn Baldwin */ 24383c41143SJohn Baldwin static void 24483c41143SJohn Baldwin pcib_probe_windows(struct pcib_softc *sc) 24583c41143SJohn Baldwin { 24683c41143SJohn Baldwin pci_addr_t max; 24783c41143SJohn Baldwin device_t dev; 24883c41143SJohn Baldwin uint32_t val; 24983c41143SJohn Baldwin 25083c41143SJohn Baldwin dev = sc->dev; 25183c41143SJohn Baldwin 25283c41143SJohn Baldwin /* Determine if the I/O port window is implemented. */ 25383c41143SJohn Baldwin val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 25483c41143SJohn Baldwin if (val == 0) { 25583c41143SJohn Baldwin /* 25683c41143SJohn Baldwin * If 'val' is zero, then only 16-bits of I/O space 25783c41143SJohn Baldwin * are supported. 25883c41143SJohn Baldwin */ 25983c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); 26083c41143SJohn Baldwin if (pci_read_config(dev, PCIR_IOBASEL_1, 1) != 0) { 26183c41143SJohn Baldwin sc->io.valid = 1; 26283c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEL_1, 0, 1); 26383c41143SJohn Baldwin } 26483c41143SJohn Baldwin } else 26583c41143SJohn Baldwin sc->io.valid = 1; 26683c41143SJohn Baldwin 26783c41143SJohn Baldwin /* Read the existing I/O port window. */ 26883c41143SJohn Baldwin if (sc->io.valid) { 26983c41143SJohn Baldwin sc->io.reg = PCIR_IOBASEL_1; 27083c41143SJohn Baldwin sc->io.step = 12; 27183c41143SJohn Baldwin sc->io.mask = WIN_IO; 27283c41143SJohn Baldwin sc->io.name = "I/O port"; 27383c41143SJohn Baldwin if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 27483c41143SJohn Baldwin sc->io.base = PCI_PPBIOBASE( 27583c41143SJohn Baldwin pci_read_config(dev, PCIR_IOBASEH_1, 2), val); 27683c41143SJohn Baldwin sc->io.limit = PCI_PPBIOLIMIT( 27783c41143SJohn Baldwin pci_read_config(dev, PCIR_IOLIMITH_1, 2), 27883c41143SJohn Baldwin pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 27983c41143SJohn Baldwin max = 0xffffffff; 28083c41143SJohn Baldwin } else { 28183c41143SJohn Baldwin sc->io.base = PCI_PPBIOBASE(0, val); 28283c41143SJohn Baldwin sc->io.limit = PCI_PPBIOLIMIT(0, 28383c41143SJohn Baldwin pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 28483c41143SJohn Baldwin max = 0xffff; 28583c41143SJohn Baldwin } 28683c41143SJohn Baldwin pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max); 28783c41143SJohn Baldwin } 28883c41143SJohn Baldwin 28983c41143SJohn Baldwin /* Read the existing memory window. */ 29083c41143SJohn Baldwin sc->mem.valid = 1; 29183c41143SJohn Baldwin sc->mem.reg = PCIR_MEMBASE_1; 29283c41143SJohn Baldwin sc->mem.step = 20; 29383c41143SJohn Baldwin sc->mem.mask = WIN_MEM; 29483c41143SJohn Baldwin sc->mem.name = "memory"; 29583c41143SJohn Baldwin sc->mem.base = PCI_PPBMEMBASE(0, 29683c41143SJohn Baldwin pci_read_config(dev, PCIR_MEMBASE_1, 2)); 29783c41143SJohn Baldwin sc->mem.limit = PCI_PPBMEMLIMIT(0, 29883c41143SJohn Baldwin pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 29983c41143SJohn Baldwin pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, 0xffffffff); 30083c41143SJohn Baldwin 30183c41143SJohn Baldwin /* Determine if the prefetchable memory window is implemented. */ 30283c41143SJohn Baldwin val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 30383c41143SJohn Baldwin if (val == 0) { 30483c41143SJohn Baldwin /* 30583c41143SJohn Baldwin * If 'val' is zero, then only 32-bits of memory space 30683c41143SJohn Baldwin * are supported. 30783c41143SJohn Baldwin */ 30883c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); 30983c41143SJohn Baldwin if (pci_read_config(dev, PCIR_PMBASEL_1, 2) != 0) { 31083c41143SJohn Baldwin sc->pmem.valid = 1; 31183c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEL_1, 0, 2); 31283c41143SJohn Baldwin } 31383c41143SJohn Baldwin } else 31483c41143SJohn Baldwin sc->pmem.valid = 1; 31583c41143SJohn Baldwin 31683c41143SJohn Baldwin /* Read the existing prefetchable memory window. */ 31783c41143SJohn Baldwin if (sc->pmem.valid) { 31883c41143SJohn Baldwin sc->pmem.reg = PCIR_PMBASEL_1; 31983c41143SJohn Baldwin sc->pmem.step = 20; 32083c41143SJohn Baldwin sc->pmem.mask = WIN_PMEM; 32183c41143SJohn Baldwin sc->pmem.name = "prefetch"; 32283c41143SJohn Baldwin if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 32383c41143SJohn Baldwin sc->pmem.base = PCI_PPBMEMBASE( 32483c41143SJohn Baldwin pci_read_config(dev, PCIR_PMBASEH_1, 4), val); 32583c41143SJohn Baldwin sc->pmem.limit = PCI_PPBMEMLIMIT( 32683c41143SJohn Baldwin pci_read_config(dev, PCIR_PMLIMITH_1, 4), 32783c41143SJohn Baldwin pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 32883c41143SJohn Baldwin max = 0xffffffffffffffff; 32983c41143SJohn Baldwin } else { 33083c41143SJohn Baldwin sc->pmem.base = PCI_PPBMEMBASE(0, val); 33183c41143SJohn Baldwin sc->pmem.limit = PCI_PPBMEMLIMIT(0, 33283c41143SJohn Baldwin pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 33383c41143SJohn Baldwin max = 0xffffffff; 33483c41143SJohn Baldwin } 33583c41143SJohn Baldwin pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY, 33683c41143SJohn Baldwin RF_PREFETCHABLE, max); 33783c41143SJohn Baldwin } 33883c41143SJohn Baldwin } 33983c41143SJohn Baldwin 34083c41143SJohn Baldwin #else 34183c41143SJohn Baldwin 342bb0d0a8eSMike Smith /* 343b0a2d4b8SWarner Losh * Is the prefetch window open (eg, can we allocate memory in it?) 344b0a2d4b8SWarner Losh */ 345b0a2d4b8SWarner Losh static int 346b0a2d4b8SWarner Losh pcib_is_prefetch_open(struct pcib_softc *sc) 347b0a2d4b8SWarner Losh { 348b0a2d4b8SWarner Losh return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); 349b0a2d4b8SWarner Losh } 350b0a2d4b8SWarner Losh 351b0a2d4b8SWarner Losh /* 352b0a2d4b8SWarner Losh * Is the nonprefetch window open (eg, can we allocate memory in it?) 353b0a2d4b8SWarner Losh */ 354b0a2d4b8SWarner Losh static int 355b0a2d4b8SWarner Losh pcib_is_nonprefetch_open(struct pcib_softc *sc) 356b0a2d4b8SWarner Losh { 357b0a2d4b8SWarner Losh return (sc->membase > 0 && sc->membase < sc->memlimit); 358b0a2d4b8SWarner Losh } 359b0a2d4b8SWarner Losh 360b0a2d4b8SWarner Losh /* 361b0a2d4b8SWarner Losh * Is the io window open (eg, can we allocate ports in it?) 362b0a2d4b8SWarner Losh */ 363b0a2d4b8SWarner Losh static int 364b0a2d4b8SWarner Losh pcib_is_io_open(struct pcib_softc *sc) 365b0a2d4b8SWarner Losh { 366b0a2d4b8SWarner Losh return (sc->iobase > 0 && sc->iobase < sc->iolimit); 367b0a2d4b8SWarner Losh } 368b0a2d4b8SWarner Losh 369b0a2d4b8SWarner Losh /* 370e36af292SJung-uk Kim * Get current I/O decode. 371e36af292SJung-uk Kim */ 372e36af292SJung-uk Kim static void 373e36af292SJung-uk Kim pcib_get_io_decode(struct pcib_softc *sc) 374e36af292SJung-uk Kim { 375e36af292SJung-uk Kim device_t dev; 376e36af292SJung-uk Kim uint32_t iolow; 377e36af292SJung-uk Kim 378e36af292SJung-uk Kim dev = sc->dev; 379e36af292SJung-uk Kim 380e36af292SJung-uk Kim iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); 381e36af292SJung-uk Kim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 382e36af292SJung-uk Kim sc->iobase = PCI_PPBIOBASE( 383e36af292SJung-uk Kim pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow); 384e36af292SJung-uk Kim else 385e36af292SJung-uk Kim sc->iobase = PCI_PPBIOBASE(0, iolow); 386e36af292SJung-uk Kim 387e36af292SJung-uk Kim iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); 388e36af292SJung-uk Kim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 389e36af292SJung-uk Kim sc->iolimit = PCI_PPBIOLIMIT( 390e36af292SJung-uk Kim pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow); 391e36af292SJung-uk Kim else 392e36af292SJung-uk Kim sc->iolimit = PCI_PPBIOLIMIT(0, iolow); 393e36af292SJung-uk Kim } 394e36af292SJung-uk Kim 395e36af292SJung-uk Kim /* 396e36af292SJung-uk Kim * Get current memory decode. 397e36af292SJung-uk Kim */ 398e36af292SJung-uk Kim static void 399e36af292SJung-uk Kim pcib_get_mem_decode(struct pcib_softc *sc) 400e36af292SJung-uk Kim { 401e36af292SJung-uk Kim device_t dev; 402e36af292SJung-uk Kim pci_addr_t pmemlow; 403e36af292SJung-uk Kim 404e36af292SJung-uk Kim dev = sc->dev; 405e36af292SJung-uk Kim 406e36af292SJung-uk Kim sc->membase = PCI_PPBMEMBASE(0, 407e36af292SJung-uk Kim pci_read_config(dev, PCIR_MEMBASE_1, 2)); 408e36af292SJung-uk Kim sc->memlimit = PCI_PPBMEMLIMIT(0, 409e36af292SJung-uk Kim pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 410e36af292SJung-uk Kim 411e36af292SJung-uk Kim pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2); 412e36af292SJung-uk Kim if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 413e36af292SJung-uk Kim sc->pmembase = PCI_PPBMEMBASE( 414e36af292SJung-uk Kim pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow); 415e36af292SJung-uk Kim else 416e36af292SJung-uk Kim sc->pmembase = PCI_PPBMEMBASE(0, pmemlow); 417e36af292SJung-uk Kim 418e36af292SJung-uk Kim pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2); 419e36af292SJung-uk Kim if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 420e36af292SJung-uk Kim sc->pmemlimit = PCI_PPBMEMLIMIT( 421e36af292SJung-uk Kim pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow); 422e36af292SJung-uk Kim else 423e36af292SJung-uk Kim sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow); 424e36af292SJung-uk Kim } 425e36af292SJung-uk Kim 426e36af292SJung-uk Kim /* 427e36af292SJung-uk Kim * Restore previous I/O decode. 428e36af292SJung-uk Kim */ 429e36af292SJung-uk Kim static void 430e36af292SJung-uk Kim pcib_set_io_decode(struct pcib_softc *sc) 431e36af292SJung-uk Kim { 432e36af292SJung-uk Kim device_t dev; 433e36af292SJung-uk Kim uint32_t iohi; 434e36af292SJung-uk Kim 435e36af292SJung-uk Kim dev = sc->dev; 436e36af292SJung-uk Kim 437e36af292SJung-uk Kim iohi = sc->iobase >> 16; 438e36af292SJung-uk Kim if (iohi > 0) 439e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2); 440e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1); 441e36af292SJung-uk Kim 442e36af292SJung-uk Kim iohi = sc->iolimit >> 16; 443e36af292SJung-uk Kim if (iohi > 0) 444e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2); 445e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1); 446e36af292SJung-uk Kim } 447e36af292SJung-uk Kim 448e36af292SJung-uk Kim /* 449e36af292SJung-uk Kim * Restore previous memory decode. 450e36af292SJung-uk Kim */ 451e36af292SJung-uk Kim static void 452e36af292SJung-uk Kim pcib_set_mem_decode(struct pcib_softc *sc) 453e36af292SJung-uk Kim { 454e36af292SJung-uk Kim device_t dev; 455e36af292SJung-uk Kim pci_addr_t pmemhi; 456e36af292SJung-uk Kim 457e36af292SJung-uk Kim dev = sc->dev; 458e36af292SJung-uk Kim 459e36af292SJung-uk Kim pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2); 460e36af292SJung-uk Kim pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2); 461e36af292SJung-uk Kim 462e36af292SJung-uk Kim pmemhi = sc->pmembase >> 32; 463e36af292SJung-uk Kim if (pmemhi > 0) 464e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4); 465e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2); 466e36af292SJung-uk Kim 467e36af292SJung-uk Kim pmemhi = sc->pmemlimit >> 32; 468e36af292SJung-uk Kim if (pmemhi > 0) 469e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4); 470e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2); 471e36af292SJung-uk Kim } 47283c41143SJohn Baldwin #endif 473e36af292SJung-uk Kim 474e36af292SJung-uk Kim /* 475e36af292SJung-uk Kim * Get current bridge configuration. 476e36af292SJung-uk Kim */ 477e36af292SJung-uk Kim static void 478e36af292SJung-uk Kim pcib_cfg_save(struct pcib_softc *sc) 479e36af292SJung-uk Kim { 480e36af292SJung-uk Kim device_t dev; 481e36af292SJung-uk Kim 482e36af292SJung-uk Kim dev = sc->dev; 483e36af292SJung-uk Kim 484e36af292SJung-uk Kim sc->command = pci_read_config(dev, PCIR_COMMAND, 2); 485e36af292SJung-uk Kim sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1); 486e36af292SJung-uk Kim sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); 487e36af292SJung-uk Kim sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 488e36af292SJung-uk Kim sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 489e36af292SJung-uk Kim sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 49083c41143SJohn Baldwin #ifndef NEW_PCIB 491e36af292SJung-uk Kim if (sc->command & PCIM_CMD_PORTEN) 492e36af292SJung-uk Kim pcib_get_io_decode(sc); 493e36af292SJung-uk Kim if (sc->command & PCIM_CMD_MEMEN) 494e36af292SJung-uk Kim pcib_get_mem_decode(sc); 49583c41143SJohn Baldwin #endif 496e36af292SJung-uk Kim } 497e36af292SJung-uk Kim 498e36af292SJung-uk Kim /* 499e36af292SJung-uk Kim * Restore previous bridge configuration. 500e36af292SJung-uk Kim */ 501e36af292SJung-uk Kim static void 502e36af292SJung-uk Kim pcib_cfg_restore(struct pcib_softc *sc) 503e36af292SJung-uk Kim { 504e36af292SJung-uk Kim device_t dev; 505e36af292SJung-uk Kim 506e36af292SJung-uk Kim dev = sc->dev; 507e36af292SJung-uk Kim 508e36af292SJung-uk Kim pci_write_config(dev, PCIR_COMMAND, sc->command, 2); 509e36af292SJung-uk Kim pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); 510e36af292SJung-uk Kim pci_write_config(dev, PCIR_SECBUS_1, sc->secbus, 1); 511e36af292SJung-uk Kim pci_write_config(dev, PCIR_SUBBUS_1, sc->subbus, 1); 512e36af292SJung-uk Kim pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2); 513e36af292SJung-uk Kim pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1); 51483c41143SJohn Baldwin #ifdef NEW_PCIB 51583c41143SJohn Baldwin pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM); 51683c41143SJohn Baldwin #else 517e36af292SJung-uk Kim if (sc->command & PCIM_CMD_PORTEN) 518e36af292SJung-uk Kim pcib_set_io_decode(sc); 519e36af292SJung-uk Kim if (sc->command & PCIM_CMD_MEMEN) 520e36af292SJung-uk Kim pcib_set_mem_decode(sc); 52183c41143SJohn Baldwin #endif 522e36af292SJung-uk Kim } 523e36af292SJung-uk Kim 524e36af292SJung-uk Kim /* 525bb0d0a8eSMike Smith * Generic device interface 526bb0d0a8eSMike Smith */ 527bb0d0a8eSMike Smith static int 528bb0d0a8eSMike Smith pcib_probe(device_t dev) 529bb0d0a8eSMike Smith { 530bb0d0a8eSMike Smith if ((pci_get_class(dev) == PCIC_BRIDGE) && 531bb0d0a8eSMike Smith (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { 532bb0d0a8eSMike Smith device_set_desc(dev, "PCI-PCI bridge"); 533bb0d0a8eSMike Smith return(-10000); 534bb0d0a8eSMike Smith } 535bb0d0a8eSMike Smith return(ENXIO); 536bb0d0a8eSMike Smith } 537bb0d0a8eSMike Smith 5386f0d5884SJohn Baldwin void 5396f0d5884SJohn Baldwin pcib_attach_common(device_t dev) 540bb0d0a8eSMike Smith { 541bb0d0a8eSMike Smith struct pcib_softc *sc; 542abf07f13SWarner Losh struct sysctl_ctx_list *sctx; 543abf07f13SWarner Losh struct sysctl_oid *soid; 544bb0d0a8eSMike Smith 545bb0d0a8eSMike Smith sc = device_get_softc(dev); 546bb0d0a8eSMike Smith sc->dev = dev; 547bb0d0a8eSMike Smith 5484fa59183SMike Smith /* 5494fa59183SMike Smith * Get current bridge configuration. 5504fa59183SMike Smith */ 55155aaf894SMarius Strobl sc->domain = pci_get_domain(dev); 5524fa59183SMike Smith sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 553e36af292SJung-uk Kim pcib_cfg_save(sc); 5544fa59183SMike Smith 5554fa59183SMike Smith /* 556abf07f13SWarner Losh * Setup sysctl reporting nodes 557abf07f13SWarner Losh */ 558abf07f13SWarner Losh sctx = device_get_sysctl_ctx(dev); 559abf07f13SWarner Losh soid = device_get_sysctl_tree(dev); 560abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", 561abf07f13SWarner Losh CTLFLAG_RD, &sc->domain, 0, "Domain number"); 562abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", 563abf07f13SWarner Losh CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); 564abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", 565abf07f13SWarner Losh CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number"); 566abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", 567abf07f13SWarner Losh CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number"); 568abf07f13SWarner Losh 569abf07f13SWarner Losh /* 5704fa59183SMike Smith * Quirk handling. 5714fa59183SMike Smith */ 5724fa59183SMike Smith switch (pci_get_devid(dev)) { 5734fa59183SMike Smith case 0x12258086: /* Intel 82454KX/GX (Orion) */ 5744fa59183SMike Smith { 575b0cb115fSWarner Losh uint8_t supbus; 5764fa59183SMike Smith 5774fa59183SMike Smith supbus = pci_read_config(dev, 0x41, 1); 5784fa59183SMike Smith if (supbus != 0xff) { 5794fa59183SMike Smith sc->secbus = supbus + 1; 5804fa59183SMike Smith sc->subbus = supbus + 1; 5814fa59183SMike Smith } 5824fa59183SMike Smith break; 5834fa59183SMike Smith } 5844fa59183SMike Smith 585e4b59fc5SWarner Losh /* 586e4b59fc5SWarner Losh * The i82380FB mobile docking controller is a PCI-PCI bridge, 587e4b59fc5SWarner Losh * and it is a subtractive bridge. However, the ProgIf is wrong 588e4b59fc5SWarner Losh * so the normal setting of PCIB_SUBTRACTIVE bit doesn't 589e4b59fc5SWarner Losh * happen. There's also a Toshiba bridge that behaves this 590e4b59fc5SWarner Losh * way. 591e4b59fc5SWarner Losh */ 592e4b59fc5SWarner Losh case 0x124b8086: /* Intel 82380FB Mobile */ 593e4b59fc5SWarner Losh case 0x060513d7: /* Toshiba ???? */ 594e4b59fc5SWarner Losh sc->flags |= PCIB_SUBTRACTIVE; 595e4b59fc5SWarner Losh break; 596c94d6dbeSJung-uk Kim 597c94d6dbeSJung-uk Kim /* Compaq R3000 BIOS sets wrong subordinate bus number. */ 598c94d6dbeSJung-uk Kim case 0x00dd10de: 599c94d6dbeSJung-uk Kim { 600c94d6dbeSJung-uk Kim char *cp; 601c94d6dbeSJung-uk Kim 6021def0ca6SJung-uk Kim if ((cp = getenv("smbios.planar.maker")) == NULL) 603c94d6dbeSJung-uk Kim break; 6041def0ca6SJung-uk Kim if (strncmp(cp, "Compal", 6) != 0) { 6051def0ca6SJung-uk Kim freeenv(cp); 606c94d6dbeSJung-uk Kim break; 6071def0ca6SJung-uk Kim } 6081def0ca6SJung-uk Kim freeenv(cp); 6091def0ca6SJung-uk Kim if ((cp = getenv("smbios.planar.product")) == NULL) 6101def0ca6SJung-uk Kim break; 6111def0ca6SJung-uk Kim if (strncmp(cp, "08A0", 4) != 0) { 6121def0ca6SJung-uk Kim freeenv(cp); 6131def0ca6SJung-uk Kim break; 6141def0ca6SJung-uk Kim } 6151def0ca6SJung-uk Kim freeenv(cp); 616c94d6dbeSJung-uk Kim if (sc->subbus < 0xa) { 617c94d6dbeSJung-uk Kim pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1); 618c94d6dbeSJung-uk Kim sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 619c94d6dbeSJung-uk Kim } 620c94d6dbeSJung-uk Kim break; 621c94d6dbeSJung-uk Kim } 622e4b59fc5SWarner Losh } 623e4b59fc5SWarner Losh 62422bf1c7fSJohn Baldwin if (pci_msi_device_blacklisted(dev)) 62522bf1c7fSJohn Baldwin sc->flags |= PCIB_DISABLE_MSI; 62622bf1c7fSJohn Baldwin 627e4b59fc5SWarner Losh /* 628e4b59fc5SWarner Losh * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, 629e4b59fc5SWarner Losh * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, 630e4b59fc5SWarner Losh * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. 631e4b59fc5SWarner Losh * This means they act as if they were subtractively decoding 632e4b59fc5SWarner Losh * bridges and pass all transactions. Mark them and real ProgIf 1 633e4b59fc5SWarner Losh * parts as subtractive. 634e4b59fc5SWarner Losh */ 635e4b59fc5SWarner Losh if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || 636657d9f9fSJohn Baldwin pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE) 637e4b59fc5SWarner Losh sc->flags |= PCIB_SUBTRACTIVE; 638e4b59fc5SWarner Losh 63983c41143SJohn Baldwin #ifdef NEW_PCIB 64083c41143SJohn Baldwin pcib_probe_windows(sc); 64183c41143SJohn Baldwin #endif 642bb0d0a8eSMike Smith if (bootverbose) { 64355aaf894SMarius Strobl device_printf(dev, " domain %d\n", sc->domain); 644bb0d0a8eSMike Smith device_printf(dev, " secondary bus %d\n", sc->secbus); 645bb0d0a8eSMike Smith device_printf(dev, " subordinate bus %d\n", sc->subbus); 64683c41143SJohn Baldwin #ifdef NEW_PCIB 64783c41143SJohn Baldwin if (pcib_is_window_open(&sc->io)) 64883c41143SJohn Baldwin device_printf(dev, " I/O decode 0x%jx-0x%jx\n", 64983c41143SJohn Baldwin (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit); 65083c41143SJohn Baldwin if (pcib_is_window_open(&sc->mem)) 65183c41143SJohn Baldwin device_printf(dev, " memory decode 0x%jx-0x%jx\n", 65283c41143SJohn Baldwin (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit); 65383c41143SJohn Baldwin if (pcib_is_window_open(&sc->pmem)) 65483c41143SJohn Baldwin device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 65583c41143SJohn Baldwin (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit); 65683c41143SJohn Baldwin #else 65783c41143SJohn Baldwin if (pcib_is_io_open(sc)) 65883c41143SJohn Baldwin device_printf(dev, " I/O decode 0x%x-0x%x\n", 65983c41143SJohn Baldwin sc->iobase, sc->iolimit); 660b0a2d4b8SWarner Losh if (pcib_is_nonprefetch_open(sc)) 661b0a2d4b8SWarner Losh device_printf(dev, " memory decode 0x%jx-0x%jx\n", 662b0a2d4b8SWarner Losh (uintmax_t)sc->membase, (uintmax_t)sc->memlimit); 663b0a2d4b8SWarner Losh if (pcib_is_prefetch_open(sc)) 664b0a2d4b8SWarner Losh device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 665b0a2d4b8SWarner Losh (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 66683c41143SJohn Baldwin #endif 667b0a2d4b8SWarner Losh else 668b0a2d4b8SWarner Losh device_printf(dev, " no prefetched decode\n"); 669e4b59fc5SWarner Losh if (sc->flags & PCIB_SUBTRACTIVE) 670e4b59fc5SWarner Losh device_printf(dev, " Subtractively decoded bridge.\n"); 671bb0d0a8eSMike Smith } 672bb0d0a8eSMike Smith 673bb0d0a8eSMike Smith /* 674bb0d0a8eSMike Smith * XXX If the secondary bus number is zero, we should assign a bus number 6757e178674SWarner Losh * since the BIOS hasn't, then initialise the bridge. A simple 6767e178674SWarner Losh * bus_alloc_resource with the a couple of busses seems like the right 6777e178674SWarner Losh * approach, but we don't know what busses the BIOS might have already 6787e178674SWarner Losh * assigned to other bridges on this bus that probe later than we do. 6797e178674SWarner Losh * 6807e178674SWarner Losh * If the subordinate bus number is less than the secondary bus number, 681bb0d0a8eSMike Smith * we should pick a better value. One sensible alternative would be to 682bb0d0a8eSMike Smith * pick 255; the only tradeoff here is that configuration transactions 6837e178674SWarner Losh * would be more widely routed than absolutely necessary. We could 6847e178674SWarner Losh * then do a walk of the tree later and fix it. 685bb0d0a8eSMike Smith */ 6866f0d5884SJohn Baldwin } 687bb0d0a8eSMike Smith 68838906aedSJohn Baldwin int 6896f0d5884SJohn Baldwin pcib_attach(device_t dev) 6906f0d5884SJohn Baldwin { 6916f0d5884SJohn Baldwin struct pcib_softc *sc; 6926f0d5884SJohn Baldwin device_t child; 6936f0d5884SJohn Baldwin 6946f0d5884SJohn Baldwin pcib_attach_common(dev); 6956f0d5884SJohn Baldwin sc = device_get_softc(dev); 696bb0d0a8eSMike Smith if (sc->secbus != 0) { 697cea0a895SJohn Baldwin child = device_add_child(dev, "pci", sc->secbus); 698bb0d0a8eSMike Smith if (child != NULL) 699bb0d0a8eSMike Smith return(bus_generic_attach(dev)); 700bb0d0a8eSMike Smith } 701bb0d0a8eSMike Smith 702bb0d0a8eSMike Smith /* no secondary bus; we should have fixed this */ 703bb0d0a8eSMike Smith return(0); 704bb0d0a8eSMike Smith } 705bb0d0a8eSMike Smith 7066f0d5884SJohn Baldwin int 707e36af292SJung-uk Kim pcib_suspend(device_t dev) 708e36af292SJung-uk Kim { 70962508c53SJohn Baldwin device_t pcib; 710e36af292SJung-uk Kim int dstate, error; 711e36af292SJung-uk Kim 712e36af292SJung-uk Kim pcib_cfg_save(device_get_softc(dev)); 713e36af292SJung-uk Kim error = bus_generic_suspend(dev); 714f3e0b109SJung-uk Kim if (error == 0 && pci_do_power_suspend) { 715e36af292SJung-uk Kim dstate = PCI_POWERSTATE_D3; 71662508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 71762508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) 718e36af292SJung-uk Kim pci_set_powerstate(dev, dstate); 719e36af292SJung-uk Kim } 720e36af292SJung-uk Kim return (error); 721e36af292SJung-uk Kim } 722e36af292SJung-uk Kim 723e36af292SJung-uk Kim int 724e36af292SJung-uk Kim pcib_resume(device_t dev) 725e36af292SJung-uk Kim { 72662508c53SJohn Baldwin device_t pcib; 727e36af292SJung-uk Kim 728e36af292SJung-uk Kim if (pci_do_power_resume) { 72962508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 73062508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0) 731e36af292SJung-uk Kim pci_set_powerstate(dev, PCI_POWERSTATE_D0); 732e36af292SJung-uk Kim } 733e36af292SJung-uk Kim pcib_cfg_restore(device_get_softc(dev)); 734e36af292SJung-uk Kim return (bus_generic_resume(dev)); 735e36af292SJung-uk Kim } 736e36af292SJung-uk Kim 737e36af292SJung-uk Kim int 738bb0d0a8eSMike Smith pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 739bb0d0a8eSMike Smith { 740bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 741bb0d0a8eSMike Smith 742bb0d0a8eSMike Smith switch (which) { 74355aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 74455aaf894SMarius Strobl *result = sc->domain; 74555aaf894SMarius Strobl return(0); 746bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 747bb0d0a8eSMike Smith *result = sc->secbus; 748bb0d0a8eSMike Smith return(0); 749bb0d0a8eSMike Smith } 750bb0d0a8eSMike Smith return(ENOENT); 751bb0d0a8eSMike Smith } 752bb0d0a8eSMike Smith 7536f0d5884SJohn Baldwin int 754bb0d0a8eSMike Smith pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 755bb0d0a8eSMike Smith { 756bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 757bb0d0a8eSMike Smith 758bb0d0a8eSMike Smith switch (which) { 75955aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 76055aaf894SMarius Strobl return(EINVAL); 761bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 762bb0d0a8eSMike Smith sc->secbus = value; 76355aaf894SMarius Strobl return(0); 764bb0d0a8eSMike Smith } 765bb0d0a8eSMike Smith return(ENOENT); 766bb0d0a8eSMike Smith } 767bb0d0a8eSMike Smith 76883c41143SJohn Baldwin #ifdef NEW_PCIB 76983c41143SJohn Baldwin /* 77083c41143SJohn Baldwin * Attempt to allocate a resource from the existing resources assigned 77183c41143SJohn Baldwin * to a window. 77283c41143SJohn Baldwin */ 77383c41143SJohn Baldwin static struct resource * 77483c41143SJohn Baldwin pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w, 77583c41143SJohn Baldwin device_t child, int type, int *rid, u_long start, u_long end, u_long count, 77683c41143SJohn Baldwin u_int flags) 77783c41143SJohn Baldwin { 77883c41143SJohn Baldwin struct resource *res; 77983c41143SJohn Baldwin 78083c41143SJohn Baldwin if (!pcib_is_window_open(w)) 78183c41143SJohn Baldwin return (NULL); 78283c41143SJohn Baldwin 78383c41143SJohn Baldwin res = rman_reserve_resource(&w->rman, start, end, count, 78483c41143SJohn Baldwin flags & ~RF_ACTIVE, child); 78583c41143SJohn Baldwin if (res == NULL) 78683c41143SJohn Baldwin return (NULL); 78783c41143SJohn Baldwin 78883c41143SJohn Baldwin if (bootverbose) 78983c41143SJohn Baldwin device_printf(sc->dev, 79083c41143SJohn Baldwin "allocated %s range (%#lx-%#lx) for rid %x of %s\n", 79183c41143SJohn Baldwin w->name, rman_get_start(res), rman_get_end(res), *rid, 79283c41143SJohn Baldwin pcib_child_name(child)); 79383c41143SJohn Baldwin rman_set_rid(res, *rid); 79483c41143SJohn Baldwin 79583c41143SJohn Baldwin /* 79683c41143SJohn Baldwin * If the resource should be active, pass that request up the 79783c41143SJohn Baldwin * tree. This assumes the parent drivers can handle 79883c41143SJohn Baldwin * activating sub-allocated resources. 79983c41143SJohn Baldwin */ 80083c41143SJohn Baldwin if (flags & RF_ACTIVE) { 80183c41143SJohn Baldwin if (bus_activate_resource(child, type, *rid, res) != 0) { 80283c41143SJohn Baldwin rman_release_resource(res); 80383c41143SJohn Baldwin return (NULL); 80483c41143SJohn Baldwin } 80583c41143SJohn Baldwin } 80683c41143SJohn Baldwin 80783c41143SJohn Baldwin return (res); 80883c41143SJohn Baldwin } 80983c41143SJohn Baldwin 81083c41143SJohn Baldwin /* 81183c41143SJohn Baldwin * Attempt to grow a window to make room for a given resource request. 81283c41143SJohn Baldwin * The 'step' parameter is log_2 of the desired I/O window's alignment. 81383c41143SJohn Baldwin */ 81483c41143SJohn Baldwin static int 81583c41143SJohn Baldwin pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, 81683c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 81783c41143SJohn Baldwin { 81883c41143SJohn Baldwin u_long align, start_free, end_free, front, back; 81983c41143SJohn Baldwin int error, rid; 82083c41143SJohn Baldwin 82183c41143SJohn Baldwin /* 82283c41143SJohn Baldwin * Clamp the desired resource range to the maximum address 82383c41143SJohn Baldwin * this window supports. Reject impossible requests. 82483c41143SJohn Baldwin */ 82583c41143SJohn Baldwin if (!w->valid) 82683c41143SJohn Baldwin return (EINVAL); 82783c41143SJohn Baldwin if (end > w->rman.rm_end) 82883c41143SJohn Baldwin end = w->rman.rm_end; 82983c41143SJohn Baldwin if (start + count - 1 > end || start + count < start) 83083c41143SJohn Baldwin return (EINVAL); 83183c41143SJohn Baldwin 83283c41143SJohn Baldwin /* 83383c41143SJohn Baldwin * If there is no resource at all, just try to allocate enough 83483c41143SJohn Baldwin * aligned space for this resource. 83583c41143SJohn Baldwin */ 83683c41143SJohn Baldwin if (w->res == NULL) { 83783c41143SJohn Baldwin if (RF_ALIGNMENT(flags) < w->step) { 83883c41143SJohn Baldwin flags &= ~RF_ALIGNMENT_MASK; 83983c41143SJohn Baldwin flags |= RF_ALIGNMENT_LOG2(w->step); 84083c41143SJohn Baldwin } 84183c41143SJohn Baldwin start &= ~((1ul << w->step) - 1); 84283c41143SJohn Baldwin end |= ((1ul << w->step) - 1); 84383c41143SJohn Baldwin count = roundup2(count, 1ul << w->step); 84483c41143SJohn Baldwin rid = w->reg; 84583c41143SJohn Baldwin w->res = bus_alloc_resource(sc->dev, type, &rid, start, end, 84683c41143SJohn Baldwin count, flags & ~RF_ACTIVE); 84783c41143SJohn Baldwin if (w->res == NULL) { 84883c41143SJohn Baldwin if (bootverbose) 84983c41143SJohn Baldwin device_printf(sc->dev, 85083c41143SJohn Baldwin "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n", 85183c41143SJohn Baldwin w->name, start, end, count); 85283c41143SJohn Baldwin return (ENXIO); 85383c41143SJohn Baldwin } 85483c41143SJohn Baldwin if (bootverbose) 85583c41143SJohn Baldwin device_printf(sc->dev, 85683c41143SJohn Baldwin "allocated initial %s window of %#lx-%#lx\n", 85783c41143SJohn Baldwin w->name, rman_get_start(w->res), 85883c41143SJohn Baldwin rman_get_end(w->res)); 85983c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 86083c41143SJohn Baldwin rman_get_end(w->res)); 86183c41143SJohn Baldwin if (error) { 86283c41143SJohn Baldwin if (bootverbose) 86383c41143SJohn Baldwin device_printf(sc->dev, 86483c41143SJohn Baldwin "failed to add initial %s window to rman\n", 86583c41143SJohn Baldwin w->name); 86683c41143SJohn Baldwin bus_release_resource(sc->dev, type, w->reg, w->res); 86783c41143SJohn Baldwin w->res = NULL; 86883c41143SJohn Baldwin return (error); 86983c41143SJohn Baldwin } 87083c41143SJohn Baldwin pcib_activate_window(sc, type); 87183c41143SJohn Baldwin goto updatewin; 87283c41143SJohn Baldwin } 87383c41143SJohn Baldwin 87483c41143SJohn Baldwin /* 87583c41143SJohn Baldwin * See if growing the window would help. Compute the minimum 87683c41143SJohn Baldwin * amount of address space needed on both the front and back 87783c41143SJohn Baldwin * ends of the existing window to satisfy the allocation. 87883c41143SJohn Baldwin * 87983c41143SJohn Baldwin * For each end, build a candidate region adjusting for the 88083c41143SJohn Baldwin * required alignment, etc. If there is a free region at the 88183c41143SJohn Baldwin * edge of the window, grow from the inner edge of the free 88283c41143SJohn Baldwin * region. Otherwise grow from the window boundary. 88383c41143SJohn Baldwin * 88483c41143SJohn Baldwin * XXX: Special case: if w->res is completely empty and the 88583c41143SJohn Baldwin * request size is larger than w->res, we should find the 88683c41143SJohn Baldwin * optimal aligned buffer containing w->res and allocate that. 88783c41143SJohn Baldwin */ 88883c41143SJohn Baldwin if (bootverbose) 88983c41143SJohn Baldwin device_printf(sc->dev, 89083c41143SJohn Baldwin "attempting to grow %s window for (%#lx-%#lx,%#lx)\n", 89183c41143SJohn Baldwin w->name, start, end, count); 89283c41143SJohn Baldwin align = 1ul << RF_ALIGNMENT(flags); 89383c41143SJohn Baldwin if (start < rman_get_start(w->res)) { 89483c41143SJohn Baldwin if (rman_first_free_region(&w->rman, &start_free, &end_free) != 89583c41143SJohn Baldwin 0 || start_free != rman_get_start(w->res)) 89683c41143SJohn Baldwin end_free = rman_get_start(w->res) - 1; 89783c41143SJohn Baldwin if (end_free > end) 89883c41143SJohn Baldwin end_free = end; 89983c41143SJohn Baldwin 90083c41143SJohn Baldwin /* Move end_free down until it is properly aligned. */ 90183c41143SJohn Baldwin end_free &= ~(align - 1); 902a49dcb46SJohn Baldwin end_free--; 903a49dcb46SJohn Baldwin front = end_free - (count - 1); 90483c41143SJohn Baldwin 90583c41143SJohn Baldwin /* 90683c41143SJohn Baldwin * The resource would now be allocated at (front, 90783c41143SJohn Baldwin * end_free). Ensure that fits in the (start, end) 90883c41143SJohn Baldwin * bounds. end_free is checked above. If 'front' is 90983c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 91083c41143SJohn Baldwin * Also check for underflow. 91183c41143SJohn Baldwin */ 91283c41143SJohn Baldwin if (front >= start && front <= end_free) { 91383c41143SJohn Baldwin if (bootverbose) 91483c41143SJohn Baldwin printf("\tfront candidate range: %#lx-%#lx\n", 91583c41143SJohn Baldwin front, end_free); 91683c41143SJohn Baldwin front &= (1ul << w->step) - 1; 91783c41143SJohn Baldwin front = rman_get_start(w->res) - front; 91883c41143SJohn Baldwin } else 91983c41143SJohn Baldwin front = 0; 92083c41143SJohn Baldwin } else 92183c41143SJohn Baldwin front = 0; 92283c41143SJohn Baldwin if (end > rman_get_end(w->res)) { 92383c41143SJohn Baldwin if (rman_last_free_region(&w->rman, &start_free, &end_free) != 92483c41143SJohn Baldwin 0 || end_free != rman_get_end(w->res)) 92583c41143SJohn Baldwin start_free = rman_get_end(w->res) + 1; 92683c41143SJohn Baldwin if (start_free < start) 92783c41143SJohn Baldwin start_free = start; 92883c41143SJohn Baldwin 92983c41143SJohn Baldwin /* Move start_free up until it is properly aligned. */ 93083c41143SJohn Baldwin start_free = roundup2(start_free, align); 931a49dcb46SJohn Baldwin back = start_free + count - 1; 93283c41143SJohn Baldwin 93383c41143SJohn Baldwin /* 93483c41143SJohn Baldwin * The resource would now be allocated at (start_free, 93583c41143SJohn Baldwin * back). Ensure that fits in the (start, end) 93683c41143SJohn Baldwin * bounds. start_free is checked above. If 'back' is 93783c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 93883c41143SJohn Baldwin * Also check for overflow. 93983c41143SJohn Baldwin */ 94083c41143SJohn Baldwin if (back <= end && start_free <= back) { 94183c41143SJohn Baldwin if (bootverbose) 94283c41143SJohn Baldwin printf("\tback candidate range: %#lx-%#lx\n", 94383c41143SJohn Baldwin start_free, back); 944a27d4bdcSJohn Baldwin back = roundup2(back + 1, 1ul << w->step) - 1; 94583c41143SJohn Baldwin back -= rman_get_end(w->res); 94683c41143SJohn Baldwin } else 94783c41143SJohn Baldwin back = 0; 94883c41143SJohn Baldwin } else 94983c41143SJohn Baldwin back = 0; 95083c41143SJohn Baldwin 95183c41143SJohn Baldwin /* 95283c41143SJohn Baldwin * Try to allocate the smallest needed region first. 95383c41143SJohn Baldwin * If that fails, fall back to the other region. 95483c41143SJohn Baldwin */ 95583c41143SJohn Baldwin error = ENOSPC; 95683c41143SJohn Baldwin while (front != 0 || back != 0) { 95783c41143SJohn Baldwin if (front != 0 && (front <= back || back == 0)) { 95883c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 95983c41143SJohn Baldwin rman_get_start(w->res) - front, 96083c41143SJohn Baldwin rman_get_end(w->res)); 96183c41143SJohn Baldwin if (error == 0) 96283c41143SJohn Baldwin break; 96383c41143SJohn Baldwin front = 0; 96483c41143SJohn Baldwin } else { 96583c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 96683c41143SJohn Baldwin rman_get_start(w->res), 96783c41143SJohn Baldwin rman_get_end(w->res) + back); 96883c41143SJohn Baldwin if (error == 0) 96983c41143SJohn Baldwin break; 97083c41143SJohn Baldwin back = 0; 97183c41143SJohn Baldwin } 97283c41143SJohn Baldwin } 97383c41143SJohn Baldwin 97483c41143SJohn Baldwin if (error) 97583c41143SJohn Baldwin return (error); 97683c41143SJohn Baldwin if (bootverbose) 97783c41143SJohn Baldwin device_printf(sc->dev, "grew %s window to %#lx-%#lx\n", 97883c41143SJohn Baldwin w->name, rman_get_start(w->res), rman_get_end(w->res)); 97983c41143SJohn Baldwin 98083c41143SJohn Baldwin /* Add the newly allocated region to the resource manager. */ 98183c41143SJohn Baldwin if (w->base != rman_get_start(w->res)) { 98283c41143SJohn Baldwin KASSERT(w->limit == rman_get_end(w->res), ("both ends moved")); 98383c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 98483c41143SJohn Baldwin w->base - 1); 98583c41143SJohn Baldwin } else { 98683c41143SJohn Baldwin KASSERT(w->limit != rman_get_end(w->res), 98783c41143SJohn Baldwin ("neither end moved")); 98883c41143SJohn Baldwin error = rman_manage_region(&w->rman, w->limit + 1, 98983c41143SJohn Baldwin rman_get_end(w->res)); 99083c41143SJohn Baldwin } 99183c41143SJohn Baldwin if (error) { 99283c41143SJohn Baldwin if (bootverbose) 99383c41143SJohn Baldwin device_printf(sc->dev, 99483c41143SJohn Baldwin "failed to expand %s resource manager\n", w->name); 99583c41143SJohn Baldwin bus_adjust_resource(sc->dev, type, w->res, w->base, w->limit); 99683c41143SJohn Baldwin return (error); 99783c41143SJohn Baldwin } 99883c41143SJohn Baldwin 99983c41143SJohn Baldwin updatewin: 100083c41143SJohn Baldwin /* Save the new window. */ 100183c41143SJohn Baldwin w->base = rman_get_start(w->res); 100283c41143SJohn Baldwin w->limit = rman_get_end(w->res); 100383c41143SJohn Baldwin KASSERT((w->base & ((1ul << w->step) - 1)) == 0, 100483c41143SJohn Baldwin ("start address is not aligned")); 100583c41143SJohn Baldwin KASSERT((w->limit & ((1ul << w->step) - 1)) == (1ul << w->step) - 1, 100683c41143SJohn Baldwin ("end address is not aligned")); 100783c41143SJohn Baldwin pcib_write_windows(sc, w->mask); 100883c41143SJohn Baldwin return (0); 100983c41143SJohn Baldwin } 101083c41143SJohn Baldwin 101183c41143SJohn Baldwin /* 101283c41143SJohn Baldwin * We have to trap resource allocation requests and ensure that the bridge 101383c41143SJohn Baldwin * is set up to, or capable of handling them. 101483c41143SJohn Baldwin */ 101583c41143SJohn Baldwin struct resource * 101683c41143SJohn Baldwin pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 101783c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 101883c41143SJohn Baldwin { 101983c41143SJohn Baldwin struct pcib_softc *sc; 102083c41143SJohn Baldwin struct resource *r; 102183c41143SJohn Baldwin 102283c41143SJohn Baldwin sc = device_get_softc(dev); 102383c41143SJohn Baldwin 102483c41143SJohn Baldwin /* 102583c41143SJohn Baldwin * VGA resources are decoded iff the VGA enable bit is set in 102683c41143SJohn Baldwin * the bridge control register. VGA resources do not fall into 102783c41143SJohn Baldwin * the resource windows and are passed up to the parent. 102883c41143SJohn Baldwin */ 102983c41143SJohn Baldwin if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) || 103083c41143SJohn Baldwin (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) { 103183c41143SJohn Baldwin if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) 103283c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, 103383c41143SJohn Baldwin rid, start, end, count, flags)); 103483c41143SJohn Baldwin else 103583c41143SJohn Baldwin return (NULL); 103683c41143SJohn Baldwin } 103783c41143SJohn Baldwin 103883c41143SJohn Baldwin switch (type) { 103983c41143SJohn Baldwin case SYS_RES_IOPORT: 104083c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start, 104183c41143SJohn Baldwin end, count, flags); 104283c41143SJohn Baldwin if (r != NULL) 104383c41143SJohn Baldwin break; 104483c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->io, type, start, end, count, 104583c41143SJohn Baldwin flags) == 0) 104683c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, 104783c41143SJohn Baldwin rid, start, end, count, flags); 104883c41143SJohn Baldwin break; 104983c41143SJohn Baldwin case SYS_RES_MEMORY: 105083c41143SJohn Baldwin /* 105183c41143SJohn Baldwin * For prefetchable resources, prefer the prefetchable 105283c41143SJohn Baldwin * memory window, but fall back to the regular memory 105383c41143SJohn Baldwin * window if that fails. Try both windows before 105483c41143SJohn Baldwin * attempting to grow a window in case the firmware 105583c41143SJohn Baldwin * has used a range in the regular memory window to 105683c41143SJohn Baldwin * map a prefetchable BAR. 105783c41143SJohn Baldwin */ 105883c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 105983c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, type, 106083c41143SJohn Baldwin rid, start, end, count, flags); 106183c41143SJohn Baldwin if (r != NULL) 106283c41143SJohn Baldwin break; 106383c41143SJohn Baldwin } 106483c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid, 106583c41143SJohn Baldwin start, end, count, flags); 106683c41143SJohn Baldwin if (r != NULL) 106783c41143SJohn Baldwin break; 106883c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 106983c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->pmem, type, start, end, 107083c41143SJohn Baldwin count, flags) == 0) { 107183c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, 107283c41143SJohn Baldwin type, rid, start, end, count, flags); 107383c41143SJohn Baldwin if (r != NULL) 107483c41143SJohn Baldwin break; 107583c41143SJohn Baldwin } 107683c41143SJohn Baldwin } 107783c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->mem, type, start, end, count, 107883c41143SJohn Baldwin flags & ~RF_PREFETCHABLE) == 0) 107983c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, 108083c41143SJohn Baldwin rid, start, end, count, flags); 108183c41143SJohn Baldwin break; 108283c41143SJohn Baldwin default: 108383c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 108483c41143SJohn Baldwin start, end, count, flags)); 108583c41143SJohn Baldwin } 108683c41143SJohn Baldwin 108783c41143SJohn Baldwin /* 108883c41143SJohn Baldwin * If attempts to suballocate from the window fail but this is a 108983c41143SJohn Baldwin * subtractive bridge, pass the request up the tree. 109083c41143SJohn Baldwin */ 109183c41143SJohn Baldwin if (sc->flags & PCIB_SUBTRACTIVE && r == NULL) 109283c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 109383c41143SJohn Baldwin start, end, count, flags)); 109483c41143SJohn Baldwin return (r); 109583c41143SJohn Baldwin } 109683c41143SJohn Baldwin 109783c41143SJohn Baldwin int 109883c41143SJohn Baldwin pcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r, 109983c41143SJohn Baldwin u_long start, u_long end) 110083c41143SJohn Baldwin { 110183c41143SJohn Baldwin struct pcib_softc *sc; 110283c41143SJohn Baldwin 110383c41143SJohn Baldwin sc = device_get_softc(bus); 110483c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) 110583c41143SJohn Baldwin return (rman_adjust_resource(r, start, end)); 110683c41143SJohn Baldwin return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 110783c41143SJohn Baldwin } 110883c41143SJohn Baldwin 110983c41143SJohn Baldwin int 111083c41143SJohn Baldwin pcib_release_resource(device_t dev, device_t child, int type, int rid, 111183c41143SJohn Baldwin struct resource *r) 111283c41143SJohn Baldwin { 111383c41143SJohn Baldwin struct pcib_softc *sc; 111483c41143SJohn Baldwin int error; 111583c41143SJohn Baldwin 111683c41143SJohn Baldwin sc = device_get_softc(dev); 111783c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) { 111883c41143SJohn Baldwin if (rman_get_flags(r) & RF_ACTIVE) { 111983c41143SJohn Baldwin error = bus_deactivate_resource(child, type, rid, r); 112083c41143SJohn Baldwin if (error) 112183c41143SJohn Baldwin return (error); 112283c41143SJohn Baldwin } 112383c41143SJohn Baldwin return (rman_release_resource(r)); 112483c41143SJohn Baldwin } 112583c41143SJohn Baldwin return (bus_generic_release_resource(dev, child, type, rid, r)); 112683c41143SJohn Baldwin } 112783c41143SJohn Baldwin #else 1128bb0d0a8eSMike Smith /* 1129bb0d0a8eSMike Smith * We have to trap resource allocation requests and ensure that the bridge 1130bb0d0a8eSMike Smith * is set up to, or capable of handling them. 1131bb0d0a8eSMike Smith */ 11326f0d5884SJohn Baldwin struct resource * 1133bb0d0a8eSMike Smith pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1134bb0d0a8eSMike Smith u_long start, u_long end, u_long count, u_int flags) 1135bb0d0a8eSMike Smith { 1136bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 113726043836SJohn Baldwin const char *name, *suffix; 1138a8b354a8SWarner Losh int ok; 1139bb0d0a8eSMike Smith 1140bb0d0a8eSMike Smith /* 1141bb0d0a8eSMike Smith * Fail the allocation for this range if it's not supported. 1142bb0d0a8eSMike Smith */ 114326043836SJohn Baldwin name = device_get_nameunit(child); 114426043836SJohn Baldwin if (name == NULL) { 114526043836SJohn Baldwin name = ""; 114626043836SJohn Baldwin suffix = ""; 114726043836SJohn Baldwin } else 114826043836SJohn Baldwin suffix = " "; 1149bb0d0a8eSMike Smith switch (type) { 1150bb0d0a8eSMike Smith case SYS_RES_IOPORT: 1151a8b354a8SWarner Losh ok = 0; 1152e4b59fc5SWarner Losh if (!pcib_is_io_open(sc)) 1153e4b59fc5SWarner Losh break; 1154a8b354a8SWarner Losh ok = (start >= sc->iobase && end <= sc->iolimit); 1155d98d9b12SMarcel Moolenaar 1156d98d9b12SMarcel Moolenaar /* 1157d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA I/O addresses when the 1158d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1159d98d9b12SMarcel Moolenaar */ 1160d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_ioport_range(start, end)) 1161d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1162d98d9b12SMarcel Moolenaar 1163e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1164a8b354a8SWarner Losh if (!ok) { 116512b8c86eSWarner Losh if (start < sc->iobase) 116612b8c86eSWarner Losh start = sc->iobase; 116712b8c86eSWarner Losh if (end > sc->iolimit) 116812b8c86eSWarner Losh end = sc->iolimit; 11692daa7a07SWarner Losh if (start < end) 11702daa7a07SWarner Losh ok = 1; 1171a8b354a8SWarner Losh } 11721c54ff33SMatthew N. Dodd } else { 1173e4b59fc5SWarner Losh ok = 1; 11749dffe835SWarner Losh #if 0 1175795dceffSWarner Losh /* 1176795dceffSWarner Losh * If we overlap with the subtractive range, then 1177795dceffSWarner Losh * pick the upper range to use. 1178795dceffSWarner Losh */ 1179795dceffSWarner Losh if (start < sc->iolimit && end > sc->iobase) 1180795dceffSWarner Losh start = sc->iolimit + 1; 11819dffe835SWarner Losh #endif 118212b8c86eSWarner Losh } 1183a8b354a8SWarner Losh if (end < start) { 11842daa7a07SWarner Losh device_printf(dev, "ioport: end (%lx) < start (%lx)\n", 11852daa7a07SWarner Losh end, start); 1186a8b354a8SWarner Losh start = 0; 1187a8b354a8SWarner Losh end = 0; 1188a8b354a8SWarner Losh ok = 0; 1189a8b354a8SWarner Losh } 1190a8b354a8SWarner Losh if (!ok) { 119126043836SJohn Baldwin device_printf(dev, "%s%srequested unsupported I/O " 1192a8b354a8SWarner Losh "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", 119326043836SJohn Baldwin name, suffix, start, end, sc->iobase, sc->iolimit); 1194bb0d0a8eSMike Smith return (NULL); 1195bb0d0a8eSMike Smith } 11964fa59183SMike Smith if (bootverbose) 11972daa7a07SWarner Losh device_printf(dev, 119826043836SJohn Baldwin "%s%srequested I/O range 0x%lx-0x%lx: in range\n", 119926043836SJohn Baldwin name, suffix, start, end); 1200bb0d0a8eSMike Smith break; 1201bb0d0a8eSMike Smith 1202bb0d0a8eSMike Smith case SYS_RES_MEMORY: 1203a8b354a8SWarner Losh ok = 0; 1204a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) 1205a8b354a8SWarner Losh ok = ok || (start >= sc->membase && end <= sc->memlimit); 1206a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) 1207a8b354a8SWarner Losh ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); 1208d98d9b12SMarcel Moolenaar 1209d98d9b12SMarcel Moolenaar /* 1210d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA memory addresses when the 1211d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1212d98d9b12SMarcel Moolenaar */ 1213d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_memory_range(start, end)) 1214d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1215d98d9b12SMarcel Moolenaar 1216e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1217a8b354a8SWarner Losh if (!ok) { 1218a8b354a8SWarner Losh ok = 1; 1219a8b354a8SWarner Losh if (flags & RF_PREFETCHABLE) { 1220a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1221a8b354a8SWarner Losh if (start < sc->pmembase) 1222a8b354a8SWarner Losh start = sc->pmembase; 1223a8b354a8SWarner Losh if (end > sc->pmemlimit) 1224a8b354a8SWarner Losh end = sc->pmemlimit; 1225a8b354a8SWarner Losh } else { 1226a8b354a8SWarner Losh ok = 0; 1227a8b354a8SWarner Losh } 1228a8b354a8SWarner Losh } else { /* non-prefetchable */ 1229a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1230a8b354a8SWarner Losh if (start < sc->membase) 123112b8c86eSWarner Losh start = sc->membase; 123212b8c86eSWarner Losh if (end > sc->memlimit) 123312b8c86eSWarner Losh end = sc->memlimit; 12341c54ff33SMatthew N. Dodd } else { 1235a8b354a8SWarner Losh ok = 0; 1236a8b354a8SWarner Losh } 1237a8b354a8SWarner Losh } 1238a8b354a8SWarner Losh } 1239a8b354a8SWarner Losh } else if (!ok) { 1240e4b59fc5SWarner Losh ok = 1; /* subtractive bridge: always ok */ 12419dffe835SWarner Losh #if 0 1242a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1243795dceffSWarner Losh if (start < sc->memlimit && end > sc->membase) 1244795dceffSWarner Losh start = sc->memlimit + 1; 1245a8b354a8SWarner Losh } 1246a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1247795dceffSWarner Losh if (start < sc->pmemlimit && end > sc->pmembase) 1248795dceffSWarner Losh start = sc->pmemlimit + 1; 12491c54ff33SMatthew N. Dodd } 12509dffe835SWarner Losh #endif 125112b8c86eSWarner Losh } 1252a8b354a8SWarner Losh if (end < start) { 12532daa7a07SWarner Losh device_printf(dev, "memory: end (%lx) < start (%lx)\n", 12542daa7a07SWarner Losh end, start); 1255a8b354a8SWarner Losh start = 0; 1256a8b354a8SWarner Losh end = 0; 1257a8b354a8SWarner Losh ok = 0; 1258a8b354a8SWarner Losh } 1259a8b354a8SWarner Losh if (!ok && bootverbose) 126034428485SWarner Losh device_printf(dev, 126126043836SJohn Baldwin "%s%srequested unsupported memory range %#lx-%#lx " 1262b0a2d4b8SWarner Losh "(decoding %#jx-%#jx, %#jx-%#jx)\n", 126326043836SJohn Baldwin name, suffix, start, end, 1264b0a2d4b8SWarner Losh (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, 1265b0a2d4b8SWarner Losh (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 1266a8b354a8SWarner Losh if (!ok) 1267bb0d0a8eSMike Smith return (NULL); 12684fa59183SMike Smith if (bootverbose) 126926043836SJohn Baldwin device_printf(dev,"%s%srequested memory range " 12702daa7a07SWarner Losh "0x%lx-0x%lx: good\n", 127126043836SJohn Baldwin name, suffix, start, end); 12724fa59183SMike Smith break; 12734fa59183SMike Smith 1274bb0d0a8eSMike Smith default: 12754fa59183SMike Smith break; 1276bb0d0a8eSMike Smith } 1277bb0d0a8eSMike Smith /* 1278bb0d0a8eSMike Smith * Bridge is OK decoding this resource, so pass it up. 1279bb0d0a8eSMike Smith */ 12802daa7a07SWarner Losh return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 12812daa7a07SWarner Losh count, flags)); 1282bb0d0a8eSMike Smith } 128383c41143SJohn Baldwin #endif 1284bb0d0a8eSMike Smith 1285bb0d0a8eSMike Smith /* 1286bb0d0a8eSMike Smith * PCIB interface. 1287bb0d0a8eSMike Smith */ 12886f0d5884SJohn Baldwin int 1289bb0d0a8eSMike Smith pcib_maxslots(device_t dev) 1290bb0d0a8eSMike Smith { 12914fa59183SMike Smith return(PCI_SLOTMAX); 1292bb0d0a8eSMike Smith } 1293bb0d0a8eSMike Smith 1294bb0d0a8eSMike Smith /* 1295bb0d0a8eSMike Smith * Since we are a child of a PCI bus, its parent must support the pcib interface. 1296bb0d0a8eSMike Smith */ 1297b0cb115fSWarner Losh uint32_t 1298795dceffSWarner Losh pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 1299bb0d0a8eSMike Smith { 1300bb0d0a8eSMike Smith return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); 1301bb0d0a8eSMike Smith } 1302bb0d0a8eSMike Smith 13036f0d5884SJohn Baldwin void 1304795dceffSWarner Losh pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) 1305bb0d0a8eSMike Smith { 1306bb0d0a8eSMike Smith PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); 1307bb0d0a8eSMike Smith } 1308bb0d0a8eSMike Smith 1309bb0d0a8eSMike Smith /* 1310bb0d0a8eSMike Smith * Route an interrupt across a PCI bridge. 1311bb0d0a8eSMike Smith */ 13122c2d1d07SBenno Rice int 1313bb0d0a8eSMike Smith pcib_route_interrupt(device_t pcib, device_t dev, int pin) 1314bb0d0a8eSMike Smith { 1315bb0d0a8eSMike Smith device_t bus; 1316bb0d0a8eSMike Smith int parent_intpin; 1317bb0d0a8eSMike Smith int intnum; 1318bb0d0a8eSMike Smith 1319bb0d0a8eSMike Smith /* 1320bb0d0a8eSMike Smith * 1321bb0d0a8eSMike Smith * The PCI standard defines a swizzle of the child-side device/intpin to 1322bb0d0a8eSMike Smith * the parent-side intpin as follows. 1323bb0d0a8eSMike Smith * 1324bb0d0a8eSMike Smith * device = device on child bus 1325bb0d0a8eSMike Smith * child_intpin = intpin on child bus slot (0-3) 1326bb0d0a8eSMike Smith * parent_intpin = intpin on parent bus slot (0-3) 1327bb0d0a8eSMike Smith * 1328bb0d0a8eSMike Smith * parent_intpin = (device + child_intpin) % 4 1329bb0d0a8eSMike Smith */ 1330cdc95e1bSBernd Walter parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; 1331bb0d0a8eSMike Smith 1332bb0d0a8eSMike Smith /* 1333bb0d0a8eSMike Smith * Our parent is a PCI bus. Its parent must export the pcib interface 1334bb0d0a8eSMike Smith * which includes the ability to route interrupts. 1335bb0d0a8eSMike Smith */ 1336bb0d0a8eSMike Smith bus = device_get_parent(pcib); 1337bb0d0a8eSMike Smith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 133839981fedSJohn Baldwin if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { 1339c6a121abSJohn Baldwin device_printf(pcib, "slot %d INT%c is routed to irq %d\n", 1340c6a121abSJohn Baldwin pci_get_slot(dev), 'A' + pin - 1, intnum); 13418046c4b9SMike Smith } 1342bb0d0a8eSMike Smith return(intnum); 1343bb0d0a8eSMike Smith } 1344b173edafSJohn Baldwin 1345e706f7f0SJohn Baldwin /* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ 13469bf4c9c1SJohn Baldwin int 13479bf4c9c1SJohn Baldwin pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 13489bf4c9c1SJohn Baldwin { 1349bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13509bf4c9c1SJohn Baldwin device_t bus; 13519bf4c9c1SJohn Baldwin 135222bf1c7fSJohn Baldwin if (sc->flags & PCIB_DISABLE_MSI) 135322bf1c7fSJohn Baldwin return (ENXIO); 13549bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13559bf4c9c1SJohn Baldwin return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 13569bf4c9c1SJohn Baldwin irqs)); 13579bf4c9c1SJohn Baldwin } 13589bf4c9c1SJohn Baldwin 1359e706f7f0SJohn Baldwin /* Pass request to release MSI/MSI-X messages up to the parent bridge. */ 13609bf4c9c1SJohn Baldwin int 13619bf4c9c1SJohn Baldwin pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 13629bf4c9c1SJohn Baldwin { 13639bf4c9c1SJohn Baldwin device_t bus; 13649bf4c9c1SJohn Baldwin 13659bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13669bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); 13679bf4c9c1SJohn Baldwin } 13689bf4c9c1SJohn Baldwin 13699bf4c9c1SJohn Baldwin /* Pass request to alloc an MSI-X message up to the parent bridge. */ 13709bf4c9c1SJohn Baldwin int 1371e706f7f0SJohn Baldwin pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 13729bf4c9c1SJohn Baldwin { 1373bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13749bf4c9c1SJohn Baldwin device_t bus; 13759bf4c9c1SJohn Baldwin 137622bf1c7fSJohn Baldwin if (sc->flags & PCIB_DISABLE_MSI) 137722bf1c7fSJohn Baldwin return (ENXIO); 13789bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 1379e706f7f0SJohn Baldwin return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 13805fe82bcaSJohn Baldwin } 13815fe82bcaSJohn Baldwin 13829bf4c9c1SJohn Baldwin /* Pass request to release an MSI-X message up to the parent bridge. */ 13839bf4c9c1SJohn Baldwin int 13849bf4c9c1SJohn Baldwin pcib_release_msix(device_t pcib, device_t dev, int irq) 13859bf4c9c1SJohn Baldwin { 13869bf4c9c1SJohn Baldwin device_t bus; 13879bf4c9c1SJohn Baldwin 13889bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13899bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); 13909bf4c9c1SJohn Baldwin } 13919bf4c9c1SJohn Baldwin 1392e706f7f0SJohn Baldwin /* Pass request to map MSI/MSI-X message up to parent bridge. */ 1393e706f7f0SJohn Baldwin int 1394e706f7f0SJohn Baldwin pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 1395e706f7f0SJohn Baldwin uint32_t *data) 1396e706f7f0SJohn Baldwin { 1397e706f7f0SJohn Baldwin device_t bus; 13984522ac77SLuoqi Chen int error; 1399e706f7f0SJohn Baldwin 1400e706f7f0SJohn Baldwin bus = device_get_parent(pcib); 14014522ac77SLuoqi Chen error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 14024522ac77SLuoqi Chen if (error) 14034522ac77SLuoqi Chen return (error); 14044522ac77SLuoqi Chen 14054522ac77SLuoqi Chen pci_ht_map_msi(pcib, *addr); 14064522ac77SLuoqi Chen return (0); 1407e706f7f0SJohn Baldwin } 1408e706f7f0SJohn Baldwin 140962508c53SJohn Baldwin /* Pass request for device power state up to parent bridge. */ 141062508c53SJohn Baldwin int 141162508c53SJohn Baldwin pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 141262508c53SJohn Baldwin { 141362508c53SJohn Baldwin device_t bus; 141462508c53SJohn Baldwin 141562508c53SJohn Baldwin bus = device_get_parent(pcib); 141662508c53SJohn Baldwin return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); 141762508c53SJohn Baldwin } 1418