pci_pci.c revision 279443
169783Smsmith/*- 269783Smsmith * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier 369783Smsmith * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 469783Smsmith * Copyright (c) 2000 BSDi 569783Smsmith * All rights reserved. 669783Smsmith * 769783Smsmith * Redistribution and use in source and binary forms, with or without 869783Smsmith * modification, are permitted provided that the following conditions 969783Smsmith * are met: 1069783Smsmith * 1. Redistributions of source code must retain the above copyright 1169783Smsmith * notice, this list of conditions and the following disclaimer. 1269783Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1369783Smsmith * notice, this list of conditions and the following disclaimer in the 1469783Smsmith * documentation and/or other materials provided with the distribution. 1569783Smsmith * 3. The name of the author may not be used to endorse or promote products 1669783Smsmith * derived from this software without specific prior written permission. 1769783Smsmith * 1869783Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1969783Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2069783Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2169783Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2269783Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2369783Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2469783Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2569783Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2669783Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2769783Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2869783Smsmith * SUCH DAMAGE. 2969783Smsmith */ 3069783Smsmith 31119418Sobrien#include <sys/cdefs.h> 32119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/pci/pci_pci.c 279443 2015-03-01 00:39:40Z rstone $"); 33119418Sobrien 3469783Smsmith/* 3569783Smsmith * PCI:PCI bridge support. 3669783Smsmith */ 3769783Smsmith 3869783Smsmith#include <sys/param.h> 39221393Sjhb#include <sys/bus.h> 4069783Smsmith#include <sys/kernel.h> 41221393Sjhb#include <sys/malloc.h> 42129876Sphk#include <sys/module.h> 43107546Simp#include <sys/rman.h> 44106844Smdodd#include <sys/sysctl.h> 45221393Sjhb#include <sys/systm.h> 4669783Smsmith 47119285Simp#include <dev/pci/pcivar.h> 48119285Simp#include <dev/pci/pcireg.h> 49211430Sjhb#include <dev/pci/pci_private.h> 50119285Simp#include <dev/pci/pcib_private.h> 5169783Smsmith 5269783Smsmith#include "pcib_if.h" 5369783Smsmith 5469783Smsmithstatic int pcib_probe(device_t dev); 55200341Sjkimstatic int pcib_suspend(device_t dev); 56200341Sjkimstatic int pcib_resume(device_t dev); 57211430Sjhbstatic int pcib_power_for_sleep(device_t pcib, device_t dev, 58211430Sjhb int *pstate); 59264011Srstonestatic uint16_t pcib_ari_get_rid(device_t pcib, device_t dev); 60264011Srstonestatic uint32_t pcib_read_config(device_t dev, u_int b, u_int s, 61264011Srstone u_int f, u_int reg, int width); 62264011Srstonestatic void pcib_write_config(device_t dev, u_int b, u_int s, 63264011Srstone u_int f, u_int reg, uint32_t val, int width); 64264011Srstonestatic int pcib_ari_maxslots(device_t dev); 65264011Srstonestatic int pcib_ari_maxfuncs(device_t dev); 66264011Srstonestatic int pcib_try_enable_ari(device_t pcib, device_t dev); 67279443Srstonestatic int pcib_ari_enabled(device_t pcib); 68279443Srstonestatic void pcib_ari_decode_rid(device_t pcib, uint16_t rid, 69279443Srstone int *bus, int *slot, int *func); 7069783Smsmith 7169783Smsmithstatic device_method_t pcib_methods[] = { 7269783Smsmith /* Device interface */ 7369783Smsmith DEVMETHOD(device_probe, pcib_probe), 7469783Smsmith DEVMETHOD(device_attach, pcib_attach), 75145661Simp DEVMETHOD(device_detach, bus_generic_detach), 7669783Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 77200341Sjkim DEVMETHOD(device_suspend, pcib_suspend), 78200341Sjkim DEVMETHOD(device_resume, pcib_resume), 7969783Smsmith 8069783Smsmith /* Bus interface */ 8169783Smsmith DEVMETHOD(bus_read_ivar, pcib_read_ivar), 8269783Smsmith DEVMETHOD(bus_write_ivar, pcib_write_ivar), 8369783Smsmith DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), 84221393Sjhb#ifdef NEW_PCIB 85221393Sjhb DEVMETHOD(bus_adjust_resource, pcib_adjust_resource), 86221393Sjhb DEVMETHOD(bus_release_resource, pcib_release_resource), 87221393Sjhb#else 88221324Sjhb DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 8969783Smsmith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 90221393Sjhb#endif 9169783Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 9269783Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 9369783Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 9469783Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 9569783Smsmith 9669783Smsmith /* pcib interface */ 97264011Srstone DEVMETHOD(pcib_maxslots, pcib_ari_maxslots), 98264011Srstone DEVMETHOD(pcib_maxfuncs, pcib_ari_maxfuncs), 9969783Smsmith DEVMETHOD(pcib_read_config, pcib_read_config), 10069783Smsmith DEVMETHOD(pcib_write_config, pcib_write_config), 10169783Smsmith DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 102164264Sjhb DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), 103164264Sjhb DEVMETHOD(pcib_release_msi, pcib_release_msi), 104164264Sjhb DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), 105164264Sjhb DEVMETHOD(pcib_release_msix, pcib_release_msix), 106169221Sjhb DEVMETHOD(pcib_map_msi, pcib_map_msi), 107211430Sjhb DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep), 108264011Srstone DEVMETHOD(pcib_get_rid, pcib_ari_get_rid), 109264011Srstone DEVMETHOD(pcib_try_enable_ari, pcib_try_enable_ari), 110279443Srstone DEVMETHOD(pcib_ari_enabled, pcib_ari_enabled), 111279443Srstone DEVMETHOD(pcib_decode_rid, pcib_ari_decode_rid), 11269783Smsmith 113227843Smarius DEVMETHOD_END 11469783Smsmith}; 11569783Smsmith 116154079Sjhbstatic devclass_t pcib_devclass; 11769783Smsmith 118154079SjhbDEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); 119253120SmariusDRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, NULL, NULL); 12069783Smsmith 121221393Sjhb#ifdef NEW_PCIB 122261527SjhbSYSCTL_DECL(_hw_pci); 123221393Sjhb 124261527Sjhbstatic int pci_clear_pcib; 125261527SjhbSYSCTL_INT(_hw_pci, OID_AUTO, clear_pcib, CTLFLAG_RDTUN, &pci_clear_pcib, 0, 126261527Sjhb "Clear firmware-assigned resources for PCI-PCI bridge I/O windows."); 127261527Sjhb 128221393Sjhb/* 129221393Sjhb * Is a resource from a child device sub-allocated from one of our 130221393Sjhb * resource managers? 131221393Sjhb */ 132221393Sjhbstatic int 133221393Sjhbpcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r) 134221393Sjhb{ 135221393Sjhb 136221393Sjhb switch (type) { 137261790Sjhb#ifdef PCI_RES_BUS 138261790Sjhb case PCI_RES_BUS: 139261790Sjhb return (rman_is_region_manager(r, &sc->bus.rman)); 140261790Sjhb#endif 141221393Sjhb case SYS_RES_IOPORT: 142221393Sjhb return (rman_is_region_manager(r, &sc->io.rman)); 143221393Sjhb case SYS_RES_MEMORY: 144221393Sjhb /* Prefetchable resources may live in either memory rman. */ 145221393Sjhb if (rman_get_flags(r) & RF_PREFETCHABLE && 146221393Sjhb rman_is_region_manager(r, &sc->pmem.rman)) 147221393Sjhb return (1); 148221393Sjhb return (rman_is_region_manager(r, &sc->mem.rman)); 149221393Sjhb } 150221393Sjhb return (0); 151221393Sjhb} 152221393Sjhb 153221393Sjhbstatic int 154221393Sjhbpcib_is_window_open(struct pcib_window *pw) 155221393Sjhb{ 156221393Sjhb 157221393Sjhb return (pw->valid && pw->base < pw->limit); 158221393Sjhb} 159221393Sjhb 160221393Sjhb/* 161221393Sjhb * XXX: If RF_ACTIVE did not also imply allocating a bus space tag and 162221393Sjhb * handle for the resource, we could pass RF_ACTIVE up to the PCI bus 163221393Sjhb * when allocating the resource windows and rely on the PCI bus driver 164221393Sjhb * to do this for us. 165221393Sjhb */ 166221393Sjhbstatic void 167221393Sjhbpcib_activate_window(struct pcib_softc *sc, int type) 168221393Sjhb{ 169221393Sjhb 170221393Sjhb PCI_ENABLE_IO(device_get_parent(sc->dev), sc->dev, type); 171221393Sjhb} 172221393Sjhb 173221393Sjhbstatic void 174221393Sjhbpcib_write_windows(struct pcib_softc *sc, int mask) 175221393Sjhb{ 176221393Sjhb device_t dev; 177221393Sjhb uint32_t val; 178221393Sjhb 179221393Sjhb dev = sc->dev; 180221393Sjhb if (sc->io.valid && mask & WIN_IO) { 181221393Sjhb val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 182221393Sjhb if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 183221393Sjhb pci_write_config(dev, PCIR_IOBASEH_1, 184221393Sjhb sc->io.base >> 16, 2); 185221393Sjhb pci_write_config(dev, PCIR_IOLIMITH_1, 186221393Sjhb sc->io.limit >> 16, 2); 187221393Sjhb } 188221393Sjhb pci_write_config(dev, PCIR_IOBASEL_1, sc->io.base >> 8, 1); 189221393Sjhb pci_write_config(dev, PCIR_IOLIMITL_1, sc->io.limit >> 8, 1); 190221393Sjhb } 191221393Sjhb 192221393Sjhb if (mask & WIN_MEM) { 193221393Sjhb pci_write_config(dev, PCIR_MEMBASE_1, sc->mem.base >> 16, 2); 194221393Sjhb pci_write_config(dev, PCIR_MEMLIMIT_1, sc->mem.limit >> 16, 2); 195221393Sjhb } 196221393Sjhb 197221393Sjhb if (sc->pmem.valid && mask & WIN_PMEM) { 198221393Sjhb val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 199221393Sjhb if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 200221393Sjhb pci_write_config(dev, PCIR_PMBASEH_1, 201221393Sjhb sc->pmem.base >> 32, 4); 202221393Sjhb pci_write_config(dev, PCIR_PMLIMITH_1, 203221393Sjhb sc->pmem.limit >> 32, 4); 204221393Sjhb } 205221393Sjhb pci_write_config(dev, PCIR_PMBASEL_1, sc->pmem.base >> 16, 2); 206221393Sjhb pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmem.limit >> 16, 2); 207221393Sjhb } 208221393Sjhb} 209221393Sjhb 210253450Sjhb/* 211253450Sjhb * This is used to reject I/O port allocations that conflict with an 212253450Sjhb * ISA alias range. 213253450Sjhb */ 214253450Sjhbstatic int 215253450Sjhbpcib_is_isa_range(struct pcib_softc *sc, u_long start, u_long end, u_long count) 216253450Sjhb{ 217253450Sjhb u_long next_alias; 218253450Sjhb 219253450Sjhb if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE)) 220253450Sjhb return (0); 221253450Sjhb 222253450Sjhb /* Only check fixed ranges for overlap. */ 223253450Sjhb if (start + count - 1 != end) 224253450Sjhb return (0); 225253450Sjhb 226253450Sjhb /* ISA aliases are only in the lower 64KB of I/O space. */ 227253450Sjhb if (start >= 65536) 228253450Sjhb return (0); 229253450Sjhb 230253450Sjhb /* Check for overlap with 0x000 - 0x0ff as a special case. */ 231253450Sjhb if (start < 0x100) 232253450Sjhb goto alias; 233253450Sjhb 234253450Sjhb /* 235253450Sjhb * If the start address is an alias, the range is an alias. 236253450Sjhb * Otherwise, compute the start of the next alias range and 237253450Sjhb * check if it is before the end of the candidate range. 238253450Sjhb */ 239253450Sjhb if ((start & 0x300) != 0) 240253450Sjhb goto alias; 241253450Sjhb next_alias = (start & ~0x3fful) | 0x100; 242253450Sjhb if (next_alias <= end) 243253450Sjhb goto alias; 244253450Sjhb return (0); 245253450Sjhb 246253450Sjhbalias: 247253450Sjhb if (bootverbose) 248253450Sjhb device_printf(sc->dev, 249253450Sjhb "I/O range %#lx-%#lx overlaps with an ISA alias\n", start, 250253450Sjhb end); 251253450Sjhb return (1); 252253450Sjhb} 253253450Sjhb 254221393Sjhbstatic void 255253450Sjhbpcib_add_window_resources(struct pcib_window *w, struct resource **res, 256253450Sjhb int count) 257253450Sjhb{ 258253450Sjhb struct resource **newarray; 259253450Sjhb int error, i; 260253450Sjhb 261253450Sjhb newarray = malloc(sizeof(struct resource *) * (w->count + count), 262253450Sjhb M_DEVBUF, M_WAITOK); 263253450Sjhb if (w->res != NULL) 264253450Sjhb bcopy(w->res, newarray, sizeof(struct resource *) * w->count); 265253450Sjhb bcopy(res, newarray + w->count, sizeof(struct resource *) * count); 266253450Sjhb free(w->res, M_DEVBUF); 267253450Sjhb w->res = newarray; 268253450Sjhb w->count += count; 269253450Sjhb 270253450Sjhb for (i = 0; i < count; i++) { 271253450Sjhb error = rman_manage_region(&w->rman, rman_get_start(res[i]), 272253450Sjhb rman_get_end(res[i])); 273253450Sjhb if (error) 274253450Sjhb panic("Failed to add resource to rman"); 275253450Sjhb } 276253450Sjhb} 277253450Sjhb 278253450Sjhbtypedef void (nonisa_callback)(u_long start, u_long end, void *arg); 279253450Sjhb 280253450Sjhbstatic void 281253450Sjhbpcib_walk_nonisa_ranges(u_long start, u_long end, nonisa_callback *cb, 282253450Sjhb void *arg) 283253450Sjhb{ 284253450Sjhb u_long next_end; 285253450Sjhb 286253450Sjhb /* 287253450Sjhb * If start is within an ISA alias range, move up to the start 288253450Sjhb * of the next non-alias range. As a special case, addresses 289253450Sjhb * in the range 0x000 - 0x0ff should also be skipped since 290253450Sjhb * those are used for various system I/O devices in ISA 291253450Sjhb * systems. 292253450Sjhb */ 293253450Sjhb if (start <= 65535) { 294253450Sjhb if (start < 0x100 || (start & 0x300) != 0) { 295253450Sjhb start &= ~0x3ff; 296253450Sjhb start += 0x400; 297253450Sjhb } 298253450Sjhb } 299253450Sjhb 300253450Sjhb /* ISA aliases are only in the lower 64KB of I/O space. */ 301253450Sjhb while (start <= MIN(end, 65535)) { 302253450Sjhb next_end = MIN(start | 0xff, end); 303253450Sjhb cb(start, next_end, arg); 304253450Sjhb start += 0x400; 305253450Sjhb } 306253450Sjhb 307253450Sjhb if (start <= end) 308253450Sjhb cb(start, end, arg); 309253450Sjhb} 310253450Sjhb 311253450Sjhbstatic void 312253450Sjhbcount_ranges(u_long start, u_long end, void *arg) 313253450Sjhb{ 314253450Sjhb int *countp; 315253450Sjhb 316253450Sjhb countp = arg; 317253450Sjhb (*countp)++; 318253450Sjhb} 319253450Sjhb 320253450Sjhbstruct alloc_state { 321253450Sjhb struct resource **res; 322253450Sjhb struct pcib_softc *sc; 323253450Sjhb int count, error; 324253450Sjhb}; 325253450Sjhb 326253450Sjhbstatic void 327253450Sjhballoc_ranges(u_long start, u_long end, void *arg) 328253450Sjhb{ 329253450Sjhb struct alloc_state *as; 330253450Sjhb struct pcib_window *w; 331253450Sjhb int rid; 332253450Sjhb 333253450Sjhb as = arg; 334253450Sjhb if (as->error != 0) 335253450Sjhb return; 336253450Sjhb 337253450Sjhb w = &as->sc->io; 338253450Sjhb rid = w->reg; 339253450Sjhb if (bootverbose) 340253450Sjhb device_printf(as->sc->dev, 341253450Sjhb "allocating non-ISA range %#lx-%#lx\n", start, end); 342253450Sjhb as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT, 343253450Sjhb &rid, start, end, end - start + 1, 0); 344253450Sjhb if (as->res[as->count] == NULL) 345253450Sjhb as->error = ENXIO; 346253450Sjhb else 347253450Sjhb as->count++; 348253450Sjhb} 349253450Sjhb 350253450Sjhbstatic int 351253450Sjhbpcib_alloc_nonisa_ranges(struct pcib_softc *sc, u_long start, u_long end) 352253450Sjhb{ 353253450Sjhb struct alloc_state as; 354253450Sjhb int i, new_count; 355253450Sjhb 356253450Sjhb /* First, see how many ranges we need. */ 357253450Sjhb new_count = 0; 358253450Sjhb pcib_walk_nonisa_ranges(start, end, count_ranges, &new_count); 359253450Sjhb 360253450Sjhb /* Second, allocate the ranges. */ 361253450Sjhb as.res = malloc(sizeof(struct resource *) * new_count, M_DEVBUF, 362253450Sjhb M_WAITOK); 363253450Sjhb as.sc = sc; 364253450Sjhb as.count = 0; 365253450Sjhb as.error = 0; 366253450Sjhb pcib_walk_nonisa_ranges(start, end, alloc_ranges, &as); 367253450Sjhb if (as.error != 0) { 368253450Sjhb for (i = 0; i < as.count; i++) 369253450Sjhb bus_release_resource(sc->dev, SYS_RES_IOPORT, 370253450Sjhb sc->io.reg, as.res[i]); 371253450Sjhb free(as.res, M_DEVBUF); 372253450Sjhb return (as.error); 373253450Sjhb } 374253450Sjhb KASSERT(as.count == new_count, ("%s: count mismatch", __func__)); 375253450Sjhb 376253450Sjhb /* Third, add the ranges to the window. */ 377253450Sjhb pcib_add_window_resources(&sc->io, as.res, as.count); 378253450Sjhb free(as.res, M_DEVBUF); 379253450Sjhb return (0); 380253450Sjhb} 381253450Sjhb 382253450Sjhbstatic void 383221393Sjhbpcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, 384221393Sjhb int flags, pci_addr_t max_address) 385221393Sjhb{ 386253450Sjhb struct resource *res; 387221393Sjhb char buf[64]; 388221393Sjhb int error, rid; 389221393Sjhb 390221393Sjhb if (max_address != (u_long)max_address) 391221393Sjhb max_address = ~0ul; 392221393Sjhb w->rman.rm_start = 0; 393221393Sjhb w->rman.rm_end = max_address; 394221393Sjhb w->rman.rm_type = RMAN_ARRAY; 395221393Sjhb snprintf(buf, sizeof(buf), "%s %s window", 396221393Sjhb device_get_nameunit(sc->dev), w->name); 397221393Sjhb w->rman.rm_descr = strdup(buf, M_DEVBUF); 398221393Sjhb error = rman_init(&w->rman); 399221393Sjhb if (error) 400221393Sjhb panic("Failed to initialize %s %s rman", 401221393Sjhb device_get_nameunit(sc->dev), w->name); 402221393Sjhb 403221393Sjhb if (!pcib_is_window_open(w)) 404221393Sjhb return; 405221393Sjhb 406221393Sjhb if (w->base > max_address || w->limit > max_address) { 407221393Sjhb device_printf(sc->dev, 408221393Sjhb "initial %s window has too many bits, ignoring\n", w->name); 409221393Sjhb return; 410221393Sjhb } 411253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE) 412253450Sjhb (void)pcib_alloc_nonisa_ranges(sc, w->base, w->limit); 413253450Sjhb else { 414253450Sjhb rid = w->reg; 415253450Sjhb res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit, 416253450Sjhb w->limit - w->base + 1, flags); 417253450Sjhb if (res != NULL) 418253450Sjhb pcib_add_window_resources(w, &res, 1); 419253450Sjhb } 420221393Sjhb if (w->res == NULL) { 421221393Sjhb device_printf(sc->dev, 422221393Sjhb "failed to allocate initial %s window: %#jx-%#jx\n", 423221393Sjhb w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 424221393Sjhb w->base = max_address; 425221393Sjhb w->limit = 0; 426221393Sjhb pcib_write_windows(sc, w->mask); 427221393Sjhb return; 428221393Sjhb } 429221393Sjhb pcib_activate_window(sc, type); 430221393Sjhb} 431221393Sjhb 432221393Sjhb/* 433221393Sjhb * Initialize I/O windows. 434221393Sjhb */ 435221393Sjhbstatic void 436221393Sjhbpcib_probe_windows(struct pcib_softc *sc) 437221393Sjhb{ 438221393Sjhb pci_addr_t max; 439221393Sjhb device_t dev; 440221393Sjhb uint32_t val; 441221393Sjhb 442221393Sjhb dev = sc->dev; 443221393Sjhb 444261527Sjhb if (pci_clear_pcib) { 445261527Sjhb pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); 446261527Sjhb pci_write_config(dev, PCIR_IOBASEH_1, 0xffff, 2); 447261527Sjhb pci_write_config(dev, PCIR_IOLIMITL_1, 0, 1); 448261527Sjhb pci_write_config(dev, PCIR_IOLIMITH_1, 0, 2); 449261527Sjhb pci_write_config(dev, PCIR_MEMBASE_1, 0xffff, 2); 450261527Sjhb pci_write_config(dev, PCIR_MEMLIMIT_1, 0, 2); 451261527Sjhb pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); 452261527Sjhb pci_write_config(dev, PCIR_PMBASEH_1, 0xffffffff, 4); 453261527Sjhb pci_write_config(dev, PCIR_PMLIMITL_1, 0, 2); 454261527Sjhb pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4); 455261527Sjhb } 456261527Sjhb 457221393Sjhb /* Determine if the I/O port window is implemented. */ 458221393Sjhb val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 459221393Sjhb if (val == 0) { 460221393Sjhb /* 461221393Sjhb * If 'val' is zero, then only 16-bits of I/O space 462221393Sjhb * are supported. 463221393Sjhb */ 464221393Sjhb pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); 465221393Sjhb if (pci_read_config(dev, PCIR_IOBASEL_1, 1) != 0) { 466221393Sjhb sc->io.valid = 1; 467221393Sjhb pci_write_config(dev, PCIR_IOBASEL_1, 0, 1); 468221393Sjhb } 469221393Sjhb } else 470221393Sjhb sc->io.valid = 1; 471221393Sjhb 472221393Sjhb /* Read the existing I/O port window. */ 473221393Sjhb if (sc->io.valid) { 474221393Sjhb sc->io.reg = PCIR_IOBASEL_1; 475221393Sjhb sc->io.step = 12; 476221393Sjhb sc->io.mask = WIN_IO; 477221393Sjhb sc->io.name = "I/O port"; 478221393Sjhb if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 479221393Sjhb sc->io.base = PCI_PPBIOBASE( 480221393Sjhb pci_read_config(dev, PCIR_IOBASEH_1, 2), val); 481221393Sjhb sc->io.limit = PCI_PPBIOLIMIT( 482221393Sjhb pci_read_config(dev, PCIR_IOLIMITH_1, 2), 483221393Sjhb pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 484221393Sjhb max = 0xffffffff; 485221393Sjhb } else { 486221393Sjhb sc->io.base = PCI_PPBIOBASE(0, val); 487221393Sjhb sc->io.limit = PCI_PPBIOLIMIT(0, 488221393Sjhb pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 489221393Sjhb max = 0xffff; 490221393Sjhb } 491221393Sjhb pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max); 492221393Sjhb } 493221393Sjhb 494221393Sjhb /* Read the existing memory window. */ 495221393Sjhb sc->mem.valid = 1; 496221393Sjhb sc->mem.reg = PCIR_MEMBASE_1; 497221393Sjhb sc->mem.step = 20; 498221393Sjhb sc->mem.mask = WIN_MEM; 499221393Sjhb sc->mem.name = "memory"; 500221393Sjhb sc->mem.base = PCI_PPBMEMBASE(0, 501221393Sjhb pci_read_config(dev, PCIR_MEMBASE_1, 2)); 502221393Sjhb sc->mem.limit = PCI_PPBMEMLIMIT(0, 503221393Sjhb pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 504221393Sjhb pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, 0xffffffff); 505221393Sjhb 506221393Sjhb /* Determine if the prefetchable memory window is implemented. */ 507221393Sjhb val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 508221393Sjhb if (val == 0) { 509221393Sjhb /* 510221393Sjhb * If 'val' is zero, then only 32-bits of memory space 511221393Sjhb * are supported. 512221393Sjhb */ 513221393Sjhb pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); 514221393Sjhb if (pci_read_config(dev, PCIR_PMBASEL_1, 2) != 0) { 515221393Sjhb sc->pmem.valid = 1; 516221393Sjhb pci_write_config(dev, PCIR_PMBASEL_1, 0, 2); 517221393Sjhb } 518221393Sjhb } else 519221393Sjhb sc->pmem.valid = 1; 520221393Sjhb 521221393Sjhb /* Read the existing prefetchable memory window. */ 522221393Sjhb if (sc->pmem.valid) { 523221393Sjhb sc->pmem.reg = PCIR_PMBASEL_1; 524221393Sjhb sc->pmem.step = 20; 525221393Sjhb sc->pmem.mask = WIN_PMEM; 526221393Sjhb sc->pmem.name = "prefetch"; 527221393Sjhb if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 528221393Sjhb sc->pmem.base = PCI_PPBMEMBASE( 529221393Sjhb pci_read_config(dev, PCIR_PMBASEH_1, 4), val); 530221393Sjhb sc->pmem.limit = PCI_PPBMEMLIMIT( 531221393Sjhb pci_read_config(dev, PCIR_PMLIMITH_1, 4), 532221393Sjhb pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 533221393Sjhb max = 0xffffffffffffffff; 534221393Sjhb } else { 535221393Sjhb sc->pmem.base = PCI_PPBMEMBASE(0, val); 536221393Sjhb sc->pmem.limit = PCI_PPBMEMLIMIT(0, 537221393Sjhb pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 538221393Sjhb max = 0xffffffff; 539221393Sjhb } 540221393Sjhb pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY, 541221393Sjhb RF_PREFETCHABLE, max); 542221393Sjhb } 543221393Sjhb} 544221393Sjhb 545261790Sjhb#ifdef PCI_RES_BUS 546261790Sjhb/* 547261790Sjhb * Allocate a suitable secondary bus for this bridge if needed and 548261790Sjhb * initialize the resource manager for the secondary bus range. Note 549261790Sjhb * that the minimum count is a desired value and this may allocate a 550261790Sjhb * smaller range. 551261790Sjhb */ 552261790Sjhbvoid 553261790Sjhbpcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count) 554261790Sjhb{ 555261790Sjhb char buf[64]; 556261790Sjhb int error, rid; 557261790Sjhb 558261790Sjhb switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) { 559261790Sjhb case PCIM_HDRTYPE_BRIDGE: 560261790Sjhb bus->sub_reg = PCIR_SUBBUS_1; 561261790Sjhb break; 562261790Sjhb case PCIM_HDRTYPE_CARDBUS: 563261790Sjhb bus->sub_reg = PCIR_SUBBUS_2; 564261790Sjhb break; 565261790Sjhb default: 566261790Sjhb panic("not a PCI bridge"); 567261790Sjhb } 568261790Sjhb bus->dev = dev; 569261790Sjhb bus->rman.rm_start = 0; 570261790Sjhb bus->rman.rm_end = PCI_BUSMAX; 571261790Sjhb bus->rman.rm_type = RMAN_ARRAY; 572261790Sjhb snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev)); 573261790Sjhb bus->rman.rm_descr = strdup(buf, M_DEVBUF); 574261790Sjhb error = rman_init(&bus->rman); 575261790Sjhb if (error) 576261790Sjhb panic("Failed to initialize %s bus number rman", 577261790Sjhb device_get_nameunit(dev)); 578261790Sjhb 579261790Sjhb /* 580261790Sjhb * Allocate a bus range. This will return an existing bus range 581261790Sjhb * if one exists, or a new bus range if one does not. 582261790Sjhb */ 583261790Sjhb rid = 0; 584261790Sjhb bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul, 585261790Sjhb min_count, 0); 586261790Sjhb if (bus->res == NULL) { 587261790Sjhb /* 588261790Sjhb * Fall back to just allocating a range of a single bus 589261790Sjhb * number. 590261790Sjhb */ 591261790Sjhb bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul, 592261790Sjhb 1, 0); 593261790Sjhb } else if (rman_get_size(bus->res) < min_count) 594261790Sjhb /* 595261790Sjhb * Attempt to grow the existing range to satisfy the 596261790Sjhb * minimum desired count. 597261790Sjhb */ 598261790Sjhb (void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res, 599261790Sjhb rman_get_start(bus->res), rman_get_start(bus->res) + 600261790Sjhb min_count - 1); 601261790Sjhb 602261790Sjhb /* 603261790Sjhb * Add the initial resource to the rman. 604261790Sjhb */ 605261790Sjhb if (bus->res != NULL) { 606261790Sjhb error = rman_manage_region(&bus->rman, rman_get_start(bus->res), 607261790Sjhb rman_get_end(bus->res)); 608261790Sjhb if (error) 609261790Sjhb panic("Failed to add resource to rman"); 610261790Sjhb bus->sec = rman_get_start(bus->res); 611261790Sjhb bus->sub = rman_get_end(bus->res); 612261790Sjhb } 613261790Sjhb} 614261790Sjhb 615261790Sjhbstatic struct resource * 616261790Sjhbpcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid, 617261790Sjhb u_long start, u_long end, u_long count, u_int flags) 618261790Sjhb{ 619261790Sjhb struct resource *res; 620261790Sjhb 621261790Sjhb res = rman_reserve_resource(&bus->rman, start, end, count, flags, 622261790Sjhb child); 623261790Sjhb if (res == NULL) 624261790Sjhb return (NULL); 625261790Sjhb 626261790Sjhb if (bootverbose) 627261790Sjhb device_printf(bus->dev, 628261790Sjhb "allocated bus range (%lu-%lu) for rid %d of %s\n", 629261790Sjhb rman_get_start(res), rman_get_end(res), *rid, 630261790Sjhb pcib_child_name(child)); 631261790Sjhb rman_set_rid(res, *rid); 632261790Sjhb return (res); 633261790Sjhb} 634261790Sjhb 635261790Sjhb/* 636261790Sjhb * Attempt to grow the secondary bus range. This is much simpler than 637261790Sjhb * for I/O windows as the range can only be grown by increasing 638261790Sjhb * subbus. 639261790Sjhb */ 640261790Sjhbstatic int 641261790Sjhbpcib_grow_subbus(struct pcib_secbus *bus, u_long new_end) 642261790Sjhb{ 643261790Sjhb u_long old_end; 644261790Sjhb int error; 645261790Sjhb 646261790Sjhb old_end = rman_get_end(bus->res); 647261790Sjhb KASSERT(new_end > old_end, ("attempt to shrink subbus")); 648261790Sjhb error = bus_adjust_resource(bus->dev, PCI_RES_BUS, bus->res, 649261790Sjhb rman_get_start(bus->res), new_end); 650261790Sjhb if (error) 651261790Sjhb return (error); 652261790Sjhb if (bootverbose) 653261790Sjhb device_printf(bus->dev, "grew bus range to %lu-%lu\n", 654261790Sjhb rman_get_start(bus->res), rman_get_end(bus->res)); 655261790Sjhb error = rman_manage_region(&bus->rman, old_end + 1, 656261790Sjhb rman_get_end(bus->res)); 657261790Sjhb if (error) 658261790Sjhb panic("Failed to add resource to rman"); 659261790Sjhb bus->sub = rman_get_end(bus->res); 660261790Sjhb pci_write_config(bus->dev, bus->sub_reg, bus->sub, 1); 661261790Sjhb return (0); 662261790Sjhb} 663261790Sjhb 664261790Sjhbstruct resource * 665261790Sjhbpcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid, 666261790Sjhb u_long start, u_long end, u_long count, u_int flags) 667261790Sjhb{ 668261790Sjhb struct resource *res; 669261790Sjhb u_long start_free, end_free, new_end; 670261790Sjhb 671261790Sjhb /* 672261790Sjhb * First, see if the request can be satisified by the existing 673261790Sjhb * bus range. 674261790Sjhb */ 675261790Sjhb res = pcib_suballoc_bus(bus, child, rid, start, end, count, flags); 676261790Sjhb if (res != NULL) 677261790Sjhb return (res); 678261790Sjhb 679261790Sjhb /* 680261790Sjhb * Figure out a range to grow the bus range. First, find the 681261790Sjhb * first bus number after the last allocated bus in the rman and 682261790Sjhb * enforce that as a minimum starting point for the range. 683261790Sjhb */ 684261790Sjhb if (rman_last_free_region(&bus->rman, &start_free, &end_free) != 0 || 685261790Sjhb end_free != bus->sub) 686261790Sjhb start_free = bus->sub + 1; 687261790Sjhb if (start_free < start) 688261790Sjhb start_free = start; 689261790Sjhb new_end = start_free + count - 1; 690261790Sjhb 691261790Sjhb /* 692261790Sjhb * See if this new range would satisfy the request if it 693261790Sjhb * succeeds. 694261790Sjhb */ 695261790Sjhb if (new_end > end) 696261790Sjhb return (NULL); 697261790Sjhb 698261790Sjhb /* Finally, attempt to grow the existing resource. */ 699261790Sjhb if (bootverbose) { 700261790Sjhb device_printf(bus->dev, 701261790Sjhb "attempting to grow bus range for %lu buses\n", count); 702261790Sjhb printf("\tback candidate range: %lu-%lu\n", start_free, 703261790Sjhb new_end); 704261790Sjhb } 705261790Sjhb if (pcib_grow_subbus(bus, new_end) == 0) 706261790Sjhb return (pcib_suballoc_bus(bus, child, rid, start, end, count, 707261790Sjhb flags)); 708261790Sjhb return (NULL); 709261790Sjhb} 710261790Sjhb#endif 711261790Sjhb 712221393Sjhb#else 713221393Sjhb 714221393Sjhb/* 715163805Simp * Is the prefetch window open (eg, can we allocate memory in it?) 716163805Simp */ 717163805Simpstatic int 718163805Simppcib_is_prefetch_open(struct pcib_softc *sc) 719163805Simp{ 720163805Simp return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); 721163805Simp} 722163805Simp 723163805Simp/* 724163805Simp * Is the nonprefetch window open (eg, can we allocate memory in it?) 725163805Simp */ 726163805Simpstatic int 727163805Simppcib_is_nonprefetch_open(struct pcib_softc *sc) 728163805Simp{ 729163805Simp return (sc->membase > 0 && sc->membase < sc->memlimit); 730163805Simp} 731163805Simp 732163805Simp/* 733163805Simp * Is the io window open (eg, can we allocate ports in it?) 734163805Simp */ 735163805Simpstatic int 736163805Simppcib_is_io_open(struct pcib_softc *sc) 737163805Simp{ 738163805Simp return (sc->iobase > 0 && sc->iobase < sc->iolimit); 739163805Simp} 740163805Simp 741163805Simp/* 742200341Sjkim * Get current I/O decode. 743200341Sjkim */ 744200341Sjkimstatic void 745200341Sjkimpcib_get_io_decode(struct pcib_softc *sc) 746200341Sjkim{ 747200341Sjkim device_t dev; 748200341Sjkim uint32_t iolow; 749200341Sjkim 750200341Sjkim dev = sc->dev; 751200341Sjkim 752200341Sjkim iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); 753200341Sjkim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 754200341Sjkim sc->iobase = PCI_PPBIOBASE( 755200341Sjkim pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow); 756200341Sjkim else 757200341Sjkim sc->iobase = PCI_PPBIOBASE(0, iolow); 758200341Sjkim 759200341Sjkim iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); 760200341Sjkim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 761200341Sjkim sc->iolimit = PCI_PPBIOLIMIT( 762200341Sjkim pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow); 763200341Sjkim else 764200341Sjkim sc->iolimit = PCI_PPBIOLIMIT(0, iolow); 765200341Sjkim} 766200341Sjkim 767200341Sjkim/* 768200341Sjkim * Get current memory decode. 769200341Sjkim */ 770200341Sjkimstatic void 771200341Sjkimpcib_get_mem_decode(struct pcib_softc *sc) 772200341Sjkim{ 773200341Sjkim device_t dev; 774200341Sjkim pci_addr_t pmemlow; 775200341Sjkim 776200341Sjkim dev = sc->dev; 777200341Sjkim 778200341Sjkim sc->membase = PCI_PPBMEMBASE(0, 779200341Sjkim pci_read_config(dev, PCIR_MEMBASE_1, 2)); 780200341Sjkim sc->memlimit = PCI_PPBMEMLIMIT(0, 781200341Sjkim pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 782200341Sjkim 783200341Sjkim pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2); 784200341Sjkim if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 785200341Sjkim sc->pmembase = PCI_PPBMEMBASE( 786200341Sjkim pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow); 787200341Sjkim else 788200341Sjkim sc->pmembase = PCI_PPBMEMBASE(0, pmemlow); 789200341Sjkim 790200341Sjkim pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2); 791200341Sjkim if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 792200341Sjkim sc->pmemlimit = PCI_PPBMEMLIMIT( 793200341Sjkim pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow); 794200341Sjkim else 795200341Sjkim sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow); 796200341Sjkim} 797200341Sjkim 798200341Sjkim/* 799200341Sjkim * Restore previous I/O decode. 800200341Sjkim */ 801200341Sjkimstatic void 802200341Sjkimpcib_set_io_decode(struct pcib_softc *sc) 803200341Sjkim{ 804200341Sjkim device_t dev; 805200341Sjkim uint32_t iohi; 806200341Sjkim 807200341Sjkim dev = sc->dev; 808200341Sjkim 809200341Sjkim iohi = sc->iobase >> 16; 810200341Sjkim if (iohi > 0) 811200341Sjkim pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2); 812200341Sjkim pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1); 813200341Sjkim 814200341Sjkim iohi = sc->iolimit >> 16; 815200341Sjkim if (iohi > 0) 816200341Sjkim pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2); 817200341Sjkim pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1); 818200341Sjkim} 819200341Sjkim 820200341Sjkim/* 821200341Sjkim * Restore previous memory decode. 822200341Sjkim */ 823200341Sjkimstatic void 824200341Sjkimpcib_set_mem_decode(struct pcib_softc *sc) 825200341Sjkim{ 826200341Sjkim device_t dev; 827200341Sjkim pci_addr_t pmemhi; 828200341Sjkim 829200341Sjkim dev = sc->dev; 830200341Sjkim 831200341Sjkim pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2); 832200341Sjkim pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2); 833200341Sjkim 834200341Sjkim pmemhi = sc->pmembase >> 32; 835200341Sjkim if (pmemhi > 0) 836200341Sjkim pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4); 837200341Sjkim pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2); 838200341Sjkim 839200341Sjkim pmemhi = sc->pmemlimit >> 32; 840200341Sjkim if (pmemhi > 0) 841200341Sjkim pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4); 842200341Sjkim pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2); 843200341Sjkim} 844221393Sjhb#endif 845200341Sjkim 846200341Sjkim/* 847200341Sjkim * Get current bridge configuration. 848200341Sjkim */ 849200341Sjkimstatic void 850200341Sjkimpcib_cfg_save(struct pcib_softc *sc) 851200341Sjkim{ 852200341Sjkim device_t dev; 853200341Sjkim 854200341Sjkim dev = sc->dev; 855200341Sjkim 856200341Sjkim sc->command = pci_read_config(dev, PCIR_COMMAND, 2); 857200341Sjkim sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1); 858261790Sjhb sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1); 859261790Sjhb sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1); 860200341Sjkim sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 861200341Sjkim sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); 862221393Sjhb#ifndef NEW_PCIB 863200341Sjkim if (sc->command & PCIM_CMD_PORTEN) 864200341Sjkim pcib_get_io_decode(sc); 865200341Sjkim if (sc->command & PCIM_CMD_MEMEN) 866200341Sjkim pcib_get_mem_decode(sc); 867221393Sjhb#endif 868200341Sjkim} 869200341Sjkim 870200341Sjkim/* 871200341Sjkim * Restore previous bridge configuration. 872200341Sjkim */ 873200341Sjkimstatic void 874200341Sjkimpcib_cfg_restore(struct pcib_softc *sc) 875200341Sjkim{ 876200341Sjkim device_t dev; 877200341Sjkim 878200341Sjkim dev = sc->dev; 879200341Sjkim 880200341Sjkim pci_write_config(dev, PCIR_COMMAND, sc->command, 2); 881200341Sjkim pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); 882261790Sjhb pci_write_config(dev, PCIR_SECBUS_1, sc->bus.sec, 1); 883261790Sjhb pci_write_config(dev, PCIR_SUBBUS_1, sc->bus.sub, 1); 884200341Sjkim pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2); 885200341Sjkim pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1); 886221393Sjhb#ifdef NEW_PCIB 887221393Sjhb pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM); 888221393Sjhb#else 889200341Sjkim if (sc->command & PCIM_CMD_PORTEN) 890200341Sjkim pcib_set_io_decode(sc); 891200341Sjkim if (sc->command & PCIM_CMD_MEMEN) 892200341Sjkim pcib_set_mem_decode(sc); 893221393Sjhb#endif 894200341Sjkim} 895200341Sjkim 896200341Sjkim/* 89769783Smsmith * Generic device interface 89869783Smsmith */ 89969783Smsmithstatic int 90069783Smsmithpcib_probe(device_t dev) 90169783Smsmith{ 90269783Smsmith if ((pci_get_class(dev) == PCIC_BRIDGE) && 90369783Smsmith (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { 90469783Smsmith device_set_desc(dev, "PCI-PCI bridge"); 90569783Smsmith return(-10000); 90669783Smsmith } 90769783Smsmith return(ENXIO); 90869783Smsmith} 90969783Smsmith 910102441Sjhbvoid 911102441Sjhbpcib_attach_common(device_t dev) 91269783Smsmith{ 91369783Smsmith struct pcib_softc *sc; 914181789Simp struct sysctl_ctx_list *sctx; 915181789Simp struct sysctl_oid *soid; 916253450Sjhb int comma; 91769783Smsmith 91869783Smsmith sc = device_get_softc(dev); 91969783Smsmith sc->dev = dev; 92069783Smsmith 92169908Smsmith /* 92269908Smsmith * Get current bridge configuration. 92369908Smsmith */ 924200341Sjkim sc->domain = pci_get_domain(dev); 925200341Sjkim sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); 926200341Sjkim pcib_cfg_save(sc); 92769783Smsmith 92869908Smsmith /* 929261790Sjhb * The primary bus register should always be the bus of the 930261790Sjhb * parent. 931261790Sjhb */ 932261790Sjhb sc->pribus = pci_get_bus(dev); 933261790Sjhb pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); 934261790Sjhb 935261790Sjhb /* 936181789Simp * Setup sysctl reporting nodes 937181789Simp */ 938181789Simp sctx = device_get_sysctl_ctx(dev); 939181789Simp soid = device_get_sysctl_tree(dev); 940181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", 941182706Simp CTLFLAG_RD, &sc->domain, 0, "Domain number"); 942181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", 943182706Simp CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); 944181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", 945261790Sjhb CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number"); 946181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", 947261790Sjhb CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number"); 948181789Simp 949181789Simp /* 95069908Smsmith * Quirk handling. 95169908Smsmith */ 95269908Smsmith switch (pci_get_devid(dev)) { 953261790Sjhb#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS) 954124365Simp case 0x12258086: /* Intel 82454KX/GX (Orion) */ 95569908Smsmith { 956119266Simp uint8_t supbus; 95769908Smsmith 95869908Smsmith supbus = pci_read_config(dev, 0x41, 1); 95969908Smsmith if (supbus != 0xff) { 960261790Sjhb sc->bus.sec = supbus + 1; 961261790Sjhb sc->bus.sub = supbus + 1; 96269908Smsmith } 963124365Simp break; 96469908Smsmith } 965261790Sjhb#endif 966124365Simp 967124365Simp /* 968124365Simp * The i82380FB mobile docking controller is a PCI-PCI bridge, 969124365Simp * and it is a subtractive bridge. However, the ProgIf is wrong 970124365Simp * so the normal setting of PCIB_SUBTRACTIVE bit doesn't 971124365Simp * happen. There's also a Toshiba bridge that behaves this 972124365Simp * way. 973124365Simp */ 974124365Simp case 0x124b8086: /* Intel 82380FB Mobile */ 975124365Simp case 0x060513d7: /* Toshiba ???? */ 976124365Simp sc->flags |= PCIB_SUBTRACTIVE; 97769908Smsmith break; 978149521Sjkim 979261790Sjhb#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS) 980149521Sjkim /* Compaq R3000 BIOS sets wrong subordinate bus number. */ 981149521Sjkim case 0x00dd10de: 982149521Sjkim { 983149521Sjkim char *cp; 984149521Sjkim 985273174Sdavide if ((cp = kern_getenv("smbios.planar.maker")) == NULL) 986149521Sjkim break; 987157949Sjkim if (strncmp(cp, "Compal", 6) != 0) { 988157949Sjkim freeenv(cp); 989149521Sjkim break; 990157949Sjkim } 991157949Sjkim freeenv(cp); 992273174Sdavide if ((cp = kern_getenv("smbios.planar.product")) == NULL) 993157949Sjkim break; 994157949Sjkim if (strncmp(cp, "08A0", 4) != 0) { 995157949Sjkim freeenv(cp); 996157949Sjkim break; 997157949Sjkim } 998157949Sjkim freeenv(cp); 999261790Sjhb if (sc->bus.sub < 0xa) { 1000149521Sjkim pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1); 1001261790Sjhb sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1); 1002149521Sjkim } 1003149521Sjkim break; 1004149521Sjkim } 1005261790Sjhb#endif 100669908Smsmith } 100769908Smsmith 1008165995Sjhb if (pci_msi_device_blacklisted(dev)) 1009165995Sjhb sc->flags |= PCIB_DISABLE_MSI; 1010165995Sjhb 1011253120Smarius if (pci_msix_device_blacklisted(dev)) 1012253120Smarius sc->flags |= PCIB_DISABLE_MSIX; 1013253120Smarius 1014124365Simp /* 1015124365Simp * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, 1016124365Simp * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, 1017124365Simp * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. 1018124365Simp * This means they act as if they were subtractively decoding 1019124365Simp * bridges and pass all transactions. Mark them and real ProgIf 1 1020124365Simp * parts as subtractive. 1021124365Simp */ 1022124365Simp if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || 1023168157Sjhb pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE) 1024124365Simp sc->flags |= PCIB_SUBTRACTIVE; 1025221393Sjhb 1026221393Sjhb#ifdef NEW_PCIB 1027261790Sjhb#ifdef PCI_RES_BUS 1028261790Sjhb pcib_setup_secbus(dev, &sc->bus, 1); 1029261790Sjhb#endif 1030221393Sjhb pcib_probe_windows(sc); 1031221393Sjhb#endif 103269783Smsmith if (bootverbose) { 1033172394Smarius device_printf(dev, " domain %d\n", sc->domain); 1034261790Sjhb device_printf(dev, " secondary bus %d\n", sc->bus.sec); 1035261790Sjhb device_printf(dev, " subordinate bus %d\n", sc->bus.sub); 1036221393Sjhb#ifdef NEW_PCIB 1037221393Sjhb if (pcib_is_window_open(&sc->io)) 1038221393Sjhb device_printf(dev, " I/O decode 0x%jx-0x%jx\n", 1039221393Sjhb (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit); 1040221393Sjhb if (pcib_is_window_open(&sc->mem)) 1041221393Sjhb device_printf(dev, " memory decode 0x%jx-0x%jx\n", 1042221393Sjhb (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit); 1043221393Sjhb if (pcib_is_window_open(&sc->pmem)) 1044221393Sjhb device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 1045221393Sjhb (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit); 1046221393Sjhb#else 1047221393Sjhb if (pcib_is_io_open(sc)) 1048221393Sjhb device_printf(dev, " I/O decode 0x%x-0x%x\n", 1049221393Sjhb sc->iobase, sc->iolimit); 1050163805Simp if (pcib_is_nonprefetch_open(sc)) 1051163805Simp device_printf(dev, " memory decode 0x%jx-0x%jx\n", 1052163805Simp (uintmax_t)sc->membase, (uintmax_t)sc->memlimit); 1053163805Simp if (pcib_is_prefetch_open(sc)) 1054163805Simp device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 1055163805Simp (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 1056221393Sjhb#endif 1057253450Sjhb if (sc->bridgectl & (PCIB_BCR_ISA_ENABLE | PCIB_BCR_VGA_ENABLE) || 1058253450Sjhb sc->flags & PCIB_SUBTRACTIVE) { 1059253450Sjhb device_printf(dev, " special decode "); 1060253450Sjhb comma = 0; 1061253450Sjhb if (sc->bridgectl & PCIB_BCR_ISA_ENABLE) { 1062253450Sjhb printf("ISA"); 1063253450Sjhb comma = 1; 1064253450Sjhb } 1065253450Sjhb if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) { 1066253450Sjhb printf("%sVGA", comma ? ", " : ""); 1067253450Sjhb comma = 1; 1068253450Sjhb } 1069253450Sjhb if (sc->flags & PCIB_SUBTRACTIVE) 1070253450Sjhb printf("%ssubtractive", comma ? ", " : ""); 1071253450Sjhb printf("\n"); 1072253450Sjhb } 107369783Smsmith } 107469783Smsmith 107569783Smsmith /* 1076239103Sjhb * Always enable busmastering on bridges so that transactions 1077239103Sjhb * initiated on the secondary bus are passed through to the 1078239103Sjhb * primary bus. 1079239103Sjhb */ 1080239103Sjhb pci_enable_busmaster(dev); 1081102441Sjhb} 108269783Smsmith 1083103042Sjhbint 1084102441Sjhbpcib_attach(device_t dev) 1085102441Sjhb{ 1086102441Sjhb struct pcib_softc *sc; 1087102441Sjhb device_t child; 1088102441Sjhb 1089102441Sjhb pcib_attach_common(dev); 1090102441Sjhb sc = device_get_softc(dev); 1091261790Sjhb if (sc->bus.sec != 0) { 1092261790Sjhb child = device_add_child(dev, "pci", sc->bus.sec); 109369783Smsmith if (child != NULL) 109469783Smsmith return(bus_generic_attach(dev)); 1095181798Simp } 109669783Smsmith 109769783Smsmith /* no secondary bus; we should have fixed this */ 109869783Smsmith return(0); 109969783Smsmith} 110069783Smsmith 1101102441Sjhbint 1102200341Sjkimpcib_suspend(device_t dev) 1103200341Sjkim{ 1104211430Sjhb device_t pcib; 1105200341Sjkim int dstate, error; 1106200341Sjkim 1107200341Sjkim pcib_cfg_save(device_get_softc(dev)); 1108200341Sjkim error = bus_generic_suspend(dev); 1109214110Sjkim if (error == 0 && pci_do_power_suspend) { 1110211430Sjhb dstate = PCI_POWERSTATE_D3; 1111211430Sjhb pcib = device_get_parent(device_get_parent(dev)); 1112211430Sjhb if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) 1113200341Sjkim pci_set_powerstate(dev, dstate); 1114200341Sjkim } 1115200341Sjkim return (error); 1116200341Sjkim} 1117200341Sjkim 1118200341Sjkimint 1119200341Sjkimpcib_resume(device_t dev) 1120200341Sjkim{ 1121211430Sjhb device_t pcib; 1122277710Sjhb int dstate; 1123200341Sjkim 1124200341Sjkim if (pci_do_power_resume) { 1125211430Sjhb pcib = device_get_parent(device_get_parent(dev)); 1126277710Sjhb dstate = PCI_POWERSTATE_D0; 1127277710Sjhb if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) 1128277710Sjhb pci_set_powerstate(dev, dstate); 1129200341Sjkim } 1130200341Sjkim pcib_cfg_restore(device_get_softc(dev)); 1131200341Sjkim return (bus_generic_resume(dev)); 1132200341Sjkim} 1133200341Sjkim 1134200341Sjkimint 113569783Smsmithpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 113669783Smsmith{ 113769783Smsmith struct pcib_softc *sc = device_get_softc(dev); 113869783Smsmith 113969783Smsmith switch (which) { 1140172394Smarius case PCIB_IVAR_DOMAIN: 1141172394Smarius *result = sc->domain; 1142172394Smarius return(0); 114369783Smsmith case PCIB_IVAR_BUS: 1144261790Sjhb *result = sc->bus.sec; 114569783Smsmith return(0); 114669783Smsmith } 114769783Smsmith return(ENOENT); 114869783Smsmith} 114969783Smsmith 1150102441Sjhbint 115169783Smsmithpcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 115269783Smsmith{ 115369783Smsmith 115469783Smsmith switch (which) { 1155172394Smarius case PCIB_IVAR_DOMAIN: 1156172394Smarius return(EINVAL); 115769783Smsmith case PCIB_IVAR_BUS: 1158261790Sjhb return(EINVAL); 115969783Smsmith } 116069783Smsmith return(ENOENT); 116169783Smsmith} 116269783Smsmith 1163221393Sjhb#ifdef NEW_PCIB 116469783Smsmith/* 1165221393Sjhb * Attempt to allocate a resource from the existing resources assigned 1166221393Sjhb * to a window. 1167221393Sjhb */ 1168221393Sjhbstatic struct resource * 1169221393Sjhbpcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w, 1170221393Sjhb device_t child, int type, int *rid, u_long start, u_long end, u_long count, 1171221393Sjhb u_int flags) 1172221393Sjhb{ 1173221393Sjhb struct resource *res; 1174221393Sjhb 1175221393Sjhb if (!pcib_is_window_open(w)) 1176221393Sjhb return (NULL); 1177221393Sjhb 1178221393Sjhb res = rman_reserve_resource(&w->rman, start, end, count, 1179221393Sjhb flags & ~RF_ACTIVE, child); 1180221393Sjhb if (res == NULL) 1181221393Sjhb return (NULL); 1182221393Sjhb 1183221393Sjhb if (bootverbose) 1184221393Sjhb device_printf(sc->dev, 1185221393Sjhb "allocated %s range (%#lx-%#lx) for rid %x of %s\n", 1186221393Sjhb w->name, rman_get_start(res), rman_get_end(res), *rid, 1187221393Sjhb pcib_child_name(child)); 1188221393Sjhb rman_set_rid(res, *rid); 1189221393Sjhb 1190221393Sjhb /* 1191221393Sjhb * If the resource should be active, pass that request up the 1192221393Sjhb * tree. This assumes the parent drivers can handle 1193221393Sjhb * activating sub-allocated resources. 1194221393Sjhb */ 1195221393Sjhb if (flags & RF_ACTIVE) { 1196221393Sjhb if (bus_activate_resource(child, type, *rid, res) != 0) { 1197221393Sjhb rman_release_resource(res); 1198221393Sjhb return (NULL); 1199221393Sjhb } 1200221393Sjhb } 1201221393Sjhb 1202221393Sjhb return (res); 1203221393Sjhb} 1204221393Sjhb 1205253450Sjhb/* Allocate a fresh resource range for an unconfigured window. */ 1206253450Sjhbstatic int 1207253450Sjhbpcib_alloc_new_window(struct pcib_softc *sc, struct pcib_window *w, int type, 1208253450Sjhb u_long start, u_long end, u_long count, u_int flags) 1209253450Sjhb{ 1210253450Sjhb struct resource *res; 1211253450Sjhb u_long base, limit, wmask; 1212253450Sjhb int rid; 1213253450Sjhb 1214253450Sjhb /* 1215253450Sjhb * If this is an I/O window on a bridge with ISA enable set 1216253450Sjhb * and the start address is below 64k, then try to allocate an 1217253450Sjhb * initial window of 0x1000 bytes long starting at address 1218253450Sjhb * 0xf000 and walking down. Note that if the original request 1219253450Sjhb * was larger than the non-aliased range size of 0x100 our 1220253450Sjhb * caller would have raised the start address up to 64k 1221253450Sjhb * already. 1222253450Sjhb */ 1223253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && 1224253450Sjhb start < 65536) { 1225253450Sjhb for (base = 0xf000; (long)base >= 0; base -= 0x1000) { 1226253450Sjhb limit = base + 0xfff; 1227253450Sjhb 1228253450Sjhb /* 1229253450Sjhb * Skip ranges that wouldn't work for the 1230253450Sjhb * original request. Note that the actual 1231253450Sjhb * window that overlaps are the non-alias 1232253450Sjhb * ranges within [base, limit], so this isn't 1233253450Sjhb * quite a simple comparison. 1234253450Sjhb */ 1235253450Sjhb if (start + count > limit - 0x400) 1236253450Sjhb continue; 1237253450Sjhb if (base == 0) { 1238253450Sjhb /* 1239253450Sjhb * The first open region for the window at 1240253450Sjhb * 0 is 0x400-0x4ff. 1241253450Sjhb */ 1242253450Sjhb if (end - count + 1 < 0x400) 1243253450Sjhb continue; 1244253450Sjhb } else { 1245253450Sjhb if (end - count + 1 < base) 1246253450Sjhb continue; 1247253450Sjhb } 1248253450Sjhb 1249253450Sjhb if (pcib_alloc_nonisa_ranges(sc, base, limit) == 0) { 1250253450Sjhb w->base = base; 1251253450Sjhb w->limit = limit; 1252253450Sjhb return (0); 1253253450Sjhb } 1254253450Sjhb } 1255253450Sjhb return (ENOSPC); 1256253450Sjhb } 1257253450Sjhb 1258253450Sjhb wmask = (1ul << w->step) - 1; 1259253450Sjhb if (RF_ALIGNMENT(flags) < w->step) { 1260253450Sjhb flags &= ~RF_ALIGNMENT_MASK; 1261253450Sjhb flags |= RF_ALIGNMENT_LOG2(w->step); 1262253450Sjhb } 1263253450Sjhb start &= ~wmask; 1264253450Sjhb end |= wmask; 1265253450Sjhb count = roundup2(count, 1ul << w->step); 1266253450Sjhb rid = w->reg; 1267253450Sjhb res = bus_alloc_resource(sc->dev, type, &rid, start, end, count, 1268253450Sjhb flags & ~RF_ACTIVE); 1269253450Sjhb if (res == NULL) 1270253450Sjhb return (ENOSPC); 1271253450Sjhb pcib_add_window_resources(w, &res, 1); 1272253450Sjhb pcib_activate_window(sc, type); 1273253450Sjhb w->base = rman_get_start(res); 1274253450Sjhb w->limit = rman_get_end(res); 1275253450Sjhb return (0); 1276253450Sjhb} 1277253450Sjhb 1278253450Sjhb/* Try to expand an existing window to the requested base and limit. */ 1279253450Sjhbstatic int 1280253450Sjhbpcib_expand_window(struct pcib_softc *sc, struct pcib_window *w, int type, 1281253450Sjhb u_long base, u_long limit) 1282253450Sjhb{ 1283253450Sjhb struct resource *res; 1284253450Sjhb int error, i, force_64k_base; 1285253450Sjhb 1286253450Sjhb KASSERT(base <= w->base && limit >= w->limit, 1287253450Sjhb ("attempting to shrink window")); 1288253450Sjhb 1289253450Sjhb /* 1290253450Sjhb * XXX: pcib_grow_window() doesn't try to do this anyway and 1291253450Sjhb * the error handling for all the edge cases would be tedious. 1292253450Sjhb */ 1293253450Sjhb KASSERT(limit == w->limit || base == w->base, 1294253450Sjhb ("attempting to grow both ends of a window")); 1295253450Sjhb 1296253450Sjhb /* 1297253450Sjhb * Yet more special handling for requests to expand an I/O 1298253450Sjhb * window behind an ISA-enabled bridge. Since I/O windows 1299253450Sjhb * have to grow in 0x1000 increments and the end of the 0xffff 1300253450Sjhb * range is an alias, growing a window below 64k will always 1301253450Sjhb * result in allocating new resources and never adjusting an 1302253450Sjhb * existing resource. 1303253450Sjhb */ 1304253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && 1305253450Sjhb (limit <= 65535 || (base <= 65535 && base != w->base))) { 1306253450Sjhb KASSERT(limit == w->limit || limit <= 65535, 1307253450Sjhb ("attempting to grow both ends across 64k ISA alias")); 1308253450Sjhb 1309253450Sjhb if (base != w->base) 1310253450Sjhb error = pcib_alloc_nonisa_ranges(sc, base, w->base - 1); 1311253450Sjhb else 1312253450Sjhb error = pcib_alloc_nonisa_ranges(sc, w->limit + 1, 1313253450Sjhb limit); 1314253450Sjhb if (error == 0) { 1315253450Sjhb w->base = base; 1316253450Sjhb w->limit = limit; 1317253450Sjhb } 1318253450Sjhb return (error); 1319253450Sjhb } 1320253450Sjhb 1321253450Sjhb /* 1322253450Sjhb * Find the existing resource to adjust. Usually there is only one, 1323253450Sjhb * but for an ISA-enabled bridge we might be growing the I/O window 1324253450Sjhb * above 64k and need to find the existing resource that maps all 1325253450Sjhb * of the area above 64k. 1326253450Sjhb */ 1327253450Sjhb for (i = 0; i < w->count; i++) { 1328253450Sjhb if (rman_get_end(w->res[i]) == w->limit) 1329253450Sjhb break; 1330253450Sjhb } 1331253450Sjhb KASSERT(i != w->count, ("did not find existing resource")); 1332253450Sjhb res = w->res[i]; 1333253450Sjhb 1334253450Sjhb /* 1335253450Sjhb * Usually the resource we found should match the window's 1336253450Sjhb * existing range. The one exception is the ISA-enabled case 1337253450Sjhb * mentioned above in which case the resource should start at 1338253450Sjhb * 64k. 1339253450Sjhb */ 1340253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && 1341253450Sjhb w->base <= 65535) { 1342253450Sjhb KASSERT(rman_get_start(res) == 65536, 1343253450Sjhb ("existing resource mismatch")); 1344253450Sjhb force_64k_base = 1; 1345253450Sjhb } else { 1346253450Sjhb KASSERT(w->base == rman_get_start(res), 1347253450Sjhb ("existing resource mismatch")); 1348253450Sjhb force_64k_base = 0; 1349253450Sjhb } 1350253450Sjhb 1351253450Sjhb error = bus_adjust_resource(sc->dev, type, res, force_64k_base ? 1352253450Sjhb rman_get_start(res) : base, limit); 1353253450Sjhb if (error) 1354253450Sjhb return (error); 1355253450Sjhb 1356253450Sjhb /* Add the newly allocated region to the resource manager. */ 1357253450Sjhb if (w->base != base) { 1358253450Sjhb error = rman_manage_region(&w->rman, base, w->base - 1); 1359253450Sjhb w->base = base; 1360253450Sjhb } else { 1361253450Sjhb error = rman_manage_region(&w->rman, w->limit + 1, limit); 1362253450Sjhb w->limit = limit; 1363253450Sjhb } 1364253450Sjhb if (error) { 1365253450Sjhb if (bootverbose) 1366253450Sjhb device_printf(sc->dev, 1367253450Sjhb "failed to expand %s resource manager\n", w->name); 1368253450Sjhb (void)bus_adjust_resource(sc->dev, type, res, force_64k_base ? 1369253450Sjhb rman_get_start(res) : w->base, w->limit); 1370253450Sjhb } 1371253450Sjhb return (error); 1372253450Sjhb} 1373253450Sjhb 1374221393Sjhb/* 1375221393Sjhb * Attempt to grow a window to make room for a given resource request. 1376221393Sjhb */ 1377221393Sjhbstatic int 1378221393Sjhbpcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, 1379221393Sjhb u_long start, u_long end, u_long count, u_int flags) 1380221393Sjhb{ 1381237272Sjhb u_long align, start_free, end_free, front, back, wmask; 1382253450Sjhb int error; 1383221393Sjhb 1384221393Sjhb /* 1385221393Sjhb * Clamp the desired resource range to the maximum address 1386221393Sjhb * this window supports. Reject impossible requests. 1387253450Sjhb * 1388253450Sjhb * For I/O port requests behind a bridge with the ISA enable 1389253450Sjhb * bit set, force large allocations to start above 64k. 1390221393Sjhb */ 1391221393Sjhb if (!w->valid) 1392221393Sjhb return (EINVAL); 1393253450Sjhb if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 && 1394253450Sjhb start < 65536) 1395253450Sjhb start = 65536; 1396221393Sjhb if (end > w->rman.rm_end) 1397221393Sjhb end = w->rman.rm_end; 1398221393Sjhb if (start + count - 1 > end || start + count < start) 1399221393Sjhb return (EINVAL); 1400237272Sjhb wmask = (1ul << w->step) - 1; 1401221393Sjhb 1402221393Sjhb /* 1403221393Sjhb * If there is no resource at all, just try to allocate enough 1404221393Sjhb * aligned space for this resource. 1405221393Sjhb */ 1406221393Sjhb if (w->res == NULL) { 1407253450Sjhb error = pcib_alloc_new_window(sc, w, type, start, end, count, 1408253450Sjhb flags); 1409253450Sjhb if (error) { 1410221393Sjhb if (bootverbose) 1411221393Sjhb device_printf(sc->dev, 1412221393Sjhb "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n", 1413221393Sjhb w->name, start, end, count); 1414253450Sjhb return (error); 1415221393Sjhb } 1416221393Sjhb if (bootverbose) 1417221393Sjhb device_printf(sc->dev, 1418253450Sjhb "allocated initial %s window of %#jx-%#jx\n", 1419253450Sjhb w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 1420221393Sjhb goto updatewin; 1421221393Sjhb } 1422221393Sjhb 1423221393Sjhb /* 1424221393Sjhb * See if growing the window would help. Compute the minimum 1425221393Sjhb * amount of address space needed on both the front and back 1426221393Sjhb * ends of the existing window to satisfy the allocation. 1427221393Sjhb * 1428221393Sjhb * For each end, build a candidate region adjusting for the 1429221393Sjhb * required alignment, etc. If there is a free region at the 1430221393Sjhb * edge of the window, grow from the inner edge of the free 1431221393Sjhb * region. Otherwise grow from the window boundary. 1432221393Sjhb * 1433253450Sjhb * Growing an I/O window below 64k for a bridge with the ISA 1434253450Sjhb * enable bit doesn't require any special magic as the step 1435253450Sjhb * size of an I/O window (1k) always includes multiple 1436253450Sjhb * non-alias ranges when it is grown in either direction. 1437253450Sjhb * 1438221393Sjhb * XXX: Special case: if w->res is completely empty and the 1439221393Sjhb * request size is larger than w->res, we should find the 1440221393Sjhb * optimal aligned buffer containing w->res and allocate that. 1441221393Sjhb */ 1442221393Sjhb if (bootverbose) 1443221393Sjhb device_printf(sc->dev, 1444221393Sjhb "attempting to grow %s window for (%#lx-%#lx,%#lx)\n", 1445221393Sjhb w->name, start, end, count); 1446221393Sjhb align = 1ul << RF_ALIGNMENT(flags); 1447253450Sjhb if (start < w->base) { 1448221393Sjhb if (rman_first_free_region(&w->rman, &start_free, &end_free) != 1449253450Sjhb 0 || start_free != w->base) 1450253450Sjhb end_free = w->base; 1451221393Sjhb if (end_free > end) 1452237008Sjhb end_free = end + 1; 1453221393Sjhb 1454221393Sjhb /* Move end_free down until it is properly aligned. */ 1455221393Sjhb end_free &= ~(align - 1); 1456222930Sjhb end_free--; 1457222930Sjhb front = end_free - (count - 1); 1458221393Sjhb 1459221393Sjhb /* 1460221393Sjhb * The resource would now be allocated at (front, 1461221393Sjhb * end_free). Ensure that fits in the (start, end) 1462221393Sjhb * bounds. end_free is checked above. If 'front' is 1463221393Sjhb * ok, ensure it is properly aligned for this window. 1464221393Sjhb * Also check for underflow. 1465221393Sjhb */ 1466221393Sjhb if (front >= start && front <= end_free) { 1467221393Sjhb if (bootverbose) 1468221393Sjhb printf("\tfront candidate range: %#lx-%#lx\n", 1469221393Sjhb front, end_free); 1470237272Sjhb front &= ~wmask; 1471253450Sjhb front = w->base - front; 1472221393Sjhb } else 1473221393Sjhb front = 0; 1474221393Sjhb } else 1475221393Sjhb front = 0; 1476253450Sjhb if (end > w->limit) { 1477221393Sjhb if (rman_last_free_region(&w->rman, &start_free, &end_free) != 1478253450Sjhb 0 || end_free != w->limit) 1479253450Sjhb start_free = w->limit + 1; 1480221393Sjhb if (start_free < start) 1481221393Sjhb start_free = start; 1482221393Sjhb 1483221393Sjhb /* Move start_free up until it is properly aligned. */ 1484221393Sjhb start_free = roundup2(start_free, align); 1485222930Sjhb back = start_free + count - 1; 1486221393Sjhb 1487221393Sjhb /* 1488221393Sjhb * The resource would now be allocated at (start_free, 1489221393Sjhb * back). Ensure that fits in the (start, end) 1490221393Sjhb * bounds. start_free is checked above. If 'back' is 1491221393Sjhb * ok, ensure it is properly aligned for this window. 1492221393Sjhb * Also check for overflow. 1493221393Sjhb */ 1494221393Sjhb if (back <= end && start_free <= back) { 1495221393Sjhb if (bootverbose) 1496221393Sjhb printf("\tback candidate range: %#lx-%#lx\n", 1497221393Sjhb start_free, back); 1498237272Sjhb back |= wmask; 1499253450Sjhb back -= w->limit; 1500221393Sjhb } else 1501221393Sjhb back = 0; 1502221393Sjhb } else 1503221393Sjhb back = 0; 1504221393Sjhb 1505221393Sjhb /* 1506221393Sjhb * Try to allocate the smallest needed region first. 1507221393Sjhb * If that fails, fall back to the other region. 1508221393Sjhb */ 1509221393Sjhb error = ENOSPC; 1510221393Sjhb while (front != 0 || back != 0) { 1511221393Sjhb if (front != 0 && (front <= back || back == 0)) { 1512253450Sjhb error = pcib_expand_window(sc, w, type, w->base - front, 1513253450Sjhb w->limit); 1514221393Sjhb if (error == 0) 1515221393Sjhb break; 1516221393Sjhb front = 0; 1517221393Sjhb } else { 1518253450Sjhb error = pcib_expand_window(sc, w, type, w->base, 1519253450Sjhb w->limit + back); 1520221393Sjhb if (error == 0) 1521221393Sjhb break; 1522221393Sjhb back = 0; 1523221393Sjhb } 1524221393Sjhb } 1525221393Sjhb 1526221393Sjhb if (error) 1527221393Sjhb return (error); 1528221393Sjhb if (bootverbose) 1529253450Sjhb device_printf(sc->dev, "grew %s window to %#jx-%#jx\n", 1530253450Sjhb w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 1531221393Sjhb 1532221393Sjhbupdatewin: 1533253450Sjhb /* Write the new window. */ 1534237272Sjhb KASSERT((w->base & wmask) == 0, ("start address is not aligned")); 1535237272Sjhb KASSERT((w->limit & wmask) == wmask, ("end address is not aligned")); 1536221393Sjhb pcib_write_windows(sc, w->mask); 1537221393Sjhb return (0); 1538221393Sjhb} 1539221393Sjhb 1540221393Sjhb/* 154169783Smsmith * We have to trap resource allocation requests and ensure that the bridge 154269783Smsmith * is set up to, or capable of handling them. 154369783Smsmith */ 1544102441Sjhbstruct resource * 1545221393Sjhbpcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1546221393Sjhb u_long start, u_long end, u_long count, u_int flags) 1547221393Sjhb{ 1548221393Sjhb struct pcib_softc *sc; 1549221393Sjhb struct resource *r; 1550221393Sjhb 1551221393Sjhb sc = device_get_softc(dev); 1552221393Sjhb 1553221393Sjhb /* 1554221393Sjhb * VGA resources are decoded iff the VGA enable bit is set in 1555221393Sjhb * the bridge control register. VGA resources do not fall into 1556221393Sjhb * the resource windows and are passed up to the parent. 1557221393Sjhb */ 1558221393Sjhb if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) || 1559221393Sjhb (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) { 1560221393Sjhb if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) 1561221393Sjhb return (bus_generic_alloc_resource(dev, child, type, 1562221393Sjhb rid, start, end, count, flags)); 1563221393Sjhb else 1564221393Sjhb return (NULL); 1565221393Sjhb } 1566221393Sjhb 1567221393Sjhb switch (type) { 1568261790Sjhb#ifdef PCI_RES_BUS 1569261790Sjhb case PCI_RES_BUS: 1570261790Sjhb return (pcib_alloc_subbus(&sc->bus, child, rid, start, end, 1571261790Sjhb count, flags)); 1572261790Sjhb#endif 1573221393Sjhb case SYS_RES_IOPORT: 1574253450Sjhb if (pcib_is_isa_range(sc, start, end, count)) 1575253450Sjhb return (NULL); 1576221393Sjhb r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start, 1577221393Sjhb end, count, flags); 1578237673Smarius if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 1579221393Sjhb break; 1580221393Sjhb if (pcib_grow_window(sc, &sc->io, type, start, end, count, 1581221393Sjhb flags) == 0) 1582221393Sjhb r = pcib_suballoc_resource(sc, &sc->io, child, type, 1583221393Sjhb rid, start, end, count, flags); 1584221393Sjhb break; 1585221393Sjhb case SYS_RES_MEMORY: 1586221393Sjhb /* 1587221393Sjhb * For prefetchable resources, prefer the prefetchable 1588221393Sjhb * memory window, but fall back to the regular memory 1589221393Sjhb * window if that fails. Try both windows before 1590221393Sjhb * attempting to grow a window in case the firmware 1591221393Sjhb * has used a range in the regular memory window to 1592221393Sjhb * map a prefetchable BAR. 1593221393Sjhb */ 1594221393Sjhb if (flags & RF_PREFETCHABLE) { 1595221393Sjhb r = pcib_suballoc_resource(sc, &sc->pmem, child, type, 1596221393Sjhb rid, start, end, count, flags); 1597221393Sjhb if (r != NULL) 1598221393Sjhb break; 1599221393Sjhb } 1600221393Sjhb r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid, 1601221393Sjhb start, end, count, flags); 1602237673Smarius if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 1603221393Sjhb break; 1604221393Sjhb if (flags & RF_PREFETCHABLE) { 1605221393Sjhb if (pcib_grow_window(sc, &sc->pmem, type, start, end, 1606221393Sjhb count, flags) == 0) { 1607221393Sjhb r = pcib_suballoc_resource(sc, &sc->pmem, child, 1608221393Sjhb type, rid, start, end, count, flags); 1609221393Sjhb if (r != NULL) 1610221393Sjhb break; 1611221393Sjhb } 1612221393Sjhb } 1613221393Sjhb if (pcib_grow_window(sc, &sc->mem, type, start, end, count, 1614221393Sjhb flags & ~RF_PREFETCHABLE) == 0) 1615221393Sjhb r = pcib_suballoc_resource(sc, &sc->mem, child, type, 1616221393Sjhb rid, start, end, count, flags); 1617221393Sjhb break; 1618221393Sjhb default: 1619221393Sjhb return (bus_generic_alloc_resource(dev, child, type, rid, 1620221393Sjhb start, end, count, flags)); 1621221393Sjhb } 1622221393Sjhb 1623221393Sjhb /* 1624221393Sjhb * If attempts to suballocate from the window fail but this is a 1625221393Sjhb * subtractive bridge, pass the request up the tree. 1626221393Sjhb */ 1627221393Sjhb if (sc->flags & PCIB_SUBTRACTIVE && r == NULL) 1628221393Sjhb return (bus_generic_alloc_resource(dev, child, type, rid, 1629221393Sjhb start, end, count, flags)); 1630221393Sjhb return (r); 1631221393Sjhb} 1632221393Sjhb 1633221393Sjhbint 1634221393Sjhbpcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r, 1635221393Sjhb u_long start, u_long end) 1636221393Sjhb{ 1637221393Sjhb struct pcib_softc *sc; 1638221393Sjhb 1639221393Sjhb sc = device_get_softc(bus); 1640221393Sjhb if (pcib_is_resource_managed(sc, type, r)) 1641221393Sjhb return (rman_adjust_resource(r, start, end)); 1642221393Sjhb return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 1643221393Sjhb} 1644221393Sjhb 1645221393Sjhbint 1646221393Sjhbpcib_release_resource(device_t dev, device_t child, int type, int rid, 1647221393Sjhb struct resource *r) 1648221393Sjhb{ 1649221393Sjhb struct pcib_softc *sc; 1650221393Sjhb int error; 1651221393Sjhb 1652221393Sjhb sc = device_get_softc(dev); 1653221393Sjhb if (pcib_is_resource_managed(sc, type, r)) { 1654221393Sjhb if (rman_get_flags(r) & RF_ACTIVE) { 1655221393Sjhb error = bus_deactivate_resource(child, type, rid, r); 1656221393Sjhb if (error) 1657221393Sjhb return (error); 1658221393Sjhb } 1659221393Sjhb return (rman_release_resource(r)); 1660221393Sjhb } 1661221393Sjhb return (bus_generic_release_resource(dev, child, type, rid, r)); 1662221393Sjhb} 1663221393Sjhb#else 1664221393Sjhb/* 1665221393Sjhb * We have to trap resource allocation requests and ensure that the bridge 1666221393Sjhb * is set up to, or capable of handling them. 1667221393Sjhb */ 1668221393Sjhbstruct resource * 166969783Smsmithpcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 1670142051Simp u_long start, u_long end, u_long count, u_int flags) 167169783Smsmith{ 1672124365Simp struct pcib_softc *sc = device_get_softc(dev); 1673164130Sjhb const char *name, *suffix; 1674124365Simp int ok; 167569783Smsmith 167669783Smsmith /* 167769783Smsmith * Fail the allocation for this range if it's not supported. 167869783Smsmith */ 1679164130Sjhb name = device_get_nameunit(child); 1680164130Sjhb if (name == NULL) { 1681164130Sjhb name = ""; 1682164130Sjhb suffix = ""; 1683164130Sjhb } else 1684164130Sjhb suffix = " "; 168569783Smsmith switch (type) { 168669783Smsmith case SYS_RES_IOPORT: 1687107546Simp ok = 0; 1688124365Simp if (!pcib_is_io_open(sc)) 1689124365Simp break; 1690124365Simp ok = (start >= sc->iobase && end <= sc->iolimit); 1691145652Smarcel 1692145652Smarcel /* 1693145652Smarcel * Make sure we allow access to VGA I/O addresses when the 1694145652Smarcel * bridge has the "VGA Enable" bit set. 1695145652Smarcel */ 1696145652Smarcel if (!ok && pci_is_vga_ioport_range(start, end)) 1697145652Smarcel ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1698145652Smarcel 1699124365Simp if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1700124365Simp if (!ok) { 1701124365Simp if (start < sc->iobase) 1702124365Simp start = sc->iobase; 1703124365Simp if (end > sc->iolimit) 1704124365Simp end = sc->iolimit; 1705142051Simp if (start < end) 1706142051Simp ok = 1; 1707124365Simp } 1708106844Smdodd } else { 1709124365Simp ok = 1; 1710189844Simp#if 0 1711189792Simp /* 1712189792Simp * If we overlap with the subtractive range, then 1713189792Simp * pick the upper range to use. 1714189792Simp */ 1715189792Simp if (start < sc->iolimit && end > sc->iobase) 1716189792Simp start = sc->iolimit + 1; 1717189844Simp#endif 1718106844Smdodd } 1719124365Simp if (end < start) { 1720142051Simp device_printf(dev, "ioport: end (%lx) < start (%lx)\n", 1721142051Simp end, start); 1722124365Simp start = 0; 1723124365Simp end = 0; 1724124365Simp ok = 0; 1725124365Simp } 1726124365Simp if (!ok) { 1727164130Sjhb device_printf(dev, "%s%srequested unsupported I/O " 1728124365Simp "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", 1729164130Sjhb name, suffix, start, end, sc->iobase, sc->iolimit); 1730124365Simp return (NULL); 1731124365Simp } 1732124365Simp if (bootverbose) 1733142051Simp device_printf(dev, 1734164130Sjhb "%s%srequested I/O range 0x%lx-0x%lx: in range\n", 1735164130Sjhb name, suffix, start, end); 1736124365Simp break; 173769783Smsmith 173869783Smsmith case SYS_RES_MEMORY: 1739107546Simp ok = 0; 1740107546Simp if (pcib_is_nonprefetch_open(sc)) 1741124365Simp ok = ok || (start >= sc->membase && end <= sc->memlimit); 1742107546Simp if (pcib_is_prefetch_open(sc)) 1743124365Simp ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); 1744145652Smarcel 1745145652Smarcel /* 1746145652Smarcel * Make sure we allow access to VGA memory addresses when the 1747145652Smarcel * bridge has the "VGA Enable" bit set. 1748145652Smarcel */ 1749145652Smarcel if (!ok && pci_is_vga_memory_range(start, end)) 1750145652Smarcel ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 1751145652Smarcel 1752124365Simp if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 1753124365Simp if (!ok) { 1754124365Simp ok = 1; 1755124365Simp if (flags & RF_PREFETCHABLE) { 1756124365Simp if (pcib_is_prefetch_open(sc)) { 1757124365Simp if (start < sc->pmembase) 1758124365Simp start = sc->pmembase; 1759124365Simp if (end > sc->pmemlimit) 1760124365Simp end = sc->pmemlimit; 1761124365Simp } else { 1762124365Simp ok = 0; 1763124365Simp } 1764124365Simp } else { /* non-prefetchable */ 1765124365Simp if (pcib_is_nonprefetch_open(sc)) { 1766124365Simp if (start < sc->membase) 1767124365Simp start = sc->membase; 1768124365Simp if (end > sc->memlimit) 1769124365Simp end = sc->memlimit; 1770124365Simp } else { 1771124365Simp ok = 0; 1772124365Simp } 1773124365Simp } 1774107546Simp } 1775107546Simp } else if (!ok) { 1776124365Simp ok = 1; /* subtractive bridge: always ok */ 1777189844Simp#if 0 1778124365Simp if (pcib_is_nonprefetch_open(sc)) { 1779189792Simp if (start < sc->memlimit && end > sc->membase) 1780189792Simp start = sc->memlimit + 1; 1781124365Simp } 1782124365Simp if (pcib_is_prefetch_open(sc)) { 1783189792Simp if (start < sc->pmemlimit && end > sc->pmembase) 1784189792Simp start = sc->pmemlimit + 1; 1785124365Simp } 1786189844Simp#endif 1787106844Smdodd } 1788124365Simp if (end < start) { 1789142051Simp device_printf(dev, "memory: end (%lx) < start (%lx)\n", 1790142051Simp end, start); 1791124365Simp start = 0; 1792124365Simp end = 0; 1793124365Simp ok = 0; 1794124365Simp } 1795124365Simp if (!ok && bootverbose) 1796124365Simp device_printf(dev, 1797164130Sjhb "%s%srequested unsupported memory range %#lx-%#lx " 1798163805Simp "(decoding %#jx-%#jx, %#jx-%#jx)\n", 1799164130Sjhb name, suffix, start, end, 1800163805Simp (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, 1801163805Simp (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 1802124365Simp if (!ok) 1803124365Simp return (NULL); 1804124365Simp if (bootverbose) 1805164130Sjhb device_printf(dev,"%s%srequested memory range " 1806142051Simp "0x%lx-0x%lx: good\n", 1807164130Sjhb name, suffix, start, end); 1808124365Simp break; 180969908Smsmith 181069783Smsmith default: 1811124365Simp break; 181269783Smsmith } 1813124365Simp /* 1814124365Simp * Bridge is OK decoding this resource, so pass it up. 1815124365Simp */ 1816142051Simp return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 1817142051Simp count, flags)); 181869783Smsmith} 1819221393Sjhb#endif 182069783Smsmith 182169783Smsmith/* 1822264011Srstone * If ARI is enabled on this downstream port, translate the function number 1823264011Srstone * to the non-ARI slot/function. The downstream port will convert it back in 1824264011Srstone * hardware. If ARI is not enabled slot and func are not modified. 1825264011Srstone */ 1826264011Srstonestatic __inline void 1827264011Srstonepcib_xlate_ari(device_t pcib, int bus, int *slot, int *func) 1828264011Srstone{ 1829264011Srstone struct pcib_softc *sc; 1830264011Srstone int ari_func; 1831264011Srstone 1832264011Srstone sc = device_get_softc(pcib); 1833264011Srstone ari_func = *func; 1834264011Srstone 1835264011Srstone if (sc->flags & PCIB_ENABLE_ARI) { 1836264011Srstone KASSERT(*slot == 0, 1837264011Srstone ("Non-zero slot number with ARI enabled!")); 1838264011Srstone *slot = PCIE_ARI_SLOT(ari_func); 1839264011Srstone *func = PCIE_ARI_FUNC(ari_func); 1840264011Srstone } 1841264011Srstone} 1842264011Srstone 1843264011Srstone 1844264011Srstonestatic void 1845264011Srstonepcib_enable_ari(struct pcib_softc *sc, uint32_t pcie_pos) 1846264011Srstone{ 1847264011Srstone uint32_t ctl2; 1848264011Srstone 1849264011Srstone ctl2 = pci_read_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, 4); 1850264011Srstone ctl2 |= PCIEM_CTL2_ARI; 1851264011Srstone pci_write_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, ctl2, 4); 1852264011Srstone 1853264011Srstone sc->flags |= PCIB_ENABLE_ARI; 1854264011Srstone} 1855264011Srstone 1856264011Srstone/* 185769783Smsmith * PCIB interface. 185869783Smsmith */ 1859102441Sjhbint 186069783Smsmithpcib_maxslots(device_t dev) 186169783Smsmith{ 1862264011Srstone return (PCI_SLOTMAX); 186369783Smsmith} 186469783Smsmith 1865264011Srstonestatic int 1866264011Srstonepcib_ari_maxslots(device_t dev) 1867264011Srstone{ 1868264011Srstone struct pcib_softc *sc; 1869264011Srstone 1870264011Srstone sc = device_get_softc(dev); 1871264011Srstone 1872264011Srstone if (sc->flags & PCIB_ENABLE_ARI) 1873264011Srstone return (PCIE_ARI_SLOTMAX); 1874264011Srstone else 1875264011Srstone return (PCI_SLOTMAX); 1876264011Srstone} 1877264011Srstone 1878264011Srstonestatic int 1879264011Srstonepcib_ari_maxfuncs(device_t dev) 1880264011Srstone{ 1881264011Srstone struct pcib_softc *sc; 1882264011Srstone 1883264011Srstone sc = device_get_softc(dev); 1884264011Srstone 1885264011Srstone if (sc->flags & PCIB_ENABLE_ARI) 1886264011Srstone return (PCIE_ARI_FUNCMAX); 1887264011Srstone else 1888264011Srstone return (PCI_FUNCMAX); 1889264011Srstone} 1890264011Srstone 1891279443Srstonestatic void 1892279443Srstonepcib_ari_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot, 1893279443Srstone int *func) 1894279443Srstone{ 1895279443Srstone struct pcib_softc *sc; 1896279443Srstone 1897279443Srstone sc = device_get_softc(pcib); 1898279443Srstone 1899279443Srstone *bus = PCI_RID2BUS(rid); 1900279443Srstone if (sc->flags & PCIB_ENABLE_ARI) { 1901279443Srstone *slot = PCIE_ARI_RID2SLOT(rid); 1902279443Srstone *func = PCIE_ARI_RID2FUNC(rid); 1903279443Srstone } else { 1904279443Srstone *slot = PCI_RID2SLOT(rid); 1905279443Srstone *func = PCI_RID2FUNC(rid); 1906279443Srstone } 1907279443Srstone} 1908279443Srstone 190969783Smsmith/* 191069783Smsmith * Since we are a child of a PCI bus, its parent must support the pcib interface. 191169783Smsmith */ 1912264011Srstonestatic uint32_t 1913189792Simppcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 191469783Smsmith{ 1915264011Srstone 1916264011Srstone pcib_xlate_ari(dev, b, &s, &f); 1917264011Srstone return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, 1918264011Srstone f, reg, width)); 191969783Smsmith} 192069783Smsmith 1921264011Srstonestatic void 1922189792Simppcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) 192369783Smsmith{ 1924264011Srstone 1925264011Srstone pcib_xlate_ari(dev, b, &s, &f); 1926264011Srstone PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, 1927264011Srstone reg, val, width); 192869783Smsmith} 192969783Smsmith 193069783Smsmith/* 193169783Smsmith * Route an interrupt across a PCI bridge. 193269783Smsmith */ 1933109229Sbennoint 193469783Smsmithpcib_route_interrupt(device_t pcib, device_t dev, int pin) 193569783Smsmith{ 193669783Smsmith device_t bus; 193769783Smsmith int parent_intpin; 193869783Smsmith int intnum; 193969783Smsmith 194069783Smsmith /* 194169783Smsmith * 194269783Smsmith * The PCI standard defines a swizzle of the child-side device/intpin to 194369783Smsmith * the parent-side intpin as follows. 194469783Smsmith * 194569783Smsmith * device = device on child bus 194669783Smsmith * child_intpin = intpin on child bus slot (0-3) 194769783Smsmith * parent_intpin = intpin on parent bus slot (0-3) 194869783Smsmith * 194969783Smsmith * parent_intpin = (device + child_intpin) % 4 195069783Smsmith */ 1951115234Sticso parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; 195269783Smsmith 195369783Smsmith /* 195469783Smsmith * Our parent is a PCI bus. Its parent must export the pcib interface 195569783Smsmith * which includes the ability to route interrupts. 195669783Smsmith */ 195769783Smsmith bus = device_get_parent(pcib); 195869783Smsmith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 1959131398Sjhb if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { 1960102977Sjhb device_printf(pcib, "slot %d INT%c is routed to irq %d\n", 1961102977Sjhb pci_get_slot(dev), 'A' + pin - 1, intnum); 196290554Smsmith } 196369783Smsmith return(intnum); 196469783Smsmith} 1965107172Sjhb 1966169221Sjhb/* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ 1967164264Sjhbint 1968164264Sjhbpcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 1969164264Sjhb{ 1970169902Sgallatin struct pcib_softc *sc = device_get_softc(pcib); 1971164264Sjhb device_t bus; 1972164264Sjhb 1973165995Sjhb if (sc->flags & PCIB_DISABLE_MSI) 1974165995Sjhb return (ENXIO); 1975164264Sjhb bus = device_get_parent(pcib); 1976164264Sjhb return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 1977164264Sjhb irqs)); 1978164264Sjhb} 1979164264Sjhb 1980169221Sjhb/* Pass request to release MSI/MSI-X messages up to the parent bridge. */ 1981164264Sjhbint 1982164264Sjhbpcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 1983164264Sjhb{ 1984164264Sjhb device_t bus; 1985164264Sjhb 1986164264Sjhb bus = device_get_parent(pcib); 1987164264Sjhb return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); 1988164264Sjhb} 1989164264Sjhb 1990164264Sjhb/* Pass request to alloc an MSI-X message up to the parent bridge. */ 1991164264Sjhbint 1992169221Sjhbpcib_alloc_msix(device_t pcib, device_t dev, int *irq) 1993164264Sjhb{ 1994169902Sgallatin struct pcib_softc *sc = device_get_softc(pcib); 1995164264Sjhb device_t bus; 1996164264Sjhb 1997253120Smarius if (sc->flags & PCIB_DISABLE_MSIX) 1998165995Sjhb return (ENXIO); 1999164264Sjhb bus = device_get_parent(pcib); 2000169221Sjhb return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 2001164264Sjhb} 2002164264Sjhb 2003169221Sjhb/* Pass request to release an MSI-X message up to the parent bridge. */ 2004166176Sjhbint 2005169221Sjhbpcib_release_msix(device_t pcib, device_t dev, int irq) 2006166176Sjhb{ 2007166176Sjhb device_t bus; 2008166176Sjhb 2009166176Sjhb bus = device_get_parent(pcib); 2010169221Sjhb return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); 2011166176Sjhb} 2012166176Sjhb 2013169221Sjhb/* Pass request to map MSI/MSI-X message up to parent bridge. */ 2014164264Sjhbint 2015169221Sjhbpcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 2016169221Sjhb uint32_t *data) 2017164264Sjhb{ 2018164264Sjhb device_t bus; 2019180753Sluoqi int error; 2020164264Sjhb 2021164264Sjhb bus = device_get_parent(pcib); 2022180753Sluoqi error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 2023180753Sluoqi if (error) 2024180753Sluoqi return (error); 2025180753Sluoqi 2026180753Sluoqi pci_ht_map_msi(pcib, *addr); 2027180753Sluoqi return (0); 2028164264Sjhb} 2029164264Sjhb 2030211430Sjhb/* Pass request for device power state up to parent bridge. */ 2031211430Sjhbint 2032211430Sjhbpcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 2033211430Sjhb{ 2034211430Sjhb device_t bus; 2035211430Sjhb 2036211430Sjhb bus = device_get_parent(pcib); 2037211430Sjhb return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); 2038211430Sjhb} 2039264007Srstone 2040279443Srstonestatic int 2041279443Srstonepcib_ari_enabled(device_t pcib) 2042279443Srstone{ 2043279443Srstone struct pcib_softc *sc; 2044279443Srstone 2045279443Srstone sc = device_get_softc(pcib); 2046279443Srstone 2047279443Srstone return ((sc->flags & PCIB_ENABLE_ARI) != 0); 2048279443Srstone} 2049279443Srstone 2050264011Srstonestatic uint16_t 2051264011Srstonepcib_ari_get_rid(device_t pcib, device_t dev) 2052264011Srstone{ 2053264011Srstone struct pcib_softc *sc; 2054264011Srstone uint8_t bus, slot, func; 2055264011Srstone 2056264011Srstone sc = device_get_softc(pcib); 2057264011Srstone 2058264011Srstone if (sc->flags & PCIB_ENABLE_ARI) { 2059264011Srstone bus = pci_get_bus(dev); 2060264011Srstone func = pci_get_function(dev); 2061264011Srstone 2062264011Srstone return (PCI_ARI_RID(bus, func)); 2063264011Srstone } else { 2064264011Srstone bus = pci_get_bus(dev); 2065264011Srstone slot = pci_get_slot(dev); 2066264011Srstone func = pci_get_function(dev); 2067264011Srstone 2068264011Srstone return (PCI_RID(bus, slot, func)); 2069264011Srstone } 2070264011Srstone} 2071264011Srstone 2072264011Srstone/* 2073264011Srstone * Check that the downstream port (pcib) and the endpoint device (dev) both 2074264011Srstone * support ARI. If so, enable it and return 0, otherwise return an error. 2075264011Srstone */ 2076264011Srstonestatic int 2077264011Srstonepcib_try_enable_ari(device_t pcib, device_t dev) 2078264011Srstone{ 2079264011Srstone struct pcib_softc *sc; 2080264011Srstone int error; 2081264011Srstone uint32_t cap2; 2082264011Srstone int ari_cap_off; 2083264011Srstone uint32_t ari_ver; 2084264011Srstone uint32_t pcie_pos; 2085264011Srstone 2086264011Srstone sc = device_get_softc(pcib); 2087264011Srstone 2088264011Srstone /* 2089264011Srstone * ARI is controlled in a register in the PCIe capability structure. 2090264011Srstone * If the downstream port does not have the PCIe capability structure 2091264011Srstone * then it does not support ARI. 2092264011Srstone */ 2093264011Srstone error = pci_find_cap(pcib, PCIY_EXPRESS, &pcie_pos); 2094264011Srstone if (error != 0) 2095264011Srstone return (ENODEV); 2096264011Srstone 2097264011Srstone /* Check that the PCIe port advertises ARI support. */ 2098264011Srstone cap2 = pci_read_config(pcib, pcie_pos + PCIER_DEVICE_CAP2, 4); 2099264011Srstone if (!(cap2 & PCIEM_CAP2_ARI)) 2100264011Srstone return (ENODEV); 2101264011Srstone 2102264011Srstone /* 2103264011Srstone * Check that the endpoint device advertises ARI support via the ARI 2104264011Srstone * extended capability structure. 2105264011Srstone */ 2106264011Srstone error = pci_find_extcap(dev, PCIZ_ARI, &ari_cap_off); 2107264011Srstone if (error != 0) 2108264011Srstone return (ENODEV); 2109264011Srstone 2110264011Srstone /* 2111264011Srstone * Finally, check that the endpoint device supports the same version 2112264011Srstone * of ARI that we do. 2113264011Srstone */ 2114264011Srstone ari_ver = pci_read_config(dev, ari_cap_off, 4); 2115264011Srstone if (PCI_EXTCAP_VER(ari_ver) != PCIB_SUPPORTED_ARI_VER) { 2116264011Srstone if (bootverbose) 2117264011Srstone device_printf(pcib, 2118264011Srstone "Unsupported version of ARI (%d) detected\n", 2119264011Srstone PCI_EXTCAP_VER(ari_ver)); 2120264011Srstone 2121264011Srstone return (ENXIO); 2122264011Srstone } 2123264011Srstone 2124264011Srstone pcib_enable_ari(sc, pcie_pos); 2125264011Srstone 2126264011Srstone return (0); 2127264011Srstone} 2128264011Srstone 2129