pci_host_generic.c revision 292215
1284317Sbr/*- 2284317Sbr * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3284317Sbr * Copyright (c) 2014 The FreeBSD Foundation 4284317Sbr * All rights reserved. 5284317Sbr * 6284317Sbr * This software was developed by Semihalf under 7284317Sbr * the sponsorship of the FreeBSD Foundation. 8284317Sbr * 9284317Sbr * Redistribution and use in source and binary forms, with or without 10284317Sbr * modification, are permitted provided that the following conditions 11284317Sbr * are met: 12284317Sbr * 1. Redistributions of source code must retain the above copyright 13284317Sbr * notice, this list of conditions and the following disclaimer. 14284317Sbr * 2. Redistributions in binary form must reproduce the above copyright 15284317Sbr * notice, this list of conditions and the following disclaimer in the 16284317Sbr * documentation and/or other materials provided with the distribution. 17284317Sbr * 18284317Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19284317Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20284317Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21284317Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22284317Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23284317Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24284317Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25284317Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26284317Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27284317Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28284317Sbr * SUCH DAMAGE. 29284317Sbr */ 30284317Sbr 31284317Sbr/* Generic ECAM PCIe driver */ 32284317Sbr 33284317Sbr#include <sys/cdefs.h> 34284317Sbr__FBSDID("$FreeBSD: head/sys/dev/pci/pci_host_generic.c 292215 2015-12-14 17:08:40Z andrew $"); 35284317Sbr 36284317Sbr#include <sys/param.h> 37284317Sbr#include <sys/systm.h> 38284317Sbr#include <sys/malloc.h> 39284317Sbr#include <sys/kernel.h> 40284317Sbr#include <sys/rman.h> 41284317Sbr#include <sys/module.h> 42284317Sbr#include <sys/bus.h> 43284317Sbr#include <sys/endian.h> 44284317Sbr#include <sys/cpuset.h> 45284317Sbr#include <sys/rwlock.h> 46292215Sandrew 47284317Sbr#include <dev/ofw/openfirm.h> 48284317Sbr#include <dev/ofw/ofw_bus.h> 49284317Sbr#include <dev/ofw/ofw_bus_subr.h> 50292215Sandrew#include <dev/ofw/ofw_pci.h> 51284317Sbr#include <dev/pci/pcivar.h> 52284317Sbr#include <dev/pci/pcireg.h> 53284317Sbr#include <dev/pci/pcib_private.h> 54292215Sandrew 55284317Sbr#include <machine/cpu.h> 56284317Sbr#include <machine/bus.h> 57284317Sbr#include <machine/intr.h> 58284317Sbr#include <vm/vm_page.h> 59284317Sbr 60284317Sbr#include "pcib_if.h" 61284317Sbr 62284317Sbr/* Assembling ECAM Configuration Address */ 63284317Sbr#define PCIE_BUS_SHIFT 20 64284317Sbr#define PCIE_SLOT_SHIFT 15 65284317Sbr#define PCIE_FUNC_SHIFT 12 66284317Sbr#define PCIE_BUS_MASK 0xFF 67284317Sbr#define PCIE_SLOT_MASK 0x1F 68284317Sbr#define PCIE_FUNC_MASK 0x07 69284317Sbr#define PCIE_REG_MASK 0xFFF 70284317Sbr 71284317Sbr#define PCIE_ADDR_OFFSET(bus, slot, func, reg) \ 72284317Sbr ((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT) | \ 73284317Sbr (((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT) | \ 74284317Sbr (((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT) | \ 75284317Sbr ((reg) & PCIE_REG_MASK)) 76284317Sbr 77284317Sbr#define MAX_RANGES_TUPLES 5 78284317Sbr#define MIN_RANGES_TUPLES 2 79284317Sbr 80284317Sbr#define PCI_IO_WINDOW_OFFSET 0x1000 81284317Sbr 82284317Sbr#define SPACE_CODE_SHIFT 24 83284317Sbr#define SPACE_CODE_MASK 0x3 84284317Sbr#define SPACE_CODE_IO_SPACE 0x1 85284317Sbr#define PROPS_CELL_SIZE 1 86284317Sbr#define PCI_ADDR_CELL_SIZE 2 87284317Sbr 88284317Sbrstruct pcie_range { 89284317Sbr uint64_t pci_base; 90284317Sbr uint64_t phys_base; 91284317Sbr uint64_t size; 92284317Sbr uint64_t flags; 93284317Sbr#define FLAG_IO (1 << 0) 94284317Sbr#define FLAG_MEM (1 << 1) 95284317Sbr}; 96284317Sbr 97284317Sbrstruct generic_pcie_softc { 98284317Sbr struct pcie_range ranges[MAX_RANGES_TUPLES]; 99284317Sbr int nranges; 100284317Sbr struct rman mem_rman; 101284317Sbr struct rman io_rman; 102284317Sbr struct resource *res; 103284317Sbr struct resource *res1; 104284317Sbr int ecam; 105284317Sbr bus_space_tag_t bst; 106284317Sbr bus_space_handle_t bsh; 107284317Sbr device_t dev; 108284317Sbr bus_space_handle_t ioh; 109292215Sandrew struct ofw_bus_iinfo pci_iinfo; 110284317Sbr}; 111284317Sbr 112284317Sbr/* Forward prototypes */ 113284317Sbr 114284317Sbrstatic int generic_pcie_probe(device_t dev); 115284317Sbrstatic int generic_pcie_attach(device_t dev); 116284317Sbrstatic int parse_pci_mem_ranges(struct generic_pcie_softc *sc); 117284317Sbrstatic uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, 118284317Sbr u_int func, u_int reg, int bytes); 119284317Sbrstatic void generic_pcie_write_config(device_t dev, u_int bus, u_int slot, 120284317Sbr u_int func, u_int reg, uint32_t val, int bytes); 121284317Sbrstatic int generic_pcie_maxslots(device_t dev); 122284317Sbrstatic int generic_pcie_read_ivar(device_t dev, device_t child, int index, 123284317Sbr uintptr_t *result); 124284317Sbrstatic int generic_pcie_write_ivar(device_t dev, device_t child, int index, 125284317Sbr uintptr_t value); 126284317Sbrstatic struct resource *generic_pcie_alloc_resource(device_t dev, 127284317Sbr device_t child, int type, int *rid, u_long start, u_long end, 128284317Sbr u_long count, u_int flags); 129284317Sbrstatic int generic_pcie_release_resource(device_t dev, device_t child, 130284317Sbr int type, int rid, struct resource *res); 131284317Sbr 132284317Sbrstatic int 133284317Sbrgeneric_pcie_probe(device_t dev) 134284317Sbr{ 135284317Sbr 136284317Sbr if (!ofw_bus_status_okay(dev)) 137284317Sbr return (ENXIO); 138284317Sbr 139284317Sbr if (ofw_bus_is_compatible(dev, "pci-host-ecam-generic")) { 140284317Sbr device_set_desc(dev, "Generic PCI host controller"); 141284317Sbr return (BUS_PROBE_DEFAULT); 142284317Sbr } 143284317Sbr 144284317Sbr return (ENXIO); 145284317Sbr} 146284317Sbr 147284317Sbrstatic int 148284317Sbrgeneric_pcie_attach(device_t dev) 149284317Sbr{ 150284317Sbr struct generic_pcie_softc *sc; 151284317Sbr uint64_t phys_base; 152284317Sbr uint64_t pci_base; 153284317Sbr uint64_t size; 154284317Sbr int error; 155284317Sbr int tuple; 156284317Sbr int rid; 157284317Sbr 158284317Sbr sc = device_get_softc(dev); 159284317Sbr sc->dev = dev; 160284317Sbr 161284317Sbr rid = 0; 162284317Sbr sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 163284317Sbr if (sc->res == NULL) { 164284317Sbr device_printf(dev, "could not map memory.\n"); 165284317Sbr return (ENXIO); 166284317Sbr } 167284317Sbr 168284317Sbr sc->bst = rman_get_bustag(sc->res); 169284317Sbr sc->bsh = rman_get_bushandle(sc->res); 170284317Sbr 171284317Sbr sc->mem_rman.rm_type = RMAN_ARRAY; 172284317Sbr sc->mem_rman.rm_descr = "PCIe Memory"; 173284317Sbr sc->io_rman.rm_type = RMAN_ARRAY; 174284317Sbr sc->io_rman.rm_descr = "PCIe IO window"; 175284317Sbr 176284317Sbr /* Retrieve 'ranges' property from FDT */ 177284317Sbr if (bootverbose) 178284317Sbr device_printf(dev, "parsing FDT for ECAM%d:\n", 179284317Sbr sc->ecam); 180284317Sbr if (parse_pci_mem_ranges(sc)) 181284317Sbr return (ENXIO); 182284317Sbr 183284317Sbr /* Initialize rman and allocate memory regions */ 184284317Sbr error = rman_init(&sc->mem_rman); 185284317Sbr if (error) { 186284317Sbr device_printf(dev, "rman_init() failed. error = %d\n", error); 187284317Sbr return (error); 188284317Sbr } 189284317Sbr 190284317Sbr error = rman_init(&sc->io_rman); 191284317Sbr if (error) { 192284317Sbr device_printf(dev, "rman_init() failed. error = %d\n", error); 193284317Sbr return (error); 194284317Sbr } 195284317Sbr 196284317Sbr for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { 197284317Sbr phys_base = sc->ranges[tuple].phys_base; 198284317Sbr pci_base = sc->ranges[tuple].pci_base; 199284317Sbr size = sc->ranges[tuple].size; 200284317Sbr if (phys_base == 0 || size == 0) 201284317Sbr continue; /* empty range element */ 202284317Sbr if (sc->ranges[tuple].flags & FLAG_MEM) { 203284317Sbr error = rman_manage_region(&sc->mem_rman, 204284317Sbr phys_base, 205284317Sbr phys_base + size); 206284317Sbr } else if (sc->ranges[tuple].flags & FLAG_IO) { 207284317Sbr error = rman_manage_region(&sc->io_rman, 208284317Sbr pci_base + PCI_IO_WINDOW_OFFSET, 209284317Sbr pci_base + PCI_IO_WINDOW_OFFSET + size); 210284317Sbr } else 211284317Sbr continue; 212284317Sbr if (error) { 213284317Sbr device_printf(dev, "rman_manage_region() failed." 214284317Sbr "error = %d\n", error); 215284317Sbr rman_fini(&sc->mem_rman); 216284317Sbr return (error); 217284317Sbr } 218284317Sbr } 219284317Sbr 220292215Sandrew ofw_bus_setup_iinfo(ofw_bus_get_node(dev), &sc->pci_iinfo, 221292215Sandrew sizeof(cell_t)); 222284317Sbr 223292215Sandrew 224284317Sbr device_add_child(dev, "pci", -1); 225284317Sbr return (bus_generic_attach(dev)); 226284317Sbr} 227284317Sbr 228284317Sbrstatic int 229284317Sbrparse_pci_mem_ranges(struct generic_pcie_softc *sc) 230284317Sbr{ 231284317Sbr pcell_t pci_addr_cells, parent_addr_cells; 232284317Sbr pcell_t attributes, size_cells; 233284317Sbr cell_t *base_ranges; 234284317Sbr int nbase_ranges; 235284317Sbr phandle_t node; 236284317Sbr int i, j, k; 237284317Sbr int tuple; 238284317Sbr 239284317Sbr node = ofw_bus_get_node(sc->dev); 240284317Sbr 241284317Sbr OF_getencprop(node, "#address-cells", &pci_addr_cells, 242284317Sbr sizeof(pci_addr_cells)); 243284317Sbr OF_getencprop(node, "#size-cells", &size_cells, 244284317Sbr sizeof(size_cells)); 245284317Sbr OF_getencprop(OF_parent(node), "#address-cells", &parent_addr_cells, 246284317Sbr sizeof(parent_addr_cells)); 247284317Sbr 248284317Sbr if (parent_addr_cells != 2 || pci_addr_cells != 3 || size_cells != 2) { 249284317Sbr device_printf(sc->dev, 250284317Sbr "Unexpected number of address or size cells in FDT\n"); 251284317Sbr return (ENXIO); 252284317Sbr } 253284317Sbr 254284317Sbr nbase_ranges = OF_getproplen(node, "ranges"); 255284317Sbr sc->nranges = nbase_ranges / sizeof(cell_t) / 256284317Sbr (parent_addr_cells + pci_addr_cells + size_cells); 257284317Sbr base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); 258284317Sbr OF_getencprop(node, "ranges", base_ranges, nbase_ranges); 259284317Sbr 260284317Sbr for (i = 0, j = 0; i < sc->nranges; i++) { 261284317Sbr attributes = (base_ranges[j++] >> SPACE_CODE_SHIFT) & \ 262284317Sbr SPACE_CODE_MASK; 263284317Sbr if (attributes == SPACE_CODE_IO_SPACE) { 264284317Sbr sc->ranges[i].flags |= FLAG_IO; 265284317Sbr } else { 266284317Sbr sc->ranges[i].flags |= FLAG_MEM; 267284317Sbr } 268284317Sbr 269284317Sbr sc->ranges[i].pci_base = 0; 270284317Sbr for (k = 0; k < (pci_addr_cells - 1); k++) { 271284317Sbr sc->ranges[i].pci_base <<= 32; 272284317Sbr sc->ranges[i].pci_base |= base_ranges[j++]; 273284317Sbr } 274284317Sbr sc->ranges[i].phys_base = 0; 275284317Sbr for (k = 0; k < parent_addr_cells; k++) { 276284317Sbr sc->ranges[i].phys_base <<= 32; 277284317Sbr sc->ranges[i].phys_base |= base_ranges[j++]; 278284317Sbr } 279284317Sbr sc->ranges[i].size = 0; 280284317Sbr for (k = 0; k < size_cells; k++) { 281284317Sbr sc->ranges[i].size <<= 32; 282284317Sbr sc->ranges[i].size |= base_ranges[j++]; 283284317Sbr } 284284317Sbr } 285284317Sbr 286284317Sbr for (; i < MAX_RANGES_TUPLES; i++) { 287284317Sbr /* zero-fill remaining tuples to mark empty elements in array */ 288284317Sbr sc->ranges[i].pci_base = 0; 289284317Sbr sc->ranges[i].phys_base = 0; 290284317Sbr sc->ranges[i].size = 0; 291284317Sbr } 292284317Sbr 293284317Sbr if (bootverbose) { 294284317Sbr for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { 295284317Sbr device_printf(sc->dev, 296284317Sbr "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx\n", 297284317Sbr sc->ranges[tuple].pci_base, 298284317Sbr sc->ranges[tuple].phys_base, 299284317Sbr sc->ranges[tuple].size); 300284317Sbr } 301284317Sbr } 302284317Sbr 303284317Sbr free(base_ranges, M_DEVBUF); 304284317Sbr return (0); 305284317Sbr} 306284317Sbr 307284317Sbrstatic uint32_t 308284317Sbrgeneric_pcie_read_config(device_t dev, u_int bus, u_int slot, 309284317Sbr u_int func, u_int reg, int bytes) 310284317Sbr{ 311284317Sbr struct generic_pcie_softc *sc; 312284317Sbr bus_space_handle_t h; 313284317Sbr bus_space_tag_t t; 314284317Sbr uint64_t offset; 315284317Sbr uint32_t data; 316284317Sbr 317284317Sbr if (bus > 255 || slot > 31 || func > 7 || reg > 4095) 318284317Sbr return (~0U); 319284317Sbr 320284317Sbr sc = device_get_softc(dev); 321284317Sbr 322284317Sbr offset = PCIE_ADDR_OFFSET(bus, slot, func, reg); 323284317Sbr t = sc->bst; 324284317Sbr h = sc->bsh; 325284317Sbr 326284317Sbr switch (bytes) { 327284317Sbr case 1: 328284317Sbr data = bus_space_read_1(t, h, offset); 329284317Sbr break; 330284317Sbr case 2: 331284317Sbr data = le16toh(bus_space_read_2(t, h, offset)); 332284317Sbr break; 333284317Sbr case 4: 334284317Sbr data = le32toh(bus_space_read_4(t, h, offset)); 335284317Sbr break; 336284317Sbr default: 337284317Sbr return (~0U); 338284317Sbr } 339284317Sbr 340284317Sbr return (data); 341284317Sbr} 342284317Sbr 343284317Sbrstatic void 344284317Sbrgeneric_pcie_write_config(device_t dev, u_int bus, u_int slot, 345284317Sbr u_int func, u_int reg, uint32_t val, int bytes) 346284317Sbr{ 347284317Sbr struct generic_pcie_softc *sc; 348284317Sbr bus_space_handle_t h; 349284317Sbr bus_space_tag_t t; 350284317Sbr uint64_t offset; 351284317Sbr 352284317Sbr if (bus > 255 || slot > 31 || func > 7 || reg > 4095) 353284317Sbr return; 354284317Sbr 355284317Sbr sc = device_get_softc(dev); 356284317Sbr 357284317Sbr offset = PCIE_ADDR_OFFSET(bus, slot, func, reg); 358284317Sbr 359284317Sbr t = sc->bst; 360284317Sbr h = sc->bsh; 361284317Sbr 362284317Sbr switch (bytes) { 363284317Sbr case 1: 364284317Sbr bus_space_write_1(t, h, offset, val); 365284317Sbr break; 366284317Sbr case 2: 367284317Sbr bus_space_write_2(t, h, offset, htole16(val)); 368284317Sbr break; 369284317Sbr case 4: 370284317Sbr bus_space_write_4(t, h, offset, htole32(val)); 371284317Sbr break; 372284317Sbr default: 373284317Sbr return; 374284317Sbr } 375284317Sbr} 376284317Sbr 377284317Sbrstatic int 378284317Sbrgeneric_pcie_maxslots(device_t dev) 379284317Sbr{ 380284317Sbr 381284317Sbr return (31); /* max slots per bus acc. to standard */ 382284317Sbr} 383284317Sbr 384284317Sbrstatic int 385292215Sandrewgeneric_pcie_route_interrupt(device_t bus, device_t dev, int pin) 386292215Sandrew{ 387292215Sandrew struct generic_pcie_softc *sc; 388292215Sandrew struct ofw_pci_register reg; 389292215Sandrew uint32_t pintr, mintr[2]; 390292215Sandrew phandle_t iparent; 391292215Sandrew int intrcells; 392292215Sandrew 393292215Sandrew sc = device_get_softc(bus); 394292215Sandrew pintr = pin; 395292215Sandrew 396292215Sandrew bzero(®, sizeof(reg)); 397292215Sandrew reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | 398292215Sandrew (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | 399292215Sandrew (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); 400292215Sandrew 401292215Sandrew intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), 402292215Sandrew &sc->pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), 403292215Sandrew mintr, sizeof(mintr), &iparent); 404292215Sandrew if (intrcells) { 405292215Sandrew pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr); 406292215Sandrew return (pintr); 407292215Sandrew } 408292215Sandrew 409292215Sandrew device_printf(bus, "could not route pin %d for device %d.%d\n", 410292215Sandrew pin, pci_get_slot(dev), pci_get_function(dev)); 411292215Sandrew return (PCI_INVALID_IRQ); 412292215Sandrew} 413292215Sandrew 414292215Sandrew 415292215Sandrewstatic int 416284317Sbrgeneric_pcie_read_ivar(device_t dev, device_t child, int index, 417284317Sbr uintptr_t *result) 418284317Sbr{ 419284317Sbr struct generic_pcie_softc *sc; 420284317Sbr int secondary_bus; 421284317Sbr 422284317Sbr sc = device_get_softc(dev); 423284317Sbr 424284317Sbr if (index == PCIB_IVAR_BUS) { 425284317Sbr /* this pcib adds only pci bus 0 as child */ 426284317Sbr secondary_bus = 0; 427284317Sbr *result = secondary_bus; 428284317Sbr return (0); 429284317Sbr 430284317Sbr } 431284317Sbr 432284317Sbr if (index == PCIB_IVAR_DOMAIN) { 433284317Sbr *result = sc->ecam; 434284317Sbr return (0); 435284317Sbr } 436284317Sbr 437284317Sbr device_printf(dev, "ERROR: Unknown index.\n"); 438284317Sbr return (ENOENT); 439284317Sbr} 440284317Sbr 441284317Sbrstatic int 442284317Sbrgeneric_pcie_write_ivar(device_t dev, device_t child, int index, 443284317Sbr uintptr_t value) 444284317Sbr{ 445284317Sbr 446284317Sbr return (ENOENT); 447284317Sbr} 448284317Sbr 449284317Sbrstatic struct rman * 450284317Sbrgeneric_pcie_rman(struct generic_pcie_softc *sc, int type) 451284317Sbr{ 452284317Sbr 453284317Sbr switch (type) { 454284317Sbr case SYS_RES_IOPORT: 455284317Sbr return (&sc->io_rman); 456284317Sbr case SYS_RES_MEMORY: 457284317Sbr return (&sc->mem_rman); 458284317Sbr default: 459284317Sbr break; 460284317Sbr } 461284317Sbr 462284317Sbr return (NULL); 463284317Sbr} 464284317Sbr 465284317Sbrstatic int 466284317Sbrgeneric_pcie_release_resource(device_t dev, device_t child, int type, 467284317Sbr int rid, struct resource *res) 468284317Sbr{ 469284317Sbr struct generic_pcie_softc *sc; 470284317Sbr struct rman *rm; 471284317Sbr 472284317Sbr sc = device_get_softc(dev); 473284317Sbr 474284317Sbr rm = generic_pcie_rman(sc, type); 475284317Sbr if (rm != NULL) { 476284317Sbr KASSERT(rman_is_region_manager(res, rm), ("rman mismatch")); 477284317Sbr rman_release_resource(res); 478284317Sbr } 479284317Sbr 480284317Sbr return (bus_generic_release_resource(dev, child, type, rid, res)); 481284317Sbr} 482284317Sbr 483284317Sbrstatic struct resource * 484284317Sbrgeneric_pcie_alloc_resource(device_t dev, device_t child, int type, int *rid, 485284317Sbr u_long start, u_long end, u_long count, u_int flags) 486284317Sbr{ 487284317Sbr struct generic_pcie_softc *sc; 488284317Sbr struct resource *res; 489284317Sbr struct rman *rm; 490284317Sbr 491284317Sbr sc = device_get_softc(dev); 492284317Sbr 493284317Sbr rm = generic_pcie_rman(sc, type); 494284317Sbr if (rm == NULL) 495284317Sbr return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 496284317Sbr type, rid, start, end, count, flags)); 497284317Sbr 498284317Sbr if (bootverbose) { 499284317Sbr device_printf(dev, 500284317Sbr "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n", 501284317Sbr start, end, count); 502284317Sbr } 503284317Sbr 504284317Sbr res = rman_reserve_resource(rm, start, end, count, flags, child); 505284317Sbr if (res == NULL) 506284317Sbr goto fail; 507284317Sbr 508284317Sbr rman_set_rid(res, *rid); 509284317Sbr 510284317Sbr if (flags & RF_ACTIVE) 511284317Sbr if (bus_activate_resource(child, type, *rid, res)) { 512284317Sbr rman_release_resource(res); 513284317Sbr goto fail; 514284317Sbr } 515284317Sbr 516284317Sbr return (res); 517284317Sbr 518284317Sbrfail: 519284317Sbr if (bootverbose) { 520284317Sbr device_printf(dev, "%s FAIL: type=%d, rid=%d, " 521284317Sbr "start=%016lx, end=%016lx, count=%016lx, flags=%x\n", 522284317Sbr __func__, type, *rid, start, end, count, flags); 523284317Sbr } 524284317Sbr 525284317Sbr return (NULL); 526284317Sbr} 527284317Sbr 528284317Sbrstatic int 529284317Sbrgeneric_pcie_adjust_resource(device_t dev, device_t child, int type, 530284317Sbr struct resource *res, u_long start, u_long end) 531284317Sbr{ 532284317Sbr struct generic_pcie_softc *sc; 533284317Sbr struct rman *rm; 534284317Sbr 535284317Sbr sc = device_get_softc(dev); 536284317Sbr 537284317Sbr rm = generic_pcie_rman(sc, type); 538284317Sbr if (rm != NULL) 539284317Sbr return (rman_adjust_resource(res, start, end)); 540284317Sbr return (bus_generic_adjust_resource(dev, child, type, res, start, end)); 541284317Sbr} 542284317Sbr 543284317Sbrstatic int 544284317Sbrgeneric_pcie_activate_resource(device_t dev, device_t child, int type, int rid, 545284317Sbr struct resource *r) 546284317Sbr{ 547284317Sbr struct generic_pcie_softc *sc; 548284317Sbr uint64_t phys_base; 549284317Sbr uint64_t pci_base; 550284317Sbr uint64_t size; 551284317Sbr int found; 552284317Sbr int res; 553284317Sbr int i; 554284317Sbr 555284317Sbr sc = device_get_softc(dev); 556284317Sbr 557284317Sbr if ((res = rman_activate_resource(r)) != 0) 558284317Sbr return (res); 559284317Sbr 560284317Sbr switch(type) { 561284317Sbr case SYS_RES_IOPORT: 562284317Sbr found = 0; 563284317Sbr for (i = 0; i < MAX_RANGES_TUPLES; i++) { 564284317Sbr pci_base = sc->ranges[i].pci_base; 565284317Sbr phys_base = sc->ranges[i].phys_base; 566284317Sbr size = sc->ranges[i].size; 567284317Sbr 568284317Sbr if ((rid > pci_base) && (rid < (pci_base + size))) { 569284317Sbr found = 1; 570284317Sbr break; 571284317Sbr } 572284317Sbr } 573284317Sbr if (found) { 574284317Sbr rman_set_start(r, rman_get_start(r) + phys_base); 575284317Sbr BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, 576284317Sbr type, rid, r); 577284317Sbr } else { 578284317Sbr device_printf(dev, "Failed to activate IOPORT resource\n"); 579284317Sbr res = 0; 580284317Sbr } 581284317Sbr break; 582284317Sbr case SYS_RES_MEMORY: 583284317Sbr BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type, rid, r); 584284317Sbr break; 585284317Sbr default: 586284317Sbr break; 587284317Sbr } 588284317Sbr 589284317Sbr return (res); 590284317Sbr} 591284317Sbr 592284317Sbrstatic int 593284317Sbrgeneric_pcie_deactivate_resource(device_t dev, device_t child, int type, int rid, 594284317Sbr struct resource *r) 595284317Sbr{ 596284317Sbr struct generic_pcie_softc *sc; 597284317Sbr vm_offset_t vaddr; 598284317Sbr int res; 599284317Sbr 600284317Sbr sc = device_get_softc(dev); 601284317Sbr 602284317Sbr if ((res = rman_deactivate_resource(r)) != 0) 603284317Sbr return (res); 604284317Sbr 605284317Sbr switch(type) { 606284317Sbr case SYS_RES_IOPORT: 607284317Sbr case SYS_RES_MEMORY: 608284317Sbr vaddr = (vm_offset_t)rman_get_virtual(r); 609284317Sbr pmap_unmapdev(vaddr, rman_get_size(r)); 610284317Sbr break; 611284317Sbr default: 612284317Sbr break; 613284317Sbr } 614284317Sbr 615284317Sbr return (res); 616284317Sbr} 617284317Sbr 618284317Sbrstatic device_method_t generic_pcie_methods[] = { 619284317Sbr DEVMETHOD(device_probe, generic_pcie_probe), 620284317Sbr DEVMETHOD(device_attach, generic_pcie_attach), 621284317Sbr DEVMETHOD(bus_read_ivar, generic_pcie_read_ivar), 622284317Sbr DEVMETHOD(bus_write_ivar, generic_pcie_write_ivar), 623284317Sbr DEVMETHOD(bus_alloc_resource, generic_pcie_alloc_resource), 624284317Sbr DEVMETHOD(bus_adjust_resource, generic_pcie_adjust_resource), 625284317Sbr DEVMETHOD(bus_release_resource, generic_pcie_release_resource), 626284317Sbr DEVMETHOD(bus_activate_resource, generic_pcie_activate_resource), 627284317Sbr DEVMETHOD(bus_deactivate_resource, generic_pcie_deactivate_resource), 628284317Sbr DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 629284317Sbr DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 630292215Sandrew 631292215Sandrew /* pcib interface */ 632284317Sbr DEVMETHOD(pcib_maxslots, generic_pcie_maxslots), 633292215Sandrew DEVMETHOD(pcib_route_interrupt, generic_pcie_route_interrupt), 634284317Sbr DEVMETHOD(pcib_read_config, generic_pcie_read_config), 635284317Sbr DEVMETHOD(pcib_write_config, generic_pcie_write_config), 636292215Sandrew#if defined(__aarch64__) 637292215Sandrew DEVMETHOD(pcib_alloc_msi, arm_alloc_msi), 638292215Sandrew DEVMETHOD(pcib_release_msi, arm_release_msi), 639292215Sandrew DEVMETHOD(pcib_alloc_msix, arm_alloc_msix), 640292215Sandrew DEVMETHOD(pcib_release_msix, arm_release_msix), 641292215Sandrew DEVMETHOD(pcib_map_msi, arm_map_msi), 642292215Sandrew#endif 643292215Sandrew 644284317Sbr DEVMETHOD_END 645284317Sbr}; 646284317Sbr 647284317Sbrstatic driver_t generic_pcie_driver = { 648284317Sbr "pcib", 649284317Sbr generic_pcie_methods, 650284317Sbr sizeof(struct generic_pcie_softc), 651284317Sbr}; 652284317Sbr 653284317Sbrstatic devclass_t generic_pcie_devclass; 654284317Sbr 655284317SbrDRIVER_MODULE(pcib, simplebus, generic_pcie_driver, 656284317Sbrgeneric_pcie_devclass, 0, 0); 657284317SbrDRIVER_MODULE(pcib, ofwbus, generic_pcie_driver, 658284317Sbrgeneric_pcie_devclass, 0, 0); 659