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)); 103*68e9cbd3SMarius Strobl DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, NULL, NULL); 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 627*68e9cbd3SMarius Strobl if (pci_msix_device_blacklisted(dev)) 628*68e9cbd3SMarius Strobl sc->flags |= PCIB_DISABLE_MSIX; 629*68e9cbd3SMarius Strobl 630e4b59fc5SWarner Losh /* 631e4b59fc5SWarner Losh * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, 632e4b59fc5SWarner Losh * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, 633e4b59fc5SWarner Losh * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. 634e4b59fc5SWarner Losh * This means they act as if they were subtractively decoding 635e4b59fc5SWarner Losh * bridges and pass all transactions. Mark them and real ProgIf 1 636e4b59fc5SWarner Losh * parts as subtractive. 637e4b59fc5SWarner Losh */ 638e4b59fc5SWarner Losh if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || 639657d9f9fSJohn Baldwin pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE) 640e4b59fc5SWarner Losh sc->flags |= PCIB_SUBTRACTIVE; 641e4b59fc5SWarner Losh 64283c41143SJohn Baldwin #ifdef NEW_PCIB 64383c41143SJohn Baldwin pcib_probe_windows(sc); 64483c41143SJohn Baldwin #endif 645bb0d0a8eSMike Smith if (bootverbose) { 64655aaf894SMarius Strobl device_printf(dev, " domain %d\n", sc->domain); 647bb0d0a8eSMike Smith device_printf(dev, " secondary bus %d\n", sc->secbus); 648bb0d0a8eSMike Smith device_printf(dev, " subordinate bus %d\n", sc->subbus); 64983c41143SJohn Baldwin #ifdef NEW_PCIB 65083c41143SJohn Baldwin if (pcib_is_window_open(&sc->io)) 65183c41143SJohn Baldwin device_printf(dev, " I/O decode 0x%jx-0x%jx\n", 65283c41143SJohn Baldwin (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit); 65383c41143SJohn Baldwin if (pcib_is_window_open(&sc->mem)) 65483c41143SJohn Baldwin device_printf(dev, " memory decode 0x%jx-0x%jx\n", 65583c41143SJohn Baldwin (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit); 65683c41143SJohn Baldwin if (pcib_is_window_open(&sc->pmem)) 65783c41143SJohn Baldwin device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 65883c41143SJohn Baldwin (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit); 65983c41143SJohn Baldwin #else 66083c41143SJohn Baldwin if (pcib_is_io_open(sc)) 66183c41143SJohn Baldwin device_printf(dev, " I/O decode 0x%x-0x%x\n", 66283c41143SJohn Baldwin sc->iobase, sc->iolimit); 663b0a2d4b8SWarner Losh if (pcib_is_nonprefetch_open(sc)) 664b0a2d4b8SWarner Losh device_printf(dev, " memory decode 0x%jx-0x%jx\n", 665b0a2d4b8SWarner Losh (uintmax_t)sc->membase, (uintmax_t)sc->memlimit); 666b0a2d4b8SWarner Losh if (pcib_is_prefetch_open(sc)) 667b0a2d4b8SWarner Losh device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 668b0a2d4b8SWarner Losh (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 66983c41143SJohn Baldwin #endif 670b0a2d4b8SWarner Losh else 671b0a2d4b8SWarner Losh device_printf(dev, " no prefetched decode\n"); 672e4b59fc5SWarner Losh if (sc->flags & PCIB_SUBTRACTIVE) 673e4b59fc5SWarner Losh device_printf(dev, " Subtractively decoded bridge.\n"); 674bb0d0a8eSMike Smith } 675bb0d0a8eSMike Smith 676bb0d0a8eSMike Smith /* 677bb0d0a8eSMike Smith * XXX If the secondary bus number is zero, we should assign a bus number 6787e178674SWarner Losh * since the BIOS hasn't, then initialise the bridge. A simple 6797e178674SWarner Losh * bus_alloc_resource with the a couple of busses seems like the right 6807e178674SWarner Losh * approach, but we don't know what busses the BIOS might have already 6817e178674SWarner Losh * assigned to other bridges on this bus that probe later than we do. 6827e178674SWarner Losh * 6837e178674SWarner Losh * If the subordinate bus number is less than the secondary bus number, 684bb0d0a8eSMike Smith * we should pick a better value. One sensible alternative would be to 685bb0d0a8eSMike Smith * pick 255; the only tradeoff here is that configuration transactions 6867e178674SWarner Losh * would be more widely routed than absolutely necessary. We could 6877e178674SWarner Losh * then do a walk of the tree later and fix it. 688bb0d0a8eSMike Smith */ 689ef888152SJohn Baldwin 690ef888152SJohn Baldwin /* 691ef888152SJohn Baldwin * Always enable busmastering on bridges so that transactions 692ef888152SJohn Baldwin * initiated on the secondary bus are passed through to the 693ef888152SJohn Baldwin * primary bus. 694ef888152SJohn Baldwin */ 695ef888152SJohn Baldwin pci_enable_busmaster(dev); 6966f0d5884SJohn Baldwin } 697bb0d0a8eSMike Smith 69838906aedSJohn Baldwin int 6996f0d5884SJohn Baldwin pcib_attach(device_t dev) 7006f0d5884SJohn Baldwin { 7016f0d5884SJohn Baldwin struct pcib_softc *sc; 7026f0d5884SJohn Baldwin device_t child; 7036f0d5884SJohn Baldwin 7046f0d5884SJohn Baldwin pcib_attach_common(dev); 7056f0d5884SJohn Baldwin sc = device_get_softc(dev); 706bb0d0a8eSMike Smith if (sc->secbus != 0) { 707cea0a895SJohn Baldwin child = device_add_child(dev, "pci", sc->secbus); 708bb0d0a8eSMike Smith if (child != NULL) 709bb0d0a8eSMike Smith return(bus_generic_attach(dev)); 710bb0d0a8eSMike Smith } 711bb0d0a8eSMike Smith 712bb0d0a8eSMike Smith /* no secondary bus; we should have fixed this */ 713bb0d0a8eSMike Smith return(0); 714bb0d0a8eSMike Smith } 715bb0d0a8eSMike Smith 7166f0d5884SJohn Baldwin int 717e36af292SJung-uk Kim pcib_suspend(device_t dev) 718e36af292SJung-uk Kim { 71962508c53SJohn Baldwin device_t pcib; 720e36af292SJung-uk Kim int dstate, error; 721e36af292SJung-uk Kim 722e36af292SJung-uk Kim pcib_cfg_save(device_get_softc(dev)); 723e36af292SJung-uk Kim error = bus_generic_suspend(dev); 724f3e0b109SJung-uk Kim if (error == 0 && pci_do_power_suspend) { 725e36af292SJung-uk Kim dstate = PCI_POWERSTATE_D3; 72662508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 72762508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) 728e36af292SJung-uk Kim pci_set_powerstate(dev, dstate); 729e36af292SJung-uk Kim } 730e36af292SJung-uk Kim return (error); 731e36af292SJung-uk Kim } 732e36af292SJung-uk Kim 733e36af292SJung-uk Kim int 734e36af292SJung-uk Kim pcib_resume(device_t dev) 735e36af292SJung-uk Kim { 73662508c53SJohn Baldwin device_t pcib; 737e36af292SJung-uk Kim 738e36af292SJung-uk Kim if (pci_do_power_resume) { 73962508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 74062508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0) 741e36af292SJung-uk Kim pci_set_powerstate(dev, PCI_POWERSTATE_D0); 742e36af292SJung-uk Kim } 743e36af292SJung-uk Kim pcib_cfg_restore(device_get_softc(dev)); 744e36af292SJung-uk Kim return (bus_generic_resume(dev)); 745e36af292SJung-uk Kim } 746e36af292SJung-uk Kim 747e36af292SJung-uk Kim int 748bb0d0a8eSMike Smith pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 749bb0d0a8eSMike Smith { 750bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 751bb0d0a8eSMike Smith 752bb0d0a8eSMike Smith switch (which) { 75355aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 75455aaf894SMarius Strobl *result = sc->domain; 75555aaf894SMarius Strobl return(0); 756bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 757bb0d0a8eSMike Smith *result = sc->secbus; 758bb0d0a8eSMike Smith return(0); 759bb0d0a8eSMike Smith } 760bb0d0a8eSMike Smith return(ENOENT); 761bb0d0a8eSMike Smith } 762bb0d0a8eSMike Smith 7636f0d5884SJohn Baldwin int 764bb0d0a8eSMike Smith pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 765bb0d0a8eSMike Smith { 766bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 767bb0d0a8eSMike Smith 768bb0d0a8eSMike Smith switch (which) { 76955aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 77055aaf894SMarius Strobl return(EINVAL); 771bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 772bb0d0a8eSMike Smith sc->secbus = value; 77355aaf894SMarius Strobl return(0); 774bb0d0a8eSMike Smith } 775bb0d0a8eSMike Smith return(ENOENT); 776bb0d0a8eSMike Smith } 777bb0d0a8eSMike Smith 77883c41143SJohn Baldwin #ifdef NEW_PCIB 77983c41143SJohn Baldwin /* 78083c41143SJohn Baldwin * Attempt to allocate a resource from the existing resources assigned 78183c41143SJohn Baldwin * to a window. 78283c41143SJohn Baldwin */ 78383c41143SJohn Baldwin static struct resource * 78483c41143SJohn Baldwin pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w, 78583c41143SJohn Baldwin device_t child, int type, int *rid, u_long start, u_long end, u_long count, 78683c41143SJohn Baldwin u_int flags) 78783c41143SJohn Baldwin { 78883c41143SJohn Baldwin struct resource *res; 78983c41143SJohn Baldwin 79083c41143SJohn Baldwin if (!pcib_is_window_open(w)) 79183c41143SJohn Baldwin return (NULL); 79283c41143SJohn Baldwin 79383c41143SJohn Baldwin res = rman_reserve_resource(&w->rman, start, end, count, 79483c41143SJohn Baldwin flags & ~RF_ACTIVE, child); 79583c41143SJohn Baldwin if (res == NULL) 79683c41143SJohn Baldwin return (NULL); 79783c41143SJohn Baldwin 79883c41143SJohn Baldwin if (bootverbose) 79983c41143SJohn Baldwin device_printf(sc->dev, 80083c41143SJohn Baldwin "allocated %s range (%#lx-%#lx) for rid %x of %s\n", 80183c41143SJohn Baldwin w->name, rman_get_start(res), rman_get_end(res), *rid, 80283c41143SJohn Baldwin pcib_child_name(child)); 80383c41143SJohn Baldwin rman_set_rid(res, *rid); 80483c41143SJohn Baldwin 80583c41143SJohn Baldwin /* 80683c41143SJohn Baldwin * If the resource should be active, pass that request up the 80783c41143SJohn Baldwin * tree. This assumes the parent drivers can handle 80883c41143SJohn Baldwin * activating sub-allocated resources. 80983c41143SJohn Baldwin */ 81083c41143SJohn Baldwin if (flags & RF_ACTIVE) { 81183c41143SJohn Baldwin if (bus_activate_resource(child, type, *rid, res) != 0) { 81283c41143SJohn Baldwin rman_release_resource(res); 81383c41143SJohn Baldwin return (NULL); 81483c41143SJohn Baldwin } 81583c41143SJohn Baldwin } 81683c41143SJohn Baldwin 81783c41143SJohn Baldwin return (res); 81883c41143SJohn Baldwin } 81983c41143SJohn Baldwin 82083c41143SJohn Baldwin /* 82183c41143SJohn Baldwin * Attempt to grow a window to make room for a given resource request. 82283c41143SJohn Baldwin * The 'step' parameter is log_2 of the desired I/O window's alignment. 82383c41143SJohn Baldwin */ 82483c41143SJohn Baldwin static int 82583c41143SJohn Baldwin pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, 82683c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 82783c41143SJohn Baldwin { 828a7b5acacSJohn Baldwin u_long align, start_free, end_free, front, back, wmask; 82983c41143SJohn Baldwin int error, rid; 83083c41143SJohn Baldwin 83183c41143SJohn Baldwin /* 83283c41143SJohn Baldwin * Clamp the desired resource range to the maximum address 83383c41143SJohn Baldwin * this window supports. Reject impossible requests. 83483c41143SJohn Baldwin */ 83583c41143SJohn Baldwin if (!w->valid) 83683c41143SJohn Baldwin return (EINVAL); 83783c41143SJohn Baldwin if (end > w->rman.rm_end) 83883c41143SJohn Baldwin end = w->rman.rm_end; 83983c41143SJohn Baldwin if (start + count - 1 > end || start + count < start) 84083c41143SJohn Baldwin return (EINVAL); 841a7b5acacSJohn Baldwin wmask = (1ul << w->step) - 1; 84283c41143SJohn Baldwin 84383c41143SJohn Baldwin /* 84483c41143SJohn Baldwin * If there is no resource at all, just try to allocate enough 84583c41143SJohn Baldwin * aligned space for this resource. 84683c41143SJohn Baldwin */ 84783c41143SJohn Baldwin if (w->res == NULL) { 84883c41143SJohn Baldwin if (RF_ALIGNMENT(flags) < w->step) { 84983c41143SJohn Baldwin flags &= ~RF_ALIGNMENT_MASK; 85083c41143SJohn Baldwin flags |= RF_ALIGNMENT_LOG2(w->step); 85183c41143SJohn Baldwin } 852a7b5acacSJohn Baldwin start &= ~wmask; 853a7b5acacSJohn Baldwin end |= wmask; 85483c41143SJohn Baldwin count = roundup2(count, 1ul << w->step); 85583c41143SJohn Baldwin rid = w->reg; 85683c41143SJohn Baldwin w->res = bus_alloc_resource(sc->dev, type, &rid, start, end, 85783c41143SJohn Baldwin count, flags & ~RF_ACTIVE); 85883c41143SJohn Baldwin if (w->res == NULL) { 85983c41143SJohn Baldwin if (bootverbose) 86083c41143SJohn Baldwin device_printf(sc->dev, 86183c41143SJohn Baldwin "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n", 86283c41143SJohn Baldwin w->name, start, end, count); 86383c41143SJohn Baldwin return (ENXIO); 86483c41143SJohn Baldwin } 86583c41143SJohn Baldwin if (bootverbose) 86683c41143SJohn Baldwin device_printf(sc->dev, 86783c41143SJohn Baldwin "allocated initial %s window of %#lx-%#lx\n", 86883c41143SJohn Baldwin w->name, rman_get_start(w->res), 86983c41143SJohn Baldwin rman_get_end(w->res)); 87083c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 87183c41143SJohn Baldwin rman_get_end(w->res)); 87283c41143SJohn Baldwin if (error) { 87383c41143SJohn Baldwin if (bootverbose) 87483c41143SJohn Baldwin device_printf(sc->dev, 87583c41143SJohn Baldwin "failed to add initial %s window to rman\n", 87683c41143SJohn Baldwin w->name); 87783c41143SJohn Baldwin bus_release_resource(sc->dev, type, w->reg, w->res); 87883c41143SJohn Baldwin w->res = NULL; 87983c41143SJohn Baldwin return (error); 88083c41143SJohn Baldwin } 88183c41143SJohn Baldwin pcib_activate_window(sc, type); 88283c41143SJohn Baldwin goto updatewin; 88383c41143SJohn Baldwin } 88483c41143SJohn Baldwin 88583c41143SJohn Baldwin /* 88683c41143SJohn Baldwin * See if growing the window would help. Compute the minimum 88783c41143SJohn Baldwin * amount of address space needed on both the front and back 88883c41143SJohn Baldwin * ends of the existing window to satisfy the allocation. 88983c41143SJohn Baldwin * 89083c41143SJohn Baldwin * For each end, build a candidate region adjusting for the 89183c41143SJohn Baldwin * required alignment, etc. If there is a free region at the 89283c41143SJohn Baldwin * edge of the window, grow from the inner edge of the free 89383c41143SJohn Baldwin * region. Otherwise grow from the window boundary. 89483c41143SJohn Baldwin * 89583c41143SJohn Baldwin * XXX: Special case: if w->res is completely empty and the 89683c41143SJohn Baldwin * request size is larger than w->res, we should find the 89783c41143SJohn Baldwin * optimal aligned buffer containing w->res and allocate that. 89883c41143SJohn Baldwin */ 89983c41143SJohn Baldwin if (bootverbose) 90083c41143SJohn Baldwin device_printf(sc->dev, 90183c41143SJohn Baldwin "attempting to grow %s window for (%#lx-%#lx,%#lx)\n", 90283c41143SJohn Baldwin w->name, start, end, count); 90383c41143SJohn Baldwin align = 1ul << RF_ALIGNMENT(flags); 90483c41143SJohn Baldwin if (start < rman_get_start(w->res)) { 90583c41143SJohn Baldwin if (rman_first_free_region(&w->rman, &start_free, &end_free) != 90683c41143SJohn Baldwin 0 || start_free != rman_get_start(w->res)) 907ddac8cc9SJohn Baldwin end_free = rman_get_start(w->res); 90883c41143SJohn Baldwin if (end_free > end) 909ddac8cc9SJohn Baldwin end_free = end + 1; 91083c41143SJohn Baldwin 91183c41143SJohn Baldwin /* Move end_free down until it is properly aligned. */ 91283c41143SJohn Baldwin end_free &= ~(align - 1); 913a49dcb46SJohn Baldwin end_free--; 914a49dcb46SJohn Baldwin front = end_free - (count - 1); 91583c41143SJohn Baldwin 91683c41143SJohn Baldwin /* 91783c41143SJohn Baldwin * The resource would now be allocated at (front, 91883c41143SJohn Baldwin * end_free). Ensure that fits in the (start, end) 91983c41143SJohn Baldwin * bounds. end_free is checked above. If 'front' is 92083c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 92183c41143SJohn Baldwin * Also check for underflow. 92283c41143SJohn Baldwin */ 92383c41143SJohn Baldwin if (front >= start && front <= end_free) { 92483c41143SJohn Baldwin if (bootverbose) 92583c41143SJohn Baldwin printf("\tfront candidate range: %#lx-%#lx\n", 92683c41143SJohn Baldwin front, end_free); 927a7b5acacSJohn Baldwin front &= ~wmask; 92883c41143SJohn Baldwin front = rman_get_start(w->res) - front; 92983c41143SJohn Baldwin } else 93083c41143SJohn Baldwin front = 0; 93183c41143SJohn Baldwin } else 93283c41143SJohn Baldwin front = 0; 93383c41143SJohn Baldwin if (end > rman_get_end(w->res)) { 93483c41143SJohn Baldwin if (rman_last_free_region(&w->rman, &start_free, &end_free) != 93583c41143SJohn Baldwin 0 || end_free != rman_get_end(w->res)) 93683c41143SJohn Baldwin start_free = rman_get_end(w->res) + 1; 93783c41143SJohn Baldwin if (start_free < start) 93883c41143SJohn Baldwin start_free = start; 93983c41143SJohn Baldwin 94083c41143SJohn Baldwin /* Move start_free up until it is properly aligned. */ 94183c41143SJohn Baldwin start_free = roundup2(start_free, align); 942a49dcb46SJohn Baldwin back = start_free + count - 1; 94383c41143SJohn Baldwin 94483c41143SJohn Baldwin /* 94583c41143SJohn Baldwin * The resource would now be allocated at (start_free, 94683c41143SJohn Baldwin * back). Ensure that fits in the (start, end) 94783c41143SJohn Baldwin * bounds. start_free is checked above. If 'back' is 94883c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 94983c41143SJohn Baldwin * Also check for overflow. 95083c41143SJohn Baldwin */ 95183c41143SJohn Baldwin if (back <= end && start_free <= back) { 95283c41143SJohn Baldwin if (bootverbose) 95383c41143SJohn Baldwin printf("\tback candidate range: %#lx-%#lx\n", 95483c41143SJohn Baldwin start_free, back); 955a7b5acacSJohn Baldwin back |= wmask; 95683c41143SJohn Baldwin back -= rman_get_end(w->res); 95783c41143SJohn Baldwin } else 95883c41143SJohn Baldwin back = 0; 95983c41143SJohn Baldwin } else 96083c41143SJohn Baldwin back = 0; 96183c41143SJohn Baldwin 96283c41143SJohn Baldwin /* 96383c41143SJohn Baldwin * Try to allocate the smallest needed region first. 96483c41143SJohn Baldwin * If that fails, fall back to the other region. 96583c41143SJohn Baldwin */ 96683c41143SJohn Baldwin error = ENOSPC; 96783c41143SJohn Baldwin while (front != 0 || back != 0) { 96883c41143SJohn Baldwin if (front != 0 && (front <= back || back == 0)) { 96983c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 97083c41143SJohn Baldwin rman_get_start(w->res) - front, 97183c41143SJohn Baldwin rman_get_end(w->res)); 97283c41143SJohn Baldwin if (error == 0) 97383c41143SJohn Baldwin break; 97483c41143SJohn Baldwin front = 0; 97583c41143SJohn Baldwin } else { 97683c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 97783c41143SJohn Baldwin rman_get_start(w->res), 97883c41143SJohn Baldwin rman_get_end(w->res) + back); 97983c41143SJohn Baldwin if (error == 0) 98083c41143SJohn Baldwin break; 98183c41143SJohn Baldwin back = 0; 98283c41143SJohn Baldwin } 98383c41143SJohn Baldwin } 98483c41143SJohn Baldwin 98583c41143SJohn Baldwin if (error) 98683c41143SJohn Baldwin return (error); 98783c41143SJohn Baldwin if (bootverbose) 98883c41143SJohn Baldwin device_printf(sc->dev, "grew %s window to %#lx-%#lx\n", 98983c41143SJohn Baldwin w->name, rman_get_start(w->res), rman_get_end(w->res)); 99083c41143SJohn Baldwin 99183c41143SJohn Baldwin /* Add the newly allocated region to the resource manager. */ 99283c41143SJohn Baldwin if (w->base != rman_get_start(w->res)) { 99383c41143SJohn Baldwin KASSERT(w->limit == rman_get_end(w->res), ("both ends moved")); 99483c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 99583c41143SJohn Baldwin w->base - 1); 99683c41143SJohn Baldwin } else { 99783c41143SJohn Baldwin KASSERT(w->limit != rman_get_end(w->res), 99883c41143SJohn Baldwin ("neither end moved")); 99983c41143SJohn Baldwin error = rman_manage_region(&w->rman, w->limit + 1, 100083c41143SJohn Baldwin rman_get_end(w->res)); 100183c41143SJohn Baldwin } 100283c41143SJohn Baldwin if (error) { 100383c41143SJohn Baldwin if (bootverbose) 100483c41143SJohn Baldwin device_printf(sc->dev, 100583c41143SJohn Baldwin "failed to expand %s resource manager\n", w->name); 100683c41143SJohn Baldwin bus_adjust_resource(sc->dev, type, w->res, w->base, w->limit); 100783c41143SJohn Baldwin return (error); 100883c41143SJohn Baldwin } 100983c41143SJohn Baldwin 101083c41143SJohn Baldwin updatewin: 101183c41143SJohn Baldwin /* Save the new window. */ 101283c41143SJohn Baldwin w->base = rman_get_start(w->res); 101383c41143SJohn Baldwin w->limit = rman_get_end(w->res); 1014a7b5acacSJohn Baldwin KASSERT((w->base & wmask) == 0, ("start address is not aligned")); 1015a7b5acacSJohn Baldwin KASSERT((w->limit & wmask) == wmask, ("end address is not aligned")); 101683c41143SJohn Baldwin pcib_write_windows(sc, w->mask); 101783c41143SJohn Baldwin return (0); 101883c41143SJohn Baldwin } 101983c41143SJohn Baldwin 102083c41143SJohn Baldwin /* 102183c41143SJohn Baldwin * We have to trap resource allocation requests and ensure that the bridge 102283c41143SJohn Baldwin * is set up to, or capable of handling them. 102383c41143SJohn Baldwin */ 102483c41143SJohn Baldwin struct resource * 102583c41143SJohn Baldwin pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 102683c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 102783c41143SJohn Baldwin { 102883c41143SJohn Baldwin struct pcib_softc *sc; 102983c41143SJohn Baldwin struct resource *r; 103083c41143SJohn Baldwin 103183c41143SJohn Baldwin sc = device_get_softc(dev); 103283c41143SJohn Baldwin 103383c41143SJohn Baldwin /* 103483c41143SJohn Baldwin * VGA resources are decoded iff the VGA enable bit is set in 103583c41143SJohn Baldwin * the bridge control register. VGA resources do not fall into 103683c41143SJohn Baldwin * the resource windows and are passed up to the parent. 103783c41143SJohn Baldwin */ 103883c41143SJohn Baldwin if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) || 103983c41143SJohn Baldwin (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) { 104083c41143SJohn Baldwin if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) 104183c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, 104283c41143SJohn Baldwin rid, start, end, count, flags)); 104383c41143SJohn Baldwin else 104483c41143SJohn Baldwin return (NULL); 104583c41143SJohn Baldwin } 104683c41143SJohn Baldwin 104783c41143SJohn Baldwin switch (type) { 104883c41143SJohn Baldwin case SYS_RES_IOPORT: 104983c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start, 105083c41143SJohn Baldwin end, count, flags); 1051a6c82265SMarius Strobl if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 105283c41143SJohn Baldwin break; 105383c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->io, type, start, end, count, 105483c41143SJohn Baldwin flags) == 0) 105583c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, 105683c41143SJohn Baldwin rid, start, end, count, flags); 105783c41143SJohn Baldwin break; 105883c41143SJohn Baldwin case SYS_RES_MEMORY: 105983c41143SJohn Baldwin /* 106083c41143SJohn Baldwin * For prefetchable resources, prefer the prefetchable 106183c41143SJohn Baldwin * memory window, but fall back to the regular memory 106283c41143SJohn Baldwin * window if that fails. Try both windows before 106383c41143SJohn Baldwin * attempting to grow a window in case the firmware 106483c41143SJohn Baldwin * has used a range in the regular memory window to 106583c41143SJohn Baldwin * map a prefetchable BAR. 106683c41143SJohn Baldwin */ 106783c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 106883c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, type, 106983c41143SJohn Baldwin rid, start, end, count, flags); 107083c41143SJohn Baldwin if (r != NULL) 107183c41143SJohn Baldwin break; 107283c41143SJohn Baldwin } 107383c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid, 107483c41143SJohn Baldwin start, end, count, flags); 1075a6c82265SMarius Strobl if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 107683c41143SJohn Baldwin break; 107783c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 107883c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->pmem, type, start, end, 107983c41143SJohn Baldwin count, flags) == 0) { 108083c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, 108183c41143SJohn Baldwin type, rid, start, end, count, flags); 108283c41143SJohn Baldwin if (r != NULL) 108383c41143SJohn Baldwin break; 108483c41143SJohn Baldwin } 108583c41143SJohn Baldwin } 108683c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->mem, type, start, end, count, 108783c41143SJohn Baldwin flags & ~RF_PREFETCHABLE) == 0) 108883c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, 108983c41143SJohn Baldwin rid, start, end, count, flags); 109083c41143SJohn Baldwin break; 109183c41143SJohn Baldwin default: 109283c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 109383c41143SJohn Baldwin start, end, count, flags)); 109483c41143SJohn Baldwin } 109583c41143SJohn Baldwin 109683c41143SJohn Baldwin /* 109783c41143SJohn Baldwin * If attempts to suballocate from the window fail but this is a 109883c41143SJohn Baldwin * subtractive bridge, pass the request up the tree. 109983c41143SJohn Baldwin */ 110083c41143SJohn Baldwin if (sc->flags & PCIB_SUBTRACTIVE && r == NULL) 110183c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 110283c41143SJohn Baldwin start, end, count, flags)); 110383c41143SJohn Baldwin return (r); 110483c41143SJohn Baldwin } 110583c41143SJohn Baldwin 110683c41143SJohn Baldwin int 110783c41143SJohn Baldwin pcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r, 110883c41143SJohn Baldwin u_long start, u_long end) 110983c41143SJohn Baldwin { 111083c41143SJohn Baldwin struct pcib_softc *sc; 111183c41143SJohn Baldwin 111283c41143SJohn Baldwin sc = device_get_softc(bus); 111383c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) 111483c41143SJohn Baldwin return (rman_adjust_resource(r, start, end)); 111583c41143SJohn Baldwin return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 111683c41143SJohn Baldwin } 111783c41143SJohn Baldwin 111883c41143SJohn Baldwin int 111983c41143SJohn Baldwin pcib_release_resource(device_t dev, device_t child, int type, int rid, 112083c41143SJohn Baldwin struct resource *r) 112183c41143SJohn Baldwin { 112283c41143SJohn Baldwin struct pcib_softc *sc; 112383c41143SJohn Baldwin int error; 112483c41143SJohn Baldwin 112583c41143SJohn Baldwin sc = device_get_softc(dev); 112683c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) { 112783c41143SJohn Baldwin if (rman_get_flags(r) & RF_ACTIVE) { 112883c41143SJohn Baldwin error = bus_deactivate_resource(child, type, rid, r); 112983c41143SJohn Baldwin if (error) 113083c41143SJohn Baldwin return (error); 113183c41143SJohn Baldwin } 113283c41143SJohn Baldwin return (rman_release_resource(r)); 113383c41143SJohn Baldwin } 113483c41143SJohn Baldwin return (bus_generic_release_resource(dev, child, type, rid, r)); 113583c41143SJohn Baldwin } 113683c41143SJohn Baldwin #else 1137bb0d0a8eSMike Smith /* 1138bb0d0a8eSMike Smith * We have to trap resource allocation requests and ensure that the bridge 1139bb0d0a8eSMike Smith * is set up to, or capable of handling them. 1140bb0d0a8eSMike Smith */ 11416f0d5884SJohn Baldwin struct resource * 1142bb0d0a8eSMike Smith pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1143bb0d0a8eSMike Smith u_long start, u_long end, u_long count, u_int flags) 1144bb0d0a8eSMike Smith { 1145bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 114626043836SJohn Baldwin const char *name, *suffix; 1147a8b354a8SWarner Losh int ok; 1148bb0d0a8eSMike Smith 1149bb0d0a8eSMike Smith /* 1150bb0d0a8eSMike Smith * Fail the allocation for this range if it's not supported. 1151bb0d0a8eSMike Smith */ 115226043836SJohn Baldwin name = device_get_nameunit(child); 115326043836SJohn Baldwin if (name == NULL) { 115426043836SJohn Baldwin name = ""; 115526043836SJohn Baldwin suffix = ""; 115626043836SJohn Baldwin } else 115726043836SJohn Baldwin suffix = " "; 1158bb0d0a8eSMike Smith switch (type) { 1159bb0d0a8eSMike Smith case SYS_RES_IOPORT: 1160a8b354a8SWarner Losh ok = 0; 1161e4b59fc5SWarner Losh if (!pcib_is_io_open(sc)) 1162e4b59fc5SWarner Losh break; 1163a8b354a8SWarner Losh ok = (start >= sc->iobase && end <= sc->iolimit); 1164d98d9b12SMarcel Moolenaar 1165d98d9b12SMarcel Moolenaar /* 1166d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA I/O addresses when the 1167d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1168d98d9b12SMarcel Moolenaar */ 1169d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_ioport_range(start, end)) 1170d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1171d98d9b12SMarcel Moolenaar 1172e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1173a8b354a8SWarner Losh if (!ok) { 117412b8c86eSWarner Losh if (start < sc->iobase) 117512b8c86eSWarner Losh start = sc->iobase; 117612b8c86eSWarner Losh if (end > sc->iolimit) 117712b8c86eSWarner Losh end = sc->iolimit; 11782daa7a07SWarner Losh if (start < end) 11792daa7a07SWarner Losh ok = 1; 1180a8b354a8SWarner Losh } 11811c54ff33SMatthew N. Dodd } else { 1182e4b59fc5SWarner Losh ok = 1; 11839dffe835SWarner Losh #if 0 1184795dceffSWarner Losh /* 1185795dceffSWarner Losh * If we overlap with the subtractive range, then 1186795dceffSWarner Losh * pick the upper range to use. 1187795dceffSWarner Losh */ 1188795dceffSWarner Losh if (start < sc->iolimit && end > sc->iobase) 1189795dceffSWarner Losh start = sc->iolimit + 1; 11909dffe835SWarner Losh #endif 119112b8c86eSWarner Losh } 1192a8b354a8SWarner Losh if (end < start) { 11932daa7a07SWarner Losh device_printf(dev, "ioport: end (%lx) < start (%lx)\n", 11942daa7a07SWarner Losh end, start); 1195a8b354a8SWarner Losh start = 0; 1196a8b354a8SWarner Losh end = 0; 1197a8b354a8SWarner Losh ok = 0; 1198a8b354a8SWarner Losh } 1199a8b354a8SWarner Losh if (!ok) { 120026043836SJohn Baldwin device_printf(dev, "%s%srequested unsupported I/O " 1201a8b354a8SWarner Losh "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", 120226043836SJohn Baldwin name, suffix, start, end, sc->iobase, sc->iolimit); 1203bb0d0a8eSMike Smith return (NULL); 1204bb0d0a8eSMike Smith } 12054fa59183SMike Smith if (bootverbose) 12062daa7a07SWarner Losh device_printf(dev, 120726043836SJohn Baldwin "%s%srequested I/O range 0x%lx-0x%lx: in range\n", 120826043836SJohn Baldwin name, suffix, start, end); 1209bb0d0a8eSMike Smith break; 1210bb0d0a8eSMike Smith 1211bb0d0a8eSMike Smith case SYS_RES_MEMORY: 1212a8b354a8SWarner Losh ok = 0; 1213a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) 1214a8b354a8SWarner Losh ok = ok || (start >= sc->membase && end <= sc->memlimit); 1215a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) 1216a8b354a8SWarner Losh ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); 1217d98d9b12SMarcel Moolenaar 1218d98d9b12SMarcel Moolenaar /* 1219d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA memory addresses when the 1220d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1221d98d9b12SMarcel Moolenaar */ 1222d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_memory_range(start, end)) 1223d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1224d98d9b12SMarcel Moolenaar 1225e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1226a8b354a8SWarner Losh if (!ok) { 1227a8b354a8SWarner Losh ok = 1; 1228a8b354a8SWarner Losh if (flags & RF_PREFETCHABLE) { 1229a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1230a8b354a8SWarner Losh if (start < sc->pmembase) 1231a8b354a8SWarner Losh start = sc->pmembase; 1232a8b354a8SWarner Losh if (end > sc->pmemlimit) 1233a8b354a8SWarner Losh end = sc->pmemlimit; 1234a8b354a8SWarner Losh } else { 1235a8b354a8SWarner Losh ok = 0; 1236a8b354a8SWarner Losh } 1237a8b354a8SWarner Losh } else { /* non-prefetchable */ 1238a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1239a8b354a8SWarner Losh if (start < sc->membase) 124012b8c86eSWarner Losh start = sc->membase; 124112b8c86eSWarner Losh if (end > sc->memlimit) 124212b8c86eSWarner Losh end = sc->memlimit; 12431c54ff33SMatthew N. Dodd } else { 1244a8b354a8SWarner Losh ok = 0; 1245a8b354a8SWarner Losh } 1246a8b354a8SWarner Losh } 1247a8b354a8SWarner Losh } 1248a8b354a8SWarner Losh } else if (!ok) { 1249e4b59fc5SWarner Losh ok = 1; /* subtractive bridge: always ok */ 12509dffe835SWarner Losh #if 0 1251a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1252795dceffSWarner Losh if (start < sc->memlimit && end > sc->membase) 1253795dceffSWarner Losh start = sc->memlimit + 1; 1254a8b354a8SWarner Losh } 1255a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1256795dceffSWarner Losh if (start < sc->pmemlimit && end > sc->pmembase) 1257795dceffSWarner Losh start = sc->pmemlimit + 1; 12581c54ff33SMatthew N. Dodd } 12599dffe835SWarner Losh #endif 126012b8c86eSWarner Losh } 1261a8b354a8SWarner Losh if (end < start) { 12622daa7a07SWarner Losh device_printf(dev, "memory: end (%lx) < start (%lx)\n", 12632daa7a07SWarner Losh end, start); 1264a8b354a8SWarner Losh start = 0; 1265a8b354a8SWarner Losh end = 0; 1266a8b354a8SWarner Losh ok = 0; 1267a8b354a8SWarner Losh } 1268a8b354a8SWarner Losh if (!ok && bootverbose) 126934428485SWarner Losh device_printf(dev, 127026043836SJohn Baldwin "%s%srequested unsupported memory range %#lx-%#lx " 1271b0a2d4b8SWarner Losh "(decoding %#jx-%#jx, %#jx-%#jx)\n", 127226043836SJohn Baldwin name, suffix, start, end, 1273b0a2d4b8SWarner Losh (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, 1274b0a2d4b8SWarner Losh (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 1275a8b354a8SWarner Losh if (!ok) 1276bb0d0a8eSMike Smith return (NULL); 12774fa59183SMike Smith if (bootverbose) 127826043836SJohn Baldwin device_printf(dev,"%s%srequested memory range " 12792daa7a07SWarner Losh "0x%lx-0x%lx: good\n", 128026043836SJohn Baldwin name, suffix, start, end); 12814fa59183SMike Smith break; 12824fa59183SMike Smith 1283bb0d0a8eSMike Smith default: 12844fa59183SMike Smith break; 1285bb0d0a8eSMike Smith } 1286bb0d0a8eSMike Smith /* 1287bb0d0a8eSMike Smith * Bridge is OK decoding this resource, so pass it up. 1288bb0d0a8eSMike Smith */ 12892daa7a07SWarner Losh return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 12902daa7a07SWarner Losh count, flags)); 1291bb0d0a8eSMike Smith } 129283c41143SJohn Baldwin #endif 1293bb0d0a8eSMike Smith 1294bb0d0a8eSMike Smith /* 1295bb0d0a8eSMike Smith * PCIB interface. 1296bb0d0a8eSMike Smith */ 12976f0d5884SJohn Baldwin int 1298bb0d0a8eSMike Smith pcib_maxslots(device_t dev) 1299bb0d0a8eSMike Smith { 13004fa59183SMike Smith return(PCI_SLOTMAX); 1301bb0d0a8eSMike Smith } 1302bb0d0a8eSMike Smith 1303bb0d0a8eSMike Smith /* 1304bb0d0a8eSMike Smith * Since we are a child of a PCI bus, its parent must support the pcib interface. 1305bb0d0a8eSMike Smith */ 1306b0cb115fSWarner Losh uint32_t 1307795dceffSWarner Losh pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 1308bb0d0a8eSMike Smith { 1309bb0d0a8eSMike Smith return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); 1310bb0d0a8eSMike Smith } 1311bb0d0a8eSMike Smith 13126f0d5884SJohn Baldwin void 1313795dceffSWarner Losh pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) 1314bb0d0a8eSMike Smith { 1315bb0d0a8eSMike Smith PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); 1316bb0d0a8eSMike Smith } 1317bb0d0a8eSMike Smith 1318bb0d0a8eSMike Smith /* 1319bb0d0a8eSMike Smith * Route an interrupt across a PCI bridge. 1320bb0d0a8eSMike Smith */ 13212c2d1d07SBenno Rice int 1322bb0d0a8eSMike Smith pcib_route_interrupt(device_t pcib, device_t dev, int pin) 1323bb0d0a8eSMike Smith { 1324bb0d0a8eSMike Smith device_t bus; 1325bb0d0a8eSMike Smith int parent_intpin; 1326bb0d0a8eSMike Smith int intnum; 1327bb0d0a8eSMike Smith 1328bb0d0a8eSMike Smith /* 1329bb0d0a8eSMike Smith * 1330bb0d0a8eSMike Smith * The PCI standard defines a swizzle of the child-side device/intpin to 1331bb0d0a8eSMike Smith * the parent-side intpin as follows. 1332bb0d0a8eSMike Smith * 1333bb0d0a8eSMike Smith * device = device on child bus 1334bb0d0a8eSMike Smith * child_intpin = intpin on child bus slot (0-3) 1335bb0d0a8eSMike Smith * parent_intpin = intpin on parent bus slot (0-3) 1336bb0d0a8eSMike Smith * 1337bb0d0a8eSMike Smith * parent_intpin = (device + child_intpin) % 4 1338bb0d0a8eSMike Smith */ 1339cdc95e1bSBernd Walter parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; 1340bb0d0a8eSMike Smith 1341bb0d0a8eSMike Smith /* 1342bb0d0a8eSMike Smith * Our parent is a PCI bus. Its parent must export the pcib interface 1343bb0d0a8eSMike Smith * which includes the ability to route interrupts. 1344bb0d0a8eSMike Smith */ 1345bb0d0a8eSMike Smith bus = device_get_parent(pcib); 1346bb0d0a8eSMike Smith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 134739981fedSJohn Baldwin if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { 1348c6a121abSJohn Baldwin device_printf(pcib, "slot %d INT%c is routed to irq %d\n", 1349c6a121abSJohn Baldwin pci_get_slot(dev), 'A' + pin - 1, intnum); 13508046c4b9SMike Smith } 1351bb0d0a8eSMike Smith return(intnum); 1352bb0d0a8eSMike Smith } 1353b173edafSJohn Baldwin 1354e706f7f0SJohn Baldwin /* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ 13559bf4c9c1SJohn Baldwin int 13569bf4c9c1SJohn Baldwin pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 13579bf4c9c1SJohn Baldwin { 1358bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13599bf4c9c1SJohn Baldwin device_t bus; 13609bf4c9c1SJohn Baldwin 136122bf1c7fSJohn Baldwin if (sc->flags & PCIB_DISABLE_MSI) 136222bf1c7fSJohn Baldwin return (ENXIO); 13639bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13649bf4c9c1SJohn Baldwin return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 13659bf4c9c1SJohn Baldwin irqs)); 13669bf4c9c1SJohn Baldwin } 13679bf4c9c1SJohn Baldwin 1368e706f7f0SJohn Baldwin /* Pass request to release MSI/MSI-X messages up to the parent bridge. */ 13699bf4c9c1SJohn Baldwin int 13709bf4c9c1SJohn Baldwin pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 13719bf4c9c1SJohn Baldwin { 13729bf4c9c1SJohn Baldwin device_t bus; 13739bf4c9c1SJohn Baldwin 13749bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13759bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); 13769bf4c9c1SJohn Baldwin } 13779bf4c9c1SJohn Baldwin 13789bf4c9c1SJohn Baldwin /* Pass request to alloc an MSI-X message up to the parent bridge. */ 13799bf4c9c1SJohn Baldwin int 1380e706f7f0SJohn Baldwin pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 13819bf4c9c1SJohn Baldwin { 1382bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13839bf4c9c1SJohn Baldwin device_t bus; 13849bf4c9c1SJohn Baldwin 1385*68e9cbd3SMarius Strobl if (sc->flags & PCIB_DISABLE_MSIX) 138622bf1c7fSJohn Baldwin return (ENXIO); 13879bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 1388e706f7f0SJohn Baldwin return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 13895fe82bcaSJohn Baldwin } 13905fe82bcaSJohn Baldwin 13919bf4c9c1SJohn Baldwin /* Pass request to release an MSI-X message up to the parent bridge. */ 13929bf4c9c1SJohn Baldwin int 13939bf4c9c1SJohn Baldwin pcib_release_msix(device_t pcib, device_t dev, int irq) 13949bf4c9c1SJohn Baldwin { 13959bf4c9c1SJohn Baldwin device_t bus; 13969bf4c9c1SJohn Baldwin 13979bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13989bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); 13999bf4c9c1SJohn Baldwin } 14009bf4c9c1SJohn Baldwin 1401e706f7f0SJohn Baldwin /* Pass request to map MSI/MSI-X message up to parent bridge. */ 1402e706f7f0SJohn Baldwin int 1403e706f7f0SJohn Baldwin pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 1404e706f7f0SJohn Baldwin uint32_t *data) 1405e706f7f0SJohn Baldwin { 1406e706f7f0SJohn Baldwin device_t bus; 14074522ac77SLuoqi Chen int error; 1408e706f7f0SJohn Baldwin 1409e706f7f0SJohn Baldwin bus = device_get_parent(pcib); 14104522ac77SLuoqi Chen error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 14114522ac77SLuoqi Chen if (error) 14124522ac77SLuoqi Chen return (error); 14134522ac77SLuoqi Chen 14144522ac77SLuoqi Chen pci_ht_map_msi(pcib, *addr); 14154522ac77SLuoqi Chen return (0); 1416e706f7f0SJohn Baldwin } 1417e706f7f0SJohn Baldwin 141862508c53SJohn Baldwin /* Pass request for device power state up to parent bridge. */ 141962508c53SJohn Baldwin int 142062508c53SJohn Baldwin pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 142162508c53SJohn Baldwin { 142262508c53SJohn Baldwin device_t bus; 142362508c53SJohn Baldwin 142462508c53SJohn Baldwin bus = device_get_parent(pcib); 142562508c53SJohn Baldwin return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); 142662508c53SJohn Baldwin } 1427