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: releng/11.0/sys/dev/pci/pci_pci.c 314125 2017-02-23 07:11:48Z delphij $"); 33119418Sobrien 3469783Smsmith/* 3569783Smsmith * PCI:PCI bridge support. 3669783Smsmith */ 3769783Smsmith 38299142Sjhb#include "opt_pci.h" 39299142Sjhb 4069783Smsmith#include <sys/param.h> 41221393Sjhb#include <sys/bus.h> 4269783Smsmith#include <sys/kernel.h> 43221393Sjhb#include <sys/malloc.h> 44129876Sphk#include <sys/module.h> 45107546Simp#include <sys/rman.h> 46106844Smdodd#include <sys/sysctl.h> 47221393Sjhb#include <sys/systm.h> 48299142Sjhb#include <sys/taskqueue.h> 4969783Smsmith 50119285Simp#include <dev/pci/pcivar.h> 51119285Simp#include <dev/pci/pcireg.h> 52211430Sjhb#include <dev/pci/pci_private.h> 53119285Simp#include <dev/pci/pcib_private.h> 5469783Smsmith 5569783Smsmith#include "pcib_if.h" 5669783Smsmith 5769783Smsmithstatic int pcib_probe(device_t dev); 58200341Sjkimstatic int pcib_suspend(device_t dev); 59200341Sjkimstatic int pcib_resume(device_t dev); 60211430Sjhbstatic int pcib_power_for_sleep(device_t pcib, device_t dev, 61211430Sjhb int *pstate); 62299929Sandrewstatic int pcib_ari_get_id(device_t pcib, device_t dev, 63299929Sandrew enum pci_id_type type, uintptr_t *id); 64289494Sjmgstatic uint32_t pcib_read_config(device_t dev, u_int b, u_int s, 65264011Srstone u_int f, u_int reg, int width); 66264011Srstonestatic void pcib_write_config(device_t dev, u_int b, u_int s, 67264011Srstone u_int f, u_int reg, uint32_t val, int width); 68264011Srstonestatic int pcib_ari_maxslots(device_t dev); 69264011Srstonestatic int pcib_ari_maxfuncs(device_t dev); 70264011Srstonestatic int pcib_try_enable_ari(device_t pcib, device_t dev); 71279443Srstonestatic int pcib_ari_enabled(device_t pcib); 72279443Srstonestatic void pcib_ari_decode_rid(device_t pcib, uint16_t rid, 73279443Srstone int *bus, int *slot, int *func); 74299142Sjhb#ifdef PCI_HP 75299142Sjhbstatic void pcib_pcie_ab_timeout(void *arg); 76299142Sjhbstatic void pcib_pcie_cc_timeout(void *arg); 77299142Sjhbstatic void pcib_pcie_dll_timeout(void *arg); 78299142Sjhb#endif 7969783Smsmith 8069783Smsmithstatic device_method_t pcib_methods[] = { 8169783Smsmith /* Device interface */ 8269783Smsmith DEVMETHOD(device_probe, pcib_probe), 8369783Smsmith DEVMETHOD(device_attach, pcib_attach), 84300249Sjhb DEVMETHOD(device_detach, pcib_detach), 8569783Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 86200341Sjkim DEVMETHOD(device_suspend, pcib_suspend), 87200341Sjkim DEVMETHOD(device_resume, pcib_resume), 8869783Smsmith 8969783Smsmith /* Bus interface */ 90299142Sjhb DEVMETHOD(bus_child_present, pcib_child_present), 9169783Smsmith DEVMETHOD(bus_read_ivar, pcib_read_ivar), 9269783Smsmith DEVMETHOD(bus_write_ivar, pcib_write_ivar), 9369783Smsmith DEVMETHOD(bus_alloc_resource, pcib_alloc_resource), 94221393Sjhb#ifdef NEW_PCIB 95221393Sjhb DEVMETHOD(bus_adjust_resource, pcib_adjust_resource), 96221393Sjhb DEVMETHOD(bus_release_resource, pcib_release_resource), 97221393Sjhb#else 98221324Sjhb DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 9969783Smsmith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 100221393Sjhb#endif 10169783Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 10269783Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 10369783Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 10469783Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 10569783Smsmith 10669783Smsmith /* pcib interface */ 107264011Srstone DEVMETHOD(pcib_maxslots, pcib_ari_maxslots), 108264011Srstone DEVMETHOD(pcib_maxfuncs, pcib_ari_maxfuncs), 10969783Smsmith DEVMETHOD(pcib_read_config, pcib_read_config), 11069783Smsmith DEVMETHOD(pcib_write_config, pcib_write_config), 11169783Smsmith DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), 112164264Sjhb DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), 113164264Sjhb DEVMETHOD(pcib_release_msi, pcib_release_msi), 114164264Sjhb DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), 115164264Sjhb DEVMETHOD(pcib_release_msix, pcib_release_msix), 116169221Sjhb DEVMETHOD(pcib_map_msi, pcib_map_msi), 117211430Sjhb DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep), 118299929Sandrew DEVMETHOD(pcib_get_id, pcib_ari_get_id), 119264011Srstone DEVMETHOD(pcib_try_enable_ari, pcib_try_enable_ari), 120279443Srstone DEVMETHOD(pcib_ari_enabled, pcib_ari_enabled), 121279443Srstone DEVMETHOD(pcib_decode_rid, pcib_ari_decode_rid), 12269783Smsmith 123227843Smarius DEVMETHOD_END 12469783Smsmith}; 12569783Smsmith 126154079Sjhbstatic devclass_t pcib_devclass; 12769783Smsmith 128154079SjhbDEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); 129253120SmariusDRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, NULL, NULL); 13069783Smsmith 131303781Sjhb#if defined(NEW_PCIB) || defined(PCI_HP) 132261527SjhbSYSCTL_DECL(_hw_pci); 133303781Sjhb#endif 134221393Sjhb 135303781Sjhb#ifdef NEW_PCIB 136261527Sjhbstatic int pci_clear_pcib; 137261527SjhbSYSCTL_INT(_hw_pci, OID_AUTO, clear_pcib, CTLFLAG_RDTUN, &pci_clear_pcib, 0, 138261527Sjhb "Clear firmware-assigned resources for PCI-PCI bridge I/O windows."); 139261527Sjhb 140221393Sjhb/* 141221393Sjhb * Is a resource from a child device sub-allocated from one of our 142221393Sjhb * resource managers? 143221393Sjhb */ 144221393Sjhbstatic int 145221393Sjhbpcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r) 146221393Sjhb{ 147221393Sjhb 148221393Sjhb switch (type) { 149261790Sjhb#ifdef PCI_RES_BUS 150261790Sjhb case PCI_RES_BUS: 151261790Sjhb return (rman_is_region_manager(r, &sc->bus.rman)); 152261790Sjhb#endif 153221393Sjhb case SYS_RES_IOPORT: 154221393Sjhb return (rman_is_region_manager(r, &sc->io.rman)); 155221393Sjhb case SYS_RES_MEMORY: 156221393Sjhb /* Prefetchable resources may live in either memory rman. */ 157221393Sjhb if (rman_get_flags(r) & RF_PREFETCHABLE && 158221393Sjhb rman_is_region_manager(r, &sc->pmem.rman)) 159221393Sjhb return (1); 160221393Sjhb return (rman_is_region_manager(r, &sc->mem.rman)); 161221393Sjhb } 162221393Sjhb return (0); 163221393Sjhb} 164221393Sjhb 165221393Sjhbstatic int 166221393Sjhbpcib_is_window_open(struct pcib_window *pw) 167221393Sjhb{ 168221393Sjhb 169221393Sjhb return (pw->valid && pw->base < pw->limit); 170221393Sjhb} 171221393Sjhb 172221393Sjhb/* 173221393Sjhb * XXX: If RF_ACTIVE did not also imply allocating a bus space tag and 174221393Sjhb * handle for the resource, we could pass RF_ACTIVE up to the PCI bus 175221393Sjhb * when allocating the resource windows and rely on the PCI bus driver 176221393Sjhb * to do this for us. 177221393Sjhb */ 178221393Sjhbstatic void 179221393Sjhbpcib_activate_window(struct pcib_softc *sc, int type) 180221393Sjhb{ 181221393Sjhb 182221393Sjhb PCI_ENABLE_IO(device_get_parent(sc->dev), sc->dev, type); 183221393Sjhb} 184221393Sjhb 185221393Sjhbstatic void 186221393Sjhbpcib_write_windows(struct pcib_softc *sc, int mask) 187221393Sjhb{ 188221393Sjhb device_t dev; 189221393Sjhb uint32_t val; 190221393Sjhb 191221393Sjhb dev = sc->dev; 192221393Sjhb if (sc->io.valid && mask & WIN_IO) { 193221393Sjhb val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 194221393Sjhb if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 195221393Sjhb pci_write_config(dev, PCIR_IOBASEH_1, 196221393Sjhb sc->io.base >> 16, 2); 197221393Sjhb pci_write_config(dev, PCIR_IOLIMITH_1, 198221393Sjhb sc->io.limit >> 16, 2); 199221393Sjhb } 200221393Sjhb pci_write_config(dev, PCIR_IOBASEL_1, sc->io.base >> 8, 1); 201221393Sjhb pci_write_config(dev, PCIR_IOLIMITL_1, sc->io.limit >> 8, 1); 202221393Sjhb } 203221393Sjhb 204221393Sjhb if (mask & WIN_MEM) { 205221393Sjhb pci_write_config(dev, PCIR_MEMBASE_1, sc->mem.base >> 16, 2); 206221393Sjhb pci_write_config(dev, PCIR_MEMLIMIT_1, sc->mem.limit >> 16, 2); 207221393Sjhb } 208221393Sjhb 209221393Sjhb if (sc->pmem.valid && mask & WIN_PMEM) { 210221393Sjhb val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 211221393Sjhb if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 212221393Sjhb pci_write_config(dev, PCIR_PMBASEH_1, 213221393Sjhb sc->pmem.base >> 32, 4); 214221393Sjhb pci_write_config(dev, PCIR_PMLIMITH_1, 215221393Sjhb sc->pmem.limit >> 32, 4); 216221393Sjhb } 217221393Sjhb pci_write_config(dev, PCIR_PMBASEL_1, sc->pmem.base >> 16, 2); 218221393Sjhb pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmem.limit >> 16, 2); 219221393Sjhb } 220221393Sjhb} 221221393Sjhb 222253450Sjhb/* 223253450Sjhb * This is used to reject I/O port allocations that conflict with an 224253450Sjhb * ISA alias range. 225253450Sjhb */ 226253450Sjhbstatic int 227294883Sjhibbitspcib_is_isa_range(struct pcib_softc *sc, rman_res_t start, rman_res_t end, 228294883Sjhibbits rman_res_t count) 229253450Sjhb{ 230294883Sjhibbits rman_res_t next_alias; 231253450Sjhb 232253450Sjhb if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE)) 233253450Sjhb return (0); 234253450Sjhb 235253450Sjhb /* Only check fixed ranges for overlap. */ 236253450Sjhb if (start + count - 1 != end) 237253450Sjhb return (0); 238253450Sjhb 239253450Sjhb /* ISA aliases are only in the lower 64KB of I/O space. */ 240253450Sjhb if (start >= 65536) 241253450Sjhb return (0); 242253450Sjhb 243253450Sjhb /* Check for overlap with 0x000 - 0x0ff as a special case. */ 244253450Sjhb if (start < 0x100) 245253450Sjhb goto alias; 246253450Sjhb 247253450Sjhb /* 248253450Sjhb * If the start address is an alias, the range is an alias. 249253450Sjhb * Otherwise, compute the start of the next alias range and 250253450Sjhb * check if it is before the end of the candidate range. 251253450Sjhb */ 252253450Sjhb if ((start & 0x300) != 0) 253253450Sjhb goto alias; 254253450Sjhb next_alias = (start & ~0x3fful) | 0x100; 255253450Sjhb if (next_alias <= end) 256253450Sjhb goto alias; 257253450Sjhb return (0); 258253450Sjhb 259253450Sjhbalias: 260253450Sjhb if (bootverbose) 261253450Sjhb device_printf(sc->dev, 262297000Sjhibbits "I/O range %#jx-%#jx overlaps with an ISA alias\n", start, 263253450Sjhb end); 264253450Sjhb return (1); 265253450Sjhb} 266253450Sjhb 267221393Sjhbstatic void 268253450Sjhbpcib_add_window_resources(struct pcib_window *w, struct resource **res, 269253450Sjhb int count) 270253450Sjhb{ 271253450Sjhb struct resource **newarray; 272253450Sjhb int error, i; 273253450Sjhb 274253450Sjhb newarray = malloc(sizeof(struct resource *) * (w->count + count), 275253450Sjhb M_DEVBUF, M_WAITOK); 276253450Sjhb if (w->res != NULL) 277253450Sjhb bcopy(w->res, newarray, sizeof(struct resource *) * w->count); 278253450Sjhb bcopy(res, newarray + w->count, sizeof(struct resource *) * count); 279253450Sjhb free(w->res, M_DEVBUF); 280253450Sjhb w->res = newarray; 281253450Sjhb w->count += count; 282289494Sjmg 283253450Sjhb for (i = 0; i < count; i++) { 284253450Sjhb error = rman_manage_region(&w->rman, rman_get_start(res[i]), 285253450Sjhb rman_get_end(res[i])); 286253450Sjhb if (error) 287253450Sjhb panic("Failed to add resource to rman"); 288253450Sjhb } 289253450Sjhb} 290253450Sjhb 291294883Sjhibbitstypedef void (nonisa_callback)(rman_res_t start, rman_res_t end, void *arg); 292253450Sjhb 293253450Sjhbstatic void 294294883Sjhibbitspcib_walk_nonisa_ranges(rman_res_t start, rman_res_t end, nonisa_callback *cb, 295253450Sjhb void *arg) 296253450Sjhb{ 297294883Sjhibbits rman_res_t next_end; 298253450Sjhb 299253450Sjhb /* 300253450Sjhb * If start is within an ISA alias range, move up to the start 301253450Sjhb * of the next non-alias range. As a special case, addresses 302253450Sjhb * in the range 0x000 - 0x0ff should also be skipped since 303253450Sjhb * those are used for various system I/O devices in ISA 304253450Sjhb * systems. 305253450Sjhb */ 306253450Sjhb if (start <= 65535) { 307253450Sjhb if (start < 0x100 || (start & 0x300) != 0) { 308253450Sjhb start &= ~0x3ff; 309253450Sjhb start += 0x400; 310253450Sjhb } 311253450Sjhb } 312253450Sjhb 313253450Sjhb /* ISA aliases are only in the lower 64KB of I/O space. */ 314253450Sjhb while (start <= MIN(end, 65535)) { 315253450Sjhb next_end = MIN(start | 0xff, end); 316253450Sjhb cb(start, next_end, arg); 317253450Sjhb start += 0x400; 318253450Sjhb } 319253450Sjhb 320253450Sjhb if (start <= end) 321253450Sjhb cb(start, end, arg); 322253450Sjhb} 323253450Sjhb 324253450Sjhbstatic void 325294883Sjhibbitscount_ranges(rman_res_t start, rman_res_t end, void *arg) 326253450Sjhb{ 327253450Sjhb int *countp; 328253450Sjhb 329253450Sjhb countp = arg; 330253450Sjhb (*countp)++; 331253450Sjhb} 332253450Sjhb 333253450Sjhbstruct alloc_state { 334253450Sjhb struct resource **res; 335253450Sjhb struct pcib_softc *sc; 336253450Sjhb int count, error; 337253450Sjhb}; 338253450Sjhb 339253450Sjhbstatic void 340294883Sjhibbitsalloc_ranges(rman_res_t start, rman_res_t end, void *arg) 341253450Sjhb{ 342253450Sjhb struct alloc_state *as; 343253450Sjhb struct pcib_window *w; 344253450Sjhb int rid; 345253450Sjhb 346253450Sjhb as = arg; 347253450Sjhb if (as->error != 0) 348253450Sjhb return; 349253450Sjhb 350253450Sjhb w = &as->sc->io; 351253450Sjhb rid = w->reg; 352253450Sjhb if (bootverbose) 353253450Sjhb device_printf(as->sc->dev, 354297000Sjhibbits "allocating non-ISA range %#jx-%#jx\n", start, end); 355253450Sjhb as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT, 356253450Sjhb &rid, start, end, end - start + 1, 0); 357253450Sjhb if (as->res[as->count] == NULL) 358253450Sjhb as->error = ENXIO; 359253450Sjhb else 360253450Sjhb as->count++; 361253450Sjhb} 362253450Sjhb 363253450Sjhbstatic int 364294883Sjhibbitspcib_alloc_nonisa_ranges(struct pcib_softc *sc, rman_res_t start, rman_res_t end) 365253450Sjhb{ 366253450Sjhb struct alloc_state as; 367253450Sjhb int i, new_count; 368253450Sjhb 369253450Sjhb /* First, see how many ranges we need. */ 370253450Sjhb new_count = 0; 371253450Sjhb pcib_walk_nonisa_ranges(start, end, count_ranges, &new_count); 372253450Sjhb 373253450Sjhb /* Second, allocate the ranges. */ 374253450Sjhb as.res = malloc(sizeof(struct resource *) * new_count, M_DEVBUF, 375253450Sjhb M_WAITOK); 376253450Sjhb as.sc = sc; 377253450Sjhb as.count = 0; 378253450Sjhb as.error = 0; 379253450Sjhb pcib_walk_nonisa_ranges(start, end, alloc_ranges, &as); 380253450Sjhb if (as.error != 0) { 381253450Sjhb for (i = 0; i < as.count; i++) 382253450Sjhb bus_release_resource(sc->dev, SYS_RES_IOPORT, 383253450Sjhb sc->io.reg, as.res[i]); 384253450Sjhb free(as.res, M_DEVBUF); 385253450Sjhb return (as.error); 386253450Sjhb } 387253450Sjhb KASSERT(as.count == new_count, ("%s: count mismatch", __func__)); 388253450Sjhb 389253450Sjhb /* Third, add the ranges to the window. */ 390253450Sjhb pcib_add_window_resources(&sc->io, as.res, as.count); 391253450Sjhb free(as.res, M_DEVBUF); 392253450Sjhb return (0); 393253450Sjhb} 394253450Sjhb 395253450Sjhbstatic void 396221393Sjhbpcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, 397221393Sjhb int flags, pci_addr_t max_address) 398221393Sjhb{ 399253450Sjhb struct resource *res; 400221393Sjhb char buf[64]; 401221393Sjhb int error, rid; 402221393Sjhb 403295664Sjhibbits if (max_address != (rman_res_t)max_address) 404296336Sjhibbits max_address = ~0; 405221393Sjhb w->rman.rm_start = 0; 406221393Sjhb w->rman.rm_end = max_address; 407221393Sjhb w->rman.rm_type = RMAN_ARRAY; 408221393Sjhb snprintf(buf, sizeof(buf), "%s %s window", 409221393Sjhb device_get_nameunit(sc->dev), w->name); 410221393Sjhb w->rman.rm_descr = strdup(buf, M_DEVBUF); 411221393Sjhb error = rman_init(&w->rman); 412221393Sjhb if (error) 413221393Sjhb panic("Failed to initialize %s %s rman", 414221393Sjhb device_get_nameunit(sc->dev), w->name); 415221393Sjhb 416221393Sjhb if (!pcib_is_window_open(w)) 417221393Sjhb return; 418221393Sjhb 419221393Sjhb if (w->base > max_address || w->limit > max_address) { 420221393Sjhb device_printf(sc->dev, 421221393Sjhb "initial %s window has too many bits, ignoring\n", w->name); 422221393Sjhb return; 423221393Sjhb } 424253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE) 425253450Sjhb (void)pcib_alloc_nonisa_ranges(sc, w->base, w->limit); 426253450Sjhb else { 427253450Sjhb rid = w->reg; 428253450Sjhb res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit, 429253450Sjhb w->limit - w->base + 1, flags); 430253450Sjhb if (res != NULL) 431253450Sjhb pcib_add_window_resources(w, &res, 1); 432253450Sjhb } 433221393Sjhb if (w->res == NULL) { 434221393Sjhb device_printf(sc->dev, 435221393Sjhb "failed to allocate initial %s window: %#jx-%#jx\n", 436221393Sjhb w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 437221393Sjhb w->base = max_address; 438221393Sjhb w->limit = 0; 439221393Sjhb pcib_write_windows(sc, w->mask); 440221393Sjhb return; 441221393Sjhb } 442221393Sjhb pcib_activate_window(sc, type); 443221393Sjhb} 444221393Sjhb 445221393Sjhb/* 446221393Sjhb * Initialize I/O windows. 447221393Sjhb */ 448221393Sjhbstatic void 449221393Sjhbpcib_probe_windows(struct pcib_softc *sc) 450221393Sjhb{ 451221393Sjhb pci_addr_t max; 452221393Sjhb device_t dev; 453221393Sjhb uint32_t val; 454221393Sjhb 455221393Sjhb dev = sc->dev; 456221393Sjhb 457261527Sjhb if (pci_clear_pcib) { 458282783Sjhibbits pcib_bridge_init(dev); 459261527Sjhb } 460261527Sjhb 461221393Sjhb /* Determine if the I/O port window is implemented. */ 462221393Sjhb val = pci_read_config(dev, PCIR_IOBASEL_1, 1); 463221393Sjhb if (val == 0) { 464221393Sjhb /* 465221393Sjhb * If 'val' is zero, then only 16-bits of I/O space 466221393Sjhb * are supported. 467221393Sjhb */ 468221393Sjhb pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); 469221393Sjhb if (pci_read_config(dev, PCIR_IOBASEL_1, 1) != 0) { 470221393Sjhb sc->io.valid = 1; 471221393Sjhb pci_write_config(dev, PCIR_IOBASEL_1, 0, 1); 472221393Sjhb } 473221393Sjhb } else 474221393Sjhb sc->io.valid = 1; 475221393Sjhb 476221393Sjhb /* Read the existing I/O port window. */ 477221393Sjhb if (sc->io.valid) { 478221393Sjhb sc->io.reg = PCIR_IOBASEL_1; 479221393Sjhb sc->io.step = 12; 480221393Sjhb sc->io.mask = WIN_IO; 481221393Sjhb sc->io.name = "I/O port"; 482221393Sjhb if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 483221393Sjhb sc->io.base = PCI_PPBIOBASE( 484221393Sjhb pci_read_config(dev, PCIR_IOBASEH_1, 2), val); 485221393Sjhb sc->io.limit = PCI_PPBIOLIMIT( 486221393Sjhb pci_read_config(dev, PCIR_IOLIMITH_1, 2), 487221393Sjhb pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 488221393Sjhb max = 0xffffffff; 489221393Sjhb } else { 490221393Sjhb sc->io.base = PCI_PPBIOBASE(0, val); 491221393Sjhb sc->io.limit = PCI_PPBIOLIMIT(0, 492221393Sjhb pci_read_config(dev, PCIR_IOLIMITL_1, 1)); 493221393Sjhb max = 0xffff; 494221393Sjhb } 495221393Sjhb pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max); 496221393Sjhb } 497221393Sjhb 498221393Sjhb /* Read the existing memory window. */ 499221393Sjhb sc->mem.valid = 1; 500221393Sjhb sc->mem.reg = PCIR_MEMBASE_1; 501221393Sjhb sc->mem.step = 20; 502221393Sjhb sc->mem.mask = WIN_MEM; 503221393Sjhb sc->mem.name = "memory"; 504221393Sjhb sc->mem.base = PCI_PPBMEMBASE(0, 505221393Sjhb pci_read_config(dev, PCIR_MEMBASE_1, 2)); 506221393Sjhb sc->mem.limit = PCI_PPBMEMLIMIT(0, 507221393Sjhb pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 508221393Sjhb pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, 0xffffffff); 509221393Sjhb 510221393Sjhb /* Determine if the prefetchable memory window is implemented. */ 511221393Sjhb val = pci_read_config(dev, PCIR_PMBASEL_1, 2); 512221393Sjhb if (val == 0) { 513221393Sjhb /* 514221393Sjhb * If 'val' is zero, then only 32-bits of memory space 515221393Sjhb * are supported. 516221393Sjhb */ 517221393Sjhb pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); 518221393Sjhb if (pci_read_config(dev, PCIR_PMBASEL_1, 2) != 0) { 519221393Sjhb sc->pmem.valid = 1; 520221393Sjhb pci_write_config(dev, PCIR_PMBASEL_1, 0, 2); 521221393Sjhb } 522221393Sjhb } else 523221393Sjhb sc->pmem.valid = 1; 524221393Sjhb 525221393Sjhb /* Read the existing prefetchable memory window. */ 526221393Sjhb if (sc->pmem.valid) { 527221393Sjhb sc->pmem.reg = PCIR_PMBASEL_1; 528221393Sjhb sc->pmem.step = 20; 529221393Sjhb sc->pmem.mask = WIN_PMEM; 530221393Sjhb sc->pmem.name = "prefetch"; 531221393Sjhb if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 532221393Sjhb sc->pmem.base = PCI_PPBMEMBASE( 533221393Sjhb pci_read_config(dev, PCIR_PMBASEH_1, 4), val); 534221393Sjhb sc->pmem.limit = PCI_PPBMEMLIMIT( 535221393Sjhb pci_read_config(dev, PCIR_PMLIMITH_1, 4), 536221393Sjhb pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 537221393Sjhb max = 0xffffffffffffffff; 538221393Sjhb } else { 539221393Sjhb sc->pmem.base = PCI_PPBMEMBASE(0, val); 540221393Sjhb sc->pmem.limit = PCI_PPBMEMLIMIT(0, 541221393Sjhb pci_read_config(dev, PCIR_PMLIMITL_1, 2)); 542221393Sjhb max = 0xffffffff; 543221393Sjhb } 544221393Sjhb pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY, 545221393Sjhb RF_PREFETCHABLE, max); 546221393Sjhb } 547221393Sjhb} 548221393Sjhb 549300249Sjhbstatic void 550300249Sjhbpcib_release_window(struct pcib_softc *sc, struct pcib_window *w, int type) 551300249Sjhb{ 552300249Sjhb device_t dev; 553300249Sjhb int error, i; 554300249Sjhb 555300249Sjhb if (!w->valid) 556300249Sjhb return; 557300249Sjhb 558300249Sjhb dev = sc->dev; 559300249Sjhb error = rman_fini(&w->rman); 560300249Sjhb if (error) { 561300249Sjhb device_printf(dev, "failed to release %s rman\n", w->name); 562300249Sjhb return; 563300249Sjhb } 564300249Sjhb free(__DECONST(char *, w->rman.rm_descr), M_DEVBUF); 565300249Sjhb 566300249Sjhb for (i = 0; i < w->count; i++) { 567300249Sjhb error = bus_free_resource(dev, type, w->res[i]); 568300249Sjhb if (error) 569300249Sjhb device_printf(dev, 570300249Sjhb "failed to release %s resource: %d\n", w->name, 571300249Sjhb error); 572300249Sjhb } 573300249Sjhb free(w->res, M_DEVBUF); 574300249Sjhb} 575300249Sjhb 576300249Sjhbstatic void 577300249Sjhbpcib_free_windows(struct pcib_softc *sc) 578300249Sjhb{ 579300249Sjhb 580300249Sjhb pcib_release_window(sc, &sc->pmem, SYS_RES_MEMORY); 581300249Sjhb pcib_release_window(sc, &sc->mem, SYS_RES_MEMORY); 582300249Sjhb pcib_release_window(sc, &sc->io, SYS_RES_IOPORT); 583300249Sjhb} 584300249Sjhb 585261790Sjhb#ifdef PCI_RES_BUS 586261790Sjhb/* 587261790Sjhb * Allocate a suitable secondary bus for this bridge if needed and 588261790Sjhb * initialize the resource manager for the secondary bus range. Note 589261790Sjhb * that the minimum count is a desired value and this may allocate a 590261790Sjhb * smaller range. 591261790Sjhb */ 592261790Sjhbvoid 593261790Sjhbpcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count) 594261790Sjhb{ 595261790Sjhb char buf[64]; 596281874Sjhb int error, rid, sec_reg; 597261790Sjhb 598261790Sjhb switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) { 599261790Sjhb case PCIM_HDRTYPE_BRIDGE: 600281874Sjhb sec_reg = PCIR_SECBUS_1; 601261790Sjhb bus->sub_reg = PCIR_SUBBUS_1; 602261790Sjhb break; 603261790Sjhb case PCIM_HDRTYPE_CARDBUS: 604281874Sjhb sec_reg = PCIR_SECBUS_2; 605261790Sjhb bus->sub_reg = PCIR_SUBBUS_2; 606261790Sjhb break; 607261790Sjhb default: 608261790Sjhb panic("not a PCI bridge"); 609261790Sjhb } 610281874Sjhb bus->sec = pci_read_config(dev, sec_reg, 1); 611281874Sjhb bus->sub = pci_read_config(dev, bus->sub_reg, 1); 612261790Sjhb bus->dev = dev; 613261790Sjhb bus->rman.rm_start = 0; 614261790Sjhb bus->rman.rm_end = PCI_BUSMAX; 615261790Sjhb bus->rman.rm_type = RMAN_ARRAY; 616261790Sjhb snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev)); 617261790Sjhb bus->rman.rm_descr = strdup(buf, M_DEVBUF); 618261790Sjhb error = rman_init(&bus->rman); 619261790Sjhb if (error) 620261790Sjhb panic("Failed to initialize %s bus number rman", 621261790Sjhb device_get_nameunit(dev)); 622261790Sjhb 623261790Sjhb /* 624261790Sjhb * Allocate a bus range. This will return an existing bus range 625261790Sjhb * if one exists, or a new bus range if one does not. 626261790Sjhb */ 627261790Sjhb rid = 0; 628296137Sjhibbits bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid, 629261790Sjhb min_count, 0); 630261790Sjhb if (bus->res == NULL) { 631261790Sjhb /* 632261790Sjhb * Fall back to just allocating a range of a single bus 633261790Sjhb * number. 634261790Sjhb */ 635296137Sjhibbits bus->res = bus_alloc_resource_anywhere(dev, PCI_RES_BUS, &rid, 636261790Sjhb 1, 0); 637261790Sjhb } else if (rman_get_size(bus->res) < min_count) 638261790Sjhb /* 639261790Sjhb * Attempt to grow the existing range to satisfy the 640261790Sjhb * minimum desired count. 641261790Sjhb */ 642261790Sjhb (void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res, 643261790Sjhb rman_get_start(bus->res), rman_get_start(bus->res) + 644261790Sjhb min_count - 1); 645261790Sjhb 646261790Sjhb /* 647261790Sjhb * Add the initial resource to the rman. 648261790Sjhb */ 649261790Sjhb if (bus->res != NULL) { 650261790Sjhb error = rman_manage_region(&bus->rman, rman_get_start(bus->res), 651261790Sjhb rman_get_end(bus->res)); 652261790Sjhb if (error) 653261790Sjhb panic("Failed to add resource to rman"); 654261790Sjhb bus->sec = rman_get_start(bus->res); 655261790Sjhb bus->sub = rman_get_end(bus->res); 656261790Sjhb } 657261790Sjhb} 658261790Sjhb 659300249Sjhbvoid 660300249Sjhbpcib_free_secbus(device_t dev, struct pcib_secbus *bus) 661300249Sjhb{ 662300249Sjhb int error; 663300249Sjhb 664300249Sjhb error = rman_fini(&bus->rman); 665300249Sjhb if (error) { 666300249Sjhb device_printf(dev, "failed to release bus number rman\n"); 667300249Sjhb return; 668300249Sjhb } 669300249Sjhb free(__DECONST(char *, bus->rman.rm_descr), M_DEVBUF); 670300249Sjhb 671300249Sjhb error = bus_free_resource(dev, PCI_RES_BUS, bus->res); 672300249Sjhb if (error) 673300249Sjhb device_printf(dev, 674300249Sjhb "failed to release bus numbers resource: %d\n", error); 675300249Sjhb} 676300249Sjhb 677261790Sjhbstatic struct resource * 678261790Sjhbpcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid, 679294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 680261790Sjhb{ 681261790Sjhb struct resource *res; 682261790Sjhb 683261790Sjhb res = rman_reserve_resource(&bus->rman, start, end, count, flags, 684261790Sjhb child); 685261790Sjhb if (res == NULL) 686261790Sjhb return (NULL); 687261790Sjhb 688261790Sjhb if (bootverbose) 689261790Sjhb device_printf(bus->dev, 690297000Sjhibbits "allocated bus range (%ju-%ju) for rid %d of %s\n", 691261790Sjhb rman_get_start(res), rman_get_end(res), *rid, 692261790Sjhb pcib_child_name(child)); 693261790Sjhb rman_set_rid(res, *rid); 694261790Sjhb return (res); 695261790Sjhb} 696261790Sjhb 697261790Sjhb/* 698261790Sjhb * Attempt to grow the secondary bus range. This is much simpler than 699261790Sjhb * for I/O windows as the range can only be grown by increasing 700261790Sjhb * subbus. 701261790Sjhb */ 702261790Sjhbstatic int 703294883Sjhibbitspcib_grow_subbus(struct pcib_secbus *bus, rman_res_t new_end) 704261790Sjhb{ 705294883Sjhibbits rman_res_t old_end; 706261790Sjhb int error; 707261790Sjhb 708261790Sjhb old_end = rman_get_end(bus->res); 709261790Sjhb KASSERT(new_end > old_end, ("attempt to shrink subbus")); 710261790Sjhb error = bus_adjust_resource(bus->dev, PCI_RES_BUS, bus->res, 711261790Sjhb rman_get_start(bus->res), new_end); 712261790Sjhb if (error) 713261790Sjhb return (error); 714261790Sjhb if (bootverbose) 715297000Sjhibbits device_printf(bus->dev, "grew bus range to %ju-%ju\n", 716261790Sjhb rman_get_start(bus->res), rman_get_end(bus->res)); 717261790Sjhb error = rman_manage_region(&bus->rman, old_end + 1, 718261790Sjhb rman_get_end(bus->res)); 719261790Sjhb if (error) 720261790Sjhb panic("Failed to add resource to rman"); 721261790Sjhb bus->sub = rman_get_end(bus->res); 722261790Sjhb pci_write_config(bus->dev, bus->sub_reg, bus->sub, 1); 723261790Sjhb return (0); 724261790Sjhb} 725261790Sjhb 726261790Sjhbstruct resource * 727261790Sjhbpcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid, 728294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 729261790Sjhb{ 730261790Sjhb struct resource *res; 731294883Sjhibbits rman_res_t start_free, end_free, new_end; 732261790Sjhb 733261790Sjhb /* 734261790Sjhb * First, see if the request can be satisified by the existing 735261790Sjhb * bus range. 736261790Sjhb */ 737261790Sjhb res = pcib_suballoc_bus(bus, child, rid, start, end, count, flags); 738261790Sjhb if (res != NULL) 739261790Sjhb return (res); 740261790Sjhb 741261790Sjhb /* 742261790Sjhb * Figure out a range to grow the bus range. First, find the 743261790Sjhb * first bus number after the last allocated bus in the rman and 744261790Sjhb * enforce that as a minimum starting point for the range. 745261790Sjhb */ 746261790Sjhb if (rman_last_free_region(&bus->rman, &start_free, &end_free) != 0 || 747261790Sjhb end_free != bus->sub) 748261790Sjhb start_free = bus->sub + 1; 749261790Sjhb if (start_free < start) 750261790Sjhb start_free = start; 751261790Sjhb new_end = start_free + count - 1; 752261790Sjhb 753261790Sjhb /* 754261790Sjhb * See if this new range would satisfy the request if it 755261790Sjhb * succeeds. 756261790Sjhb */ 757261790Sjhb if (new_end > end) 758261790Sjhb return (NULL); 759261790Sjhb 760261790Sjhb /* Finally, attempt to grow the existing resource. */ 761261790Sjhb if (bootverbose) { 762261790Sjhb device_printf(bus->dev, 763297000Sjhibbits "attempting to grow bus range for %ju buses\n", count); 764297000Sjhibbits printf("\tback candidate range: %ju-%ju\n", start_free, 765261790Sjhb new_end); 766261790Sjhb } 767261790Sjhb if (pcib_grow_subbus(bus, new_end) == 0) 768261790Sjhb return (pcib_suballoc_bus(bus, child, rid, start, end, count, 769261790Sjhb flags)); 770261790Sjhb return (NULL); 771261790Sjhb} 772261790Sjhb#endif 773261790Sjhb 774221393Sjhb#else 775221393Sjhb 776221393Sjhb/* 777163805Simp * Is the prefetch window open (eg, can we allocate memory in it?) 778163805Simp */ 779163805Simpstatic int 780163805Simppcib_is_prefetch_open(struct pcib_softc *sc) 781163805Simp{ 782163805Simp return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); 783163805Simp} 784163805Simp 785163805Simp/* 786163805Simp * Is the nonprefetch window open (eg, can we allocate memory in it?) 787163805Simp */ 788163805Simpstatic int 789163805Simppcib_is_nonprefetch_open(struct pcib_softc *sc) 790163805Simp{ 791163805Simp return (sc->membase > 0 && sc->membase < sc->memlimit); 792163805Simp} 793163805Simp 794163805Simp/* 795163805Simp * Is the io window open (eg, can we allocate ports in it?) 796163805Simp */ 797163805Simpstatic int 798163805Simppcib_is_io_open(struct pcib_softc *sc) 799163805Simp{ 800163805Simp return (sc->iobase > 0 && sc->iobase < sc->iolimit); 801163805Simp} 802163805Simp 803163805Simp/* 804200341Sjkim * Get current I/O decode. 805200341Sjkim */ 806200341Sjkimstatic void 807200341Sjkimpcib_get_io_decode(struct pcib_softc *sc) 808200341Sjkim{ 809200341Sjkim device_t dev; 810200341Sjkim uint32_t iolow; 811200341Sjkim 812200341Sjkim dev = sc->dev; 813200341Sjkim 814200341Sjkim iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); 815200341Sjkim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 816200341Sjkim sc->iobase = PCI_PPBIOBASE( 817200341Sjkim pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow); 818200341Sjkim else 819200341Sjkim sc->iobase = PCI_PPBIOBASE(0, iolow); 820200341Sjkim 821200341Sjkim iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); 822200341Sjkim if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) 823200341Sjkim sc->iolimit = PCI_PPBIOLIMIT( 824200341Sjkim pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow); 825200341Sjkim else 826200341Sjkim sc->iolimit = PCI_PPBIOLIMIT(0, iolow); 827200341Sjkim} 828200341Sjkim 829200341Sjkim/* 830200341Sjkim * Get current memory decode. 831200341Sjkim */ 832200341Sjkimstatic void 833200341Sjkimpcib_get_mem_decode(struct pcib_softc *sc) 834200341Sjkim{ 835200341Sjkim device_t dev; 836200341Sjkim pci_addr_t pmemlow; 837200341Sjkim 838200341Sjkim dev = sc->dev; 839200341Sjkim 840200341Sjkim sc->membase = PCI_PPBMEMBASE(0, 841200341Sjkim pci_read_config(dev, PCIR_MEMBASE_1, 2)); 842200341Sjkim sc->memlimit = PCI_PPBMEMLIMIT(0, 843200341Sjkim pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); 844200341Sjkim 845200341Sjkim pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2); 846200341Sjkim if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 847200341Sjkim sc->pmembase = PCI_PPBMEMBASE( 848200341Sjkim pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow); 849200341Sjkim else 850200341Sjkim sc->pmembase = PCI_PPBMEMBASE(0, pmemlow); 851200341Sjkim 852200341Sjkim pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2); 853289494Sjmg if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) 854200341Sjkim sc->pmemlimit = PCI_PPBMEMLIMIT( 855200341Sjkim pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow); 856200341Sjkim else 857200341Sjkim sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow); 858200341Sjkim} 859200341Sjkim 860200341Sjkim/* 861200341Sjkim * Restore previous I/O decode. 862200341Sjkim */ 863200341Sjkimstatic void 864200341Sjkimpcib_set_io_decode(struct pcib_softc *sc) 865200341Sjkim{ 866200341Sjkim device_t dev; 867200341Sjkim uint32_t iohi; 868200341Sjkim 869200341Sjkim dev = sc->dev; 870200341Sjkim 871200341Sjkim iohi = sc->iobase >> 16; 872200341Sjkim if (iohi > 0) 873200341Sjkim pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2); 874200341Sjkim pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1); 875200341Sjkim 876200341Sjkim iohi = sc->iolimit >> 16; 877200341Sjkim if (iohi > 0) 878200341Sjkim pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2); 879200341Sjkim pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1); 880200341Sjkim} 881200341Sjkim 882200341Sjkim/* 883200341Sjkim * Restore previous memory decode. 884200341Sjkim */ 885200341Sjkimstatic void 886200341Sjkimpcib_set_mem_decode(struct pcib_softc *sc) 887200341Sjkim{ 888200341Sjkim device_t dev; 889200341Sjkim pci_addr_t pmemhi; 890200341Sjkim 891200341Sjkim dev = sc->dev; 892200341Sjkim 893200341Sjkim pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2); 894200341Sjkim pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2); 895200341Sjkim 896200341Sjkim pmemhi = sc->pmembase >> 32; 897200341Sjkim if (pmemhi > 0) 898200341Sjkim pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4); 899200341Sjkim pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2); 900200341Sjkim 901200341Sjkim pmemhi = sc->pmemlimit >> 32; 902200341Sjkim if (pmemhi > 0) 903200341Sjkim pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4); 904200341Sjkim pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2); 905200341Sjkim} 906221393Sjhb#endif 907200341Sjkim 908299142Sjhb#ifdef PCI_HP 909200341Sjkim/* 910299142Sjhb * PCI-express HotPlug support. 911299142Sjhb */ 912303781Sjhbstatic int pci_enable_pcie_hp = 1; 913303781SjhbSYSCTL_INT(_hw_pci, OID_AUTO, enable_pcie_hp, CTLFLAG_RDTUN, 914303781Sjhb &pci_enable_pcie_hp, 0, 915303781Sjhb "Enable support for native PCI-express HotPlug."); 916303781Sjhb 917299142Sjhbstatic void 918299142Sjhbpcib_probe_hotplug(struct pcib_softc *sc) 919299142Sjhb{ 920299142Sjhb device_t dev; 921304434Svangyzen uint16_t link_sta, slot_sta; 922299142Sjhb 923303781Sjhb if (!pci_enable_pcie_hp) 924303781Sjhb return; 925303781Sjhb 926299142Sjhb dev = sc->dev; 927299142Sjhb if (pci_find_cap(dev, PCIY_EXPRESS, NULL) != 0) 928299142Sjhb return; 929299142Sjhb 930299142Sjhb if (!(pcie_read_config(dev, PCIER_FLAGS, 2) & PCIEM_FLAGS_SLOT)) 931299142Sjhb return; 932299142Sjhb 933299142Sjhb sc->pcie_link_cap = pcie_read_config(dev, PCIER_LINK_CAP, 4); 934299142Sjhb sc->pcie_slot_cap = pcie_read_config(dev, PCIER_SLOT_CAP, 4); 935299142Sjhb 936304434Svangyzen if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC) == 0) 937304434Svangyzen return; 938314125Sdelphij if ((sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) == 0) 939314125Sdelphij return; 940304434Svangyzen 941303781Sjhb /* 942304434Svangyzen * Some devices report that they have an MRL when they actually 943304434Svangyzen * do not. Since they always report that the MRL is open, child 944304434Svangyzen * devices would be ignored. Try to detect these devices and 945304434Svangyzen * ignore their claim of HotPlug support. 946304434Svangyzen * 947304434Svangyzen * If there is an open MRL but the Data Link Layer is active, 948304434Svangyzen * the MRL is not real. 949303781Sjhb */ 950304434Svangyzen if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP) != 0 && 951304434Svangyzen (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) != 0) { 952304434Svangyzen link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2); 953304434Svangyzen slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); 954304434Svangyzen if ((slot_sta & PCIEM_SLOT_STA_MRLSS) != 0 && 955304434Svangyzen (link_sta & PCIEM_LINK_STA_DL_ACTIVE) != 0) { 956304434Svangyzen return; 957304434Svangyzen } 958304434Svangyzen } 959304434Svangyzen 960304434Svangyzen sc->flags |= PCIB_HOTPLUG; 961299142Sjhb} 962299142Sjhb 963299142Sjhb/* 964299142Sjhb * Send a HotPlug command to the slot control register. If this slot 965300074Sjhb * uses command completion interrupts and a previous command is still 966300074Sjhb * in progress, then the command is dropped. Once the previous 967300074Sjhb * command completes or times out, pcib_pcie_hotplug_update() will be 968300074Sjhb * invoked to post a new command based on the slot's state at that 969300074Sjhb * time. 970299142Sjhb */ 971299142Sjhbstatic void 972299142Sjhbpcib_pcie_hotplug_command(struct pcib_softc *sc, uint16_t val, uint16_t mask) 973299142Sjhb{ 974299142Sjhb device_t dev; 975299142Sjhb uint16_t ctl, new; 976299142Sjhb 977299142Sjhb dev = sc->dev; 978300074Sjhb 979300074Sjhb if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) 980299142Sjhb return; 981299142Sjhb 982300074Sjhb ctl = pcie_read_config(dev, PCIER_SLOT_CTL, 2); 983300074Sjhb new = (ctl & ~mask) | val; 984300074Sjhb if (new == ctl) 985300074Sjhb return; 986304434Svangyzen if (bootverbose) 987304434Svangyzen device_printf(dev, "HotPlug command: %04x -> %04x\n", ctl, new); 988300074Sjhb pcie_write_config(dev, PCIER_SLOT_CTL, new, 2); 989300249Sjhb if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) && 990300249Sjhb (ctl & new) & PCIEM_SLOT_CTL_CCIE) { 991300074Sjhb sc->flags |= PCIB_HOTPLUG_CMD_PENDING; 992300074Sjhb if (!cold) 993300074Sjhb callout_reset(&sc->pcie_cc_timer, hz, 994300074Sjhb pcib_pcie_cc_timeout, sc); 995299142Sjhb } 996299142Sjhb} 997299142Sjhb 998299142Sjhbstatic void 999299142Sjhbpcib_pcie_hotplug_command_completed(struct pcib_softc *sc) 1000299142Sjhb{ 1001299142Sjhb device_t dev; 1002299142Sjhb 1003299142Sjhb dev = sc->dev; 1004299142Sjhb 1005299142Sjhb if (bootverbose) 1006299142Sjhb device_printf(dev, "Command Completed\n"); 1007299142Sjhb if (!(sc->flags & PCIB_HOTPLUG_CMD_PENDING)) 1008299142Sjhb return; 1009300074Sjhb callout_stop(&sc->pcie_cc_timer); 1010300074Sjhb sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING; 1011300249Sjhb wakeup(sc); 1012299142Sjhb} 1013299142Sjhb 1014299142Sjhb/* 1015299142Sjhb * Returns true if a card is fully inserted from the user's 1016299142Sjhb * perspective. It may not yet be ready for access, but the driver 1017299142Sjhb * can now start enabling access if necessary. 1018299142Sjhb */ 1019299142Sjhbstatic bool 1020299142Sjhbpcib_hotplug_inserted(struct pcib_softc *sc) 1021299142Sjhb{ 1022299142Sjhb 1023299142Sjhb /* Pretend the card isn't present if a detach is forced. */ 1024299142Sjhb if (sc->flags & PCIB_DETACHING) 1025299142Sjhb return (false); 1026299142Sjhb 1027299142Sjhb /* Card must be present in the slot. */ 1028299142Sjhb if ((sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS) == 0) 1029299142Sjhb return (false); 1030299142Sjhb 1031299142Sjhb /* A power fault implicitly turns off power to the slot. */ 1032299142Sjhb if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD) 1033299142Sjhb return (false); 1034299142Sjhb 1035299142Sjhb /* If the MRL is disengaged, the slot is powered off. */ 1036299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP && 1037299142Sjhb (sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS) != 0) 1038299142Sjhb return (false); 1039299142Sjhb 1040299142Sjhb return (true); 1041299142Sjhb} 1042299142Sjhb 1043299142Sjhb/* 1044299142Sjhb * Returns -1 if the card is fully inserted, powered, and ready for 1045299142Sjhb * access. Otherwise, returns 0. 1046299142Sjhb */ 1047299142Sjhbstatic int 1048299142Sjhbpcib_hotplug_present(struct pcib_softc *sc) 1049299142Sjhb{ 1050299142Sjhb 1051299142Sjhb /* Card must be inserted. */ 1052299142Sjhb if (!pcib_hotplug_inserted(sc)) 1053299142Sjhb return (0); 1054299142Sjhb 1055299142Sjhb /* 1056299142Sjhb * Require the Electromechanical Interlock to be engaged if 1057299142Sjhb * present. 1058299142Sjhb */ 1059299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP && 1060299142Sjhb (sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS) == 0) 1061299142Sjhb return (0); 1062299142Sjhb 1063299142Sjhb /* Require the Data Link Layer to be active. */ 1064299142Sjhb if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) { 1065299142Sjhb if (!(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE)) 1066299142Sjhb return (0); 1067299142Sjhb } 1068299142Sjhb 1069299142Sjhb return (-1); 1070299142Sjhb} 1071299142Sjhb 1072299142Sjhbstatic void 1073299142Sjhbpcib_pcie_hotplug_update(struct pcib_softc *sc, uint16_t val, uint16_t mask, 1074299142Sjhb bool schedule_task) 1075299142Sjhb{ 1076303835Svangyzen bool card_inserted, ei_engaged; 1077299142Sjhb 1078304434Svangyzen /* Clear DETACHING if Presence Detect has cleared. */ 1079299142Sjhb if ((sc->pcie_slot_sta & (PCIEM_SLOT_STA_PDC | PCIEM_SLOT_STA_PDS)) == 1080299142Sjhb PCIEM_SLOT_STA_PDC) 1081299142Sjhb sc->flags &= ~PCIB_DETACHING; 1082299142Sjhb 1083299142Sjhb card_inserted = pcib_hotplug_inserted(sc); 1084299142Sjhb 1085299142Sjhb /* Turn the power indicator on if a card is inserted. */ 1086299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PIP) { 1087299142Sjhb mask |= PCIEM_SLOT_CTL_PIC; 1088299142Sjhb if (card_inserted) 1089299142Sjhb val |= PCIEM_SLOT_CTL_PI_ON; 1090299142Sjhb else if (sc->flags & PCIB_DETACH_PENDING) 1091299142Sjhb val |= PCIEM_SLOT_CTL_PI_BLINK; 1092299142Sjhb else 1093299142Sjhb val |= PCIEM_SLOT_CTL_PI_OFF; 1094299142Sjhb } 1095299142Sjhb 1096299142Sjhb /* Turn the power on via the Power Controller if a card is inserted. */ 1097299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP) { 1098299142Sjhb mask |= PCIEM_SLOT_CTL_PCC; 1099299142Sjhb if (card_inserted) 1100299142Sjhb val |= PCIEM_SLOT_CTL_PC_ON; 1101299142Sjhb else 1102299142Sjhb val |= PCIEM_SLOT_CTL_PC_OFF; 1103299142Sjhb } 1104299142Sjhb 1105299142Sjhb /* 1106299142Sjhb * If a card is inserted, enable the Electromechanical 1107299142Sjhb * Interlock. If a card is not inserted (or we are in the 1108299142Sjhb * process of detaching), disable the Electromechanical 1109299142Sjhb * Interlock. 1110299142Sjhb */ 1111299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_EIP) { 1112300074Sjhb mask |= PCIEM_SLOT_CTL_EIC; 1113303835Svangyzen ei_engaged = (sc->pcie_slot_sta & PCIEM_SLOT_STA_EIS) != 0; 1114303835Svangyzen if (card_inserted != ei_engaged) 1115299142Sjhb val |= PCIEM_SLOT_CTL_EIC; 1116299142Sjhb } 1117299142Sjhb 1118299142Sjhb /* 1119299142Sjhb * Start a timer to see if the Data Link Layer times out. 1120304434Svangyzen * Note that we only start the timer if Presence Detect or MRL Sensor 1121299142Sjhb * changed on this interrupt. Stop any scheduled timer if 1122299142Sjhb * the Data Link Layer is active. 1123299142Sjhb */ 1124299142Sjhb if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) { 1125299142Sjhb if (card_inserted && 1126299142Sjhb !(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) && 1127304434Svangyzen sc->pcie_slot_sta & 1128304434Svangyzen (PCIEM_SLOT_STA_MRLSC | PCIEM_SLOT_STA_PDC)) { 1129299142Sjhb if (cold) 1130299142Sjhb device_printf(sc->dev, 1131299142Sjhb "Data Link Layer inactive\n"); 1132299142Sjhb else 1133299142Sjhb callout_reset(&sc->pcie_dll_timer, hz, 1134299142Sjhb pcib_pcie_dll_timeout, sc); 1135299142Sjhb } else if (sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) 1136299142Sjhb callout_stop(&sc->pcie_dll_timer); 1137299142Sjhb } 1138299142Sjhb 1139299142Sjhb pcib_pcie_hotplug_command(sc, val, mask); 1140299142Sjhb 1141299142Sjhb /* 1142303835Svangyzen * During attach the child "pci" device is added synchronously; 1143299142Sjhb * otherwise, the task is scheduled to manage the child 1144299142Sjhb * device. 1145299142Sjhb */ 1146299142Sjhb if (schedule_task && 1147299142Sjhb (pcib_hotplug_present(sc) != 0) != (sc->child != NULL)) 1148299142Sjhb taskqueue_enqueue(taskqueue_thread, &sc->pcie_hp_task); 1149299142Sjhb} 1150299142Sjhb 1151299142Sjhbstatic void 1152299142Sjhbpcib_pcie_intr(void *arg) 1153299142Sjhb{ 1154299142Sjhb struct pcib_softc *sc; 1155299142Sjhb device_t dev; 1156299142Sjhb 1157299142Sjhb sc = arg; 1158299142Sjhb dev = sc->dev; 1159299142Sjhb sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); 1160299142Sjhb 1161299142Sjhb /* Clear the events just reported. */ 1162299142Sjhb pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2); 1163299142Sjhb 1164304434Svangyzen if (bootverbose) 1165304434Svangyzen device_printf(dev, "HotPlug interrupt: %#x\n", 1166304434Svangyzen sc->pcie_slot_sta); 1167304434Svangyzen 1168299142Sjhb if (sc->pcie_slot_sta & PCIEM_SLOT_STA_ABP) { 1169299142Sjhb if (sc->flags & PCIB_DETACH_PENDING) { 1170299142Sjhb device_printf(dev, 1171299142Sjhb "Attention Button Pressed: Detach Cancelled\n"); 1172299142Sjhb sc->flags &= ~PCIB_DETACH_PENDING; 1173299142Sjhb callout_stop(&sc->pcie_ab_timer); 1174299142Sjhb } else { 1175299142Sjhb device_printf(dev, 1176299142Sjhb "Attention Button Pressed: Detaching in 5 seconds\n"); 1177299142Sjhb sc->flags |= PCIB_DETACH_PENDING; 1178299142Sjhb callout_reset(&sc->pcie_ab_timer, 5 * hz, 1179299142Sjhb pcib_pcie_ab_timeout, sc); 1180299142Sjhb } 1181299142Sjhb } 1182299142Sjhb if (sc->pcie_slot_sta & PCIEM_SLOT_STA_PFD) 1183299142Sjhb device_printf(dev, "Power Fault Detected\n"); 1184299142Sjhb if (sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSC) 1185299142Sjhb device_printf(dev, "MRL Sensor Changed to %s\n", 1186299142Sjhb sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS ? "open" : 1187299142Sjhb "closed"); 1188299142Sjhb if (bootverbose && sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC) 1189304434Svangyzen device_printf(dev, "Presence Detect Changed to %s\n", 1190299142Sjhb sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS ? "card present" : 1191299142Sjhb "empty"); 1192299142Sjhb if (sc->pcie_slot_sta & PCIEM_SLOT_STA_CC) 1193299142Sjhb pcib_pcie_hotplug_command_completed(sc); 1194299142Sjhb if (sc->pcie_slot_sta & PCIEM_SLOT_STA_DLLSC) { 1195299142Sjhb sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2); 1196299142Sjhb if (bootverbose) 1197299142Sjhb device_printf(dev, 1198299142Sjhb "Data Link Layer State Changed to %s\n", 1199299142Sjhb sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE ? 1200299142Sjhb "active" : "inactive"); 1201299142Sjhb } 1202299142Sjhb 1203299142Sjhb pcib_pcie_hotplug_update(sc, 0, 0, true); 1204299142Sjhb} 1205299142Sjhb 1206299142Sjhbstatic void 1207299142Sjhbpcib_pcie_hotplug_task(void *context, int pending) 1208299142Sjhb{ 1209299142Sjhb struct pcib_softc *sc; 1210299142Sjhb device_t dev; 1211299142Sjhb 1212299142Sjhb sc = context; 1213299142Sjhb mtx_lock(&Giant); 1214299142Sjhb dev = sc->dev; 1215299142Sjhb if (pcib_hotplug_present(sc) != 0) { 1216299142Sjhb if (sc->child == NULL) { 1217299142Sjhb sc->child = device_add_child(dev, "pci", -1); 1218299142Sjhb bus_generic_attach(dev); 1219299142Sjhb } 1220299142Sjhb } else { 1221299142Sjhb if (sc->child != NULL) { 1222299142Sjhb if (device_delete_child(dev, sc->child) == 0) 1223299142Sjhb sc->child = NULL; 1224299142Sjhb } 1225299142Sjhb } 1226299142Sjhb mtx_unlock(&Giant); 1227299142Sjhb} 1228299142Sjhb 1229299142Sjhbstatic void 1230299142Sjhbpcib_pcie_ab_timeout(void *arg) 1231299142Sjhb{ 1232299142Sjhb struct pcib_softc *sc; 1233299142Sjhb device_t dev; 1234299142Sjhb 1235299142Sjhb sc = arg; 1236299142Sjhb dev = sc->dev; 1237299142Sjhb mtx_assert(&Giant, MA_OWNED); 1238299142Sjhb if (sc->flags & PCIB_DETACH_PENDING) { 1239299142Sjhb sc->flags |= PCIB_DETACHING; 1240299142Sjhb sc->flags &= ~PCIB_DETACH_PENDING; 1241299142Sjhb pcib_pcie_hotplug_update(sc, 0, 0, true); 1242299142Sjhb } 1243299142Sjhb} 1244299142Sjhb 1245299142Sjhbstatic void 1246299142Sjhbpcib_pcie_cc_timeout(void *arg) 1247299142Sjhb{ 1248299142Sjhb struct pcib_softc *sc; 1249299142Sjhb device_t dev; 1250300249Sjhb uint16_t sta; 1251299142Sjhb 1252299142Sjhb sc = arg; 1253299142Sjhb dev = sc->dev; 1254299142Sjhb mtx_assert(&Giant, MA_OWNED); 1255300249Sjhb sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); 1256300249Sjhb if (!(sta & PCIEM_SLOT_STA_CC)) { 1257299142Sjhb device_printf(dev, 1258304434Svangyzen "HotPlug Command Timed Out - forcing detach\n"); 1259299142Sjhb sc->flags &= ~(PCIB_HOTPLUG_CMD_PENDING | PCIB_DETACH_PENDING); 1260299142Sjhb sc->flags |= PCIB_DETACHING; 1261299142Sjhb pcib_pcie_hotplug_update(sc, 0, 0, true); 1262300249Sjhb } else { 1263300249Sjhb device_printf(dev, 1264300249Sjhb "Missed HotPlug interrupt waiting for Command Completion\n"); 1265300249Sjhb pcib_pcie_intr(sc); 1266299142Sjhb } 1267299142Sjhb} 1268299142Sjhb 1269299142Sjhbstatic void 1270299142Sjhbpcib_pcie_dll_timeout(void *arg) 1271299142Sjhb{ 1272299142Sjhb struct pcib_softc *sc; 1273299142Sjhb device_t dev; 1274299142Sjhb uint16_t sta; 1275299142Sjhb 1276299142Sjhb sc = arg; 1277299142Sjhb dev = sc->dev; 1278299142Sjhb mtx_assert(&Giant, MA_OWNED); 1279299142Sjhb sta = pcie_read_config(dev, PCIER_LINK_STA, 2); 1280299142Sjhb if (!(sta & PCIEM_LINK_STA_DL_ACTIVE)) { 1281299142Sjhb device_printf(dev, 1282299142Sjhb "Timed out waiting for Data Link Layer Active\n"); 1283299142Sjhb sc->flags |= PCIB_DETACHING; 1284299142Sjhb pcib_pcie_hotplug_update(sc, 0, 0, true); 1285299142Sjhb } else if (sta != sc->pcie_link_sta) { 1286299142Sjhb device_printf(dev, 1287299142Sjhb "Missed HotPlug interrupt waiting for DLL Active\n"); 1288299142Sjhb pcib_pcie_intr(sc); 1289299142Sjhb } 1290299142Sjhb} 1291299142Sjhb 1292299142Sjhbstatic int 1293299142Sjhbpcib_alloc_pcie_irq(struct pcib_softc *sc) 1294299142Sjhb{ 1295299142Sjhb device_t dev; 1296299142Sjhb int count, error, rid; 1297299142Sjhb 1298299142Sjhb rid = -1; 1299299142Sjhb dev = sc->dev; 1300299142Sjhb 1301299142Sjhb /* 1302299142Sjhb * For simplicity, only use MSI-X if there is a single message. 1303299142Sjhb * To support a device with multiple messages we would have to 1304299142Sjhb * use remap intr if the MSI number is not 0. 1305299142Sjhb */ 1306299142Sjhb count = pci_msix_count(dev); 1307299142Sjhb if (count == 1) { 1308299142Sjhb error = pci_alloc_msix(dev, &count); 1309299142Sjhb if (error == 0) 1310299142Sjhb rid = 1; 1311299142Sjhb } 1312299142Sjhb 1313299142Sjhb if (rid < 0 && pci_msi_count(dev) > 0) { 1314299142Sjhb count = 1; 1315299142Sjhb error = pci_alloc_msi(dev, &count); 1316299142Sjhb if (error == 0) 1317299142Sjhb rid = 1; 1318299142Sjhb } 1319299142Sjhb 1320299142Sjhb if (rid < 0) 1321299142Sjhb rid = 0; 1322299142Sjhb 1323299142Sjhb sc->pcie_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1324299142Sjhb RF_ACTIVE); 1325299142Sjhb if (sc->pcie_irq == NULL) { 1326299142Sjhb device_printf(dev, 1327299142Sjhb "Failed to allocate interrupt for PCI-e events\n"); 1328299142Sjhb if (rid > 0) 1329299142Sjhb pci_release_msi(dev); 1330299142Sjhb return (ENXIO); 1331299142Sjhb } 1332299142Sjhb 1333299142Sjhb error = bus_setup_intr(dev, sc->pcie_irq, INTR_TYPE_MISC, 1334299142Sjhb NULL, pcib_pcie_intr, sc, &sc->pcie_ihand); 1335299142Sjhb if (error) { 1336299142Sjhb device_printf(dev, "Failed to setup PCI-e interrupt handler\n"); 1337299142Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, sc->pcie_irq); 1338299142Sjhb if (rid > 0) 1339299142Sjhb pci_release_msi(dev); 1340299142Sjhb return (error); 1341299142Sjhb } 1342299142Sjhb return (0); 1343299142Sjhb} 1344299142Sjhb 1345300249Sjhbstatic int 1346300249Sjhbpcib_release_pcie_irq(struct pcib_softc *sc) 1347300249Sjhb{ 1348300249Sjhb device_t dev; 1349300249Sjhb int error; 1350300249Sjhb 1351300249Sjhb dev = sc->dev; 1352300249Sjhb error = bus_teardown_intr(dev, sc->pcie_irq, sc->pcie_ihand); 1353300249Sjhb if (error) 1354300249Sjhb return (error); 1355300249Sjhb error = bus_free_resource(dev, SYS_RES_IRQ, sc->pcie_irq); 1356300249Sjhb if (error) 1357300249Sjhb return (error); 1358300249Sjhb return (pci_release_msi(dev)); 1359300249Sjhb} 1360300249Sjhb 1361299142Sjhbstatic void 1362299142Sjhbpcib_setup_hotplug(struct pcib_softc *sc) 1363299142Sjhb{ 1364299142Sjhb device_t dev; 1365299142Sjhb uint16_t mask, val; 1366299142Sjhb 1367299142Sjhb dev = sc->dev; 1368299142Sjhb callout_init(&sc->pcie_ab_timer, 0); 1369299142Sjhb callout_init(&sc->pcie_cc_timer, 0); 1370299142Sjhb callout_init(&sc->pcie_dll_timer, 0); 1371299142Sjhb TASK_INIT(&sc->pcie_hp_task, 0, pcib_pcie_hotplug_task, sc); 1372299142Sjhb 1373299142Sjhb /* Allocate IRQ. */ 1374299142Sjhb if (pcib_alloc_pcie_irq(sc) != 0) 1375299142Sjhb return; 1376299142Sjhb 1377299142Sjhb sc->pcie_link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2); 1378299142Sjhb sc->pcie_slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2); 1379299142Sjhb 1380300249Sjhb /* Clear any events previously pending. */ 1381300249Sjhb pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2); 1382300249Sjhb 1383299142Sjhb /* Enable HotPlug events. */ 1384299142Sjhb mask = PCIEM_SLOT_CTL_DLLSCE | PCIEM_SLOT_CTL_HPIE | 1385299142Sjhb PCIEM_SLOT_CTL_CCIE | PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_MRLSCE | 1386299142Sjhb PCIEM_SLOT_CTL_PFDE | PCIEM_SLOT_CTL_ABPE; 1387299142Sjhb val = PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_HPIE; 1388299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_APB) 1389299142Sjhb val |= PCIEM_SLOT_CTL_ABPE; 1390299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP) 1391299142Sjhb val |= PCIEM_SLOT_CTL_PFDE; 1392299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP) 1393299142Sjhb val |= PCIEM_SLOT_CTL_MRLSCE; 1394299142Sjhb if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS)) 1395299142Sjhb val |= PCIEM_SLOT_CTL_CCIE; 1396299142Sjhb if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) 1397299142Sjhb val |= PCIEM_SLOT_CTL_DLLSCE; 1398299142Sjhb 1399299142Sjhb /* Turn the attention indicator off. */ 1400299142Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_AIP) { 1401299142Sjhb mask |= PCIEM_SLOT_CTL_AIC; 1402299142Sjhb val |= PCIEM_SLOT_CTL_AI_OFF; 1403299142Sjhb } 1404299142Sjhb 1405299142Sjhb pcib_pcie_hotplug_update(sc, val, mask, false); 1406299142Sjhb} 1407300249Sjhb 1408300249Sjhbstatic int 1409300249Sjhbpcib_detach_hotplug(struct pcib_softc *sc) 1410300249Sjhb{ 1411300249Sjhb uint16_t mask, val; 1412300249Sjhb int error; 1413300249Sjhb 1414300249Sjhb /* Disable the card in the slot and force it to detach. */ 1415300249Sjhb if (sc->flags & PCIB_DETACH_PENDING) { 1416300249Sjhb sc->flags &= ~PCIB_DETACH_PENDING; 1417300249Sjhb callout_stop(&sc->pcie_ab_timer); 1418300249Sjhb } 1419300249Sjhb sc->flags |= PCIB_DETACHING; 1420300249Sjhb 1421300249Sjhb if (sc->flags & PCIB_HOTPLUG_CMD_PENDING) { 1422300249Sjhb callout_stop(&sc->pcie_cc_timer); 1423300249Sjhb tsleep(sc, 0, "hpcmd", hz); 1424300249Sjhb sc->flags &= ~PCIB_HOTPLUG_CMD_PENDING; 1425300249Sjhb } 1426300249Sjhb 1427300249Sjhb /* Disable HotPlug events. */ 1428300249Sjhb mask = PCIEM_SLOT_CTL_DLLSCE | PCIEM_SLOT_CTL_HPIE | 1429300249Sjhb PCIEM_SLOT_CTL_CCIE | PCIEM_SLOT_CTL_PDCE | PCIEM_SLOT_CTL_MRLSCE | 1430300249Sjhb PCIEM_SLOT_CTL_PFDE | PCIEM_SLOT_CTL_ABPE; 1431300249Sjhb val = 0; 1432300249Sjhb 1433300249Sjhb /* Turn the attention indicator off. */ 1434300249Sjhb if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_AIP) { 1435300249Sjhb mask |= PCIEM_SLOT_CTL_AIC; 1436300249Sjhb val |= PCIEM_SLOT_CTL_AI_OFF; 1437300249Sjhb } 1438300249Sjhb 1439300249Sjhb pcib_pcie_hotplug_update(sc, val, mask, false); 1440300249Sjhb 1441300249Sjhb error = pcib_release_pcie_irq(sc); 1442300249Sjhb if (error) 1443300249Sjhb return (error); 1444300249Sjhb taskqueue_drain(taskqueue_thread, &sc->pcie_hp_task); 1445300249Sjhb callout_drain(&sc->pcie_ab_timer); 1446300249Sjhb callout_drain(&sc->pcie_cc_timer); 1447300249Sjhb callout_drain(&sc->pcie_dll_timer); 1448300249Sjhb return (0); 1449300249Sjhb} 1450299142Sjhb#endif 1451299142Sjhb 1452299142Sjhb/* 1453200341Sjkim * Get current bridge configuration. 1454200341Sjkim */ 1455200341Sjkimstatic void 1456200341Sjkimpcib_cfg_save(struct pcib_softc *sc) 1457200341Sjkim{ 1458281874Sjhb#ifndef NEW_PCIB 1459200341Sjkim device_t dev; 1460281874Sjhb uint16_t command; 1461200341Sjkim 1462200341Sjkim dev = sc->dev; 1463200341Sjkim 1464281874Sjhb command = pci_read_config(dev, PCIR_COMMAND, 2); 1465281874Sjhb if (command & PCIM_CMD_PORTEN) 1466200341Sjkim pcib_get_io_decode(sc); 1467281874Sjhb if (command & PCIM_CMD_MEMEN) 1468200341Sjkim pcib_get_mem_decode(sc); 1469221393Sjhb#endif 1470200341Sjkim} 1471200341Sjkim 1472200341Sjkim/* 1473200341Sjkim * Restore previous bridge configuration. 1474200341Sjkim */ 1475200341Sjkimstatic void 1476200341Sjkimpcib_cfg_restore(struct pcib_softc *sc) 1477200341Sjkim{ 1478200341Sjkim device_t dev; 1479281874Sjhb#ifndef NEW_PCIB 1480281874Sjhb uint16_t command; 1481281874Sjhb#endif 1482200341Sjkim dev = sc->dev; 1483200341Sjkim 1484221393Sjhb#ifdef NEW_PCIB 1485221393Sjhb pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM); 1486221393Sjhb#else 1487281874Sjhb command = pci_read_config(dev, PCIR_COMMAND, 2); 1488281874Sjhb if (command & PCIM_CMD_PORTEN) 1489200341Sjkim pcib_set_io_decode(sc); 1490281874Sjhb if (command & PCIM_CMD_MEMEN) 1491200341Sjkim pcib_set_mem_decode(sc); 1492221393Sjhb#endif 1493200341Sjkim} 1494200341Sjkim 1495200341Sjkim/* 149669783Smsmith * Generic device interface 149769783Smsmith */ 149869783Smsmithstatic int 149969783Smsmithpcib_probe(device_t dev) 150069783Smsmith{ 150169783Smsmith if ((pci_get_class(dev) == PCIC_BRIDGE) && 150269783Smsmith (pci_get_subclass(dev) == PCIS_BRIDGE_PCI)) { 150369783Smsmith device_set_desc(dev, "PCI-PCI bridge"); 1504284086Smarcel return(-10000); 150569783Smsmith } 150669783Smsmith return(ENXIO); 150769783Smsmith} 150869783Smsmith 1509102441Sjhbvoid 1510102441Sjhbpcib_attach_common(device_t dev) 151169783Smsmith{ 151269783Smsmith struct pcib_softc *sc; 1513181789Simp struct sysctl_ctx_list *sctx; 1514181789Simp struct sysctl_oid *soid; 1515253450Sjhb int comma; 151669783Smsmith 151769783Smsmith sc = device_get_softc(dev); 151869783Smsmith sc->dev = dev; 151969783Smsmith 152069908Smsmith /* 152169908Smsmith * Get current bridge configuration. 152269908Smsmith */ 1523200341Sjkim sc->domain = pci_get_domain(dev); 1524281874Sjhb#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS)) 1525281874Sjhb sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1); 1526281874Sjhb sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1); 1527281874Sjhb#endif 1528281874Sjhb sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); 1529200341Sjkim pcib_cfg_save(sc); 153069783Smsmith 153169908Smsmith /* 1532261790Sjhb * The primary bus register should always be the bus of the 1533261790Sjhb * parent. 1534261790Sjhb */ 1535261790Sjhb sc->pribus = pci_get_bus(dev); 1536261790Sjhb pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); 1537261790Sjhb 1538261790Sjhb /* 1539181789Simp * Setup sysctl reporting nodes 1540181789Simp */ 1541181789Simp sctx = device_get_sysctl_ctx(dev); 1542181789Simp soid = device_get_sysctl_tree(dev); 1543181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", 1544182706Simp CTLFLAG_RD, &sc->domain, 0, "Domain number"); 1545181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", 1546182706Simp CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); 1547181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", 1548261790Sjhb CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number"); 1549181789Simp SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", 1550261790Sjhb CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number"); 1551181789Simp 1552181789Simp /* 155369908Smsmith * Quirk handling. 155469908Smsmith */ 155569908Smsmith switch (pci_get_devid(dev)) { 1556281872Sjhb#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS)) 1557124365Simp case 0x12258086: /* Intel 82454KX/GX (Orion) */ 155869908Smsmith { 1559119266Simp uint8_t supbus; 156069908Smsmith 156169908Smsmith supbus = pci_read_config(dev, 0x41, 1); 156269908Smsmith if (supbus != 0xff) { 1563261790Sjhb sc->bus.sec = supbus + 1; 1564261790Sjhb sc->bus.sub = supbus + 1; 156569908Smsmith } 1566124365Simp break; 156769908Smsmith } 1568261790Sjhb#endif 1569124365Simp 1570124365Simp /* 1571124365Simp * The i82380FB mobile docking controller is a PCI-PCI bridge, 1572124365Simp * and it is a subtractive bridge. However, the ProgIf is wrong 1573124365Simp * so the normal setting of PCIB_SUBTRACTIVE bit doesn't 1574286480Szbb * happen. There are also Toshiba and Cavium ThunderX bridges 1575286480Szbb * that behave this way. 1576124365Simp */ 1577286480Szbb case 0xa002177d: /* Cavium ThunderX */ 1578124365Simp case 0x124b8086: /* Intel 82380FB Mobile */ 1579124365Simp case 0x060513d7: /* Toshiba ???? */ 1580124365Simp sc->flags |= PCIB_SUBTRACTIVE; 158169908Smsmith break; 1582149521Sjkim 1583281872Sjhb#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS)) 1584149521Sjkim /* Compaq R3000 BIOS sets wrong subordinate bus number. */ 1585149521Sjkim case 0x00dd10de: 1586149521Sjkim { 1587149521Sjkim char *cp; 1588149521Sjkim 1589273174Sdavide if ((cp = kern_getenv("smbios.planar.maker")) == NULL) 1590149521Sjkim break; 1591157949Sjkim if (strncmp(cp, "Compal", 6) != 0) { 1592157949Sjkim freeenv(cp); 1593149521Sjkim break; 1594157949Sjkim } 1595157949Sjkim freeenv(cp); 1596273174Sdavide if ((cp = kern_getenv("smbios.planar.product")) == NULL) 1597157949Sjkim break; 1598157949Sjkim if (strncmp(cp, "08A0", 4) != 0) { 1599157949Sjkim freeenv(cp); 1600157949Sjkim break; 1601157949Sjkim } 1602157949Sjkim freeenv(cp); 1603261790Sjhb if (sc->bus.sub < 0xa) { 1604149521Sjkim pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1); 1605261790Sjhb sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1); 1606149521Sjkim } 1607149521Sjkim break; 1608149521Sjkim } 1609261790Sjhb#endif 161069908Smsmith } 161169908Smsmith 1612165995Sjhb if (pci_msi_device_blacklisted(dev)) 1613165995Sjhb sc->flags |= PCIB_DISABLE_MSI; 1614165995Sjhb 1615253120Smarius if (pci_msix_device_blacklisted(dev)) 1616253120Smarius sc->flags |= PCIB_DISABLE_MSIX; 1617253120Smarius 1618124365Simp /* 1619124365Simp * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, 1620124365Simp * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, 1621124365Simp * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. 1622124365Simp * This means they act as if they were subtractively decoding 1623124365Simp * bridges and pass all transactions. Mark them and real ProgIf 1 1624124365Simp * parts as subtractive. 1625124365Simp */ 1626124365Simp if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || 1627168157Sjhb pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE) 1628124365Simp sc->flags |= PCIB_SUBTRACTIVE; 1629221393Sjhb 1630299142Sjhb#ifdef PCI_HP 1631299142Sjhb pcib_probe_hotplug(sc); 1632299142Sjhb#endif 1633221393Sjhb#ifdef NEW_PCIB 1634261790Sjhb#ifdef PCI_RES_BUS 1635261790Sjhb pcib_setup_secbus(dev, &sc->bus, 1); 1636261790Sjhb#endif 1637221393Sjhb pcib_probe_windows(sc); 1638221393Sjhb#endif 1639299142Sjhb#ifdef PCI_HP 1640299142Sjhb if (sc->flags & PCIB_HOTPLUG) 1641299142Sjhb pcib_setup_hotplug(sc); 1642299142Sjhb#endif 164369783Smsmith if (bootverbose) { 1644172394Smarius device_printf(dev, " domain %d\n", sc->domain); 1645261790Sjhb device_printf(dev, " secondary bus %d\n", sc->bus.sec); 1646261790Sjhb device_printf(dev, " subordinate bus %d\n", sc->bus.sub); 1647221393Sjhb#ifdef NEW_PCIB 1648221393Sjhb if (pcib_is_window_open(&sc->io)) 1649221393Sjhb device_printf(dev, " I/O decode 0x%jx-0x%jx\n", 1650221393Sjhb (uintmax_t)sc->io.base, (uintmax_t)sc->io.limit); 1651221393Sjhb if (pcib_is_window_open(&sc->mem)) 1652221393Sjhb device_printf(dev, " memory decode 0x%jx-0x%jx\n", 1653221393Sjhb (uintmax_t)sc->mem.base, (uintmax_t)sc->mem.limit); 1654221393Sjhb if (pcib_is_window_open(&sc->pmem)) 1655221393Sjhb device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 1656221393Sjhb (uintmax_t)sc->pmem.base, (uintmax_t)sc->pmem.limit); 1657221393Sjhb#else 1658221393Sjhb if (pcib_is_io_open(sc)) 1659221393Sjhb device_printf(dev, " I/O decode 0x%x-0x%x\n", 1660221393Sjhb sc->iobase, sc->iolimit); 1661163805Simp if (pcib_is_nonprefetch_open(sc)) 1662163805Simp device_printf(dev, " memory decode 0x%jx-0x%jx\n", 1663163805Simp (uintmax_t)sc->membase, (uintmax_t)sc->memlimit); 1664163805Simp if (pcib_is_prefetch_open(sc)) 1665163805Simp device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", 1666163805Simp (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 1667221393Sjhb#endif 1668253450Sjhb if (sc->bridgectl & (PCIB_BCR_ISA_ENABLE | PCIB_BCR_VGA_ENABLE) || 1669253450Sjhb sc->flags & PCIB_SUBTRACTIVE) { 1670253450Sjhb device_printf(dev, " special decode "); 1671253450Sjhb comma = 0; 1672253450Sjhb if (sc->bridgectl & PCIB_BCR_ISA_ENABLE) { 1673253450Sjhb printf("ISA"); 1674253450Sjhb comma = 1; 1675253450Sjhb } 1676253450Sjhb if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) { 1677253450Sjhb printf("%sVGA", comma ? ", " : ""); 1678253450Sjhb comma = 1; 1679253450Sjhb } 1680253450Sjhb if (sc->flags & PCIB_SUBTRACTIVE) 1681253450Sjhb printf("%ssubtractive", comma ? ", " : ""); 1682253450Sjhb printf("\n"); 1683253450Sjhb } 168469783Smsmith } 168569783Smsmith 168669783Smsmith /* 1687239103Sjhb * Always enable busmastering on bridges so that transactions 1688239103Sjhb * initiated on the secondary bus are passed through to the 1689239103Sjhb * primary bus. 1690239103Sjhb */ 1691239103Sjhb pci_enable_busmaster(dev); 1692102441Sjhb} 169369783Smsmith 1694299142Sjhb#ifdef PCI_HP 1695299142Sjhbstatic int 1696299142Sjhbpcib_present(struct pcib_softc *sc) 1697299142Sjhb{ 1698299142Sjhb 1699299142Sjhb if (sc->flags & PCIB_HOTPLUG) 1700299142Sjhb return (pcib_hotplug_present(sc) != 0); 1701299142Sjhb return (1); 1702299142Sjhb} 1703299142Sjhb#endif 1704299142Sjhb 1705103042Sjhbint 1706298711Sjhbpcib_attach_child(device_t dev) 1707298711Sjhb{ 1708298711Sjhb struct pcib_softc *sc; 1709298711Sjhb 1710298711Sjhb sc = device_get_softc(dev); 1711298711Sjhb if (sc->bus.sec == 0) { 1712298711Sjhb /* no secondary bus; we should have fixed this */ 1713298711Sjhb return(0); 1714298711Sjhb } 1715298711Sjhb 1716299142Sjhb#ifdef PCI_HP 1717299142Sjhb if (!pcib_present(sc)) { 1718299142Sjhb /* An empty HotPlug slot, so don't add a PCI bus yet. */ 1719299142Sjhb return (0); 1720299142Sjhb } 1721299142Sjhb#endif 1722299142Sjhb 1723298711Sjhb sc->child = device_add_child(dev, "pci", -1); 1724298711Sjhb return (bus_generic_attach(dev)); 1725298711Sjhb} 1726298711Sjhb 1727298711Sjhbint 1728102441Sjhbpcib_attach(device_t dev) 1729102441Sjhb{ 1730102441Sjhb 1731102441Sjhb pcib_attach_common(dev); 1732298711Sjhb return (pcib_attach_child(dev)); 173369783Smsmith} 173469783Smsmith 1735102441Sjhbint 1736300249Sjhbpcib_detach(device_t dev) 1737300249Sjhb{ 1738300249Sjhb#if defined(PCI_HP) || defined(NEW_PCIB) 1739300249Sjhb struct pcib_softc *sc; 1740300249Sjhb#endif 1741300249Sjhb int error; 1742300249Sjhb 1743300249Sjhb#if defined(PCI_HP) || defined(NEW_PCIB) 1744300249Sjhb sc = device_get_softc(dev); 1745300249Sjhb#endif 1746300249Sjhb error = bus_generic_detach(dev); 1747300249Sjhb if (error) 1748300249Sjhb return (error); 1749300249Sjhb#ifdef PCI_HP 1750300249Sjhb if (sc->flags & PCIB_HOTPLUG) { 1751300249Sjhb error = pcib_detach_hotplug(sc); 1752300249Sjhb if (error) 1753300249Sjhb return (error); 1754300249Sjhb } 1755300249Sjhb#endif 1756300249Sjhb error = device_delete_children(dev); 1757300249Sjhb if (error) 1758300249Sjhb return (error); 1759300249Sjhb#ifdef NEW_PCIB 1760300249Sjhb pcib_free_windows(sc); 1761300249Sjhb#ifdef PCI_RES_BUS 1762300249Sjhb pcib_free_secbus(dev, &sc->bus); 1763300249Sjhb#endif 1764300249Sjhb#endif 1765300249Sjhb return (0); 1766300249Sjhb} 1767300249Sjhb 1768300249Sjhbint 1769200341Sjkimpcib_suspend(device_t dev) 1770200341Sjkim{ 1771200341Sjkim 1772200341Sjkim pcib_cfg_save(device_get_softc(dev)); 1773281873Sjhb return (bus_generic_suspend(dev)); 1774200341Sjkim} 1775200341Sjkim 1776200341Sjkimint 1777200341Sjkimpcib_resume(device_t dev) 1778200341Sjkim{ 1779200341Sjkim 1780200341Sjkim pcib_cfg_restore(device_get_softc(dev)); 1781200341Sjkim return (bus_generic_resume(dev)); 1782200341Sjkim} 1783200341Sjkim 1784282783Sjhibbitsvoid 1785282783Sjhibbitspcib_bridge_init(device_t dev) 1786282783Sjhibbits{ 1787282783Sjhibbits pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); 1788282783Sjhibbits pci_write_config(dev, PCIR_IOBASEH_1, 0xffff, 2); 1789282783Sjhibbits pci_write_config(dev, PCIR_IOLIMITL_1, 0, 1); 1790282783Sjhibbits pci_write_config(dev, PCIR_IOLIMITH_1, 0, 2); 1791282783Sjhibbits pci_write_config(dev, PCIR_MEMBASE_1, 0xffff, 2); 1792282783Sjhibbits pci_write_config(dev, PCIR_MEMLIMIT_1, 0, 2); 1793282783Sjhibbits pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); 1794282783Sjhibbits pci_write_config(dev, PCIR_PMBASEH_1, 0xffffffff, 4); 1795282783Sjhibbits pci_write_config(dev, PCIR_PMLIMITL_1, 0, 2); 1796282783Sjhibbits pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4); 1797282783Sjhibbits} 1798282783Sjhibbits 1799200341Sjkimint 1800299142Sjhbpcib_child_present(device_t dev, device_t child) 1801299142Sjhb{ 1802299142Sjhb#ifdef PCI_HP 1803299142Sjhb struct pcib_softc *sc = device_get_softc(dev); 1804299142Sjhb int retval; 1805299142Sjhb 1806299142Sjhb retval = bus_child_present(dev); 1807299142Sjhb if (retval != 0 && sc->flags & PCIB_HOTPLUG) 1808299142Sjhb retval = pcib_hotplug_present(sc); 1809299142Sjhb return (retval); 1810299142Sjhb#else 1811299142Sjhb return (bus_child_present(dev)); 1812299142Sjhb#endif 1813299142Sjhb} 1814299142Sjhb 1815299142Sjhbint 181669783Smsmithpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 181769783Smsmith{ 181869783Smsmith struct pcib_softc *sc = device_get_softc(dev); 1819289494Sjmg 182069783Smsmith switch (which) { 1821172394Smarius case PCIB_IVAR_DOMAIN: 1822172394Smarius *result = sc->domain; 1823172394Smarius return(0); 182469783Smsmith case PCIB_IVAR_BUS: 1825261790Sjhb *result = sc->bus.sec; 182669783Smsmith return(0); 182769783Smsmith } 182869783Smsmith return(ENOENT); 182969783Smsmith} 183069783Smsmith 1831102441Sjhbint 183269783Smsmithpcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 183369783Smsmith{ 183469783Smsmith 183569783Smsmith switch (which) { 1836172394Smarius case PCIB_IVAR_DOMAIN: 1837172394Smarius return(EINVAL); 183869783Smsmith case PCIB_IVAR_BUS: 1839261790Sjhb return(EINVAL); 184069783Smsmith } 184169783Smsmith return(ENOENT); 184269783Smsmith} 184369783Smsmith 1844221393Sjhb#ifdef NEW_PCIB 184569783Smsmith/* 1846221393Sjhb * Attempt to allocate a resource from the existing resources assigned 1847221393Sjhb * to a window. 1848221393Sjhb */ 1849221393Sjhbstatic struct resource * 1850221393Sjhbpcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w, 1851294883Sjhibbits device_t child, int type, int *rid, rman_res_t start, rman_res_t end, 1852294883Sjhibbits rman_res_t count, u_int flags) 1853221393Sjhb{ 1854221393Sjhb struct resource *res; 1855221393Sjhb 1856221393Sjhb if (!pcib_is_window_open(w)) 1857221393Sjhb return (NULL); 1858221393Sjhb 1859221393Sjhb res = rman_reserve_resource(&w->rman, start, end, count, 1860221393Sjhb flags & ~RF_ACTIVE, child); 1861221393Sjhb if (res == NULL) 1862221393Sjhb return (NULL); 1863221393Sjhb 1864221393Sjhb if (bootverbose) 1865221393Sjhb device_printf(sc->dev, 1866297000Sjhibbits "allocated %s range (%#jx-%#jx) for rid %x of %s\n", 1867221393Sjhb w->name, rman_get_start(res), rman_get_end(res), *rid, 1868221393Sjhb pcib_child_name(child)); 1869221393Sjhb rman_set_rid(res, *rid); 1870221393Sjhb 1871221393Sjhb /* 1872221393Sjhb * If the resource should be active, pass that request up the 1873221393Sjhb * tree. This assumes the parent drivers can handle 1874221393Sjhb * activating sub-allocated resources. 1875221393Sjhb */ 1876221393Sjhb if (flags & RF_ACTIVE) { 1877221393Sjhb if (bus_activate_resource(child, type, *rid, res) != 0) { 1878221393Sjhb rman_release_resource(res); 1879221393Sjhb return (NULL); 1880221393Sjhb } 1881221393Sjhb } 1882221393Sjhb 1883221393Sjhb return (res); 1884221393Sjhb} 1885221393Sjhb 1886253450Sjhb/* Allocate a fresh resource range for an unconfigured window. */ 1887253450Sjhbstatic int 1888253450Sjhbpcib_alloc_new_window(struct pcib_softc *sc, struct pcib_window *w, int type, 1889294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 1890253450Sjhb{ 1891253450Sjhb struct resource *res; 1892294883Sjhibbits rman_res_t base, limit, wmask; 1893253450Sjhb int rid; 1894253450Sjhb 1895253450Sjhb /* 1896253450Sjhb * If this is an I/O window on a bridge with ISA enable set 1897253450Sjhb * and the start address is below 64k, then try to allocate an 1898253450Sjhb * initial window of 0x1000 bytes long starting at address 1899253450Sjhb * 0xf000 and walking down. Note that if the original request 1900253450Sjhb * was larger than the non-aliased range size of 0x100 our 1901253450Sjhb * caller would have raised the start address up to 64k 1902253450Sjhb * already. 1903253450Sjhb */ 1904253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && 1905253450Sjhb start < 65536) { 1906253450Sjhb for (base = 0xf000; (long)base >= 0; base -= 0x1000) { 1907253450Sjhb limit = base + 0xfff; 1908253450Sjhb 1909253450Sjhb /* 1910253450Sjhb * Skip ranges that wouldn't work for the 1911253450Sjhb * original request. Note that the actual 1912253450Sjhb * window that overlaps are the non-alias 1913253450Sjhb * ranges within [base, limit], so this isn't 1914253450Sjhb * quite a simple comparison. 1915253450Sjhb */ 1916253450Sjhb if (start + count > limit - 0x400) 1917253450Sjhb continue; 1918253450Sjhb if (base == 0) { 1919253450Sjhb /* 1920253450Sjhb * The first open region for the window at 1921253450Sjhb * 0 is 0x400-0x4ff. 1922253450Sjhb */ 1923253450Sjhb if (end - count + 1 < 0x400) 1924253450Sjhb continue; 1925253450Sjhb } else { 1926253450Sjhb if (end - count + 1 < base) 1927253450Sjhb continue; 1928253450Sjhb } 1929253450Sjhb 1930253450Sjhb if (pcib_alloc_nonisa_ranges(sc, base, limit) == 0) { 1931253450Sjhb w->base = base; 1932253450Sjhb w->limit = limit; 1933253450Sjhb return (0); 1934253450Sjhb } 1935253450Sjhb } 1936289494Sjmg return (ENOSPC); 1937253450Sjhb } 1938289494Sjmg 1939295664Sjhibbits wmask = ((rman_res_t)1 << w->step) - 1; 1940253450Sjhb if (RF_ALIGNMENT(flags) < w->step) { 1941253450Sjhb flags &= ~RF_ALIGNMENT_MASK; 1942253450Sjhb flags |= RF_ALIGNMENT_LOG2(w->step); 1943253450Sjhb } 1944253450Sjhb start &= ~wmask; 1945253450Sjhb end |= wmask; 1946295664Sjhibbits count = roundup2(count, (rman_res_t)1 << w->step); 1947253450Sjhb rid = w->reg; 1948253450Sjhb res = bus_alloc_resource(sc->dev, type, &rid, start, end, count, 1949253450Sjhb flags & ~RF_ACTIVE); 1950253450Sjhb if (res == NULL) 1951253450Sjhb return (ENOSPC); 1952253450Sjhb pcib_add_window_resources(w, &res, 1); 1953253450Sjhb pcib_activate_window(sc, type); 1954253450Sjhb w->base = rman_get_start(res); 1955253450Sjhb w->limit = rman_get_end(res); 1956253450Sjhb return (0); 1957253450Sjhb} 1958253450Sjhb 1959253450Sjhb/* Try to expand an existing window to the requested base and limit. */ 1960253450Sjhbstatic int 1961253450Sjhbpcib_expand_window(struct pcib_softc *sc, struct pcib_window *w, int type, 1962294883Sjhibbits rman_res_t base, rman_res_t limit) 1963253450Sjhb{ 1964253450Sjhb struct resource *res; 1965253450Sjhb int error, i, force_64k_base; 1966253450Sjhb 1967253450Sjhb KASSERT(base <= w->base && limit >= w->limit, 1968253450Sjhb ("attempting to shrink window")); 1969253450Sjhb 1970253450Sjhb /* 1971253450Sjhb * XXX: pcib_grow_window() doesn't try to do this anyway and 1972253450Sjhb * the error handling for all the edge cases would be tedious. 1973253450Sjhb */ 1974253450Sjhb KASSERT(limit == w->limit || base == w->base, 1975253450Sjhb ("attempting to grow both ends of a window")); 1976253450Sjhb 1977253450Sjhb /* 1978253450Sjhb * Yet more special handling for requests to expand an I/O 1979253450Sjhb * window behind an ISA-enabled bridge. Since I/O windows 1980253450Sjhb * have to grow in 0x1000 increments and the end of the 0xffff 1981253450Sjhb * range is an alias, growing a window below 64k will always 1982253450Sjhb * result in allocating new resources and never adjusting an 1983253450Sjhb * existing resource. 1984253450Sjhb */ 1985253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && 1986253450Sjhb (limit <= 65535 || (base <= 65535 && base != w->base))) { 1987253450Sjhb KASSERT(limit == w->limit || limit <= 65535, 1988253450Sjhb ("attempting to grow both ends across 64k ISA alias")); 1989253450Sjhb 1990253450Sjhb if (base != w->base) 1991253450Sjhb error = pcib_alloc_nonisa_ranges(sc, base, w->base - 1); 1992253450Sjhb else 1993253450Sjhb error = pcib_alloc_nonisa_ranges(sc, w->limit + 1, 1994253450Sjhb limit); 1995253450Sjhb if (error == 0) { 1996253450Sjhb w->base = base; 1997253450Sjhb w->limit = limit; 1998253450Sjhb } 1999253450Sjhb return (error); 2000253450Sjhb } 2001253450Sjhb 2002253450Sjhb /* 2003253450Sjhb * Find the existing resource to adjust. Usually there is only one, 2004253450Sjhb * but for an ISA-enabled bridge we might be growing the I/O window 2005253450Sjhb * above 64k and need to find the existing resource that maps all 2006253450Sjhb * of the area above 64k. 2007253450Sjhb */ 2008253450Sjhb for (i = 0; i < w->count; i++) { 2009253450Sjhb if (rman_get_end(w->res[i]) == w->limit) 2010253450Sjhb break; 2011253450Sjhb } 2012253450Sjhb KASSERT(i != w->count, ("did not find existing resource")); 2013253450Sjhb res = w->res[i]; 2014253450Sjhb 2015253450Sjhb /* 2016253450Sjhb * Usually the resource we found should match the window's 2017253450Sjhb * existing range. The one exception is the ISA-enabled case 2018253450Sjhb * mentioned above in which case the resource should start at 2019253450Sjhb * 64k. 2020253450Sjhb */ 2021253450Sjhb if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && 2022253450Sjhb w->base <= 65535) { 2023253450Sjhb KASSERT(rman_get_start(res) == 65536, 2024253450Sjhb ("existing resource mismatch")); 2025253450Sjhb force_64k_base = 1; 2026253450Sjhb } else { 2027253450Sjhb KASSERT(w->base == rman_get_start(res), 2028253450Sjhb ("existing resource mismatch")); 2029253450Sjhb force_64k_base = 0; 2030289494Sjmg } 2031253450Sjhb 2032253450Sjhb error = bus_adjust_resource(sc->dev, type, res, force_64k_base ? 2033253450Sjhb rman_get_start(res) : base, limit); 2034253450Sjhb if (error) 2035253450Sjhb return (error); 2036253450Sjhb 2037253450Sjhb /* Add the newly allocated region to the resource manager. */ 2038253450Sjhb if (w->base != base) { 2039253450Sjhb error = rman_manage_region(&w->rman, base, w->base - 1); 2040253450Sjhb w->base = base; 2041253450Sjhb } else { 2042253450Sjhb error = rman_manage_region(&w->rman, w->limit + 1, limit); 2043253450Sjhb w->limit = limit; 2044253450Sjhb } 2045253450Sjhb if (error) { 2046253450Sjhb if (bootverbose) 2047253450Sjhb device_printf(sc->dev, 2048253450Sjhb "failed to expand %s resource manager\n", w->name); 2049253450Sjhb (void)bus_adjust_resource(sc->dev, type, res, force_64k_base ? 2050253450Sjhb rman_get_start(res) : w->base, w->limit); 2051253450Sjhb } 2052253450Sjhb return (error); 2053253450Sjhb} 2054253450Sjhb 2055221393Sjhb/* 2056221393Sjhb * Attempt to grow a window to make room for a given resource request. 2057221393Sjhb */ 2058221393Sjhbstatic int 2059221393Sjhbpcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, 2060294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 2061221393Sjhb{ 2062294883Sjhibbits rman_res_t align, start_free, end_free, front, back, wmask; 2063253450Sjhb int error; 2064221393Sjhb 2065221393Sjhb /* 2066221393Sjhb * Clamp the desired resource range to the maximum address 2067221393Sjhb * this window supports. Reject impossible requests. 2068253450Sjhb * 2069253450Sjhb * For I/O port requests behind a bridge with the ISA enable 2070253450Sjhb * bit set, force large allocations to start above 64k. 2071221393Sjhb */ 2072221393Sjhb if (!w->valid) 2073221393Sjhb return (EINVAL); 2074253450Sjhb if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 && 2075253450Sjhb start < 65536) 2076253450Sjhb start = 65536; 2077221393Sjhb if (end > w->rman.rm_end) 2078221393Sjhb end = w->rman.rm_end; 2079221393Sjhb if (start + count - 1 > end || start + count < start) 2080221393Sjhb return (EINVAL); 2081295664Sjhibbits wmask = ((rman_res_t)1 << w->step) - 1; 2082221393Sjhb 2083221393Sjhb /* 2084221393Sjhb * If there is no resource at all, just try to allocate enough 2085221393Sjhb * aligned space for this resource. 2086221393Sjhb */ 2087221393Sjhb if (w->res == NULL) { 2088253450Sjhb error = pcib_alloc_new_window(sc, w, type, start, end, count, 2089253450Sjhb flags); 2090253450Sjhb if (error) { 2091221393Sjhb if (bootverbose) 2092221393Sjhb device_printf(sc->dev, 2093297000Sjhibbits "failed to allocate initial %s window (%#jx-%#jx,%#jx)\n", 2094221393Sjhb w->name, start, end, count); 2095253450Sjhb return (error); 2096221393Sjhb } 2097221393Sjhb if (bootverbose) 2098221393Sjhb device_printf(sc->dev, 2099253450Sjhb "allocated initial %s window of %#jx-%#jx\n", 2100253450Sjhb w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 2101221393Sjhb goto updatewin; 2102221393Sjhb } 2103221393Sjhb 2104221393Sjhb /* 2105221393Sjhb * See if growing the window would help. Compute the minimum 2106221393Sjhb * amount of address space needed on both the front and back 2107221393Sjhb * ends of the existing window to satisfy the allocation. 2108221393Sjhb * 2109221393Sjhb * For each end, build a candidate region adjusting for the 2110221393Sjhb * required alignment, etc. If there is a free region at the 2111221393Sjhb * edge of the window, grow from the inner edge of the free 2112221393Sjhb * region. Otherwise grow from the window boundary. 2113221393Sjhb * 2114253450Sjhb * Growing an I/O window below 64k for a bridge with the ISA 2115253450Sjhb * enable bit doesn't require any special magic as the step 2116253450Sjhb * size of an I/O window (1k) always includes multiple 2117253450Sjhb * non-alias ranges when it is grown in either direction. 2118253450Sjhb * 2119221393Sjhb * XXX: Special case: if w->res is completely empty and the 2120221393Sjhb * request size is larger than w->res, we should find the 2121221393Sjhb * optimal aligned buffer containing w->res and allocate that. 2122221393Sjhb */ 2123221393Sjhb if (bootverbose) 2124221393Sjhb device_printf(sc->dev, 2125297000Sjhibbits "attempting to grow %s window for (%#jx-%#jx,%#jx)\n", 2126221393Sjhb w->name, start, end, count); 2127295664Sjhibbits align = (rman_res_t)1 << RF_ALIGNMENT(flags); 2128253450Sjhb if (start < w->base) { 2129221393Sjhb if (rman_first_free_region(&w->rman, &start_free, &end_free) != 2130253450Sjhb 0 || start_free != w->base) 2131253450Sjhb end_free = w->base; 2132221393Sjhb if (end_free > end) 2133237008Sjhb end_free = end + 1; 2134221393Sjhb 2135221393Sjhb /* Move end_free down until it is properly aligned. */ 2136221393Sjhb end_free &= ~(align - 1); 2137222930Sjhb end_free--; 2138222930Sjhb front = end_free - (count - 1); 2139221393Sjhb 2140221393Sjhb /* 2141221393Sjhb * The resource would now be allocated at (front, 2142221393Sjhb * end_free). Ensure that fits in the (start, end) 2143221393Sjhb * bounds. end_free is checked above. If 'front' is 2144221393Sjhb * ok, ensure it is properly aligned for this window. 2145221393Sjhb * Also check for underflow. 2146221393Sjhb */ 2147221393Sjhb if (front >= start && front <= end_free) { 2148221393Sjhb if (bootverbose) 2149297000Sjhibbits printf("\tfront candidate range: %#jx-%#jx\n", 2150221393Sjhb front, end_free); 2151237272Sjhb front &= ~wmask; 2152253450Sjhb front = w->base - front; 2153221393Sjhb } else 2154221393Sjhb front = 0; 2155221393Sjhb } else 2156221393Sjhb front = 0; 2157253450Sjhb if (end > w->limit) { 2158221393Sjhb if (rman_last_free_region(&w->rman, &start_free, &end_free) != 2159253450Sjhb 0 || end_free != w->limit) 2160253450Sjhb start_free = w->limit + 1; 2161221393Sjhb if (start_free < start) 2162221393Sjhb start_free = start; 2163221393Sjhb 2164221393Sjhb /* Move start_free up until it is properly aligned. */ 2165221393Sjhb start_free = roundup2(start_free, align); 2166222930Sjhb back = start_free + count - 1; 2167221393Sjhb 2168221393Sjhb /* 2169221393Sjhb * The resource would now be allocated at (start_free, 2170221393Sjhb * back). Ensure that fits in the (start, end) 2171221393Sjhb * bounds. start_free is checked above. If 'back' is 2172221393Sjhb * ok, ensure it is properly aligned for this window. 2173221393Sjhb * Also check for overflow. 2174221393Sjhb */ 2175221393Sjhb if (back <= end && start_free <= back) { 2176221393Sjhb if (bootverbose) 2177297000Sjhibbits printf("\tback candidate range: %#jx-%#jx\n", 2178221393Sjhb start_free, back); 2179237272Sjhb back |= wmask; 2180253450Sjhb back -= w->limit; 2181221393Sjhb } else 2182221393Sjhb back = 0; 2183221393Sjhb } else 2184221393Sjhb back = 0; 2185221393Sjhb 2186221393Sjhb /* 2187221393Sjhb * Try to allocate the smallest needed region first. 2188221393Sjhb * If that fails, fall back to the other region. 2189221393Sjhb */ 2190221393Sjhb error = ENOSPC; 2191221393Sjhb while (front != 0 || back != 0) { 2192221393Sjhb if (front != 0 && (front <= back || back == 0)) { 2193253450Sjhb error = pcib_expand_window(sc, w, type, w->base - front, 2194253450Sjhb w->limit); 2195221393Sjhb if (error == 0) 2196221393Sjhb break; 2197221393Sjhb front = 0; 2198221393Sjhb } else { 2199253450Sjhb error = pcib_expand_window(sc, w, type, w->base, 2200253450Sjhb w->limit + back); 2201221393Sjhb if (error == 0) 2202221393Sjhb break; 2203221393Sjhb back = 0; 2204221393Sjhb } 2205221393Sjhb } 2206221393Sjhb 2207221393Sjhb if (error) 2208221393Sjhb return (error); 2209221393Sjhb if (bootverbose) 2210253450Sjhb device_printf(sc->dev, "grew %s window to %#jx-%#jx\n", 2211253450Sjhb w->name, (uintmax_t)w->base, (uintmax_t)w->limit); 2212221393Sjhb 2213221393Sjhbupdatewin: 2214253450Sjhb /* Write the new window. */ 2215237272Sjhb KASSERT((w->base & wmask) == 0, ("start address is not aligned")); 2216237272Sjhb KASSERT((w->limit & wmask) == wmask, ("end address is not aligned")); 2217221393Sjhb pcib_write_windows(sc, w->mask); 2218221393Sjhb return (0); 2219221393Sjhb} 2220221393Sjhb 2221221393Sjhb/* 222269783Smsmith * We have to trap resource allocation requests and ensure that the bridge 222369783Smsmith * is set up to, or capable of handling them. 222469783Smsmith */ 2225102441Sjhbstruct resource * 2226221393Sjhbpcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 2227294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 2228221393Sjhb{ 2229221393Sjhb struct pcib_softc *sc; 2230221393Sjhb struct resource *r; 2231221393Sjhb 2232221393Sjhb sc = device_get_softc(dev); 2233221393Sjhb 2234221393Sjhb /* 2235221393Sjhb * VGA resources are decoded iff the VGA enable bit is set in 2236221393Sjhb * the bridge control register. VGA resources do not fall into 2237221393Sjhb * the resource windows and are passed up to the parent. 2238221393Sjhb */ 2239221393Sjhb if ((type == SYS_RES_IOPORT && pci_is_vga_ioport_range(start, end)) || 2240221393Sjhb (type == SYS_RES_MEMORY && pci_is_vga_memory_range(start, end))) { 2241221393Sjhb if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) 2242221393Sjhb return (bus_generic_alloc_resource(dev, child, type, 2243221393Sjhb rid, start, end, count, flags)); 2244221393Sjhb else 2245221393Sjhb return (NULL); 2246221393Sjhb } 2247221393Sjhb 2248221393Sjhb switch (type) { 2249261790Sjhb#ifdef PCI_RES_BUS 2250261790Sjhb case PCI_RES_BUS: 2251261790Sjhb return (pcib_alloc_subbus(&sc->bus, child, rid, start, end, 2252261790Sjhb count, flags)); 2253261790Sjhb#endif 2254221393Sjhb case SYS_RES_IOPORT: 2255253450Sjhb if (pcib_is_isa_range(sc, start, end, count)) 2256253450Sjhb return (NULL); 2257221393Sjhb r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start, 2258221393Sjhb end, count, flags); 2259237673Smarius if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 2260221393Sjhb break; 2261221393Sjhb if (pcib_grow_window(sc, &sc->io, type, start, end, count, 2262221393Sjhb flags) == 0) 2263221393Sjhb r = pcib_suballoc_resource(sc, &sc->io, child, type, 2264221393Sjhb rid, start, end, count, flags); 2265221393Sjhb break; 2266221393Sjhb case SYS_RES_MEMORY: 2267221393Sjhb /* 2268221393Sjhb * For prefetchable resources, prefer the prefetchable 2269221393Sjhb * memory window, but fall back to the regular memory 2270221393Sjhb * window if that fails. Try both windows before 2271221393Sjhb * attempting to grow a window in case the firmware 2272221393Sjhb * has used a range in the regular memory window to 2273221393Sjhb * map a prefetchable BAR. 2274221393Sjhb */ 2275221393Sjhb if (flags & RF_PREFETCHABLE) { 2276221393Sjhb r = pcib_suballoc_resource(sc, &sc->pmem, child, type, 2277221393Sjhb rid, start, end, count, flags); 2278221393Sjhb if (r != NULL) 2279221393Sjhb break; 2280221393Sjhb } 2281221393Sjhb r = pcib_suballoc_resource(sc, &sc->mem, child, type, rid, 2282221393Sjhb start, end, count, flags); 2283237673Smarius if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) 2284221393Sjhb break; 2285221393Sjhb if (flags & RF_PREFETCHABLE) { 2286221393Sjhb if (pcib_grow_window(sc, &sc->pmem, type, start, end, 2287221393Sjhb count, flags) == 0) { 2288221393Sjhb r = pcib_suballoc_resource(sc, &sc->pmem, child, 2289221393Sjhb type, rid, start, end, count, flags); 2290221393Sjhb if (r != NULL) 2291221393Sjhb break; 2292221393Sjhb } 2293221393Sjhb } 2294221393Sjhb if (pcib_grow_window(sc, &sc->mem, type, start, end, count, 2295221393Sjhb flags & ~RF_PREFETCHABLE) == 0) 2296221393Sjhb r = pcib_suballoc_resource(sc, &sc->mem, child, type, 2297221393Sjhb rid, start, end, count, flags); 2298221393Sjhb break; 2299221393Sjhb default: 2300221393Sjhb return (bus_generic_alloc_resource(dev, child, type, rid, 2301221393Sjhb start, end, count, flags)); 2302221393Sjhb } 2303221393Sjhb 2304221393Sjhb /* 2305221393Sjhb * If attempts to suballocate from the window fail but this is a 2306221393Sjhb * subtractive bridge, pass the request up the tree. 2307221393Sjhb */ 2308221393Sjhb if (sc->flags & PCIB_SUBTRACTIVE && r == NULL) 2309221393Sjhb return (bus_generic_alloc_resource(dev, child, type, rid, 2310221393Sjhb start, end, count, flags)); 2311221393Sjhb return (r); 2312221393Sjhb} 2313221393Sjhb 2314221393Sjhbint 2315221393Sjhbpcib_adjust_resource(device_t bus, device_t child, int type, struct resource *r, 2316294883Sjhibbits rman_res_t start, rman_res_t end) 2317221393Sjhb{ 2318221393Sjhb struct pcib_softc *sc; 2319221393Sjhb 2320221393Sjhb sc = device_get_softc(bus); 2321221393Sjhb if (pcib_is_resource_managed(sc, type, r)) 2322221393Sjhb return (rman_adjust_resource(r, start, end)); 2323221393Sjhb return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 2324221393Sjhb} 2325221393Sjhb 2326221393Sjhbint 2327221393Sjhbpcib_release_resource(device_t dev, device_t child, int type, int rid, 2328221393Sjhb struct resource *r) 2329221393Sjhb{ 2330221393Sjhb struct pcib_softc *sc; 2331221393Sjhb int error; 2332221393Sjhb 2333221393Sjhb sc = device_get_softc(dev); 2334221393Sjhb if (pcib_is_resource_managed(sc, type, r)) { 2335221393Sjhb if (rman_get_flags(r) & RF_ACTIVE) { 2336221393Sjhb error = bus_deactivate_resource(child, type, rid, r); 2337221393Sjhb if (error) 2338221393Sjhb return (error); 2339221393Sjhb } 2340221393Sjhb return (rman_release_resource(r)); 2341221393Sjhb } 2342221393Sjhb return (bus_generic_release_resource(dev, child, type, rid, r)); 2343221393Sjhb} 2344221393Sjhb#else 2345221393Sjhb/* 2346221393Sjhb * We have to trap resource allocation requests and ensure that the bridge 2347221393Sjhb * is set up to, or capable of handling them. 2348221393Sjhb */ 2349221393Sjhbstruct resource * 2350289494Sjmgpcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 2351294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 235269783Smsmith{ 2353124365Simp struct pcib_softc *sc = device_get_softc(dev); 2354164130Sjhb const char *name, *suffix; 2355124365Simp int ok; 235669783Smsmith 235769783Smsmith /* 235869783Smsmith * Fail the allocation for this range if it's not supported. 235969783Smsmith */ 2360164130Sjhb name = device_get_nameunit(child); 2361164130Sjhb if (name == NULL) { 2362164130Sjhb name = ""; 2363164130Sjhb suffix = ""; 2364164130Sjhb } else 2365164130Sjhb suffix = " "; 236669783Smsmith switch (type) { 236769783Smsmith case SYS_RES_IOPORT: 2368107546Simp ok = 0; 2369124365Simp if (!pcib_is_io_open(sc)) 2370124365Simp break; 2371124365Simp ok = (start >= sc->iobase && end <= sc->iolimit); 2372145652Smarcel 2373145652Smarcel /* 2374145652Smarcel * Make sure we allow access to VGA I/O addresses when the 2375145652Smarcel * bridge has the "VGA Enable" bit set. 2376145652Smarcel */ 2377145652Smarcel if (!ok && pci_is_vga_ioport_range(start, end)) 2378145652Smarcel ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 2379145652Smarcel 2380124365Simp if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 2381124365Simp if (!ok) { 2382124365Simp if (start < sc->iobase) 2383124365Simp start = sc->iobase; 2384124365Simp if (end > sc->iolimit) 2385124365Simp end = sc->iolimit; 2386142051Simp if (start < end) 2387142051Simp ok = 1; 2388124365Simp } 2389106844Smdodd } else { 2390124365Simp ok = 1; 2391189844Simp#if 0 2392189792Simp /* 2393189792Simp * If we overlap with the subtractive range, then 2394189792Simp * pick the upper range to use. 2395189792Simp */ 2396189792Simp if (start < sc->iolimit && end > sc->iobase) 2397189792Simp start = sc->iolimit + 1; 2398189844Simp#endif 2399106844Smdodd } 2400124365Simp if (end < start) { 2401297000Sjhibbits device_printf(dev, "ioport: end (%jx) < start (%jx)\n", 2402142051Simp end, start); 2403124365Simp start = 0; 2404124365Simp end = 0; 2405124365Simp ok = 0; 2406124365Simp } 2407124365Simp if (!ok) { 2408164130Sjhb device_printf(dev, "%s%srequested unsupported I/O " 2409297000Sjhibbits "range 0x%jx-0x%jx (decoding 0x%x-0x%x)\n", 2410164130Sjhb name, suffix, start, end, sc->iobase, sc->iolimit); 2411124365Simp return (NULL); 2412124365Simp } 2413124365Simp if (bootverbose) 2414142051Simp device_printf(dev, 2415297000Sjhibbits "%s%srequested I/O range 0x%jx-0x%jx: in range\n", 2416164130Sjhb name, suffix, start, end); 2417124365Simp break; 241869783Smsmith 241969783Smsmith case SYS_RES_MEMORY: 2420107546Simp ok = 0; 2421107546Simp if (pcib_is_nonprefetch_open(sc)) 2422124365Simp ok = ok || (start >= sc->membase && end <= sc->memlimit); 2423107546Simp if (pcib_is_prefetch_open(sc)) 2424124365Simp ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); 2425145652Smarcel 2426145652Smarcel /* 2427145652Smarcel * Make sure we allow access to VGA memory addresses when the 2428145652Smarcel * bridge has the "VGA Enable" bit set. 2429145652Smarcel */ 2430145652Smarcel if (!ok && pci_is_vga_memory_range(start, end)) 2431145652Smarcel ok = (sc->bridgectl & PCIB_BCR_VGA_ENABLE) ? 1 : 0; 2432145652Smarcel 2433124365Simp if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { 2434124365Simp if (!ok) { 2435124365Simp ok = 1; 2436124365Simp if (flags & RF_PREFETCHABLE) { 2437124365Simp if (pcib_is_prefetch_open(sc)) { 2438124365Simp if (start < sc->pmembase) 2439124365Simp start = sc->pmembase; 2440124365Simp if (end > sc->pmemlimit) 2441124365Simp end = sc->pmemlimit; 2442124365Simp } else { 2443124365Simp ok = 0; 2444124365Simp } 2445124365Simp } else { /* non-prefetchable */ 2446124365Simp if (pcib_is_nonprefetch_open(sc)) { 2447124365Simp if (start < sc->membase) 2448124365Simp start = sc->membase; 2449124365Simp if (end > sc->memlimit) 2450124365Simp end = sc->memlimit; 2451124365Simp } else { 2452124365Simp ok = 0; 2453124365Simp } 2454124365Simp } 2455107546Simp } 2456107546Simp } else if (!ok) { 2457124365Simp ok = 1; /* subtractive bridge: always ok */ 2458189844Simp#if 0 2459124365Simp if (pcib_is_nonprefetch_open(sc)) { 2460189792Simp if (start < sc->memlimit && end > sc->membase) 2461189792Simp start = sc->memlimit + 1; 2462124365Simp } 2463124365Simp if (pcib_is_prefetch_open(sc)) { 2464189792Simp if (start < sc->pmemlimit && end > sc->pmembase) 2465189792Simp start = sc->pmemlimit + 1; 2466124365Simp } 2467189844Simp#endif 2468106844Smdodd } 2469124365Simp if (end < start) { 2470297000Sjhibbits device_printf(dev, "memory: end (%jx) < start (%jx)\n", 2471142051Simp end, start); 2472124365Simp start = 0; 2473124365Simp end = 0; 2474124365Simp ok = 0; 2475124365Simp } 2476124365Simp if (!ok && bootverbose) 2477124365Simp device_printf(dev, 2478297000Sjhibbits "%s%srequested unsupported memory range %#jx-%#jx " 2479163805Simp "(decoding %#jx-%#jx, %#jx-%#jx)\n", 2480164130Sjhb name, suffix, start, end, 2481163805Simp (uintmax_t)sc->membase, (uintmax_t)sc->memlimit, 2482163805Simp (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); 2483124365Simp if (!ok) 2484124365Simp return (NULL); 2485124365Simp if (bootverbose) 2486164130Sjhb device_printf(dev,"%s%srequested memory range " 2487297000Sjhibbits "0x%jx-0x%jx: good\n", 2488164130Sjhb name, suffix, start, end); 2489124365Simp break; 249069908Smsmith 249169783Smsmith default: 2492124365Simp break; 249369783Smsmith } 2494124365Simp /* 2495124365Simp * Bridge is OK decoding this resource, so pass it up. 2496124365Simp */ 2497142051Simp return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 2498142051Simp count, flags)); 249969783Smsmith} 2500221393Sjhb#endif 250169783Smsmith 250269783Smsmith/* 2503264011Srstone * If ARI is enabled on this downstream port, translate the function number 2504264011Srstone * to the non-ARI slot/function. The downstream port will convert it back in 2505264011Srstone * hardware. If ARI is not enabled slot and func are not modified. 2506264011Srstone */ 2507264011Srstonestatic __inline void 2508264011Srstonepcib_xlate_ari(device_t pcib, int bus, int *slot, int *func) 2509264011Srstone{ 2510264011Srstone struct pcib_softc *sc; 2511264011Srstone int ari_func; 2512264011Srstone 2513264011Srstone sc = device_get_softc(pcib); 2514264011Srstone ari_func = *func; 2515264011Srstone 2516264011Srstone if (sc->flags & PCIB_ENABLE_ARI) { 2517264011Srstone KASSERT(*slot == 0, 2518264011Srstone ("Non-zero slot number with ARI enabled!")); 2519264011Srstone *slot = PCIE_ARI_SLOT(ari_func); 2520264011Srstone *func = PCIE_ARI_FUNC(ari_func); 2521264011Srstone } 2522264011Srstone} 2523264011Srstone 2524264011Srstone 2525264011Srstonestatic void 2526264011Srstonepcib_enable_ari(struct pcib_softc *sc, uint32_t pcie_pos) 2527264011Srstone{ 2528264011Srstone uint32_t ctl2; 2529264011Srstone 2530264011Srstone ctl2 = pci_read_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, 4); 2531264011Srstone ctl2 |= PCIEM_CTL2_ARI; 2532264011Srstone pci_write_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, ctl2, 4); 2533264011Srstone 2534264011Srstone sc->flags |= PCIB_ENABLE_ARI; 2535264011Srstone} 2536264011Srstone 2537264011Srstone/* 253869783Smsmith * PCIB interface. 253969783Smsmith */ 2540102441Sjhbint 254169783Smsmithpcib_maxslots(device_t dev) 254269783Smsmith{ 2543264011Srstone return (PCI_SLOTMAX); 254469783Smsmith} 254569783Smsmith 2546264011Srstonestatic int 2547264011Srstonepcib_ari_maxslots(device_t dev) 2548264011Srstone{ 2549264011Srstone struct pcib_softc *sc; 2550264011Srstone 2551264011Srstone sc = device_get_softc(dev); 2552264011Srstone 2553264011Srstone if (sc->flags & PCIB_ENABLE_ARI) 2554264011Srstone return (PCIE_ARI_SLOTMAX); 2555264011Srstone else 2556264011Srstone return (PCI_SLOTMAX); 2557264011Srstone} 2558264011Srstone 2559264011Srstonestatic int 2560264011Srstonepcib_ari_maxfuncs(device_t dev) 2561264011Srstone{ 2562264011Srstone struct pcib_softc *sc; 2563264011Srstone 2564264011Srstone sc = device_get_softc(dev); 2565264011Srstone 2566264011Srstone if (sc->flags & PCIB_ENABLE_ARI) 2567264011Srstone return (PCIE_ARI_FUNCMAX); 2568264011Srstone else 2569264011Srstone return (PCI_FUNCMAX); 2570264011Srstone} 2571264011Srstone 2572279443Srstonestatic void 2573279443Srstonepcib_ari_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot, 2574279443Srstone int *func) 2575279443Srstone{ 2576279443Srstone struct pcib_softc *sc; 2577279443Srstone 2578279443Srstone sc = device_get_softc(pcib); 2579279443Srstone 2580279443Srstone *bus = PCI_RID2BUS(rid); 2581279443Srstone if (sc->flags & PCIB_ENABLE_ARI) { 2582279443Srstone *slot = PCIE_ARI_RID2SLOT(rid); 2583279443Srstone *func = PCIE_ARI_RID2FUNC(rid); 2584279443Srstone } else { 2585279443Srstone *slot = PCI_RID2SLOT(rid); 2586279443Srstone *func = PCI_RID2FUNC(rid); 2587279443Srstone } 2588279443Srstone} 2589279443Srstone 259069783Smsmith/* 259169783Smsmith * Since we are a child of a PCI bus, its parent must support the pcib interface. 259269783Smsmith */ 2593264011Srstonestatic uint32_t 2594189792Simppcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) 259569783Smsmith{ 2596299142Sjhb#ifdef PCI_HP 2597299142Sjhb struct pcib_softc *sc; 2598264011Srstone 2599299142Sjhb sc = device_get_softc(dev); 2600299142Sjhb if (!pcib_present(sc)) { 2601299142Sjhb switch (width) { 2602299142Sjhb case 2: 2603299142Sjhb return (0xffff); 2604299142Sjhb case 1: 2605299142Sjhb return (0xff); 2606299142Sjhb default: 2607299142Sjhb return (0xffffffff); 2608299142Sjhb } 2609299142Sjhb } 2610299142Sjhb#endif 2611264011Srstone pcib_xlate_ari(dev, b, &s, &f); 2612264011Srstone return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, 2613264011Srstone f, reg, width)); 261469783Smsmith} 261569783Smsmith 2616264011Srstonestatic void 2617189792Simppcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) 261869783Smsmith{ 2619299142Sjhb#ifdef PCI_HP 2620299142Sjhb struct pcib_softc *sc; 2621264011Srstone 2622299142Sjhb sc = device_get_softc(dev); 2623299142Sjhb if (!pcib_present(sc)) 2624299142Sjhb return; 2625299142Sjhb#endif 2626264011Srstone pcib_xlate_ari(dev, b, &s, &f); 2627264011Srstone PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, 2628264011Srstone reg, val, width); 262969783Smsmith} 263069783Smsmith 263169783Smsmith/* 263269783Smsmith * Route an interrupt across a PCI bridge. 263369783Smsmith */ 2634109229Sbennoint 263569783Smsmithpcib_route_interrupt(device_t pcib, device_t dev, int pin) 263669783Smsmith{ 263769783Smsmith device_t bus; 263869783Smsmith int parent_intpin; 263969783Smsmith int intnum; 264069783Smsmith 2641289494Sjmg /* 264269783Smsmith * 264369783Smsmith * The PCI standard defines a swizzle of the child-side device/intpin to 264469783Smsmith * the parent-side intpin as follows. 264569783Smsmith * 264669783Smsmith * device = device on child bus 264769783Smsmith * child_intpin = intpin on child bus slot (0-3) 264869783Smsmith * parent_intpin = intpin on parent bus slot (0-3) 264969783Smsmith * 265069783Smsmith * parent_intpin = (device + child_intpin) % 4 265169783Smsmith */ 2652115234Sticso parent_intpin = (pci_get_slot(dev) + (pin - 1)) % 4; 265369783Smsmith 265469783Smsmith /* 265569783Smsmith * Our parent is a PCI bus. Its parent must export the pcib interface 265669783Smsmith * which includes the ability to route interrupts. 265769783Smsmith */ 265869783Smsmith bus = device_get_parent(pcib); 265969783Smsmith intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); 2660131398Sjhb if (PCI_INTERRUPT_VALID(intnum) && bootverbose) { 2661102977Sjhb device_printf(pcib, "slot %d INT%c is routed to irq %d\n", 2662102977Sjhb pci_get_slot(dev), 'A' + pin - 1, intnum); 266390554Smsmith } 266469783Smsmith return(intnum); 266569783Smsmith} 2666107172Sjhb 2667169221Sjhb/* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */ 2668164264Sjhbint 2669164264Sjhbpcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 2670164264Sjhb{ 2671169902Sgallatin struct pcib_softc *sc = device_get_softc(pcib); 2672164264Sjhb device_t bus; 2673164264Sjhb 2674165995Sjhb if (sc->flags & PCIB_DISABLE_MSI) 2675165995Sjhb return (ENXIO); 2676164264Sjhb bus = device_get_parent(pcib); 2677164264Sjhb return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, 2678164264Sjhb irqs)); 2679164264Sjhb} 2680164264Sjhb 2681169221Sjhb/* Pass request to release MSI/MSI-X messages up to the parent bridge. */ 2682164264Sjhbint 2683164264Sjhbpcib_release_msi(device_t pcib, device_t dev, int count, int *irqs) 2684164264Sjhb{ 2685164264Sjhb device_t bus; 2686164264Sjhb 2687164264Sjhb bus = device_get_parent(pcib); 2688164264Sjhb return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs)); 2689164264Sjhb} 2690164264Sjhb 2691164264Sjhb/* Pass request to alloc an MSI-X message up to the parent bridge. */ 2692164264Sjhbint 2693169221Sjhbpcib_alloc_msix(device_t pcib, device_t dev, int *irq) 2694164264Sjhb{ 2695169902Sgallatin struct pcib_softc *sc = device_get_softc(pcib); 2696164264Sjhb device_t bus; 2697164264Sjhb 2698253120Smarius if (sc->flags & PCIB_DISABLE_MSIX) 2699165995Sjhb return (ENXIO); 2700164264Sjhb bus = device_get_parent(pcib); 2701169221Sjhb return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); 2702164264Sjhb} 2703164264Sjhb 2704169221Sjhb/* Pass request to release an MSI-X message up to the parent bridge. */ 2705166176Sjhbint 2706169221Sjhbpcib_release_msix(device_t pcib, device_t dev, int irq) 2707166176Sjhb{ 2708166176Sjhb device_t bus; 2709166176Sjhb 2710166176Sjhb bus = device_get_parent(pcib); 2711169221Sjhb return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq)); 2712166176Sjhb} 2713166176Sjhb 2714169221Sjhb/* Pass request to map MSI/MSI-X message up to parent bridge. */ 2715164264Sjhbint 2716169221Sjhbpcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 2717169221Sjhb uint32_t *data) 2718164264Sjhb{ 2719164264Sjhb device_t bus; 2720180753Sluoqi int error; 2721164264Sjhb 2722164264Sjhb bus = device_get_parent(pcib); 2723180753Sluoqi error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); 2724180753Sluoqi if (error) 2725180753Sluoqi return (error); 2726180753Sluoqi 2727180753Sluoqi pci_ht_map_msi(pcib, *addr); 2728180753Sluoqi return (0); 2729164264Sjhb} 2730164264Sjhb 2731211430Sjhb/* Pass request for device power state up to parent bridge. */ 2732211430Sjhbint 2733211430Sjhbpcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 2734211430Sjhb{ 2735211430Sjhb device_t bus; 2736211430Sjhb 2737211430Sjhb bus = device_get_parent(pcib); 2738211430Sjhb return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); 2739211430Sjhb} 2740264007Srstone 2741279443Srstonestatic int 2742279443Srstonepcib_ari_enabled(device_t pcib) 2743279443Srstone{ 2744279443Srstone struct pcib_softc *sc; 2745279443Srstone 2746279443Srstone sc = device_get_softc(pcib); 2747279443Srstone 2748279443Srstone return ((sc->flags & PCIB_ENABLE_ARI) != 0); 2749279443Srstone} 2750279443Srstone 2751299929Sandrewstatic int 2752299929Sandrewpcib_ari_get_id(device_t pcib, device_t dev, enum pci_id_type type, 2753299929Sandrew uintptr_t *id) 2754264011Srstone{ 2755264011Srstone struct pcib_softc *sc; 2756299932Sandrew device_t bus_dev; 2757264011Srstone uint8_t bus, slot, func; 2758264011Srstone 2759299932Sandrew if (type != PCI_ID_RID) { 2760299932Sandrew bus_dev = device_get_parent(pcib); 2761299932Sandrew return (PCIB_GET_ID(device_get_parent(bus_dev), dev, type, id)); 2762299932Sandrew } 2763299929Sandrew 2764264011Srstone sc = device_get_softc(pcib); 2765264011Srstone 2766264011Srstone if (sc->flags & PCIB_ENABLE_ARI) { 2767264011Srstone bus = pci_get_bus(dev); 2768264011Srstone func = pci_get_function(dev); 2769264011Srstone 2770299929Sandrew *id = (PCI_ARI_RID(bus, func)); 2771264011Srstone } else { 2772264011Srstone bus = pci_get_bus(dev); 2773264011Srstone slot = pci_get_slot(dev); 2774264011Srstone func = pci_get_function(dev); 2775264011Srstone 2776299929Sandrew *id = (PCI_RID(bus, slot, func)); 2777264011Srstone } 2778299929Sandrew 2779299929Sandrew return (0); 2780264011Srstone} 2781264011Srstone 2782264011Srstone/* 2783264011Srstone * Check that the downstream port (pcib) and the endpoint device (dev) both 2784264011Srstone * support ARI. If so, enable it and return 0, otherwise return an error. 2785264011Srstone */ 2786264011Srstonestatic int 2787264011Srstonepcib_try_enable_ari(device_t pcib, device_t dev) 2788264011Srstone{ 2789264011Srstone struct pcib_softc *sc; 2790264011Srstone int error; 2791264011Srstone uint32_t cap2; 2792264011Srstone int ari_cap_off; 2793264011Srstone uint32_t ari_ver; 2794264011Srstone uint32_t pcie_pos; 2795264011Srstone 2796264011Srstone sc = device_get_softc(pcib); 2797264011Srstone 2798264011Srstone /* 2799264011Srstone * ARI is controlled in a register in the PCIe capability structure. 2800264011Srstone * If the downstream port does not have the PCIe capability structure 2801264011Srstone * then it does not support ARI. 2802264011Srstone */ 2803264011Srstone error = pci_find_cap(pcib, PCIY_EXPRESS, &pcie_pos); 2804264011Srstone if (error != 0) 2805264011Srstone return (ENODEV); 2806264011Srstone 2807264011Srstone /* Check that the PCIe port advertises ARI support. */ 2808264011Srstone cap2 = pci_read_config(pcib, pcie_pos + PCIER_DEVICE_CAP2, 4); 2809264011Srstone if (!(cap2 & PCIEM_CAP2_ARI)) 2810264011Srstone return (ENODEV); 2811264011Srstone 2812264011Srstone /* 2813264011Srstone * Check that the endpoint device advertises ARI support via the ARI 2814264011Srstone * extended capability structure. 2815264011Srstone */ 2816264011Srstone error = pci_find_extcap(dev, PCIZ_ARI, &ari_cap_off); 2817264011Srstone if (error != 0) 2818264011Srstone return (ENODEV); 2819264011Srstone 2820264011Srstone /* 2821264011Srstone * Finally, check that the endpoint device supports the same version 2822264011Srstone * of ARI that we do. 2823264011Srstone */ 2824264011Srstone ari_ver = pci_read_config(dev, ari_cap_off, 4); 2825264011Srstone if (PCI_EXTCAP_VER(ari_ver) != PCIB_SUPPORTED_ARI_VER) { 2826264011Srstone if (bootverbose) 2827264011Srstone device_printf(pcib, 2828264011Srstone "Unsupported version of ARI (%d) detected\n", 2829264011Srstone PCI_EXTCAP_VER(ari_ver)); 2830264011Srstone 2831264011Srstone return (ENXIO); 2832264011Srstone } 2833264011Srstone 2834264011Srstone pcib_enable_ari(sc, pcie_pos); 2835264011Srstone 2836264011Srstone return (0); 2837264011Srstone} 2838