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 974b7ec270SMarius 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 */ 686*ef888152SJohn Baldwin 687*ef888152SJohn Baldwin /* 688*ef888152SJohn Baldwin * Always enable busmastering on bridges so that transactions 689*ef888152SJohn Baldwin * initiated on the secondary bus are passed through to the 690*ef888152SJohn Baldwin * primary bus. 691*ef888152SJohn Baldwin */ 692*ef888152SJohn Baldwin pci_enable_busmaster(dev); 6936f0d5884SJohn Baldwin } 694bb0d0a8eSMike Smith 69538906aedSJohn Baldwin int 6966f0d5884SJohn Baldwin pcib_attach(device_t dev) 6976f0d5884SJohn Baldwin { 6986f0d5884SJohn Baldwin struct pcib_softc *sc; 6996f0d5884SJohn Baldwin device_t child; 7006f0d5884SJohn Baldwin 7016f0d5884SJohn Baldwin pcib_attach_common(dev); 7026f0d5884SJohn Baldwin sc = device_get_softc(dev); 703bb0d0a8eSMike Smith if (sc->secbus != 0) { 704cea0a895SJohn Baldwin child = device_add_child(dev, "pci", sc->secbus); 705bb0d0a8eSMike Smith if (child != NULL) 706bb0d0a8eSMike Smith return(bus_generic_attach(dev)); 707bb0d0a8eSMike Smith } 708bb0d0a8eSMike Smith 709bb0d0a8eSMike Smith /* no secondary bus; we should have fixed this */ 710bb0d0a8eSMike Smith return(0); 711bb0d0a8eSMike Smith } 712bb0d0a8eSMike Smith 7136f0d5884SJohn Baldwin int 714e36af292SJung-uk Kim pcib_suspend(device_t dev) 715e36af292SJung-uk Kim { 71662508c53SJohn Baldwin device_t pcib; 717e36af292SJung-uk Kim int dstate, error; 718e36af292SJung-uk Kim 719e36af292SJung-uk Kim pcib_cfg_save(device_get_softc(dev)); 720e36af292SJung-uk Kim error = bus_generic_suspend(dev); 721f3e0b109SJung-uk Kim if (error == 0 && pci_do_power_suspend) { 722e36af292SJung-uk Kim dstate = PCI_POWERSTATE_D3; 72362508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 72462508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) 725e36af292SJung-uk Kim pci_set_powerstate(dev, dstate); 726e36af292SJung-uk Kim } 727e36af292SJung-uk Kim return (error); 728e36af292SJung-uk Kim } 729e36af292SJung-uk Kim 730e36af292SJung-uk Kim int 731e36af292SJung-uk Kim pcib_resume(device_t dev) 732e36af292SJung-uk Kim { 73362508c53SJohn Baldwin device_t pcib; 734e36af292SJung-uk Kim 735e36af292SJung-uk Kim if (pci_do_power_resume) { 73662508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 73762508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0) 738e36af292SJung-uk Kim pci_set_powerstate(dev, PCI_POWERSTATE_D0); 739e36af292SJung-uk Kim } 740e36af292SJung-uk Kim pcib_cfg_restore(device_get_softc(dev)); 741e36af292SJung-uk Kim return (bus_generic_resume(dev)); 742e36af292SJung-uk Kim } 743e36af292SJung-uk Kim 744e36af292SJung-uk Kim int 745bb0d0a8eSMike Smith pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 746bb0d0a8eSMike Smith { 747bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 748bb0d0a8eSMike Smith 749bb0d0a8eSMike Smith switch (which) { 75055aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 75155aaf894SMarius Strobl *result = sc->domain; 75255aaf894SMarius Strobl return(0); 753bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 754bb0d0a8eSMike Smith *result = sc->secbus; 755bb0d0a8eSMike Smith return(0); 756bb0d0a8eSMike Smith } 757bb0d0a8eSMike Smith return(ENOENT); 758bb0d0a8eSMike Smith } 759bb0d0a8eSMike Smith 7606f0d5884SJohn Baldwin int 761bb0d0a8eSMike Smith pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 762bb0d0a8eSMike Smith { 763bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 764bb0d0a8eSMike Smith 765bb0d0a8eSMike Smith switch (which) { 76655aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 76755aaf894SMarius Strobl return(EINVAL); 768bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 769bb0d0a8eSMike Smith sc->secbus = value; 77055aaf894SMarius Strobl return(0); 771bb0d0a8eSMike Smith } 772bb0d0a8eSMike Smith return(ENOENT); 773bb0d0a8eSMike Smith } 774bb0d0a8eSMike Smith 77583c41143SJohn Baldwin #ifdef NEW_PCIB 77683c41143SJohn Baldwin /* 77783c41143SJohn Baldwin * Attempt to allocate a resource from the existing resources assigned 77883c41143SJohn Baldwin * to a window. 77983c41143SJohn Baldwin */ 78083c41143SJohn Baldwin static struct resource * 78183c41143SJohn Baldwin pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w, 78283c41143SJohn Baldwin device_t child, int type, int *rid, u_long start, u_long end, u_long count, 78383c41143SJohn Baldwin u_int flags) 78483c41143SJohn Baldwin { 78583c41143SJohn Baldwin struct resource *res; 78683c41143SJohn Baldwin 78783c41143SJohn Baldwin if (!pcib_is_window_open(w)) 78883c41143SJohn Baldwin return (NULL); 78983c41143SJohn Baldwin 79083c41143SJohn Baldwin res = rman_reserve_resource(&w->rman, start, end, count, 79183c41143SJohn Baldwin flags & ~RF_ACTIVE, child); 79283c41143SJohn Baldwin if (res == NULL) 79383c41143SJohn Baldwin return (NULL); 79483c41143SJohn Baldwin 79583c41143SJohn Baldwin if (bootverbose) 79683c41143SJohn Baldwin device_printf(sc->dev, 79783c41143SJohn Baldwin "allocated %s range (%#lx-%#lx) for rid %x of %s\n", 79883c41143SJohn Baldwin w->name, rman_get_start(res), rman_get_end(res), *rid, 79983c41143SJohn Baldwin pcib_child_name(child)); 80083c41143SJohn Baldwin rman_set_rid(res, *rid); 80183c41143SJohn Baldwin 80283c41143SJohn Baldwin /* 80383c41143SJohn Baldwin * If the resource should be active, pass that request up the 80483c41143SJohn Baldwin * tree. This assumes the parent drivers can handle 80583c41143SJohn Baldwin * activating sub-allocated resources. 80683c41143SJohn Baldwin */ 80783c41143SJohn Baldwin if (flags & RF_ACTIVE) { 80883c41143SJohn Baldwin if (bus_activate_resource(child, type, *rid, res) != 0) { 80983c41143SJohn Baldwin rman_release_resource(res); 81083c41143SJohn Baldwin return (NULL); 81183c41143SJohn Baldwin } 81283c41143SJohn Baldwin } 81383c41143SJohn Baldwin 81483c41143SJohn Baldwin return (res); 81583c41143SJohn Baldwin } 81683c41143SJohn Baldwin 81783c41143SJohn Baldwin /* 81883c41143SJohn Baldwin * Attempt to grow a window to make room for a given resource request. 81983c41143SJohn Baldwin * The 'step' parameter is log_2 of the desired I/O window's alignment. 82083c41143SJohn Baldwin */ 82183c41143SJohn Baldwin static int 82283c41143SJohn Baldwin pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, 82383c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 82483c41143SJohn Baldwin { 825a7b5acacSJohn Baldwin u_long align, start_free, end_free, front, back, wmask; 82683c41143SJohn Baldwin int error, rid; 82783c41143SJohn Baldwin 82883c41143SJohn Baldwin /* 82983c41143SJohn Baldwin * Clamp the desired resource range to the maximum address 83083c41143SJohn Baldwin * this window supports. Reject impossible requests. 83183c41143SJohn Baldwin */ 83283c41143SJohn Baldwin if (!w->valid) 83383c41143SJohn Baldwin return (EINVAL); 83483c41143SJohn Baldwin if (end > w->rman.rm_end) 83583c41143SJohn Baldwin end = w->rman.rm_end; 83683c41143SJohn Baldwin if (start + count - 1 > end || start + count < start) 83783c41143SJohn Baldwin return (EINVAL); 838a7b5acacSJohn Baldwin wmask = (1ul << w->step) - 1; 83983c41143SJohn Baldwin 84083c41143SJohn Baldwin /* 84183c41143SJohn Baldwin * If there is no resource at all, just try to allocate enough 84283c41143SJohn Baldwin * aligned space for this resource. 84383c41143SJohn Baldwin */ 84483c41143SJohn Baldwin if (w->res == NULL) { 84583c41143SJohn Baldwin if (RF_ALIGNMENT(flags) < w->step) { 84683c41143SJohn Baldwin flags &= ~RF_ALIGNMENT_MASK; 84783c41143SJohn Baldwin flags |= RF_ALIGNMENT_LOG2(w->step); 84883c41143SJohn Baldwin } 849a7b5acacSJohn Baldwin start &= ~wmask; 850a7b5acacSJohn Baldwin end |= wmask; 85183c41143SJohn Baldwin count = roundup2(count, 1ul << w->step); 85283c41143SJohn Baldwin rid = w->reg; 85383c41143SJohn Baldwin w->res = bus_alloc_resource(sc->dev, type, &rid, start, end, 85483c41143SJohn Baldwin count, flags & ~RF_ACTIVE); 85583c41143SJohn Baldwin if (w->res == NULL) { 85683c41143SJohn Baldwin if (bootverbose) 85783c41143SJohn Baldwin device_printf(sc->dev, 85883c41143SJohn Baldwin "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n", 85983c41143SJohn Baldwin w->name, start, end, count); 86083c41143SJohn Baldwin return (ENXIO); 86183c41143SJohn Baldwin } 86283c41143SJohn Baldwin if (bootverbose) 86383c41143SJohn Baldwin device_printf(sc->dev, 86483c41143SJohn Baldwin "allocated initial %s window of %#lx-%#lx\n", 86583c41143SJohn Baldwin w->name, rman_get_start(w->res), 86683c41143SJohn Baldwin rman_get_end(w->res)); 86783c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 86883c41143SJohn Baldwin rman_get_end(w->res)); 86983c41143SJohn Baldwin if (error) { 87083c41143SJohn Baldwin if (bootverbose) 87183c41143SJohn Baldwin device_printf(sc->dev, 87283c41143SJohn Baldwin "failed to add initial %s window to rman\n", 87383c41143SJohn Baldwin w->name); 87483c41143SJohn Baldwin bus_release_resource(sc->dev, type, w->reg, w->res); 87583c41143SJohn Baldwin w->res = NULL; 87683c41143SJohn Baldwin return (error); 87783c41143SJohn Baldwin } 87883c41143SJohn Baldwin pcib_activate_window(sc, type); 87983c41143SJohn Baldwin goto updatewin; 88083c41143SJohn Baldwin } 88183c41143SJohn Baldwin 88283c41143SJohn Baldwin /* 88383c41143SJohn Baldwin * See if growing the window would help. Compute the minimum 88483c41143SJohn Baldwin * amount of address space needed on both the front and back 88583c41143SJohn Baldwin * ends of the existing window to satisfy the allocation. 88683c41143SJohn Baldwin * 88783c41143SJohn Baldwin * For each end, build a candidate region adjusting for the 88883c41143SJohn Baldwin * required alignment, etc. If there is a free region at the 88983c41143SJohn Baldwin * edge of the window, grow from the inner edge of the free 89083c41143SJohn Baldwin * region. Otherwise grow from the window boundary. 89183c41143SJohn Baldwin * 89283c41143SJohn Baldwin * XXX: Special case: if w->res is completely empty and the 89383c41143SJohn Baldwin * request size is larger than w->res, we should find the 89483c41143SJohn Baldwin * optimal aligned buffer containing w->res and allocate that. 89583c41143SJohn Baldwin */ 89683c41143SJohn Baldwin if (bootverbose) 89783c41143SJohn Baldwin device_printf(sc->dev, 89883c41143SJohn Baldwin "attempting to grow %s window for (%#lx-%#lx,%#lx)\n", 89983c41143SJohn Baldwin w->name, start, end, count); 90083c41143SJohn Baldwin align = 1ul << RF_ALIGNMENT(flags); 90183c41143SJohn Baldwin if (start < rman_get_start(w->res)) { 90283c41143SJohn Baldwin if (rman_first_free_region(&w->rman, &start_free, &end_free) != 90383c41143SJohn Baldwin 0 || start_free != rman_get_start(w->res)) 904ddac8cc9SJohn Baldwin end_free = rman_get_start(w->res); 90583c41143SJohn Baldwin if (end_free > end) 906ddac8cc9SJohn Baldwin end_free = end + 1; 90783c41143SJohn Baldwin 90883c41143SJohn Baldwin /* Move end_free down until it is properly aligned. */ 90983c41143SJohn Baldwin end_free &= ~(align - 1); 910a49dcb46SJohn Baldwin end_free--; 911a49dcb46SJohn Baldwin front = end_free - (count - 1); 91283c41143SJohn Baldwin 91383c41143SJohn Baldwin /* 91483c41143SJohn Baldwin * The resource would now be allocated at (front, 91583c41143SJohn Baldwin * end_free). Ensure that fits in the (start, end) 91683c41143SJohn Baldwin * bounds. end_free is checked above. If 'front' is 91783c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 91883c41143SJohn Baldwin * Also check for underflow. 91983c41143SJohn Baldwin */ 92083c41143SJohn Baldwin if (front >= start && front <= end_free) { 92183c41143SJohn Baldwin if (bootverbose) 92283c41143SJohn Baldwin printf("\tfront candidate range: %#lx-%#lx\n", 92383c41143SJohn Baldwin front, end_free); 924a7b5acacSJohn Baldwin front &= ~wmask; 92583c41143SJohn Baldwin front = rman_get_start(w->res) - front; 92683c41143SJohn Baldwin } else 92783c41143SJohn Baldwin front = 0; 92883c41143SJohn Baldwin } else 92983c41143SJohn Baldwin front = 0; 93083c41143SJohn Baldwin if (end > rman_get_end(w->res)) { 93183c41143SJohn Baldwin if (rman_last_free_region(&w->rman, &start_free, &end_free) != 93283c41143SJohn Baldwin 0 || end_free != rman_get_end(w->res)) 93383c41143SJohn Baldwin start_free = rman_get_end(w->res) + 1; 93483c41143SJohn Baldwin if (start_free < start) 93583c41143SJohn Baldwin start_free = start; 93683c41143SJohn Baldwin 93783c41143SJohn Baldwin /* Move start_free up until it is properly aligned. */ 93883c41143SJohn Baldwin start_free = roundup2(start_free, align); 939a49dcb46SJohn Baldwin back = start_free + count - 1; 94083c41143SJohn Baldwin 94183c41143SJohn Baldwin /* 94283c41143SJohn Baldwin * The resource would now be allocated at (start_free, 94383c41143SJohn Baldwin * back). Ensure that fits in the (start, end) 94483c41143SJohn Baldwin * bounds. start_free is checked above. If 'back' is 94583c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 94683c41143SJohn Baldwin * Also check for overflow. 94783c41143SJohn Baldwin */ 94883c41143SJohn Baldwin if (back <= end && start_free <= back) { 94983c41143SJohn Baldwin if (bootverbose) 95083c41143SJohn Baldwin printf("\tback candidate range: %#lx-%#lx\n", 95183c41143SJohn Baldwin start_free, back); 952a7b5acacSJohn Baldwin back |= wmask; 95383c41143SJohn Baldwin back -= rman_get_end(w->res); 95483c41143SJohn Baldwin } else 95583c41143SJohn Baldwin back = 0; 95683c41143SJohn Baldwin } else 95783c41143SJohn Baldwin back = 0; 95883c41143SJohn Baldwin 95983c41143SJohn Baldwin /* 96083c41143SJohn Baldwin * Try to allocate the smallest needed region first. 96183c41143SJohn Baldwin * If that fails, fall back to the other region. 96283c41143SJohn Baldwin */ 96383c41143SJohn Baldwin error = ENOSPC; 96483c41143SJohn Baldwin while (front != 0 || back != 0) { 96583c41143SJohn Baldwin if (front != 0 && (front <= back || back == 0)) { 96683c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 96783c41143SJohn Baldwin rman_get_start(w->res) - front, 96883c41143SJohn Baldwin rman_get_end(w->res)); 96983c41143SJohn Baldwin if (error == 0) 97083c41143SJohn Baldwin break; 97183c41143SJohn Baldwin front = 0; 97283c41143SJohn Baldwin } else { 97383c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 97483c41143SJohn Baldwin rman_get_start(w->res), 97583c41143SJohn Baldwin rman_get_end(w->res) + back); 97683c41143SJohn Baldwin if (error == 0) 97783c41143SJohn Baldwin break; 97883c41143SJohn Baldwin back = 0; 97983c41143SJohn Baldwin } 98083c41143SJohn Baldwin } 98183c41143SJohn Baldwin 98283c41143SJohn Baldwin if (error) 98383c41143SJohn Baldwin return (error); 98483c41143SJohn Baldwin if (bootverbose) 98583c41143SJohn Baldwin device_printf(sc->dev, "grew %s window to %#lx-%#lx\n", 98683c41143SJohn Baldwin w->name, rman_get_start(w->res), rman_get_end(w->res)); 98783c41143SJohn Baldwin 98883c41143SJohn Baldwin /* Add the newly allocated region to the resource manager. */ 98983c41143SJohn Baldwin if (w->base != rman_get_start(w->res)) { 99083c41143SJohn Baldwin KASSERT(w->limit == rman_get_end(w->res), ("both ends moved")); 99183c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 99283c41143SJohn Baldwin w->base - 1); 99383c41143SJohn Baldwin } else { 99483c41143SJohn Baldwin KASSERT(w->limit != rman_get_end(w->res), 99583c41143SJohn Baldwin ("neither end moved")); 99683c41143SJohn Baldwin error = rman_manage_region(&w->rman, w->limit + 1, 99783c41143SJohn Baldwin rman_get_end(w->res)); 99883c41143SJohn Baldwin } 99983c41143SJohn Baldwin if (error) { 100083c41143SJohn Baldwin if (bootverbose) 100183c41143SJohn Baldwin device_printf(sc->dev, 100283c41143SJohn Baldwin "failed to expand %s resource manager\n", w->name); 100383c41143SJohn Baldwin bus_adjust_resource(sc->dev, type, w->res, w->base, w->limit); 100483c41143SJohn Baldwin return (error); 100583c41143SJohn Baldwin } 100683c41143SJohn Baldwin 100783c41143SJohn Baldwin updatewin: 100883c41143SJohn Baldwin /* Save the new window. */ 100983c41143SJohn Baldwin w->base = rman_get_start(w->res); 101083c41143SJohn Baldwin w->limit = rman_get_end(w->res); 1011a7b5acacSJohn Baldwin KASSERT((w->base & wmask) == 0, ("start address is not aligned")); 1012a7b5acacSJohn Baldwin KASSERT((w->limit & wmask) == wmask, ("end address is not aligned")); 101383c41143SJohn Baldwin pcib_write_windows(sc, w->mask); 101483c41143SJohn Baldwin return (0); 101583c41143SJohn Baldwin } 101683c41143SJohn Baldwin 101783c41143SJohn Baldwin /* 101883c41143SJohn Baldwin * We have to trap resource allocation requests and ensure that the bridge 101983c41143SJohn Baldwin * is set up to, or capable of handling them. 102083c41143SJohn Baldwin */ 102183c41143SJohn Baldwin struct resource * 102283c41143SJohn Baldwin pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 102383c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 102483c41143SJohn Baldwin { 102583c41143SJohn Baldwin struct pcib_softc *sc; 102683c41143SJohn Baldwin struct resource *r; 102783c41143SJohn Baldwin 102883c41143SJohn Baldwin sc = device_get_softc(dev); 102983c41143SJohn Baldwin 103083c41143SJohn Baldwin /* 103183c41143SJohn Baldwin * VGA resources are decoded iff the VGA enable bit is set in 103283c41143SJohn Baldwin * the bridge control register. VGA resources do not fall into 103383c41143SJohn Baldwin * the resource windows and are passed up to the parent. 103483c41143SJohn Baldwin */ 103583c41143SJohn Baldwin if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) || 103683c41143SJohn Baldwin (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) { 103783c41143SJohn Baldwin if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) 103883c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, 103983c41143SJohn Baldwin rid, start, end, count, flags)); 104083c41143SJohn Baldwin else 104183c41143SJohn Baldwin return (NULL); 104283c41143SJohn Baldwin } 104383c41143SJohn Baldwin 104483c41143SJohn Baldwin switch (type) { 104583c41143SJohn Baldwin case SYS_RES_IOPORT: 104683c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start, 104783c41143SJohn Baldwin end, count, flags); 1048a6c82265SMarius Strobl if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 104983c41143SJohn Baldwin break; 105083c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->io, type, start, end, count, 105183c41143SJohn Baldwin flags) == 0) 105283c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, 105383c41143SJohn Baldwin rid, start, end, count, flags); 105483c41143SJohn Baldwin break; 105583c41143SJohn Baldwin case SYS_RES_MEMORY: 105683c41143SJohn Baldwin /* 105783c41143SJohn Baldwin * For prefetchable resources, prefer the prefetchable 105883c41143SJohn Baldwin * memory window, but fall back to the regular memory 105983c41143SJohn Baldwin * window if that fails. Try both windows before 106083c41143SJohn Baldwin * attempting to grow a window in case the firmware 106183c41143SJohn Baldwin * has used a range in the regular memory window to 106283c41143SJohn Baldwin * map a prefetchable BAR. 106383c41143SJohn Baldwin */ 106483c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 106583c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, type, 106683c41143SJohn Baldwin rid, start, end, count, flags); 106783c41143SJohn Baldwin if (r != NULL) 106883c41143SJohn Baldwin break; 106983c41143SJohn Baldwin } 107083c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid, 107183c41143SJohn Baldwin start, end, count, flags); 1072a6c82265SMarius Strobl if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 107383c41143SJohn Baldwin break; 107483c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 107583c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->pmem, type, start, end, 107683c41143SJohn Baldwin count, flags) == 0) { 107783c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, 107883c41143SJohn Baldwin type, rid, start, end, count, flags); 107983c41143SJohn Baldwin if (r != NULL) 108083c41143SJohn Baldwin break; 108183c41143SJohn Baldwin } 108283c41143SJohn Baldwin } 108383c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->mem, type, start, end, count, 108483c41143SJohn Baldwin flags & ~RF_PREFETCHABLE) == 0) 108583c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, 108683c41143SJohn Baldwin rid, start, end, count, flags); 108783c41143SJohn Baldwin break; 108883c41143SJohn Baldwin default: 108983c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 109083c41143SJohn Baldwin start, end, count, flags)); 109183c41143SJohn Baldwin } 109283c41143SJohn Baldwin 109383c41143SJohn Baldwin /* 109483c41143SJohn Baldwin * If attempts to suballocate from the window fail but this is a 109583c41143SJohn Baldwin * subtractive bridge, pass the request up the tree. 109683c41143SJohn Baldwin */ 109783c41143SJohn Baldwin if (sc->flags & PCIB_SUBTRACTIVE && r == NULL) 109883c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 109983c41143SJohn Baldwin start, end, count, flags)); 110083c41143SJohn Baldwin return (r); 110183c41143SJohn Baldwin } 110283c41143SJohn Baldwin 110383c41143SJohn Baldwin int 110483c41143SJohn Baldwin pcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r, 110583c41143SJohn Baldwin u_long start, u_long end) 110683c41143SJohn Baldwin { 110783c41143SJohn Baldwin struct pcib_softc *sc; 110883c41143SJohn Baldwin 110983c41143SJohn Baldwin sc = device_get_softc(bus); 111083c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) 111183c41143SJohn Baldwin return (rman_adjust_resource(r, start, end)); 111283c41143SJohn Baldwin return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 111383c41143SJohn Baldwin } 111483c41143SJohn Baldwin 111583c41143SJohn Baldwin int 111683c41143SJohn Baldwin pcib_release_resource(device_t dev, device_t child, int type, int rid, 111783c41143SJohn Baldwin struct resource *r) 111883c41143SJohn Baldwin { 111983c41143SJohn Baldwin struct pcib_softc *sc; 112083c41143SJohn Baldwin int error; 112183c41143SJohn Baldwin 112283c41143SJohn Baldwin sc = device_get_softc(dev); 112383c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) { 112483c41143SJohn Baldwin if (rman_get_flags(r) & RF_ACTIVE) { 112583c41143SJohn Baldwin error = bus_deactivate_resource(child, type, rid, r); 112683c41143SJohn Baldwin if (error) 112783c41143SJohn Baldwin return (error); 112883c41143SJohn Baldwin } 112983c41143SJohn Baldwin return (rman_release_resource(r)); 113083c41143SJohn Baldwin } 113183c41143SJohn Baldwin return (bus_generic_release_resource(dev, child, type, rid, r)); 113283c41143SJohn Baldwin } 113383c41143SJohn Baldwin #else 1134bb0d0a8eSMike Smith /* 1135bb0d0a8eSMike Smith * We have to trap resource allocation requests and ensure that the bridge 1136bb0d0a8eSMike Smith * is set up to, or capable of handling them. 1137bb0d0a8eSMike Smith */ 11386f0d5884SJohn Baldwin struct resource * 1139bb0d0a8eSMike Smith pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1140bb0d0a8eSMike Smith u_long start, u_long end, u_long count, u_int flags) 1141bb0d0a8eSMike Smith { 1142bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 114326043836SJohn Baldwin const char *name, *suffix; 1144a8b354a8SWarner Losh int ok; 1145bb0d0a8eSMike Smith 1146bb0d0a8eSMike Smith /* 1147bb0d0a8eSMike Smith * Fail the allocation for this range if it's not supported. 1148bb0d0a8eSMike Smith */ 114926043836SJohn Baldwin name = device_get_nameunit(child); 115026043836SJohn Baldwin if (name == NULL) { 115126043836SJohn Baldwin name = ""; 115226043836SJohn Baldwin suffix = ""; 115326043836SJohn Baldwin } else 115426043836SJohn Baldwin suffix = " "; 1155bb0d0a8eSMike Smith switch (type) { 1156bb0d0a8eSMike Smith case SYS_RES_IOPORT: 1157a8b354a8SWarner Losh ok = 0; 1158e4b59fc5SWarner Losh if (!pcib_is_io_open(sc)) 1159e4b59fc5SWarner Losh break; 1160a8b354a8SWarner Losh ok = (start >= sc->iobase && end <= sc->iolimit); 1161d98d9b12SMarcel Moolenaar 1162d98d9b12SMarcel Moolenaar /* 1163d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA I/O addresses when the 1164d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1165d98d9b12SMarcel Moolenaar */ 1166d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_ioport_range(start, end)) 1167d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1168d98d9b12SMarcel Moolenaar 1169e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1170a8b354a8SWarner Losh if (!ok) { 117112b8c86eSWarner Losh if (start < sc->iobase) 117212b8c86eSWarner Losh start = sc->iobase; 117312b8c86eSWarner Losh if (end > sc->iolimit) 117412b8c86eSWarner Losh end = sc->iolimit; 11752daa7a07SWarner Losh if (start < end) 11762daa7a07SWarner Losh ok = 1; 1177a8b354a8SWarner Losh } 11781c54ff33SMatthew N. Dodd } else { 1179e4b59fc5SWarner Losh ok = 1; 11809dffe835SWarner Losh #if 0 1181795dceffSWarner Losh /* 1182795dceffSWarner Losh * If we overlap with the subtractive range, then 1183795dceffSWarner Losh * pick the upper range to use. 1184795dceffSWarner Losh */ 1185795dceffSWarner Losh if (start < sc->iolimit && end > sc->iobase) 1186795dceffSWarner Losh start = sc->iolimit + 1; 11879dffe835SWarner Losh #endif 118812b8c86eSWarner Losh } 1189a8b354a8SWarner Losh if (end < start) { 11902daa7a07SWarner Losh device_printf(dev, "ioport: end (%lx) < start (%lx)\n", 11912daa7a07SWarner Losh end, start); 1192a8b354a8SWarner Losh start = 0; 1193a8b354a8SWarner Losh end = 0; 1194a8b354a8SWarner Losh ok = 0; 1195a8b354a8SWarner Losh } 1196a8b354a8SWarner Losh if (!ok) { 119726043836SJohn Baldwin device_printf(dev, "%s%srequested unsupported I/O " 1198a8b354a8SWarner Losh "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", 119926043836SJohn Baldwin name, suffix, start, end, sc->iobase, sc->iolimit); 1200bb0d0a8eSMike Smith return (NULL); 1201bb0d0a8eSMike Smith } 12024fa59183SMike Smith if (bootverbose) 12032daa7a07SWarner Losh device_printf(dev, 120426043836SJohn Baldwin "%s%srequested I/O range 0x%lx-0x%lx: in range\n", 120526043836SJohn Baldwin name, suffix, start, end); 1206bb0d0a8eSMike Smith break; 1207bb0d0a8eSMike Smith 1208bb0d0a8eSMike Smith case SYS_RES_MEMORY: 1209a8b354a8SWarner Losh ok = 0; 1210a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) 1211a8b354a8SWarner Losh ok = ok || (start >= sc->membase && end <= sc->memlimit); 1212a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) 1213a8b354a8SWarner Losh ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); 1214d98d9b12SMarcel Moolenaar 1215d98d9b12SMarcel Moolenaar /* 1216d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA memory addresses when the 1217d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1218d98d9b12SMarcel Moolenaar */ 1219d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_memory_range(start, end)) 1220d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1221d98d9b12SMarcel Moolenaar 1222e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1223a8b354a8SWarner Losh if (!ok) { 1224a8b354a8SWarner Losh ok = 1; 1225a8b354a8SWarner Losh if (flags & RF_PREFETCHABLE) { 1226a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1227a8b354a8SWarner Losh if (start < sc->pmembase) 1228a8b354a8SWarner Losh start = sc->pmembase; 1229a8b354a8SWarner Losh if (end > sc->pmemlimit) 1230a8b354a8SWarner Losh end = sc->pmemlimit; 1231a8b354a8SWarner Losh } else { 1232a8b354a8SWarner Losh ok = 0; 1233a8b354a8SWarner Losh } 1234a8b354a8SWarner Losh } else { /* non-prefetchable */ 1235a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1236a8b354a8SWarner Losh if (start < sc->membase) 123712b8c86eSWarner Losh start = sc->membase; 123812b8c86eSWarner Losh if (end > sc->memlimit) 123912b8c86eSWarner Losh end = sc->memlimit; 12401c54ff33SMatthew N. Dodd } else { 1241a8b354a8SWarner Losh ok = 0; 1242a8b354a8SWarner Losh } 1243a8b354a8SWarner Losh } 1244a8b354a8SWarner Losh } 1245a8b354a8SWarner Losh } else if (!ok) { 1246e4b59fc5SWarner Losh ok = 1; /* subtractive bridge: always ok */ 12479dffe835SWarner Losh #if 0 1248a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1249795dceffSWarner Losh if (start < sc->memlimit && end > sc->membase) 1250795dceffSWarner Losh start = sc->memlimit + 1; 1251a8b354a8SWarner Losh } 1252a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1253795dceffSWarner Losh if (start < sc->pmemlimit && end > sc->pmembase) 1254795dceffSWarner Losh start = sc->pmemlimit + 1; 12551c54ff33SMatthew N. Dodd } 12569dffe835SWarner Losh #endif 125712b8c86eSWarner Losh } 1258a8b354a8SWarner Losh if (end < start) { 12592daa7a07SWarner Losh device_printf(dev, "memory: end (%lx) < start (%lx)\n", 12602daa7a07SWarner Losh end, start); 1261a8b354a8SWarner Losh start = 0; 1262a8b354a8SWarner Losh end = 0; 1263a8b354a8SWarner Losh ok = 0; 1264a8b354a8SWarner Losh } 1265a8b354a8SWarner Losh if (!ok && bootverbose) 126634428485SWarner Losh device_printf(dev, 126726043836SJohn Baldwin "%s%srequested unsupported memory range %#lx-%#lx " 1268b0a2d4b8SWarner Losh "(decoding %#jx-%#jx, %#jx-%#jx)\n", 126926043836SJohn Baldwin name, suffix, start, end, 1270b0a2d4b8SWarner Losh (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, 1271b0a2d4b8SWarner Losh (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 1272a8b354a8SWarner Losh if (!ok) 1273bb0d0a8eSMike Smith return (NULL); 12744fa59183SMike Smith if (bootverbose) 127526043836SJohn Baldwin device_printf(dev,"%s%srequested memory range " 12762daa7a07SWarner Losh "0x%lx-0x%lx: good\n", 127726043836SJohn Baldwin name, suffix, start, end); 12784fa59183SMike Smith break; 12794fa59183SMike Smith 1280bb0d0a8eSMike Smith default: 12814fa59183SMike Smith break; 1282bb0d0a8eSMike Smith } 1283bb0d0a8eSMike Smith /* 1284bb0d0a8eSMike Smith * Bridge is OK decoding this resource, so pass it up. 1285bb0d0a8eSMike Smith */ 12862daa7a07SWarner Losh return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 12872daa7a07SWarner Losh count, flags)); 1288bb0d0a8eSMike Smith } 128983c41143SJohn Baldwin #endif 1290bb0d0a8eSMike Smith 1291bb0d0a8eSMike Smith /* 1292bb0d0a8eSMike Smith * PCIB interface. 1293bb0d0a8eSMike Smith */ 12946f0d5884SJohn Baldwin int 1295bb0d0a8eSMike Smith pcib_maxslots(device_t dev) 1296bb0d0a8eSMike Smith { 12974fa59183SMike Smith return(PCI_SLOTMAX); 1298bb0d0a8eSMike Smith } 1299bb0d0a8eSMike Smith 1300bb0d0a8eSMike Smith /* 1301bb0d0a8eSMike Smith * Since we are a child of a PCI bus, its parent must support the pcib interface. 1302bb0d0a8eSMike Smith */ 1303b0cb115fSWarner Losh uint32_t 1304795dceffSWarner Losh pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 1305bb0d0a8eSMike Smith { 1306bb0d0a8eSMike Smith return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); 1307bb0d0a8eSMike Smith } 1308bb0d0a8eSMike Smith 13096f0d5884SJohn Baldwin void 1310795dceffSWarner Losh pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) 1311bb0d0a8eSMike Smith { 1312bb0d0a8eSMike Smith PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); 1313bb0d0a8eSMike Smith } 1314bb0d0a8eSMike Smith 1315bb0d0a8eSMike Smith /* 1316bb0d0a8eSMike Smith * Route an interrupt across a PCI bridge. 1317bb0d0a8eSMike Smith */ 13182c2d1d07SBenno Rice int 1319bb0d0a8eSMike Smith pcib_route_interrupt(device_t pcib, device_t dev, int pin) 1320bb0d0a8eSMike Smith { 1321bb0d0a8eSMike Smith device_t bus; 1322bb0d0a8eSMike Smith int parent_intpin; 1323bb0d0a8eSMike Smith int intnum; 1324bb0d0a8eSMike Smith 1325bb0d0a8eSMike Smith /* 1326bb0d0a8eSMike Smith * 1327bb0d0a8eSMike Smith * The PCI standard defines a swizzle of the child-side device/intpin to 1328bb0d0a8eSMike Smith * the parent-side intpin as follows. 1329bb0d0a8eSMike Smith * 1330bb0d0a8eSMike Smith * device = device on child bus 1331bb0d0a8eSMike Smith * child_intpin = intpin on child bus slot (0-3) 1332bb0d0a8eSMike Smith * parent_intpin = intpin on parent bus slot (0-3) 1333bb0d0a8eSMike Smith * 1334bb0d0a8eSMike Smith * parent_intpin = (device + child_intpin) % 4 1335bb0d0a8eSMike Smith */ 1336cdc95e1bSBernd Walter parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; 1337bb0d0a8eSMike Smith 1338bb0d0a8eSMike Smith /* 1339bb0d0a8eSMike Smith * Our parent is a PCI bus. Its parent must export the pcib interface 1340bb0d0a8eSMike Smith * which includes the ability to route interrupts. 1341bb0d0a8eSMike Smith */ 1342bb0d0a8eSMike Smith bus = device_get_parent(pcib); 1343bb0d0a8eSMike Smith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 134439981fedSJohn Baldwin if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { 1345c6a121abSJohn Baldwin device_printf(pcib, "slot %d INT%c is routed to irq %d\n", 1346c6a121abSJohn Baldwin pci_get_slot(dev), 'A' + pin - 1, intnum); 13478046c4b9SMike Smith } 1348bb0d0a8eSMike Smith return(intnum); 1349bb0d0a8eSMike Smith } 1350b173edafSJohn Baldwin 1351e706f7f0SJohn Baldwin /* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ 13529bf4c9c1SJohn Baldwin int 13539bf4c9c1SJohn Baldwin pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 13549bf4c9c1SJohn Baldwin { 1355bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13569bf4c9c1SJohn Baldwin device_t bus; 13579bf4c9c1SJohn Baldwin 135822bf1c7fSJohn Baldwin if (sc->flags & PCIB_DISABLE_MSI) 135922bf1c7fSJohn Baldwin return (ENXIO); 13609bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13619bf4c9c1SJohn Baldwin return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 13629bf4c9c1SJohn Baldwin irqs)); 13639bf4c9c1SJohn Baldwin } 13649bf4c9c1SJohn Baldwin 1365e706f7f0SJohn Baldwin /* Pass request to release MSI/MSI-X messages up to the parent bridge. */ 13669bf4c9c1SJohn Baldwin int 13679bf4c9c1SJohn Baldwin pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 13689bf4c9c1SJohn Baldwin { 13699bf4c9c1SJohn Baldwin device_t bus; 13709bf4c9c1SJohn Baldwin 13719bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13729bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); 13739bf4c9c1SJohn Baldwin } 13749bf4c9c1SJohn Baldwin 13759bf4c9c1SJohn Baldwin /* Pass request to alloc an MSI-X message up to the parent bridge. */ 13769bf4c9c1SJohn Baldwin int 1377e706f7f0SJohn Baldwin pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 13789bf4c9c1SJohn Baldwin { 1379bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13809bf4c9c1SJohn Baldwin device_t bus; 13819bf4c9c1SJohn Baldwin 138222bf1c7fSJohn Baldwin if (sc->flags & PCIB_DISABLE_MSI) 138322bf1c7fSJohn Baldwin return (ENXIO); 13849bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 1385e706f7f0SJohn Baldwin return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 13865fe82bcaSJohn Baldwin } 13875fe82bcaSJohn Baldwin 13889bf4c9c1SJohn Baldwin /* Pass request to release an MSI-X message up to the parent bridge. */ 13899bf4c9c1SJohn Baldwin int 13909bf4c9c1SJohn Baldwin pcib_release_msix(device_t pcib, device_t dev, int irq) 13919bf4c9c1SJohn Baldwin { 13929bf4c9c1SJohn Baldwin device_t bus; 13939bf4c9c1SJohn Baldwin 13949bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13959bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); 13969bf4c9c1SJohn Baldwin } 13979bf4c9c1SJohn Baldwin 1398e706f7f0SJohn Baldwin /* Pass request to map MSI/MSI-X message up to parent bridge. */ 1399e706f7f0SJohn Baldwin int 1400e706f7f0SJohn Baldwin pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 1401e706f7f0SJohn Baldwin uint32_t *data) 1402e706f7f0SJohn Baldwin { 1403e706f7f0SJohn Baldwin device_t bus; 14044522ac77SLuoqi Chen int error; 1405e706f7f0SJohn Baldwin 1406e706f7f0SJohn Baldwin bus = device_get_parent(pcib); 14074522ac77SLuoqi Chen error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 14084522ac77SLuoqi Chen if (error) 14094522ac77SLuoqi Chen return (error); 14104522ac77SLuoqi Chen 14114522ac77SLuoqi Chen pci_ht_map_msi(pcib, *addr); 14124522ac77SLuoqi Chen return (0); 1413e706f7f0SJohn Baldwin } 1414e706f7f0SJohn Baldwin 141562508c53SJohn Baldwin /* Pass request for device power state up to parent bridge. */ 141662508c53SJohn Baldwin int 141762508c53SJohn Baldwin pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 141862508c53SJohn Baldwin { 141962508c53SJohn Baldwin device_t bus; 142062508c53SJohn Baldwin 142162508c53SJohn Baldwin bus = device_get_parent(pcib); 142262508c53SJohn Baldwin return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); 142362508c53SJohn Baldwin } 1424