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> 40*83c41143SJohn Baldwin #include <sys/kernel.h> 41*83c41143SJohn Baldwin #include <sys/libkern.h> 42*83c41143SJohn Baldwin #include <sys/malloc.h> 43*83c41143SJohn Baldwin #include <sys/module.h> 44a8b354a8SWarner Losh #include <sys/rman.h> 451c54ff33SMatthew N. Dodd #include <sys/sysctl.h> 46*83c41143SJohn Baldwin #include <sys/systm.h> 47bb0d0a8eSMike Smith 48*83c41143SJohn Baldwin #include <machine/bus.h> 49bb0d0a8eSMike Smith #include <machine/resource.h> 50bb0d0a8eSMike Smith 5138d8c994SWarner Losh #include <dev/pci/pcivar.h> 5238d8c994SWarner Losh #include <dev/pci/pcireg.h> 5362508c53SJohn Baldwin #include <dev/pci/pci_private.h> 5438d8c994SWarner Losh #include <dev/pci/pcib_private.h> 55bb0d0a8eSMike Smith 56bb0d0a8eSMike Smith #include "pcib_if.h" 57bb0d0a8eSMike Smith 58bb0d0a8eSMike Smith static int pcib_probe(device_t dev); 59e36af292SJung-uk Kim static int pcib_suspend(device_t dev); 60e36af292SJung-uk Kim static int pcib_resume(device_t dev); 6162508c53SJohn Baldwin static int pcib_power_for_sleep(device_t pcib, device_t dev, 6262508c53SJohn Baldwin int *pstate); 63bb0d0a8eSMike Smith 64bb0d0a8eSMike Smith static device_method_t pcib_methods[] = { 65bb0d0a8eSMike Smith /* Device interface */ 66bb0d0a8eSMike Smith DEVMETHOD(device_probe, pcib_probe), 67bb0d0a8eSMike Smith DEVMETHOD(device_attach, pcib_attach), 684e30440dSWarner Losh DEVMETHOD(device_detach, bus_generic_detach), 69bb0d0a8eSMike Smith DEVMETHOD(device_shutdown, bus_generic_shutdown), 70e36af292SJung-uk Kim DEVMETHOD(device_suspend, pcib_suspend), 71e36af292SJung-uk Kim DEVMETHOD(device_resume, pcib_resume), 72bb0d0a8eSMike Smith 73bb0d0a8eSMike Smith /* Bus interface */ 74bb0d0a8eSMike Smith DEVMETHOD(bus_print_child, bus_generic_print_child), 75bb0d0a8eSMike Smith DEVMETHOD(bus_read_ivar, pcib_read_ivar), 76bb0d0a8eSMike Smith DEVMETHOD(bus_write_ivar, pcib_write_ivar), 77bb0d0a8eSMike Smith DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), 78*83c41143SJohn Baldwin #ifdef NEW_PCIB 79*83c41143SJohn Baldwin DEVMETHOD(bus_adjust_resource, pcib_adjust_resource), 80*83c41143SJohn Baldwin DEVMETHOD(bus_release_resource, pcib_release_resource), 81*83c41143SJohn Baldwin #else 82d2c9344fSJohn Baldwin DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 83bb0d0a8eSMike Smith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 84*83c41143SJohn Baldwin #endif 85bb0d0a8eSMike Smith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 86bb0d0a8eSMike Smith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 87bb0d0a8eSMike Smith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 88bb0d0a8eSMike Smith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 89bb0d0a8eSMike Smith 90bb0d0a8eSMike Smith /* pcib interface */ 91bb0d0a8eSMike Smith DEVMETHOD(pcib_maxslots, pcib_maxslots), 92bb0d0a8eSMike Smith DEVMETHOD(pcib_read_config, pcib_read_config), 93bb0d0a8eSMike Smith DEVMETHOD(pcib_write_config, pcib_write_config), 94bb0d0a8eSMike Smith DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 959bf4c9c1SJohn Baldwin DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), 969bf4c9c1SJohn Baldwin DEVMETHOD(pcib_release_msi, pcib_release_msi), 979bf4c9c1SJohn Baldwin DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), 989bf4c9c1SJohn Baldwin DEVMETHOD(pcib_release_msix, pcib_release_msix), 99e706f7f0SJohn Baldwin DEVMETHOD(pcib_map_msi, pcib_map_msi), 10062508c53SJohn Baldwin DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep), 101bb0d0a8eSMike Smith 102bb0d0a8eSMike Smith { 0, 0 } 103bb0d0a8eSMike Smith }; 104bb0d0a8eSMike Smith 10504dda605SJohn Baldwin static devclass_t pcib_devclass; 106bb0d0a8eSMike Smith 10704dda605SJohn Baldwin DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); 108bb0d0a8eSMike Smith DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); 109bb0d0a8eSMike Smith 110*83c41143SJohn Baldwin #ifdef NEW_PCIB 111*83c41143SJohn Baldwin /* 112*83c41143SJohn Baldwin * XXX Todo: 113*83c41143SJohn Baldwin * - properly handle the ISA enable bit. If it is set, we should change 114*83c41143SJohn Baldwin * the behavior of the I/O window resource and rman to not allocate the 115*83c41143SJohn Baldwin * blocked ranges (upper 768 bytes of each 1K in the first 64k of the 116*83c41143SJohn Baldwin * I/O port address space). 117*83c41143SJohn Baldwin */ 118*83c41143SJohn Baldwin 119*83c41143SJohn Baldwin /* 120*83c41143SJohn Baldwin * Is a resource from a child device sub-allocated from one of our 121*83c41143SJohn Baldwin * resource managers? 122*83c41143SJohn Baldwin */ 123*83c41143SJohn Baldwin static int 124*83c41143SJohn Baldwin pcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r) 125*83c41143SJohn Baldwin { 126*83c41143SJohn Baldwin 127*83c41143SJohn Baldwin switch (type) { 128*83c41143SJohn Baldwin case SYS_RES_IOPORT: 129*83c41143SJohn Baldwin return (rman_is_region_manager(r, &sc->io.rman)); 130*83c41143SJohn Baldwin case SYS_RES_MEMORY: 131*83c41143SJohn Baldwin /* Prefetchable resources may live in either memory rman. */ 132*83c41143SJohn Baldwin if (rman_get_flags(r) & RF_PREFETCHABLE && 133*83c41143SJohn Baldwin rman_is_region_manager(r, &sc->pmem.rman)) 134*83c41143SJohn Baldwin return (1); 135*83c41143SJohn Baldwin return (rman_is_region_manager(r, &sc->mem.rman)); 136*83c41143SJohn Baldwin } 137*83c41143SJohn Baldwin return (0); 138*83c41143SJohn Baldwin } 139*83c41143SJohn Baldwin 140*83c41143SJohn Baldwin static int 141*83c41143SJohn Baldwin pcib_is_window_open(struct pcib_window *pw) 142*83c41143SJohn Baldwin { 143*83c41143SJohn Baldwin 144*83c41143SJohn Baldwin return (pw->valid && pw->base < pw->limit); 145*83c41143SJohn Baldwin } 146*83c41143SJohn Baldwin 147*83c41143SJohn Baldwin /* 148*83c41143SJohn Baldwin * XXX: If RF_ACTIVE did not also imply allocating a bus space tag and 149*83c41143SJohn Baldwin * handle for the resource, we could pass RF_ACTIVE up to the PCI bus 150*83c41143SJohn Baldwin * when allocating the resource windows and rely on the PCI bus driver 151*83c41143SJohn Baldwin * to do this for us. 152*83c41143SJohn Baldwin */ 153*83c41143SJohn Baldwin static void 154*83c41143SJohn Baldwin pcib_activate_window(struct pcib_softc *sc, int type) 155*83c41143SJohn Baldwin { 156*83c41143SJohn Baldwin 157*83c41143SJohn Baldwin PCI_ENABLE_IO(device_get_parent(sc->dev), sc->dev, type); 158*83c41143SJohn Baldwin } 159*83c41143SJohn Baldwin 160*83c41143SJohn Baldwin static void 161*83c41143SJohn Baldwin pcib_write_windows(struct pcib_softc *sc, int mask) 162*83c41143SJohn Baldwin { 163*83c41143SJohn Baldwin device_t dev; 164*83c41143SJohn Baldwin uint32_t val; 165*83c41143SJohn Baldwin 166*83c41143SJohn Baldwin dev = sc->dev; 167*83c41143SJohn Baldwin if (sc->io.valid && mask & WIN_IO) { 168*83c41143SJohn Baldwin val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 169*83c41143SJohn Baldwin if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 170*83c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEH_1, 171*83c41143SJohn Baldwin sc->io.base >> 16, 2); 172*83c41143SJohn Baldwin pci_write_config(dev, PCIR_IOLIMITH_1, 173*83c41143SJohn Baldwin sc->io.limit >> 16, 2); 174*83c41143SJohn Baldwin } 175*83c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEL_1, sc->io.base >> 8, 1); 176*83c41143SJohn Baldwin pci_write_config(dev, PCIR_IOLIMITL_1, sc->io.limit >> 8, 1); 177*83c41143SJohn Baldwin } 178*83c41143SJohn Baldwin 179*83c41143SJohn Baldwin if (mask & WIN_MEM) { 180*83c41143SJohn Baldwin pci_write_config(dev, PCIR_MEMBASE_1, sc->mem.base >> 16, 2); 181*83c41143SJohn Baldwin pci_write_config(dev, PCIR_MEMLIMIT_1, sc->mem.limit >> 16, 2); 182*83c41143SJohn Baldwin } 183*83c41143SJohn Baldwin 184*83c41143SJohn Baldwin if (sc->pmem.valid && mask & WIN_PMEM) { 185*83c41143SJohn Baldwin val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 186*83c41143SJohn Baldwin if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 187*83c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEH_1, 188*83c41143SJohn Baldwin sc->pmem.base >> 32, 4); 189*83c41143SJohn Baldwin pci_write_config(dev, PCIR_PMLIMITH_1, 190*83c41143SJohn Baldwin sc->pmem.limit >> 32, 4); 191*83c41143SJohn Baldwin } 192*83c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEL_1, sc->pmem.base >> 16, 2); 193*83c41143SJohn Baldwin pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmem.limit >> 16, 2); 194*83c41143SJohn Baldwin } 195*83c41143SJohn Baldwin } 196*83c41143SJohn Baldwin 197*83c41143SJohn Baldwin static void 198*83c41143SJohn Baldwin pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, 199*83c41143SJohn Baldwin int flags, pci_addr_t max_address) 200*83c41143SJohn Baldwin { 201*83c41143SJohn Baldwin char buf[64]; 202*83c41143SJohn Baldwin int error, rid; 203*83c41143SJohn Baldwin 204*83c41143SJohn Baldwin if (max_address != (u_long)max_address) 205*83c41143SJohn Baldwin max_address = ~0ul; 206*83c41143SJohn Baldwin w->rman.rm_start = 0; 207*83c41143SJohn Baldwin w->rman.rm_end = max_address; 208*83c41143SJohn Baldwin w->rman.rm_type = RMAN_ARRAY; 209*83c41143SJohn Baldwin snprintf(buf, sizeof(buf), "%s %s window", 210*83c41143SJohn Baldwin device_get_nameunit(sc->dev), w->name); 211*83c41143SJohn Baldwin w->rman.rm_descr = strdup(buf, M_DEVBUF); 212*83c41143SJohn Baldwin error = rman_init(&w->rman); 213*83c41143SJohn Baldwin if (error) 214*83c41143SJohn Baldwin panic("Failed to initialize %s %s rman", 215*83c41143SJohn Baldwin device_get_nameunit(sc->dev), w->name); 216*83c41143SJohn Baldwin 217*83c41143SJohn Baldwin if (!pcib_is_window_open(w)) 218*83c41143SJohn Baldwin return; 219*83c41143SJohn Baldwin 220*83c41143SJohn Baldwin if (w->base > max_address || w->limit > max_address) { 221*83c41143SJohn Baldwin device_printf(sc->dev, 222*83c41143SJohn Baldwin "initial %s window has too many bits, ignoring\n", w->name); 223*83c41143SJohn Baldwin return; 224*83c41143SJohn Baldwin } 225*83c41143SJohn Baldwin rid = w->reg; 226*83c41143SJohn Baldwin w->res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit, 227*83c41143SJohn Baldwin w->limit - w->base + 1, flags); 228*83c41143SJohn Baldwin if (w->res == NULL) { 229*83c41143SJohn Baldwin device_printf(sc->dev, 230*83c41143SJohn Baldwin "failed to allocate initial %s window: %#jx-%#jx\n", 231*83c41143SJohn Baldwin w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 232*83c41143SJohn Baldwin w->base = max_address; 233*83c41143SJohn Baldwin w->limit = 0; 234*83c41143SJohn Baldwin pcib_write_windows(sc, w->mask); 235*83c41143SJohn Baldwin return; 236*83c41143SJohn Baldwin } 237*83c41143SJohn Baldwin pcib_activate_window(sc, type); 238*83c41143SJohn Baldwin 239*83c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 240*83c41143SJohn Baldwin rman_get_end(w->res)); 241*83c41143SJohn Baldwin if (error) 242*83c41143SJohn Baldwin panic("Failed to initialize rman with resource"); 243*83c41143SJohn Baldwin } 244*83c41143SJohn Baldwin 245*83c41143SJohn Baldwin /* 246*83c41143SJohn Baldwin * Initialize I/O windows. 247*83c41143SJohn Baldwin */ 248*83c41143SJohn Baldwin static void 249*83c41143SJohn Baldwin pcib_probe_windows(struct pcib_softc *sc) 250*83c41143SJohn Baldwin { 251*83c41143SJohn Baldwin pci_addr_t max; 252*83c41143SJohn Baldwin device_t dev; 253*83c41143SJohn Baldwin uint32_t val; 254*83c41143SJohn Baldwin 255*83c41143SJohn Baldwin dev = sc->dev; 256*83c41143SJohn Baldwin 257*83c41143SJohn Baldwin /* Determine if the I/O port window is implemented. */ 258*83c41143SJohn Baldwin val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 259*83c41143SJohn Baldwin if (val == 0) { 260*83c41143SJohn Baldwin /* 261*83c41143SJohn Baldwin * If 'val' is zero, then only 16-bits of I/O space 262*83c41143SJohn Baldwin * are supported. 263*83c41143SJohn Baldwin */ 264*83c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); 265*83c41143SJohn Baldwin if (pci_read_config(dev, PCIR_IOBASEL_1, 1) != 0) { 266*83c41143SJohn Baldwin sc->io.valid = 1; 267*83c41143SJohn Baldwin pci_write_config(dev, PCIR_IOBASEL_1, 0, 1); 268*83c41143SJohn Baldwin } 269*83c41143SJohn Baldwin } else 270*83c41143SJohn Baldwin sc->io.valid = 1; 271*83c41143SJohn Baldwin 272*83c41143SJohn Baldwin /* Read the existing I/O port window. */ 273*83c41143SJohn Baldwin if (sc->io.valid) { 274*83c41143SJohn Baldwin sc->io.reg = PCIR_IOBASEL_1; 275*83c41143SJohn Baldwin sc->io.step = 12; 276*83c41143SJohn Baldwin sc->io.mask = WIN_IO; 277*83c41143SJohn Baldwin sc->io.name = "I/O port"; 278*83c41143SJohn Baldwin if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 279*83c41143SJohn Baldwin sc->io.base = PCI_PPBIOBASE( 280*83c41143SJohn Baldwin pci_read_config(dev, PCIR_IOBASEH_1, 2), val); 281*83c41143SJohn Baldwin sc->io.limit = PCI_PPBIOLIMIT( 282*83c41143SJohn Baldwin pci_read_config(dev, PCIR_IOLIMITH_1, 2), 283*83c41143SJohn Baldwin pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 284*83c41143SJohn Baldwin max = 0xffffffff; 285*83c41143SJohn Baldwin } else { 286*83c41143SJohn Baldwin sc->io.base = PCI_PPBIOBASE(0, val); 287*83c41143SJohn Baldwin sc->io.limit = PCI_PPBIOLIMIT(0, 288*83c41143SJohn Baldwin pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 289*83c41143SJohn Baldwin max = 0xffff; 290*83c41143SJohn Baldwin } 291*83c41143SJohn Baldwin pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max); 292*83c41143SJohn Baldwin } 293*83c41143SJohn Baldwin 294*83c41143SJohn Baldwin /* Read the existing memory window. */ 295*83c41143SJohn Baldwin sc->mem.valid = 1; 296*83c41143SJohn Baldwin sc->mem.reg = PCIR_MEMBASE_1; 297*83c41143SJohn Baldwin sc->mem.step = 20; 298*83c41143SJohn Baldwin sc->mem.mask = WIN_MEM; 299*83c41143SJohn Baldwin sc->mem.name = "memory"; 300*83c41143SJohn Baldwin sc->mem.base = PCI_PPBMEMBASE(0, 301*83c41143SJohn Baldwin pci_read_config(dev, PCIR_MEMBASE_1, 2)); 302*83c41143SJohn Baldwin sc->mem.limit = PCI_PPBMEMLIMIT(0, 303*83c41143SJohn Baldwin pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 304*83c41143SJohn Baldwin pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, 0xffffffff); 305*83c41143SJohn Baldwin 306*83c41143SJohn Baldwin /* Determine if the prefetchable memory window is implemented. */ 307*83c41143SJohn Baldwin val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 308*83c41143SJohn Baldwin if (val == 0) { 309*83c41143SJohn Baldwin /* 310*83c41143SJohn Baldwin * If 'val' is zero, then only 32-bits of memory space 311*83c41143SJohn Baldwin * are supported. 312*83c41143SJohn Baldwin */ 313*83c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); 314*83c41143SJohn Baldwin if (pci_read_config(dev, PCIR_PMBASEL_1, 2) != 0) { 315*83c41143SJohn Baldwin sc->pmem.valid = 1; 316*83c41143SJohn Baldwin pci_write_config(dev, PCIR_PMBASEL_1, 0, 2); 317*83c41143SJohn Baldwin } 318*83c41143SJohn Baldwin } else 319*83c41143SJohn Baldwin sc->pmem.valid = 1; 320*83c41143SJohn Baldwin 321*83c41143SJohn Baldwin /* Read the existing prefetchable memory window. */ 322*83c41143SJohn Baldwin if (sc->pmem.valid) { 323*83c41143SJohn Baldwin sc->pmem.reg = PCIR_PMBASEL_1; 324*83c41143SJohn Baldwin sc->pmem.step = 20; 325*83c41143SJohn Baldwin sc->pmem.mask = WIN_PMEM; 326*83c41143SJohn Baldwin sc->pmem.name = "prefetch"; 327*83c41143SJohn Baldwin if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 328*83c41143SJohn Baldwin sc->pmem.base = PCI_PPBMEMBASE( 329*83c41143SJohn Baldwin pci_read_config(dev, PCIR_PMBASEH_1, 4), val); 330*83c41143SJohn Baldwin sc->pmem.limit = PCI_PPBMEMLIMIT( 331*83c41143SJohn Baldwin pci_read_config(dev, PCIR_PMLIMITH_1, 4), 332*83c41143SJohn Baldwin pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 333*83c41143SJohn Baldwin max = 0xffffffffffffffff; 334*83c41143SJohn Baldwin } else { 335*83c41143SJohn Baldwin sc->pmem.base = PCI_PPBMEMBASE(0, val); 336*83c41143SJohn Baldwin sc->pmem.limit = PCI_PPBMEMLIMIT(0, 337*83c41143SJohn Baldwin pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 338*83c41143SJohn Baldwin max = 0xffffffff; 339*83c41143SJohn Baldwin } 340*83c41143SJohn Baldwin pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY, 341*83c41143SJohn Baldwin RF_PREFETCHABLE, max); 342*83c41143SJohn Baldwin } 343*83c41143SJohn Baldwin } 344*83c41143SJohn Baldwin 345*83c41143SJohn Baldwin #else 346*83c41143SJohn Baldwin 347bb0d0a8eSMike Smith /* 348b0a2d4b8SWarner Losh * Is the prefetch window open (eg, can we allocate memory in it?) 349b0a2d4b8SWarner Losh */ 350b0a2d4b8SWarner Losh static int 351b0a2d4b8SWarner Losh pcib_is_prefetch_open(struct pcib_softc *sc) 352b0a2d4b8SWarner Losh { 353b0a2d4b8SWarner Losh return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); 354b0a2d4b8SWarner Losh } 355b0a2d4b8SWarner Losh 356b0a2d4b8SWarner Losh /* 357b0a2d4b8SWarner Losh * Is the nonprefetch window open (eg, can we allocate memory in it?) 358b0a2d4b8SWarner Losh */ 359b0a2d4b8SWarner Losh static int 360b0a2d4b8SWarner Losh pcib_is_nonprefetch_open(struct pcib_softc *sc) 361b0a2d4b8SWarner Losh { 362b0a2d4b8SWarner Losh return (sc->membase > 0 && sc->membase < sc->memlimit); 363b0a2d4b8SWarner Losh } 364b0a2d4b8SWarner Losh 365b0a2d4b8SWarner Losh /* 366b0a2d4b8SWarner Losh * Is the io window open (eg, can we allocate ports in it?) 367b0a2d4b8SWarner Losh */ 368b0a2d4b8SWarner Losh static int 369b0a2d4b8SWarner Losh pcib_is_io_open(struct pcib_softc *sc) 370b0a2d4b8SWarner Losh { 371b0a2d4b8SWarner Losh return (sc->iobase > 0 && sc->iobase < sc->iolimit); 372b0a2d4b8SWarner Losh } 373b0a2d4b8SWarner Losh 374b0a2d4b8SWarner Losh /* 375e36af292SJung-uk Kim * Get current I/O decode. 376e36af292SJung-uk Kim */ 377e36af292SJung-uk Kim static void 378e36af292SJung-uk Kim pcib_get_io_decode(struct pcib_softc *sc) 379e36af292SJung-uk Kim { 380e36af292SJung-uk Kim device_t dev; 381e36af292SJung-uk Kim uint32_t iolow; 382e36af292SJung-uk Kim 383e36af292SJung-uk Kim dev = sc->dev; 384e36af292SJung-uk Kim 385e36af292SJung-uk Kim iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); 386e36af292SJung-uk Kim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 387e36af292SJung-uk Kim sc->iobase = PCI_PPBIOBASE( 388e36af292SJung-uk Kim pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow); 389e36af292SJung-uk Kim else 390e36af292SJung-uk Kim sc->iobase = PCI_PPBIOBASE(0, iolow); 391e36af292SJung-uk Kim 392e36af292SJung-uk Kim iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); 393e36af292SJung-uk Kim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 394e36af292SJung-uk Kim sc->iolimit = PCI_PPBIOLIMIT( 395e36af292SJung-uk Kim pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow); 396e36af292SJung-uk Kim else 397e36af292SJung-uk Kim sc->iolimit = PCI_PPBIOLIMIT(0, iolow); 398e36af292SJung-uk Kim } 399e36af292SJung-uk Kim 400e36af292SJung-uk Kim /* 401e36af292SJung-uk Kim * Get current memory decode. 402e36af292SJung-uk Kim */ 403e36af292SJung-uk Kim static void 404e36af292SJung-uk Kim pcib_get_mem_decode(struct pcib_softc *sc) 405e36af292SJung-uk Kim { 406e36af292SJung-uk Kim device_t dev; 407e36af292SJung-uk Kim pci_addr_t pmemlow; 408e36af292SJung-uk Kim 409e36af292SJung-uk Kim dev = sc->dev; 410e36af292SJung-uk Kim 411e36af292SJung-uk Kim sc->membase = PCI_PPBMEMBASE(0, 412e36af292SJung-uk Kim pci_read_config(dev, PCIR_MEMBASE_1, 2)); 413e36af292SJung-uk Kim sc->memlimit = PCI_PPBMEMLIMIT(0, 414e36af292SJung-uk Kim pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 415e36af292SJung-uk Kim 416e36af292SJung-uk Kim pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2); 417e36af292SJung-uk Kim if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 418e36af292SJung-uk Kim sc->pmembase = PCI_PPBMEMBASE( 419e36af292SJung-uk Kim pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow); 420e36af292SJung-uk Kim else 421e36af292SJung-uk Kim sc->pmembase = PCI_PPBMEMBASE(0, pmemlow); 422e36af292SJung-uk Kim 423e36af292SJung-uk Kim pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2); 424e36af292SJung-uk Kim if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 425e36af292SJung-uk Kim sc->pmemlimit = PCI_PPBMEMLIMIT( 426e36af292SJung-uk Kim pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow); 427e36af292SJung-uk Kim else 428e36af292SJung-uk Kim sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow); 429e36af292SJung-uk Kim } 430e36af292SJung-uk Kim 431e36af292SJung-uk Kim /* 432e36af292SJung-uk Kim * Restore previous I/O decode. 433e36af292SJung-uk Kim */ 434e36af292SJung-uk Kim static void 435e36af292SJung-uk Kim pcib_set_io_decode(struct pcib_softc *sc) 436e36af292SJung-uk Kim { 437e36af292SJung-uk Kim device_t dev; 438e36af292SJung-uk Kim uint32_t iohi; 439e36af292SJung-uk Kim 440e36af292SJung-uk Kim dev = sc->dev; 441e36af292SJung-uk Kim 442e36af292SJung-uk Kim iohi = sc->iobase >> 16; 443e36af292SJung-uk Kim if (iohi > 0) 444e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2); 445e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1); 446e36af292SJung-uk Kim 447e36af292SJung-uk Kim iohi = sc->iolimit >> 16; 448e36af292SJung-uk Kim if (iohi > 0) 449e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2); 450e36af292SJung-uk Kim pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1); 451e36af292SJung-uk Kim } 452e36af292SJung-uk Kim 453e36af292SJung-uk Kim /* 454e36af292SJung-uk Kim * Restore previous memory decode. 455e36af292SJung-uk Kim */ 456e36af292SJung-uk Kim static void 457e36af292SJung-uk Kim pcib_set_mem_decode(struct pcib_softc *sc) 458e36af292SJung-uk Kim { 459e36af292SJung-uk Kim device_t dev; 460e36af292SJung-uk Kim pci_addr_t pmemhi; 461e36af292SJung-uk Kim 462e36af292SJung-uk Kim dev = sc->dev; 463e36af292SJung-uk Kim 464e36af292SJung-uk Kim pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2); 465e36af292SJung-uk Kim pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2); 466e36af292SJung-uk Kim 467e36af292SJung-uk Kim pmemhi = sc->pmembase >> 32; 468e36af292SJung-uk Kim if (pmemhi > 0) 469e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4); 470e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2); 471e36af292SJung-uk Kim 472e36af292SJung-uk Kim pmemhi = sc->pmemlimit >> 32; 473e36af292SJung-uk Kim if (pmemhi > 0) 474e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4); 475e36af292SJung-uk Kim pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2); 476e36af292SJung-uk Kim } 477*83c41143SJohn Baldwin #endif 478e36af292SJung-uk Kim 479e36af292SJung-uk Kim /* 480e36af292SJung-uk Kim * Get current bridge configuration. 481e36af292SJung-uk Kim */ 482e36af292SJung-uk Kim static void 483e36af292SJung-uk Kim pcib_cfg_save(struct pcib_softc *sc) 484e36af292SJung-uk Kim { 485e36af292SJung-uk Kim device_t dev; 486e36af292SJung-uk Kim 487e36af292SJung-uk Kim dev = sc->dev; 488e36af292SJung-uk Kim 489e36af292SJung-uk Kim sc->command = pci_read_config(dev, PCIR_COMMAND, 2); 490e36af292SJung-uk Kim sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1); 491e36af292SJung-uk Kim sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); 492e36af292SJung-uk Kim sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 493e36af292SJung-uk Kim sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 494e36af292SJung-uk Kim sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 495*83c41143SJohn Baldwin #ifndef NEW_PCIB 496e36af292SJung-uk Kim if (sc->command & PCIM_CMD_PORTEN) 497e36af292SJung-uk Kim pcib_get_io_decode(sc); 498e36af292SJung-uk Kim if (sc->command & PCIM_CMD_MEMEN) 499e36af292SJung-uk Kim pcib_get_mem_decode(sc); 500*83c41143SJohn Baldwin #endif 501e36af292SJung-uk Kim } 502e36af292SJung-uk Kim 503e36af292SJung-uk Kim /* 504e36af292SJung-uk Kim * Restore previous bridge configuration. 505e36af292SJung-uk Kim */ 506e36af292SJung-uk Kim static void 507e36af292SJung-uk Kim pcib_cfg_restore(struct pcib_softc *sc) 508e36af292SJung-uk Kim { 509e36af292SJung-uk Kim device_t dev; 510e36af292SJung-uk Kim 511e36af292SJung-uk Kim dev = sc->dev; 512e36af292SJung-uk Kim 513e36af292SJung-uk Kim pci_write_config(dev, PCIR_COMMAND, sc->command, 2); 514e36af292SJung-uk Kim pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); 515e36af292SJung-uk Kim pci_write_config(dev, PCIR_SECBUS_1, sc->secbus, 1); 516e36af292SJung-uk Kim pci_write_config(dev, PCIR_SUBBUS_1, sc->subbus, 1); 517e36af292SJung-uk Kim pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2); 518e36af292SJung-uk Kim pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1); 519*83c41143SJohn Baldwin #ifdef NEW_PCIB 520*83c41143SJohn Baldwin pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM); 521*83c41143SJohn Baldwin #else 522e36af292SJung-uk Kim if (sc->command & PCIM_CMD_PORTEN) 523e36af292SJung-uk Kim pcib_set_io_decode(sc); 524e36af292SJung-uk Kim if (sc->command & PCIM_CMD_MEMEN) 525e36af292SJung-uk Kim pcib_set_mem_decode(sc); 526*83c41143SJohn Baldwin #endif 527e36af292SJung-uk Kim } 528e36af292SJung-uk Kim 529e36af292SJung-uk Kim /* 530bb0d0a8eSMike Smith * Generic device interface 531bb0d0a8eSMike Smith */ 532bb0d0a8eSMike Smith static int 533bb0d0a8eSMike Smith pcib_probe(device_t dev) 534bb0d0a8eSMike Smith { 535bb0d0a8eSMike Smith if ((pci_get_class(dev) == PCIC_BRIDGE) && 536bb0d0a8eSMike Smith (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { 537bb0d0a8eSMike Smith device_set_desc(dev, "PCI-PCI bridge"); 538bb0d0a8eSMike Smith return(-10000); 539bb0d0a8eSMike Smith } 540bb0d0a8eSMike Smith return(ENXIO); 541bb0d0a8eSMike Smith } 542bb0d0a8eSMike Smith 5436f0d5884SJohn Baldwin void 5446f0d5884SJohn Baldwin pcib_attach_common(device_t dev) 545bb0d0a8eSMike Smith { 546bb0d0a8eSMike Smith struct pcib_softc *sc; 547abf07f13SWarner Losh struct sysctl_ctx_list *sctx; 548abf07f13SWarner Losh struct sysctl_oid *soid; 549bb0d0a8eSMike Smith 550bb0d0a8eSMike Smith sc = device_get_softc(dev); 551bb0d0a8eSMike Smith sc->dev = dev; 552bb0d0a8eSMike Smith 5534fa59183SMike Smith /* 5544fa59183SMike Smith * Get current bridge configuration. 5554fa59183SMike Smith */ 55655aaf894SMarius Strobl sc->domain = pci_get_domain(dev); 5574fa59183SMike Smith sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 558e36af292SJung-uk Kim pcib_cfg_save(sc); 5594fa59183SMike Smith 5604fa59183SMike Smith /* 561abf07f13SWarner Losh * Setup sysctl reporting nodes 562abf07f13SWarner Losh */ 563abf07f13SWarner Losh sctx = device_get_sysctl_ctx(dev); 564abf07f13SWarner Losh soid = device_get_sysctl_tree(dev); 565abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", 566abf07f13SWarner Losh CTLFLAG_RD, &sc->domain, 0, "Domain number"); 567abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", 568abf07f13SWarner Losh CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); 569abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", 570abf07f13SWarner Losh CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number"); 571abf07f13SWarner Losh SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", 572abf07f13SWarner Losh CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number"); 573abf07f13SWarner Losh 574abf07f13SWarner Losh /* 5754fa59183SMike Smith * Quirk handling. 5764fa59183SMike Smith */ 5774fa59183SMike Smith switch (pci_get_devid(dev)) { 5784fa59183SMike Smith case 0x12258086: /* Intel 82454KX/GX (Orion) */ 5794fa59183SMike Smith { 580b0cb115fSWarner Losh uint8_t supbus; 5814fa59183SMike Smith 5824fa59183SMike Smith supbus = pci_read_config(dev, 0x41, 1); 5834fa59183SMike Smith if (supbus != 0xff) { 5844fa59183SMike Smith sc->secbus = supbus + 1; 5854fa59183SMike Smith sc->subbus = supbus + 1; 5864fa59183SMike Smith } 5874fa59183SMike Smith break; 5884fa59183SMike Smith } 5894fa59183SMike Smith 590e4b59fc5SWarner Losh /* 591e4b59fc5SWarner Losh * The i82380FB mobile docking controller is a PCI-PCI bridge, 592e4b59fc5SWarner Losh * and it is a subtractive bridge. However, the ProgIf is wrong 593e4b59fc5SWarner Losh * so the normal setting of PCIB_SUBTRACTIVE bit doesn't 594e4b59fc5SWarner Losh * happen. There's also a Toshiba bridge that behaves this 595e4b59fc5SWarner Losh * way. 596e4b59fc5SWarner Losh */ 597e4b59fc5SWarner Losh case 0x124b8086: /* Intel 82380FB Mobile */ 598e4b59fc5SWarner Losh case 0x060513d7: /* Toshiba ???? */ 599e4b59fc5SWarner Losh sc->flags |= PCIB_SUBTRACTIVE; 600e4b59fc5SWarner Losh break; 601c94d6dbeSJung-uk Kim 602c94d6dbeSJung-uk Kim /* Compaq R3000 BIOS sets wrong subordinate bus number. */ 603c94d6dbeSJung-uk Kim case 0x00dd10de: 604c94d6dbeSJung-uk Kim { 605c94d6dbeSJung-uk Kim char *cp; 606c94d6dbeSJung-uk Kim 6071def0ca6SJung-uk Kim if ((cp = getenv("smbios.planar.maker")) == NULL) 608c94d6dbeSJung-uk Kim break; 6091def0ca6SJung-uk Kim if (strncmp(cp, "Compal", 6) != 0) { 6101def0ca6SJung-uk Kim freeenv(cp); 611c94d6dbeSJung-uk Kim break; 6121def0ca6SJung-uk Kim } 6131def0ca6SJung-uk Kim freeenv(cp); 6141def0ca6SJung-uk Kim if ((cp = getenv("smbios.planar.product")) == NULL) 6151def0ca6SJung-uk Kim break; 6161def0ca6SJung-uk Kim if (strncmp(cp, "08A0", 4) != 0) { 6171def0ca6SJung-uk Kim freeenv(cp); 6181def0ca6SJung-uk Kim break; 6191def0ca6SJung-uk Kim } 6201def0ca6SJung-uk Kim freeenv(cp); 621c94d6dbeSJung-uk Kim if (sc->subbus < 0xa) { 622c94d6dbeSJung-uk Kim pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1); 623c94d6dbeSJung-uk Kim sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); 624c94d6dbeSJung-uk Kim } 625c94d6dbeSJung-uk Kim break; 626c94d6dbeSJung-uk Kim } 627e4b59fc5SWarner Losh } 628e4b59fc5SWarner Losh 62922bf1c7fSJohn Baldwin if (pci_msi_device_blacklisted(dev)) 63022bf1c7fSJohn Baldwin sc->flags |= PCIB_DISABLE_MSI; 63122bf1c7fSJohn Baldwin 632e4b59fc5SWarner Losh /* 633e4b59fc5SWarner Losh * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, 634e4b59fc5SWarner Losh * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, 635e4b59fc5SWarner Losh * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. 636e4b59fc5SWarner Losh * This means they act as if they were subtractively decoding 637e4b59fc5SWarner Losh * bridges and pass all transactions. Mark them and real ProgIf 1 638e4b59fc5SWarner Losh * parts as subtractive. 639e4b59fc5SWarner Losh */ 640e4b59fc5SWarner Losh if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || 641657d9f9fSJohn Baldwin pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE) 642e4b59fc5SWarner Losh sc->flags |= PCIB_SUBTRACTIVE; 643e4b59fc5SWarner Losh 644*83c41143SJohn Baldwin #ifdef NEW_PCIB 645*83c41143SJohn Baldwin pcib_probe_windows(sc); 646*83c41143SJohn Baldwin #endif 647bb0d0a8eSMike Smith if (bootverbose) { 64855aaf894SMarius Strobl device_printf(dev, " domain %d\n", sc->domain); 649bb0d0a8eSMike Smith device_printf(dev, " secondary bus %d\n", sc->secbus); 650bb0d0a8eSMike Smith device_printf(dev, " subordinate bus %d\n", sc->subbus); 651*83c41143SJohn Baldwin #ifdef NEW_PCIB 652*83c41143SJohn Baldwin if (pcib_is_window_open(&sc->io)) 653*83c41143SJohn Baldwin device_printf(dev, " I/O decode 0x%jx-0x%jx\n", 654*83c41143SJohn Baldwin (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit); 655*83c41143SJohn Baldwin if (pcib_is_window_open(&sc->mem)) 656*83c41143SJohn Baldwin device_printf(dev, " memory decode 0x%jx-0x%jx\n", 657*83c41143SJohn Baldwin (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit); 658*83c41143SJohn Baldwin if (pcib_is_window_open(&sc->pmem)) 659*83c41143SJohn Baldwin device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 660*83c41143SJohn Baldwin (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit); 661*83c41143SJohn Baldwin #else 662*83c41143SJohn Baldwin if (pcib_is_io_open(sc)) 663*83c41143SJohn Baldwin device_printf(dev, " I/O decode 0x%x-0x%x\n", 664*83c41143SJohn Baldwin sc->iobase, sc->iolimit); 665b0a2d4b8SWarner Losh if (pcib_is_nonprefetch_open(sc)) 666b0a2d4b8SWarner Losh device_printf(dev, " memory decode 0x%jx-0x%jx\n", 667b0a2d4b8SWarner Losh (uintmax_t)sc->membase, (uintmax_t)sc->memlimit); 668b0a2d4b8SWarner Losh if (pcib_is_prefetch_open(sc)) 669b0a2d4b8SWarner Losh device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 670b0a2d4b8SWarner Losh (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 671*83c41143SJohn Baldwin #endif 672b0a2d4b8SWarner Losh else 673b0a2d4b8SWarner Losh device_printf(dev, " no prefetched decode\n"); 674e4b59fc5SWarner Losh if (sc->flags & PCIB_SUBTRACTIVE) 675e4b59fc5SWarner Losh device_printf(dev, " Subtractively decoded bridge.\n"); 676bb0d0a8eSMike Smith } 677bb0d0a8eSMike Smith 678bb0d0a8eSMike Smith /* 679bb0d0a8eSMike Smith * XXX If the secondary bus number is zero, we should assign a bus number 6807e178674SWarner Losh * since the BIOS hasn't, then initialise the bridge. A simple 6817e178674SWarner Losh * bus_alloc_resource with the a couple of busses seems like the right 6827e178674SWarner Losh * approach, but we don't know what busses the BIOS might have already 6837e178674SWarner Losh * assigned to other bridges on this bus that probe later than we do. 6847e178674SWarner Losh * 6857e178674SWarner Losh * If the subordinate bus number is less than the secondary bus number, 686bb0d0a8eSMike Smith * we should pick a better value. One sensible alternative would be to 687bb0d0a8eSMike Smith * pick 255; the only tradeoff here is that configuration transactions 6887e178674SWarner Losh * would be more widely routed than absolutely necessary. We could 6897e178674SWarner Losh * then do a walk of the tree later and fix it. 690bb0d0a8eSMike Smith */ 6916f0d5884SJohn Baldwin } 692bb0d0a8eSMike Smith 69338906aedSJohn Baldwin int 6946f0d5884SJohn Baldwin pcib_attach(device_t dev) 6956f0d5884SJohn Baldwin { 6966f0d5884SJohn Baldwin struct pcib_softc *sc; 6976f0d5884SJohn Baldwin device_t child; 6986f0d5884SJohn Baldwin 6996f0d5884SJohn Baldwin pcib_attach_common(dev); 7006f0d5884SJohn Baldwin sc = device_get_softc(dev); 701bb0d0a8eSMike Smith if (sc->secbus != 0) { 702cea0a895SJohn Baldwin child = device_add_child(dev, "pci", sc->secbus); 703bb0d0a8eSMike Smith if (child != NULL) 704bb0d0a8eSMike Smith return(bus_generic_attach(dev)); 705bb0d0a8eSMike Smith } 706bb0d0a8eSMike Smith 707bb0d0a8eSMike Smith /* no secondary bus; we should have fixed this */ 708bb0d0a8eSMike Smith return(0); 709bb0d0a8eSMike Smith } 710bb0d0a8eSMike Smith 7116f0d5884SJohn Baldwin int 712e36af292SJung-uk Kim pcib_suspend(device_t dev) 713e36af292SJung-uk Kim { 71462508c53SJohn Baldwin device_t pcib; 715e36af292SJung-uk Kim int dstate, error; 716e36af292SJung-uk Kim 717e36af292SJung-uk Kim pcib_cfg_save(device_get_softc(dev)); 718e36af292SJung-uk Kim error = bus_generic_suspend(dev); 719f3e0b109SJung-uk Kim if (error == 0 && pci_do_power_suspend) { 720e36af292SJung-uk Kim dstate = PCI_POWERSTATE_D3; 72162508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 72262508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) 723e36af292SJung-uk Kim pci_set_powerstate(dev, dstate); 724e36af292SJung-uk Kim } 725e36af292SJung-uk Kim return (error); 726e36af292SJung-uk Kim } 727e36af292SJung-uk Kim 728e36af292SJung-uk Kim int 729e36af292SJung-uk Kim pcib_resume(device_t dev) 730e36af292SJung-uk Kim { 73162508c53SJohn Baldwin device_t pcib; 732e36af292SJung-uk Kim 733e36af292SJung-uk Kim if (pci_do_power_resume) { 73462508c53SJohn Baldwin pcib = device_get_parent(device_get_parent(dev)); 73562508c53SJohn Baldwin if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0) 736e36af292SJung-uk Kim pci_set_powerstate(dev, PCI_POWERSTATE_D0); 737e36af292SJung-uk Kim } 738e36af292SJung-uk Kim pcib_cfg_restore(device_get_softc(dev)); 739e36af292SJung-uk Kim return (bus_generic_resume(dev)); 740e36af292SJung-uk Kim } 741e36af292SJung-uk Kim 742e36af292SJung-uk Kim int 743bb0d0a8eSMike Smith pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 744bb0d0a8eSMike Smith { 745bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 746bb0d0a8eSMike Smith 747bb0d0a8eSMike Smith switch (which) { 74855aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 74955aaf894SMarius Strobl *result = sc->domain; 75055aaf894SMarius Strobl return(0); 751bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 752bb0d0a8eSMike Smith *result = sc->secbus; 753bb0d0a8eSMike Smith return(0); 754bb0d0a8eSMike Smith } 755bb0d0a8eSMike Smith return(ENOENT); 756bb0d0a8eSMike Smith } 757bb0d0a8eSMike Smith 7586f0d5884SJohn Baldwin int 759bb0d0a8eSMike Smith pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 760bb0d0a8eSMike Smith { 761bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 762bb0d0a8eSMike Smith 763bb0d0a8eSMike Smith switch (which) { 76455aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 76555aaf894SMarius Strobl return(EINVAL); 766bb0d0a8eSMike Smith case PCIB_IVAR_BUS: 767bb0d0a8eSMike Smith sc->secbus = value; 76855aaf894SMarius Strobl return(0); 769bb0d0a8eSMike Smith } 770bb0d0a8eSMike Smith return(ENOENT); 771bb0d0a8eSMike Smith } 772bb0d0a8eSMike Smith 773*83c41143SJohn Baldwin #ifdef NEW_PCIB 774*83c41143SJohn Baldwin static const char * 775*83c41143SJohn Baldwin pcib_child_name(device_t child) 776*83c41143SJohn Baldwin { 777*83c41143SJohn Baldwin static char buf[64]; 778*83c41143SJohn Baldwin 779*83c41143SJohn Baldwin if (device_get_nameunit(child) != NULL) 780*83c41143SJohn Baldwin return (device_get_nameunit(child)); 781*83c41143SJohn Baldwin snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), 782*83c41143SJohn Baldwin pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); 783*83c41143SJohn Baldwin return (buf); 784*83c41143SJohn Baldwin } 785*83c41143SJohn Baldwin 786*83c41143SJohn Baldwin /* 787*83c41143SJohn Baldwin * Attempt to allocate a resource from the existing resources assigned 788*83c41143SJohn Baldwin * to a window. 789*83c41143SJohn Baldwin */ 790*83c41143SJohn Baldwin static struct resource * 791*83c41143SJohn Baldwin pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w, 792*83c41143SJohn Baldwin device_t child, int type, int *rid, u_long start, u_long end, u_long count, 793*83c41143SJohn Baldwin u_int flags) 794*83c41143SJohn Baldwin { 795*83c41143SJohn Baldwin struct resource *res; 796*83c41143SJohn Baldwin 797*83c41143SJohn Baldwin if (!pcib_is_window_open(w)) 798*83c41143SJohn Baldwin return (NULL); 799*83c41143SJohn Baldwin 800*83c41143SJohn Baldwin res = rman_reserve_resource(&w->rman, start, end, count, 801*83c41143SJohn Baldwin flags & ~RF_ACTIVE, child); 802*83c41143SJohn Baldwin if (res == NULL) 803*83c41143SJohn Baldwin return (NULL); 804*83c41143SJohn Baldwin 805*83c41143SJohn Baldwin if (bootverbose) 806*83c41143SJohn Baldwin device_printf(sc->dev, 807*83c41143SJohn Baldwin "allocated %s range (%#lx-%#lx) for rid %x of %s\n", 808*83c41143SJohn Baldwin w->name, rman_get_start(res), rman_get_end(res), *rid, 809*83c41143SJohn Baldwin pcib_child_name(child)); 810*83c41143SJohn Baldwin rman_set_rid(res, *rid); 811*83c41143SJohn Baldwin 812*83c41143SJohn Baldwin /* 813*83c41143SJohn Baldwin * If the resource should be active, pass that request up the 814*83c41143SJohn Baldwin * tree. This assumes the parent drivers can handle 815*83c41143SJohn Baldwin * activating sub-allocated resources. 816*83c41143SJohn Baldwin */ 817*83c41143SJohn Baldwin if (flags & RF_ACTIVE) { 818*83c41143SJohn Baldwin if (bus_activate_resource(child, type, *rid, res) != 0) { 819*83c41143SJohn Baldwin rman_release_resource(res); 820*83c41143SJohn Baldwin return (NULL); 821*83c41143SJohn Baldwin } 822*83c41143SJohn Baldwin } 823*83c41143SJohn Baldwin 824*83c41143SJohn Baldwin return (res); 825*83c41143SJohn Baldwin } 826*83c41143SJohn Baldwin 827*83c41143SJohn Baldwin /* 828*83c41143SJohn Baldwin * Attempt to grow a window to make room for a given resource request. 829*83c41143SJohn Baldwin * The 'step' parameter is log_2 of the desired I/O window's alignment. 830*83c41143SJohn Baldwin */ 831*83c41143SJohn Baldwin static int 832*83c41143SJohn Baldwin pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, 833*83c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 834*83c41143SJohn Baldwin { 835*83c41143SJohn Baldwin u_long align, start_free, end_free, front, back; 836*83c41143SJohn Baldwin int error, rid; 837*83c41143SJohn Baldwin 838*83c41143SJohn Baldwin /* 839*83c41143SJohn Baldwin * Clamp the desired resource range to the maximum address 840*83c41143SJohn Baldwin * this window supports. Reject impossible requests. 841*83c41143SJohn Baldwin */ 842*83c41143SJohn Baldwin if (!w->valid) 843*83c41143SJohn Baldwin return (EINVAL); 844*83c41143SJohn Baldwin if (end > w->rman.rm_end) 845*83c41143SJohn Baldwin end = w->rman.rm_end; 846*83c41143SJohn Baldwin if (start + count - 1 > end || start + count < start) 847*83c41143SJohn Baldwin return (EINVAL); 848*83c41143SJohn Baldwin 849*83c41143SJohn Baldwin /* 850*83c41143SJohn Baldwin * If there is no resource at all, just try to allocate enough 851*83c41143SJohn Baldwin * aligned space for this resource. 852*83c41143SJohn Baldwin */ 853*83c41143SJohn Baldwin if (w->res == NULL) { 854*83c41143SJohn Baldwin if (RF_ALIGNMENT(flags) < w->step) { 855*83c41143SJohn Baldwin flags &= ~RF_ALIGNMENT_MASK; 856*83c41143SJohn Baldwin flags |= RF_ALIGNMENT_LOG2(w->step); 857*83c41143SJohn Baldwin } 858*83c41143SJohn Baldwin start &= ~((1ul << w->step) - 1); 859*83c41143SJohn Baldwin end |= ((1ul << w->step) - 1); 860*83c41143SJohn Baldwin count = roundup2(count, 1ul << w->step); 861*83c41143SJohn Baldwin rid = w->reg; 862*83c41143SJohn Baldwin w->res = bus_alloc_resource(sc->dev, type, &rid, start, end, 863*83c41143SJohn Baldwin count, flags & ~RF_ACTIVE); 864*83c41143SJohn Baldwin if (w->res == NULL) { 865*83c41143SJohn Baldwin if (bootverbose) 866*83c41143SJohn Baldwin device_printf(sc->dev, 867*83c41143SJohn Baldwin "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n", 868*83c41143SJohn Baldwin w->name, start, end, count); 869*83c41143SJohn Baldwin return (ENXIO); 870*83c41143SJohn Baldwin } 871*83c41143SJohn Baldwin if (bootverbose) 872*83c41143SJohn Baldwin device_printf(sc->dev, 873*83c41143SJohn Baldwin "allocated initial %s window of %#lx-%#lx\n", 874*83c41143SJohn Baldwin w->name, rman_get_start(w->res), 875*83c41143SJohn Baldwin rman_get_end(w->res)); 876*83c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 877*83c41143SJohn Baldwin rman_get_end(w->res)); 878*83c41143SJohn Baldwin if (error) { 879*83c41143SJohn Baldwin if (bootverbose) 880*83c41143SJohn Baldwin device_printf(sc->dev, 881*83c41143SJohn Baldwin "failed to add initial %s window to rman\n", 882*83c41143SJohn Baldwin w->name); 883*83c41143SJohn Baldwin bus_release_resource(sc->dev, type, w->reg, w->res); 884*83c41143SJohn Baldwin w->res = NULL; 885*83c41143SJohn Baldwin return (error); 886*83c41143SJohn Baldwin } 887*83c41143SJohn Baldwin pcib_activate_window(sc, type); 888*83c41143SJohn Baldwin goto updatewin; 889*83c41143SJohn Baldwin } 890*83c41143SJohn Baldwin 891*83c41143SJohn Baldwin /* 892*83c41143SJohn Baldwin * See if growing the window would help. Compute the minimum 893*83c41143SJohn Baldwin * amount of address space needed on both the front and back 894*83c41143SJohn Baldwin * ends of the existing window to satisfy the allocation. 895*83c41143SJohn Baldwin * 896*83c41143SJohn Baldwin * For each end, build a candidate region adjusting for the 897*83c41143SJohn Baldwin * required alignment, etc. If there is a free region at the 898*83c41143SJohn Baldwin * edge of the window, grow from the inner edge of the free 899*83c41143SJohn Baldwin * region. Otherwise grow from the window boundary. 900*83c41143SJohn Baldwin * 901*83c41143SJohn Baldwin * XXX: Special case: if w->res is completely empty and the 902*83c41143SJohn Baldwin * request size is larger than w->res, we should find the 903*83c41143SJohn Baldwin * optimal aligned buffer containing w->res and allocate that. 904*83c41143SJohn Baldwin */ 905*83c41143SJohn Baldwin if (bootverbose) 906*83c41143SJohn Baldwin device_printf(sc->dev, 907*83c41143SJohn Baldwin "attempting to grow %s window for (%#lx-%#lx,%#lx)\n", 908*83c41143SJohn Baldwin w->name, start, end, count); 909*83c41143SJohn Baldwin align = 1ul << RF_ALIGNMENT(flags); 910*83c41143SJohn Baldwin if (start < rman_get_start(w->res)) { 911*83c41143SJohn Baldwin if (rman_first_free_region(&w->rman, &start_free, &end_free) != 912*83c41143SJohn Baldwin 0 || start_free != rman_get_start(w->res)) 913*83c41143SJohn Baldwin end_free = rman_get_start(w->res) - 1; 914*83c41143SJohn Baldwin if (end_free > end) 915*83c41143SJohn Baldwin end_free = end; 916*83c41143SJohn Baldwin 917*83c41143SJohn Baldwin /* Move end_free down until it is properly aligned. */ 918*83c41143SJohn Baldwin end_free &= ~(align - 1); 919*83c41143SJohn Baldwin front = end_free - count; 920*83c41143SJohn Baldwin 921*83c41143SJohn Baldwin /* 922*83c41143SJohn Baldwin * The resource would now be allocated at (front, 923*83c41143SJohn Baldwin * end_free). Ensure that fits in the (start, end) 924*83c41143SJohn Baldwin * bounds. end_free is checked above. If 'front' is 925*83c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 926*83c41143SJohn Baldwin * Also check for underflow. 927*83c41143SJohn Baldwin */ 928*83c41143SJohn Baldwin if (front >= start && front <= end_free) { 929*83c41143SJohn Baldwin if (bootverbose) 930*83c41143SJohn Baldwin printf("\tfront candidate range: %#lx-%#lx\n", 931*83c41143SJohn Baldwin front, end_free); 932*83c41143SJohn Baldwin front &= (1ul << w->step) - 1; 933*83c41143SJohn Baldwin front = rman_get_start(w->res) - front; 934*83c41143SJohn Baldwin } else 935*83c41143SJohn Baldwin front = 0; 936*83c41143SJohn Baldwin } else 937*83c41143SJohn Baldwin front = 0; 938*83c41143SJohn Baldwin if (end > rman_get_end(w->res)) { 939*83c41143SJohn Baldwin if (rman_last_free_region(&w->rman, &start_free, &end_free) != 940*83c41143SJohn Baldwin 0 || end_free != rman_get_end(w->res)) 941*83c41143SJohn Baldwin start_free = rman_get_end(w->res) + 1; 942*83c41143SJohn Baldwin if (start_free < start) 943*83c41143SJohn Baldwin start_free = start; 944*83c41143SJohn Baldwin 945*83c41143SJohn Baldwin /* Move start_free up until it is properly aligned. */ 946*83c41143SJohn Baldwin start_free = roundup2(start_free, align); 947*83c41143SJohn Baldwin back = start_free + count; 948*83c41143SJohn Baldwin 949*83c41143SJohn Baldwin /* 950*83c41143SJohn Baldwin * The resource would now be allocated at (start_free, 951*83c41143SJohn Baldwin * back). Ensure that fits in the (start, end) 952*83c41143SJohn Baldwin * bounds. start_free is checked above. If 'back' is 953*83c41143SJohn Baldwin * ok, ensure it is properly aligned for this window. 954*83c41143SJohn Baldwin * Also check for overflow. 955*83c41143SJohn Baldwin */ 956*83c41143SJohn Baldwin if (back <= end && start_free <= back) { 957*83c41143SJohn Baldwin if (bootverbose) 958*83c41143SJohn Baldwin printf("\tback candidate range: %#lx-%#lx\n", 959*83c41143SJohn Baldwin start_free, back); 960*83c41143SJohn Baldwin back = roundup2(back, w->step) - 1; 961*83c41143SJohn Baldwin back -= rman_get_end(w->res); 962*83c41143SJohn Baldwin } else 963*83c41143SJohn Baldwin back = 0; 964*83c41143SJohn Baldwin } else 965*83c41143SJohn Baldwin back = 0; 966*83c41143SJohn Baldwin 967*83c41143SJohn Baldwin /* 968*83c41143SJohn Baldwin * Try to allocate the smallest needed region first. 969*83c41143SJohn Baldwin * If that fails, fall back to the other region. 970*83c41143SJohn Baldwin */ 971*83c41143SJohn Baldwin error = ENOSPC; 972*83c41143SJohn Baldwin while (front != 0 || back != 0) { 973*83c41143SJohn Baldwin if (front != 0 && (front <= back || back == 0)) { 974*83c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 975*83c41143SJohn Baldwin rman_get_start(w->res) - front, 976*83c41143SJohn Baldwin rman_get_end(w->res)); 977*83c41143SJohn Baldwin if (error == 0) 978*83c41143SJohn Baldwin break; 979*83c41143SJohn Baldwin front = 0; 980*83c41143SJohn Baldwin } else { 981*83c41143SJohn Baldwin error = bus_adjust_resource(sc->dev, type, w->res, 982*83c41143SJohn Baldwin rman_get_start(w->res), 983*83c41143SJohn Baldwin rman_get_end(w->res) + back); 984*83c41143SJohn Baldwin if (error == 0) 985*83c41143SJohn Baldwin break; 986*83c41143SJohn Baldwin back = 0; 987*83c41143SJohn Baldwin } 988*83c41143SJohn Baldwin } 989*83c41143SJohn Baldwin 990*83c41143SJohn Baldwin if (error) 991*83c41143SJohn Baldwin return (error); 992*83c41143SJohn Baldwin if (bootverbose) 993*83c41143SJohn Baldwin device_printf(sc->dev, "grew %s window to %#lx-%#lx\n", 994*83c41143SJohn Baldwin w->name, rman_get_start(w->res), rman_get_end(w->res)); 995*83c41143SJohn Baldwin 996*83c41143SJohn Baldwin /* Add the newly allocated region to the resource manager. */ 997*83c41143SJohn Baldwin if (w->base != rman_get_start(w->res)) { 998*83c41143SJohn Baldwin KASSERT(w->limit == rman_get_end(w->res), ("both ends moved")); 999*83c41143SJohn Baldwin error = rman_manage_region(&w->rman, rman_get_start(w->res), 1000*83c41143SJohn Baldwin w->base - 1); 1001*83c41143SJohn Baldwin } else { 1002*83c41143SJohn Baldwin KASSERT(w->limit != rman_get_end(w->res), 1003*83c41143SJohn Baldwin ("neither end moved")); 1004*83c41143SJohn Baldwin error = rman_manage_region(&w->rman, w->limit + 1, 1005*83c41143SJohn Baldwin rman_get_end(w->res)); 1006*83c41143SJohn Baldwin } 1007*83c41143SJohn Baldwin if (error) { 1008*83c41143SJohn Baldwin if (bootverbose) 1009*83c41143SJohn Baldwin device_printf(sc->dev, 1010*83c41143SJohn Baldwin "failed to expand %s resource manager\n", w->name); 1011*83c41143SJohn Baldwin bus_adjust_resource(sc->dev, type, w->res, w->base, w->limit); 1012*83c41143SJohn Baldwin return (error); 1013*83c41143SJohn Baldwin } 1014*83c41143SJohn Baldwin 1015*83c41143SJohn Baldwin updatewin: 1016*83c41143SJohn Baldwin /* Save the new window. */ 1017*83c41143SJohn Baldwin w->base = rman_get_start(w->res); 1018*83c41143SJohn Baldwin w->limit = rman_get_end(w->res); 1019*83c41143SJohn Baldwin KASSERT((w->base & ((1ul << w->step) - 1)) == 0, 1020*83c41143SJohn Baldwin ("start address is not aligned")); 1021*83c41143SJohn Baldwin KASSERT((w->limit & ((1ul << w->step) - 1)) == (1ul << w->step) - 1, 1022*83c41143SJohn Baldwin ("end address is not aligned")); 1023*83c41143SJohn Baldwin pcib_write_windows(sc, w->mask); 1024*83c41143SJohn Baldwin return (0); 1025*83c41143SJohn Baldwin } 1026*83c41143SJohn Baldwin 1027*83c41143SJohn Baldwin /* 1028*83c41143SJohn Baldwin * We have to trap resource allocation requests and ensure that the bridge 1029*83c41143SJohn Baldwin * is set up to, or capable of handling them. 1030*83c41143SJohn Baldwin */ 1031*83c41143SJohn Baldwin struct resource * 1032*83c41143SJohn Baldwin pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1033*83c41143SJohn Baldwin u_long start, u_long end, u_long count, u_int flags) 1034*83c41143SJohn Baldwin { 1035*83c41143SJohn Baldwin struct pcib_softc *sc; 1036*83c41143SJohn Baldwin struct resource *r; 1037*83c41143SJohn Baldwin 1038*83c41143SJohn Baldwin sc = device_get_softc(dev); 1039*83c41143SJohn Baldwin 1040*83c41143SJohn Baldwin /* 1041*83c41143SJohn Baldwin * VGA resources are decoded iff the VGA enable bit is set in 1042*83c41143SJohn Baldwin * the bridge control register. VGA resources do not fall into 1043*83c41143SJohn Baldwin * the resource windows and are passed up to the parent. 1044*83c41143SJohn Baldwin */ 1045*83c41143SJohn Baldwin if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) || 1046*83c41143SJohn Baldwin (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) { 1047*83c41143SJohn Baldwin if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) 1048*83c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, 1049*83c41143SJohn Baldwin rid, start, end, count, flags)); 1050*83c41143SJohn Baldwin else 1051*83c41143SJohn Baldwin return (NULL); 1052*83c41143SJohn Baldwin } 1053*83c41143SJohn Baldwin 1054*83c41143SJohn Baldwin switch (type) { 1055*83c41143SJohn Baldwin case SYS_RES_IOPORT: 1056*83c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start, 1057*83c41143SJohn Baldwin end, count, flags); 1058*83c41143SJohn Baldwin if (r != NULL) 1059*83c41143SJohn Baldwin break; 1060*83c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->io, type, start, end, count, 1061*83c41143SJohn Baldwin flags) == 0) 1062*83c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->io, child, type, 1063*83c41143SJohn Baldwin rid, start, end, count, flags); 1064*83c41143SJohn Baldwin break; 1065*83c41143SJohn Baldwin case SYS_RES_MEMORY: 1066*83c41143SJohn Baldwin /* 1067*83c41143SJohn Baldwin * For prefetchable resources, prefer the prefetchable 1068*83c41143SJohn Baldwin * memory window, but fall back to the regular memory 1069*83c41143SJohn Baldwin * window if that fails. Try both windows before 1070*83c41143SJohn Baldwin * attempting to grow a window in case the firmware 1071*83c41143SJohn Baldwin * has used a range in the regular memory window to 1072*83c41143SJohn Baldwin * map a prefetchable BAR. 1073*83c41143SJohn Baldwin */ 1074*83c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 1075*83c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, type, 1076*83c41143SJohn Baldwin rid, start, end, count, flags); 1077*83c41143SJohn Baldwin if (r != NULL) 1078*83c41143SJohn Baldwin break; 1079*83c41143SJohn Baldwin } 1080*83c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid, 1081*83c41143SJohn Baldwin start, end, count, flags); 1082*83c41143SJohn Baldwin if (r != NULL) 1083*83c41143SJohn Baldwin break; 1084*83c41143SJohn Baldwin if (flags & RF_PREFETCHABLE) { 1085*83c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->pmem, type, start, end, 1086*83c41143SJohn Baldwin count, flags) == 0) { 1087*83c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->pmem, child, 1088*83c41143SJohn Baldwin type, rid, start, end, count, flags); 1089*83c41143SJohn Baldwin if (r != NULL) 1090*83c41143SJohn Baldwin break; 1091*83c41143SJohn Baldwin } 1092*83c41143SJohn Baldwin } 1093*83c41143SJohn Baldwin if (pcib_grow_window(sc, &sc->mem, type, start, end, count, 1094*83c41143SJohn Baldwin flags & ~RF_PREFETCHABLE) == 0) 1095*83c41143SJohn Baldwin r = pcib_suballoc_resource(sc, &sc->mem, child, type, 1096*83c41143SJohn Baldwin rid, start, end, count, flags); 1097*83c41143SJohn Baldwin break; 1098*83c41143SJohn Baldwin default: 1099*83c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 1100*83c41143SJohn Baldwin start, end, count, flags)); 1101*83c41143SJohn Baldwin } 1102*83c41143SJohn Baldwin 1103*83c41143SJohn Baldwin /* 1104*83c41143SJohn Baldwin * If attempts to suballocate from the window fail but this is a 1105*83c41143SJohn Baldwin * subtractive bridge, pass the request up the tree. 1106*83c41143SJohn Baldwin */ 1107*83c41143SJohn Baldwin if (sc->flags & PCIB_SUBTRACTIVE && r == NULL) 1108*83c41143SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, 1109*83c41143SJohn Baldwin start, end, count, flags)); 1110*83c41143SJohn Baldwin return (r); 1111*83c41143SJohn Baldwin } 1112*83c41143SJohn Baldwin 1113*83c41143SJohn Baldwin int 1114*83c41143SJohn Baldwin pcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r, 1115*83c41143SJohn Baldwin u_long start, u_long end) 1116*83c41143SJohn Baldwin { 1117*83c41143SJohn Baldwin struct pcib_softc *sc; 1118*83c41143SJohn Baldwin 1119*83c41143SJohn Baldwin sc = device_get_softc(bus); 1120*83c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) 1121*83c41143SJohn Baldwin return (rman_adjust_resource(r, start, end)); 1122*83c41143SJohn Baldwin return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 1123*83c41143SJohn Baldwin } 1124*83c41143SJohn Baldwin 1125*83c41143SJohn Baldwin int 1126*83c41143SJohn Baldwin pcib_release_resource(device_t dev, device_t child, int type, int rid, 1127*83c41143SJohn Baldwin struct resource *r) 1128*83c41143SJohn Baldwin { 1129*83c41143SJohn Baldwin struct pcib_softc *sc; 1130*83c41143SJohn Baldwin int error; 1131*83c41143SJohn Baldwin 1132*83c41143SJohn Baldwin sc = device_get_softc(dev); 1133*83c41143SJohn Baldwin if (pcib_is_resource_managed(sc, type, r)) { 1134*83c41143SJohn Baldwin if (rman_get_flags(r) & RF_ACTIVE) { 1135*83c41143SJohn Baldwin error = bus_deactivate_resource(child, type, rid, r); 1136*83c41143SJohn Baldwin if (error) 1137*83c41143SJohn Baldwin return (error); 1138*83c41143SJohn Baldwin } 1139*83c41143SJohn Baldwin return (rman_release_resource(r)); 1140*83c41143SJohn Baldwin } 1141*83c41143SJohn Baldwin return (bus_generic_release_resource(dev, child, type, rid, r)); 1142*83c41143SJohn Baldwin } 1143*83c41143SJohn Baldwin #else 1144bb0d0a8eSMike Smith /* 1145bb0d0a8eSMike Smith * We have to trap resource allocation requests and ensure that the bridge 1146bb0d0a8eSMike Smith * is set up to, or capable of handling them. 1147bb0d0a8eSMike Smith */ 11486f0d5884SJohn Baldwin struct resource * 1149bb0d0a8eSMike Smith pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1150bb0d0a8eSMike Smith u_long start, u_long end, u_long count, u_int flags) 1151bb0d0a8eSMike Smith { 1152bb0d0a8eSMike Smith struct pcib_softc *sc = device_get_softc(dev); 115326043836SJohn Baldwin const char *name, *suffix; 1154a8b354a8SWarner Losh int ok; 1155bb0d0a8eSMike Smith 1156bb0d0a8eSMike Smith /* 1157bb0d0a8eSMike Smith * Fail the allocation for this range if it's not supported. 1158bb0d0a8eSMike Smith */ 115926043836SJohn Baldwin name = device_get_nameunit(child); 116026043836SJohn Baldwin if (name == NULL) { 116126043836SJohn Baldwin name = ""; 116226043836SJohn Baldwin suffix = ""; 116326043836SJohn Baldwin } else 116426043836SJohn Baldwin suffix = " "; 1165bb0d0a8eSMike Smith switch (type) { 1166bb0d0a8eSMike Smith case SYS_RES_IOPORT: 1167a8b354a8SWarner Losh ok = 0; 1168e4b59fc5SWarner Losh if (!pcib_is_io_open(sc)) 1169e4b59fc5SWarner Losh break; 1170a8b354a8SWarner Losh ok = (start >= sc->iobase && end <= sc->iolimit); 1171d98d9b12SMarcel Moolenaar 1172d98d9b12SMarcel Moolenaar /* 1173d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA I/O addresses when the 1174d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1175d98d9b12SMarcel Moolenaar */ 1176d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_ioport_range(start, end)) 1177d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1178d98d9b12SMarcel Moolenaar 1179e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1180a8b354a8SWarner Losh if (!ok) { 118112b8c86eSWarner Losh if (start < sc->iobase) 118212b8c86eSWarner Losh start = sc->iobase; 118312b8c86eSWarner Losh if (end > sc->iolimit) 118412b8c86eSWarner Losh end = sc->iolimit; 11852daa7a07SWarner Losh if (start < end) 11862daa7a07SWarner Losh ok = 1; 1187a8b354a8SWarner Losh } 11881c54ff33SMatthew N. Dodd } else { 1189e4b59fc5SWarner Losh ok = 1; 11909dffe835SWarner Losh #if 0 1191795dceffSWarner Losh /* 1192795dceffSWarner Losh * If we overlap with the subtractive range, then 1193795dceffSWarner Losh * pick the upper range to use. 1194795dceffSWarner Losh */ 1195795dceffSWarner Losh if (start < sc->iolimit && end > sc->iobase) 1196795dceffSWarner Losh start = sc->iolimit + 1; 11979dffe835SWarner Losh #endif 119812b8c86eSWarner Losh } 1199a8b354a8SWarner Losh if (end < start) { 12002daa7a07SWarner Losh device_printf(dev, "ioport: end (%lx) < start (%lx)\n", 12012daa7a07SWarner Losh end, start); 1202a8b354a8SWarner Losh start = 0; 1203a8b354a8SWarner Losh end = 0; 1204a8b354a8SWarner Losh ok = 0; 1205a8b354a8SWarner Losh } 1206a8b354a8SWarner Losh if (!ok) { 120726043836SJohn Baldwin device_printf(dev, "%s%srequested unsupported I/O " 1208a8b354a8SWarner Losh "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", 120926043836SJohn Baldwin name, suffix, start, end, sc->iobase, sc->iolimit); 1210bb0d0a8eSMike Smith return (NULL); 1211bb0d0a8eSMike Smith } 12124fa59183SMike Smith if (bootverbose) 12132daa7a07SWarner Losh device_printf(dev, 121426043836SJohn Baldwin "%s%srequested I/O range 0x%lx-0x%lx: in range\n", 121526043836SJohn Baldwin name, suffix, start, end); 1216bb0d0a8eSMike Smith break; 1217bb0d0a8eSMike Smith 1218bb0d0a8eSMike Smith case SYS_RES_MEMORY: 1219a8b354a8SWarner Losh ok = 0; 1220a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) 1221a8b354a8SWarner Losh ok = ok || (start >= sc->membase && end <= sc->memlimit); 1222a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) 1223a8b354a8SWarner Losh ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); 1224d98d9b12SMarcel Moolenaar 1225d98d9b12SMarcel Moolenaar /* 1226d98d9b12SMarcel Moolenaar * Make sure we allow access to VGA memory addresses when the 1227d98d9b12SMarcel Moolenaar * bridge has the "VGA Enable" bit set. 1228d98d9b12SMarcel Moolenaar */ 1229d98d9b12SMarcel Moolenaar if (!ok && pci_is_vga_memory_range(start, end)) 1230d98d9b12SMarcel Moolenaar ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1231d98d9b12SMarcel Moolenaar 1232e4b59fc5SWarner Losh if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1233a8b354a8SWarner Losh if (!ok) { 1234a8b354a8SWarner Losh ok = 1; 1235a8b354a8SWarner Losh if (flags & RF_PREFETCHABLE) { 1236a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1237a8b354a8SWarner Losh if (start < sc->pmembase) 1238a8b354a8SWarner Losh start = sc->pmembase; 1239a8b354a8SWarner Losh if (end > sc->pmemlimit) 1240a8b354a8SWarner Losh end = sc->pmemlimit; 1241a8b354a8SWarner Losh } else { 1242a8b354a8SWarner Losh ok = 0; 1243a8b354a8SWarner Losh } 1244a8b354a8SWarner Losh } else { /* non-prefetchable */ 1245a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1246a8b354a8SWarner Losh if (start < sc->membase) 124712b8c86eSWarner Losh start = sc->membase; 124812b8c86eSWarner Losh if (end > sc->memlimit) 124912b8c86eSWarner Losh end = sc->memlimit; 12501c54ff33SMatthew N. Dodd } else { 1251a8b354a8SWarner Losh ok = 0; 1252a8b354a8SWarner Losh } 1253a8b354a8SWarner Losh } 1254a8b354a8SWarner Losh } 1255a8b354a8SWarner Losh } else if (!ok) { 1256e4b59fc5SWarner Losh ok = 1; /* subtractive bridge: always ok */ 12579dffe835SWarner Losh #if 0 1258a8b354a8SWarner Losh if (pcib_is_nonprefetch_open(sc)) { 1259795dceffSWarner Losh if (start < sc->memlimit && end > sc->membase) 1260795dceffSWarner Losh start = sc->memlimit + 1; 1261a8b354a8SWarner Losh } 1262a8b354a8SWarner Losh if (pcib_is_prefetch_open(sc)) { 1263795dceffSWarner Losh if (start < sc->pmemlimit && end > sc->pmembase) 1264795dceffSWarner Losh start = sc->pmemlimit + 1; 12651c54ff33SMatthew N. Dodd } 12669dffe835SWarner Losh #endif 126712b8c86eSWarner Losh } 1268a8b354a8SWarner Losh if (end < start) { 12692daa7a07SWarner Losh device_printf(dev, "memory: end (%lx) < start (%lx)\n", 12702daa7a07SWarner Losh end, start); 1271a8b354a8SWarner Losh start = 0; 1272a8b354a8SWarner Losh end = 0; 1273a8b354a8SWarner Losh ok = 0; 1274a8b354a8SWarner Losh } 1275a8b354a8SWarner Losh if (!ok && bootverbose) 127634428485SWarner Losh device_printf(dev, 127726043836SJohn Baldwin "%s%srequested unsupported memory range %#lx-%#lx " 1278b0a2d4b8SWarner Losh "(decoding %#jx-%#jx, %#jx-%#jx)\n", 127926043836SJohn Baldwin name, suffix, start, end, 1280b0a2d4b8SWarner Losh (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, 1281b0a2d4b8SWarner Losh (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 1282a8b354a8SWarner Losh if (!ok) 1283bb0d0a8eSMike Smith return (NULL); 12844fa59183SMike Smith if (bootverbose) 128526043836SJohn Baldwin device_printf(dev,"%s%srequested memory range " 12862daa7a07SWarner Losh "0x%lx-0x%lx: good\n", 128726043836SJohn Baldwin name, suffix, start, end); 12884fa59183SMike Smith break; 12894fa59183SMike Smith 1290bb0d0a8eSMike Smith default: 12914fa59183SMike Smith break; 1292bb0d0a8eSMike Smith } 1293bb0d0a8eSMike Smith /* 1294bb0d0a8eSMike Smith * Bridge is OK decoding this resource, so pass it up. 1295bb0d0a8eSMike Smith */ 12962daa7a07SWarner Losh return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 12972daa7a07SWarner Losh count, flags)); 1298bb0d0a8eSMike Smith } 1299*83c41143SJohn Baldwin #endif 1300bb0d0a8eSMike Smith 1301bb0d0a8eSMike Smith /* 1302bb0d0a8eSMike Smith * PCIB interface. 1303bb0d0a8eSMike Smith */ 13046f0d5884SJohn Baldwin int 1305bb0d0a8eSMike Smith pcib_maxslots(device_t dev) 1306bb0d0a8eSMike Smith { 13074fa59183SMike Smith return(PCI_SLOTMAX); 1308bb0d0a8eSMike Smith } 1309bb0d0a8eSMike Smith 1310bb0d0a8eSMike Smith /* 1311bb0d0a8eSMike Smith * Since we are a child of a PCI bus, its parent must support the pcib interface. 1312bb0d0a8eSMike Smith */ 1313b0cb115fSWarner Losh uint32_t 1314795dceffSWarner Losh pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 1315bb0d0a8eSMike Smith { 1316bb0d0a8eSMike Smith return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); 1317bb0d0a8eSMike Smith } 1318bb0d0a8eSMike Smith 13196f0d5884SJohn Baldwin void 1320795dceffSWarner Losh pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) 1321bb0d0a8eSMike Smith { 1322bb0d0a8eSMike Smith PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); 1323bb0d0a8eSMike Smith } 1324bb0d0a8eSMike Smith 1325bb0d0a8eSMike Smith /* 1326bb0d0a8eSMike Smith * Route an interrupt across a PCI bridge. 1327bb0d0a8eSMike Smith */ 13282c2d1d07SBenno Rice int 1329bb0d0a8eSMike Smith pcib_route_interrupt(device_t pcib, device_t dev, int pin) 1330bb0d0a8eSMike Smith { 1331bb0d0a8eSMike Smith device_t bus; 1332bb0d0a8eSMike Smith int parent_intpin; 1333bb0d0a8eSMike Smith int intnum; 1334bb0d0a8eSMike Smith 1335bb0d0a8eSMike Smith /* 1336bb0d0a8eSMike Smith * 1337bb0d0a8eSMike Smith * The PCI standard defines a swizzle of the child-side device/intpin to 1338bb0d0a8eSMike Smith * the parent-side intpin as follows. 1339bb0d0a8eSMike Smith * 1340bb0d0a8eSMike Smith * device = device on child bus 1341bb0d0a8eSMike Smith * child_intpin = intpin on child bus slot (0-3) 1342bb0d0a8eSMike Smith * parent_intpin = intpin on parent bus slot (0-3) 1343bb0d0a8eSMike Smith * 1344bb0d0a8eSMike Smith * parent_intpin = (device + child_intpin) % 4 1345bb0d0a8eSMike Smith */ 1346cdc95e1bSBernd Walter parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; 1347bb0d0a8eSMike Smith 1348bb0d0a8eSMike Smith /* 1349bb0d0a8eSMike Smith * Our parent is a PCI bus. Its parent must export the pcib interface 1350bb0d0a8eSMike Smith * which includes the ability to route interrupts. 1351bb0d0a8eSMike Smith */ 1352bb0d0a8eSMike Smith bus = device_get_parent(pcib); 1353bb0d0a8eSMike Smith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 135439981fedSJohn Baldwin if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { 1355c6a121abSJohn Baldwin device_printf(pcib, "slot %d INT%c is routed to irq %d\n", 1356c6a121abSJohn Baldwin pci_get_slot(dev), 'A' + pin - 1, intnum); 13578046c4b9SMike Smith } 1358bb0d0a8eSMike Smith return(intnum); 1359bb0d0a8eSMike Smith } 1360b173edafSJohn Baldwin 1361e706f7f0SJohn Baldwin /* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ 13629bf4c9c1SJohn Baldwin int 13639bf4c9c1SJohn Baldwin pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 13649bf4c9c1SJohn Baldwin { 1365bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13669bf4c9c1SJohn Baldwin device_t bus; 13679bf4c9c1SJohn Baldwin 136822bf1c7fSJohn Baldwin if (sc->flags & PCIB_DISABLE_MSI) 136922bf1c7fSJohn Baldwin return (ENXIO); 13709bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13719bf4c9c1SJohn Baldwin return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 13729bf4c9c1SJohn Baldwin irqs)); 13739bf4c9c1SJohn Baldwin } 13749bf4c9c1SJohn Baldwin 1375e706f7f0SJohn Baldwin /* Pass request to release MSI/MSI-X messages up to the parent bridge. */ 13769bf4c9c1SJohn Baldwin int 13779bf4c9c1SJohn Baldwin pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 13789bf4c9c1SJohn Baldwin { 13799bf4c9c1SJohn Baldwin device_t bus; 13809bf4c9c1SJohn Baldwin 13819bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 13829bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); 13839bf4c9c1SJohn Baldwin } 13849bf4c9c1SJohn Baldwin 13859bf4c9c1SJohn Baldwin /* Pass request to alloc an MSI-X message up to the parent bridge. */ 13869bf4c9c1SJohn Baldwin int 1387e706f7f0SJohn Baldwin pcib_alloc_msix(device_t pcib, device_t dev, int *irq) 13889bf4c9c1SJohn Baldwin { 1389bd82bbb1SAndrew Gallatin struct pcib_softc *sc = device_get_softc(pcib); 13909bf4c9c1SJohn Baldwin device_t bus; 13919bf4c9c1SJohn Baldwin 139222bf1c7fSJohn Baldwin if (sc->flags & PCIB_DISABLE_MSI) 139322bf1c7fSJohn Baldwin return (ENXIO); 13949bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 1395e706f7f0SJohn Baldwin return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 13965fe82bcaSJohn Baldwin } 13975fe82bcaSJohn Baldwin 13989bf4c9c1SJohn Baldwin /* Pass request to release an MSI-X message up to the parent bridge. */ 13999bf4c9c1SJohn Baldwin int 14009bf4c9c1SJohn Baldwin pcib_release_msix(device_t pcib, device_t dev, int irq) 14019bf4c9c1SJohn Baldwin { 14029bf4c9c1SJohn Baldwin device_t bus; 14039bf4c9c1SJohn Baldwin 14049bf4c9c1SJohn Baldwin bus = device_get_parent(pcib); 14059bf4c9c1SJohn Baldwin return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); 14069bf4c9c1SJohn Baldwin } 14079bf4c9c1SJohn Baldwin 1408e706f7f0SJohn Baldwin /* Pass request to map MSI/MSI-X message up to parent bridge. */ 1409e706f7f0SJohn Baldwin int 1410e706f7f0SJohn Baldwin pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 1411e706f7f0SJohn Baldwin uint32_t *data) 1412e706f7f0SJohn Baldwin { 1413e706f7f0SJohn Baldwin device_t bus; 14144522ac77SLuoqi Chen int error; 1415e706f7f0SJohn Baldwin 1416e706f7f0SJohn Baldwin bus = device_get_parent(pcib); 14174522ac77SLuoqi Chen error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 14184522ac77SLuoqi Chen if (error) 14194522ac77SLuoqi Chen return (error); 14204522ac77SLuoqi Chen 14214522ac77SLuoqi Chen pci_ht_map_msi(pcib, *addr); 14224522ac77SLuoqi Chen return (0); 1423e706f7f0SJohn Baldwin } 1424e706f7f0SJohn Baldwin 142562508c53SJohn Baldwin /* Pass request for device power state up to parent bridge. */ 142662508c53SJohn Baldwin int 142762508c53SJohn Baldwin pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 142862508c53SJohn Baldwin { 142962508c53SJohn Baldwin device_t bus; 143062508c53SJohn Baldwin 143162508c53SJohn Baldwin bus = device_get_parent(pcib); 143262508c53SJohn Baldwin return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); 143362508c53SJohn Baldwin } 143462508c53SJohn Baldwin 1435b173edafSJohn Baldwin /* 1436b173edafSJohn Baldwin * Try to read the bus number of a host-PCI bridge using appropriate config 1437b173edafSJohn Baldwin * registers. 1438b173edafSJohn Baldwin */ 1439b173edafSJohn Baldwin int 1440b173edafSJohn Baldwin host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, 1441b0cb115fSWarner Losh uint8_t *busnum) 1442b173edafSJohn Baldwin { 1443b0cb115fSWarner Losh uint32_t id; 1444b173edafSJohn Baldwin 1445b173edafSJohn Baldwin id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); 14461bbf2464SJohn Baldwin if (id == 0xffffffff) 1447b173edafSJohn Baldwin return (0); 1448b173edafSJohn Baldwin 1449b173edafSJohn Baldwin switch (id) { 1450b173edafSJohn Baldwin case 0x12258086: 1451b173edafSJohn Baldwin /* Intel 824?? */ 1452b173edafSJohn Baldwin /* XXX This is a guess */ 1453b173edafSJohn Baldwin /* *busnum = read_config(bus, slot, func, 0x41, 1); */ 1454b173edafSJohn Baldwin *busnum = bus; 1455b173edafSJohn Baldwin break; 1456b173edafSJohn Baldwin case 0x84c48086: 1457b173edafSJohn Baldwin /* Intel 82454KX/GX (Orion) */ 1458b173edafSJohn Baldwin *busnum = read_config(bus, slot, func, 0x4a, 1); 1459b173edafSJohn Baldwin break; 1460b173edafSJohn Baldwin case 0x84ca8086: 1461b173edafSJohn Baldwin /* 1462b173edafSJohn Baldwin * For the 450nx chipset, there is a whole bundle of 1463b173edafSJohn Baldwin * things pretending to be host bridges. The MIOC will 1464b173edafSJohn Baldwin * be seen first and isn't really a pci bridge (the 1465b173edafSJohn Baldwin * actual busses are attached to the PXB's). We need to 1466b173edafSJohn Baldwin * read the registers of the MIOC to figure out the 1467b173edafSJohn Baldwin * bus numbers for the PXB channels. 1468b173edafSJohn Baldwin * 1469b173edafSJohn Baldwin * Since the MIOC doesn't have a pci bus attached, we 1470b173edafSJohn Baldwin * pretend it wasn't there. 1471b173edafSJohn Baldwin */ 1472b173edafSJohn Baldwin return (0); 1473b173edafSJohn Baldwin case 0x84cb8086: 1474b173edafSJohn Baldwin switch (slot) { 1475b173edafSJohn Baldwin case 0x12: 1476b173edafSJohn Baldwin /* Intel 82454NX PXB#0, Bus#A */ 14771bbf2464SJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd0, 1); 1478b173edafSJohn Baldwin break; 1479b173edafSJohn Baldwin case 0x13: 1480b173edafSJohn Baldwin /* Intel 82454NX PXB#0, Bus#B */ 14811bbf2464SJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; 1482b173edafSJohn Baldwin break; 1483b173edafSJohn Baldwin case 0x14: 1484b173edafSJohn Baldwin /* Intel 82454NX PXB#1, Bus#A */ 14851bbf2464SJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd3, 1); 1486b173edafSJohn Baldwin break; 1487b173edafSJohn Baldwin case 0x15: 1488b173edafSJohn Baldwin /* Intel 82454NX PXB#1, Bus#B */ 14891bbf2464SJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; 1490b173edafSJohn Baldwin break; 1491b173edafSJohn Baldwin } 1492b173edafSJohn Baldwin break; 1493b173edafSJohn Baldwin 1494b173edafSJohn Baldwin /* ServerWorks -- vendor 0x1166 */ 1495b173edafSJohn Baldwin case 0x00051166: 1496b173edafSJohn Baldwin case 0x00061166: 1497b173edafSJohn Baldwin case 0x00081166: 1498b173edafSJohn Baldwin case 0x00091166: 1499b173edafSJohn Baldwin case 0x00101166: 1500b173edafSJohn Baldwin case 0x00111166: 1501b173edafSJohn Baldwin case 0x00171166: 1502b173edafSJohn Baldwin case 0x01011166: 1503b173edafSJohn Baldwin case 0x010f1014: 15049d763248SJohn Baldwin case 0x01101166: 1505b173edafSJohn Baldwin case 0x02011166: 15069d763248SJohn Baldwin case 0x02251166: 1507b173edafSJohn Baldwin case 0x03021014: 1508b173edafSJohn Baldwin *busnum = read_config(bus, slot, func, 0x44, 1); 1509b173edafSJohn Baldwin break; 15105165a17dSJohn Baldwin 15115165a17dSJohn Baldwin /* Compaq/HP -- vendor 0x0e11 */ 15125165a17dSJohn Baldwin case 0x60100e11: 15135165a17dSJohn Baldwin *busnum = read_config(bus, slot, func, 0xc8, 1); 15145165a17dSJohn Baldwin break; 1515b173edafSJohn Baldwin default: 1516b173edafSJohn Baldwin /* Don't know how to read bus number. */ 1517b173edafSJohn Baldwin return 0; 1518b173edafSJohn Baldwin } 1519b173edafSJohn Baldwin 1520b173edafSJohn Baldwin return 1; 1521b173edafSJohn Baldwin } 1522