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: stable/11/sys/dev/pci/pci_host_generic.c 308333 2016-11-05 10:23:02Z mmel $"); 35284317Sbr 36295962Swma#include "opt_platform.h" 37295962Swma 38284317Sbr#include <sys/param.h> 39284317Sbr#include <sys/systm.h> 40284317Sbr#include <sys/malloc.h> 41284317Sbr#include <sys/kernel.h> 42284317Sbr#include <sys/rman.h> 43284317Sbr#include <sys/module.h> 44284317Sbr#include <sys/bus.h> 45284317Sbr#include <sys/endian.h> 46284317Sbr#include <sys/cpuset.h> 47284317Sbr#include <sys/rwlock.h> 48292215Sandrew 49299928Sandrew#if defined(INTRNG) 50299928Sandrew#include <machine/intr.h> 51299928Sandrew#endif 52299928Sandrew 53284317Sbr#include <dev/ofw/openfirm.h> 54284317Sbr#include <dev/ofw/ofw_bus.h> 55284317Sbr#include <dev/ofw/ofw_bus_subr.h> 56292215Sandrew#include <dev/ofw/ofw_pci.h> 57284317Sbr#include <dev/pci/pcivar.h> 58284317Sbr#include <dev/pci/pcireg.h> 59284317Sbr#include <dev/pci/pcib_private.h> 60295962Swma#include <dev/pci/pci_host_generic.h> 61292215Sandrew 62284317Sbr#include <machine/cpu.h> 63284317Sbr#include <machine/bus.h> 64284317Sbr#include <machine/intr.h> 65284317Sbr#include <vm/vm_page.h> 66284317Sbr 67284317Sbr#include "pcib_if.h" 68284317Sbr 69284317Sbr/* Assembling ECAM Configuration Address */ 70284317Sbr#define PCIE_BUS_SHIFT 20 71284317Sbr#define PCIE_SLOT_SHIFT 15 72284317Sbr#define PCIE_FUNC_SHIFT 12 73284317Sbr#define PCIE_BUS_MASK 0xFF 74284317Sbr#define PCIE_SLOT_MASK 0x1F 75284317Sbr#define PCIE_FUNC_MASK 0x07 76284317Sbr#define PCIE_REG_MASK 0xFFF 77284317Sbr 78284317Sbr#define PCIE_ADDR_OFFSET(bus, slot, func, reg) \ 79284317Sbr ((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT) | \ 80284317Sbr (((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT) | \ 81284317Sbr (((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT) | \ 82284317Sbr ((reg) & PCIE_REG_MASK)) 83284317Sbr 84284317Sbr#define PCI_IO_WINDOW_OFFSET 0x1000 85284317Sbr 86284317Sbr#define SPACE_CODE_SHIFT 24 87284317Sbr#define SPACE_CODE_MASK 0x3 88284317Sbr#define SPACE_CODE_IO_SPACE 0x1 89284317Sbr#define PROPS_CELL_SIZE 1 90284317Sbr#define PCI_ADDR_CELL_SIZE 2 91284317Sbr 92295962Swma/* OFW bus interface */ 93295962Swmastruct generic_pcie_ofw_devinfo { 94295962Swma struct ofw_bus_devinfo di_dinfo; 95295962Swma struct resource_list di_rl; 96284317Sbr}; 97284317Sbr 98284317Sbr/* Forward prototypes */ 99284317Sbr 100284317Sbrstatic int generic_pcie_probe(device_t dev); 101284317Sbrstatic int parse_pci_mem_ranges(struct generic_pcie_softc *sc); 102284317Sbrstatic uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, 103284317Sbr u_int func, u_int reg, int bytes); 104284317Sbrstatic void generic_pcie_write_config(device_t dev, u_int bus, u_int slot, 105284317Sbr u_int func, u_int reg, uint32_t val, int bytes); 106284317Sbrstatic int generic_pcie_maxslots(device_t dev); 107284317Sbrstatic int generic_pcie_read_ivar(device_t dev, device_t child, int index, 108284317Sbr uintptr_t *result); 109284317Sbrstatic int generic_pcie_write_ivar(device_t dev, device_t child, int index, 110284317Sbr uintptr_t value); 111295962Swmastatic struct resource *generic_pcie_alloc_resource_ofw(device_t, device_t, 112295962Swma int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); 113295962Swmastatic struct resource *generic_pcie_alloc_resource_pcie(device_t dev, 114295962Swma device_t child, int type, int *rid, rman_res_t start, rman_res_t end, 115295962Swma rman_res_t count, u_int flags); 116284317Sbrstatic int generic_pcie_release_resource(device_t dev, device_t child, 117284317Sbr int type, int rid, struct resource *res); 118295962Swmastatic int generic_pcie_release_resource_ofw(device_t, device_t, int, int, 119295962Swma struct resource *); 120295962Swmastatic int generic_pcie_release_resource_pcie(device_t, device_t, int, int, 121295962Swma struct resource *); 122295962Swmastatic int generic_pcie_ofw_bus_attach(device_t); 123295962Swmastatic const struct ofw_bus_devinfo *generic_pcie_ofw_get_devinfo(device_t, 124295962Swma device_t); 125284317Sbr 126295962Swmastatic __inline void 127295962Swmaget_addr_size_cells(phandle_t node, pcell_t *addr_cells, pcell_t *size_cells) 128295962Swma{ 129295962Swma 130295962Swma *addr_cells = 2; 131295962Swma /* Find address cells if present */ 132295962Swma OF_getencprop(node, "#address-cells", addr_cells, sizeof(*addr_cells)); 133295962Swma 134295962Swma *size_cells = 2; 135295962Swma /* Find size cells if present */ 136295962Swma OF_getencprop(node, "#size-cells", size_cells, sizeof(*size_cells)); 137295962Swma} 138295962Swma 139284317Sbrstatic int 140284317Sbrgeneric_pcie_probe(device_t dev) 141284317Sbr{ 142284317Sbr 143284317Sbr if (!ofw_bus_status_okay(dev)) 144284317Sbr return (ENXIO); 145284317Sbr 146284317Sbr if (ofw_bus_is_compatible(dev, "pci-host-ecam-generic")) { 147284317Sbr device_set_desc(dev, "Generic PCI host controller"); 148295962Swma return (BUS_PROBE_GENERIC); 149284317Sbr } 150296316Sbz if (ofw_bus_is_compatible(dev, "arm,gem5_pcie")) { 151296316Sbz device_set_desc(dev, "GEM5 PCIe host controller"); 152296316Sbz return (BUS_PROBE_DEFAULT); 153296316Sbz } 154284317Sbr 155284317Sbr return (ENXIO); 156284317Sbr} 157284317Sbr 158295962Swmaint 159295962Swmapci_host_generic_attach(device_t dev) 160284317Sbr{ 161284317Sbr struct generic_pcie_softc *sc; 162284317Sbr uint64_t phys_base; 163284317Sbr uint64_t pci_base; 164284317Sbr uint64_t size; 165299928Sandrew phandle_t node; 166284317Sbr int error; 167284317Sbr int tuple; 168284317Sbr int rid; 169284317Sbr 170284317Sbr sc = device_get_softc(dev); 171284317Sbr sc->dev = dev; 172284317Sbr 173295962Swma /* Retrieve 'ranges' property from FDT */ 174295962Swma if (bootverbose) 175295962Swma device_printf(dev, "parsing FDT for ECAM%d:\n", 176295962Swma sc->ecam); 177295962Swma if (parse_pci_mem_ranges(sc)) 178295962Swma return (ENXIO); 179295962Swma 180295962Swma /* Attach OFW bus */ 181295962Swma if (generic_pcie_ofw_bus_attach(dev) != 0) 182295962Swma return (ENXIO); 183295962Swma 184301031Sandrew node = ofw_bus_get_node(dev); 185301031Sandrew if (sc->coherent == 0) { 186301031Sandrew sc->coherent = OF_hasprop(node, "dma-coherent"); 187301031Sandrew } 188301032Sandrew if (bootverbose) 189301031Sandrew device_printf(dev, "Bus is%s cache-coherent\n", 190301031Sandrew sc->coherent ? "" : " not"); 191301031Sandrew 192301031Sandrew /* Create the parent DMA tag to pass down the coherent flag */ 193301031Sandrew error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 194301031Sandrew 1, 0, /* alignment, bounds */ 195301031Sandrew BUS_SPACE_MAXADDR, /* lowaddr */ 196301031Sandrew BUS_SPACE_MAXADDR, /* highaddr */ 197301031Sandrew NULL, NULL, /* filter, filterarg */ 198301031Sandrew BUS_SPACE_MAXSIZE, /* maxsize */ 199301031Sandrew BUS_SPACE_UNRESTRICTED, /* nsegments */ 200301031Sandrew BUS_SPACE_MAXSIZE, /* maxsegsize */ 201301031Sandrew sc->coherent ? BUS_DMA_COHERENT : 0, /* flags */ 202301031Sandrew NULL, NULL, /* lockfunc, lockarg */ 203301031Sandrew &sc->dmat); 204301031Sandrew if (error != 0) 205301031Sandrew return (error); 206301031Sandrew 207284317Sbr rid = 0; 208284317Sbr sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 209284317Sbr if (sc->res == NULL) { 210284317Sbr device_printf(dev, "could not map memory.\n"); 211284317Sbr return (ENXIO); 212284317Sbr } 213284317Sbr 214284317Sbr sc->bst = rman_get_bustag(sc->res); 215284317Sbr sc->bsh = rman_get_bushandle(sc->res); 216284317Sbr 217284317Sbr sc->mem_rman.rm_type = RMAN_ARRAY; 218284317Sbr sc->mem_rman.rm_descr = "PCIe Memory"; 219284317Sbr sc->io_rman.rm_type = RMAN_ARRAY; 220284317Sbr sc->io_rman.rm_descr = "PCIe IO window"; 221284317Sbr 222284317Sbr /* Initialize rman and allocate memory regions */ 223284317Sbr error = rman_init(&sc->mem_rman); 224284317Sbr if (error) { 225284317Sbr device_printf(dev, "rman_init() failed. error = %d\n", error); 226284317Sbr return (error); 227284317Sbr } 228284317Sbr 229284317Sbr error = rman_init(&sc->io_rman); 230284317Sbr if (error) { 231284317Sbr device_printf(dev, "rman_init() failed. error = %d\n", error); 232284317Sbr return (error); 233284317Sbr } 234284317Sbr 235284317Sbr for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { 236284317Sbr phys_base = sc->ranges[tuple].phys_base; 237284317Sbr pci_base = sc->ranges[tuple].pci_base; 238284317Sbr size = sc->ranges[tuple].size; 239284317Sbr if (phys_base == 0 || size == 0) 240284317Sbr continue; /* empty range element */ 241284317Sbr if (sc->ranges[tuple].flags & FLAG_MEM) { 242284317Sbr error = rman_manage_region(&sc->mem_rman, 243296316Sbz phys_base, phys_base + size - 1); 244284317Sbr } else if (sc->ranges[tuple].flags & FLAG_IO) { 245284317Sbr error = rman_manage_region(&sc->io_rman, 246296316Sbz pci_base + PCI_IO_WINDOW_OFFSET, 247296316Sbz pci_base + PCI_IO_WINDOW_OFFSET + size - 1); 248284317Sbr } else 249284317Sbr continue; 250284317Sbr if (error) { 251284317Sbr device_printf(dev, "rman_manage_region() failed." 252284317Sbr "error = %d\n", error); 253284317Sbr rman_fini(&sc->mem_rman); 254284317Sbr return (error); 255284317Sbr } 256284317Sbr } 257284317Sbr 258299928Sandrew ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(cell_t)); 259284317Sbr 260284317Sbr device_add_child(dev, "pci", -1); 261284317Sbr return (bus_generic_attach(dev)); 262284317Sbr} 263284317Sbr 264284317Sbrstatic int 265284317Sbrparse_pci_mem_ranges(struct generic_pcie_softc *sc) 266284317Sbr{ 267284317Sbr pcell_t pci_addr_cells, parent_addr_cells; 268284317Sbr pcell_t attributes, size_cells; 269284317Sbr cell_t *base_ranges; 270284317Sbr int nbase_ranges; 271284317Sbr phandle_t node; 272284317Sbr int i, j, k; 273284317Sbr int tuple; 274284317Sbr 275284317Sbr node = ofw_bus_get_node(sc->dev); 276284317Sbr 277284317Sbr OF_getencprop(node, "#address-cells", &pci_addr_cells, 278284317Sbr sizeof(pci_addr_cells)); 279284317Sbr OF_getencprop(node, "#size-cells", &size_cells, 280284317Sbr sizeof(size_cells)); 281284317Sbr OF_getencprop(OF_parent(node), "#address-cells", &parent_addr_cells, 282284317Sbr sizeof(parent_addr_cells)); 283284317Sbr 284284317Sbr if (parent_addr_cells != 2 || pci_addr_cells != 3 || size_cells != 2) { 285284317Sbr device_printf(sc->dev, 286284317Sbr "Unexpected number of address or size cells in FDT\n"); 287284317Sbr return (ENXIO); 288284317Sbr } 289284317Sbr 290284317Sbr nbase_ranges = OF_getproplen(node, "ranges"); 291284317Sbr sc->nranges = nbase_ranges / sizeof(cell_t) / 292284317Sbr (parent_addr_cells + pci_addr_cells + size_cells); 293284317Sbr base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); 294284317Sbr OF_getencprop(node, "ranges", base_ranges, nbase_ranges); 295284317Sbr 296284317Sbr for (i = 0, j = 0; i < sc->nranges; i++) { 297284317Sbr attributes = (base_ranges[j++] >> SPACE_CODE_SHIFT) & \ 298284317Sbr SPACE_CODE_MASK; 299284317Sbr if (attributes == SPACE_CODE_IO_SPACE) { 300284317Sbr sc->ranges[i].flags |= FLAG_IO; 301284317Sbr } else { 302284317Sbr sc->ranges[i].flags |= FLAG_MEM; 303284317Sbr } 304284317Sbr 305284317Sbr sc->ranges[i].pci_base = 0; 306284317Sbr for (k = 0; k < (pci_addr_cells - 1); k++) { 307284317Sbr sc->ranges[i].pci_base <<= 32; 308284317Sbr sc->ranges[i].pci_base |= base_ranges[j++]; 309284317Sbr } 310284317Sbr sc->ranges[i].phys_base = 0; 311284317Sbr for (k = 0; k < parent_addr_cells; k++) { 312284317Sbr sc->ranges[i].phys_base <<= 32; 313284317Sbr sc->ranges[i].phys_base |= base_ranges[j++]; 314284317Sbr } 315284317Sbr sc->ranges[i].size = 0; 316284317Sbr for (k = 0; k < size_cells; k++) { 317284317Sbr sc->ranges[i].size <<= 32; 318284317Sbr sc->ranges[i].size |= base_ranges[j++]; 319284317Sbr } 320284317Sbr } 321284317Sbr 322284317Sbr for (; i < MAX_RANGES_TUPLES; i++) { 323284317Sbr /* zero-fill remaining tuples to mark empty elements in array */ 324284317Sbr sc->ranges[i].pci_base = 0; 325284317Sbr sc->ranges[i].phys_base = 0; 326284317Sbr sc->ranges[i].size = 0; 327284317Sbr } 328284317Sbr 329284317Sbr if (bootverbose) { 330284317Sbr for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { 331284317Sbr device_printf(sc->dev, 332284317Sbr "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx\n", 333284317Sbr sc->ranges[tuple].pci_base, 334284317Sbr sc->ranges[tuple].phys_base, 335284317Sbr sc->ranges[tuple].size); 336284317Sbr } 337284317Sbr } 338284317Sbr 339284317Sbr free(base_ranges, M_DEVBUF); 340284317Sbr return (0); 341284317Sbr} 342284317Sbr 343284317Sbrstatic uint32_t 344284317Sbrgeneric_pcie_read_config(device_t dev, u_int bus, u_int slot, 345284317Sbr u_int func, u_int reg, 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 uint32_t data; 352284317Sbr 353295962Swma if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) || 354295962Swma (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) 355284317Sbr return (~0U); 356284317Sbr 357284317Sbr sc = device_get_softc(dev); 358284317Sbr 359284317Sbr offset = PCIE_ADDR_OFFSET(bus, slot, func, reg); 360284317Sbr t = sc->bst; 361284317Sbr h = sc->bsh; 362284317Sbr 363284317Sbr switch (bytes) { 364284317Sbr case 1: 365284317Sbr data = bus_space_read_1(t, h, offset); 366284317Sbr break; 367284317Sbr case 2: 368284317Sbr data = le16toh(bus_space_read_2(t, h, offset)); 369284317Sbr break; 370284317Sbr case 4: 371284317Sbr data = le32toh(bus_space_read_4(t, h, offset)); 372284317Sbr break; 373284317Sbr default: 374284317Sbr return (~0U); 375284317Sbr } 376284317Sbr 377284317Sbr return (data); 378284317Sbr} 379284317Sbr 380284317Sbrstatic void 381284317Sbrgeneric_pcie_write_config(device_t dev, u_int bus, u_int slot, 382284317Sbr u_int func, u_int reg, uint32_t val, int bytes) 383284317Sbr{ 384284317Sbr struct generic_pcie_softc *sc; 385284317Sbr bus_space_handle_t h; 386284317Sbr bus_space_tag_t t; 387284317Sbr uint64_t offset; 388284317Sbr 389295962Swma if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) || 390295962Swma (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) 391284317Sbr return; 392284317Sbr 393284317Sbr sc = device_get_softc(dev); 394284317Sbr 395284317Sbr offset = PCIE_ADDR_OFFSET(bus, slot, func, reg); 396284317Sbr 397284317Sbr t = sc->bst; 398284317Sbr h = sc->bsh; 399284317Sbr 400284317Sbr switch (bytes) { 401284317Sbr case 1: 402284317Sbr bus_space_write_1(t, h, offset, val); 403284317Sbr break; 404284317Sbr case 2: 405284317Sbr bus_space_write_2(t, h, offset, htole16(val)); 406284317Sbr break; 407284317Sbr case 4: 408284317Sbr bus_space_write_4(t, h, offset, htole32(val)); 409284317Sbr break; 410284317Sbr default: 411284317Sbr return; 412284317Sbr } 413284317Sbr} 414284317Sbr 415284317Sbrstatic int 416284317Sbrgeneric_pcie_maxslots(device_t dev) 417284317Sbr{ 418284317Sbr 419284317Sbr return (31); /* max slots per bus acc. to standard */ 420284317Sbr} 421284317Sbr 422284317Sbrstatic int 423292215Sandrewgeneric_pcie_route_interrupt(device_t bus, device_t dev, int pin) 424292215Sandrew{ 425292215Sandrew struct generic_pcie_softc *sc; 426292215Sandrew struct ofw_pci_register reg; 427292215Sandrew uint32_t pintr, mintr[2]; 428292215Sandrew phandle_t iparent; 429292215Sandrew int intrcells; 430292215Sandrew 431292215Sandrew sc = device_get_softc(bus); 432292215Sandrew pintr = pin; 433292215Sandrew 434292215Sandrew bzero(®, sizeof(reg)); 435292215Sandrew reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | 436292215Sandrew (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | 437292215Sandrew (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); 438292215Sandrew 439292215Sandrew intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), 440292215Sandrew &sc->pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), 441292215Sandrew mintr, sizeof(mintr), &iparent); 442292215Sandrew if (intrcells) { 443292215Sandrew pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr); 444292215Sandrew return (pintr); 445292215Sandrew } 446292215Sandrew 447292215Sandrew device_printf(bus, "could not route pin %d for device %d.%d\n", 448292215Sandrew pin, pci_get_slot(dev), pci_get_function(dev)); 449292215Sandrew return (PCI_INVALID_IRQ); 450292215Sandrew} 451292215Sandrew 452292215Sandrew 453292215Sandrewstatic int 454284317Sbrgeneric_pcie_read_ivar(device_t dev, device_t child, int index, 455284317Sbr uintptr_t *result) 456284317Sbr{ 457284317Sbr struct generic_pcie_softc *sc; 458284317Sbr int secondary_bus; 459284317Sbr 460284317Sbr sc = device_get_softc(dev); 461284317Sbr 462284317Sbr if (index == PCIB_IVAR_BUS) { 463284317Sbr /* this pcib adds only pci bus 0 as child */ 464284317Sbr secondary_bus = 0; 465284317Sbr *result = secondary_bus; 466284317Sbr return (0); 467284317Sbr 468284317Sbr } 469284317Sbr 470284317Sbr if (index == PCIB_IVAR_DOMAIN) { 471284317Sbr *result = sc->ecam; 472284317Sbr return (0); 473284317Sbr } 474284317Sbr 475295962Swma if (bootverbose) 476295962Swma device_printf(dev, "ERROR: Unknown index %d.\n", index); 477284317Sbr return (ENOENT); 478284317Sbr} 479284317Sbr 480284317Sbrstatic int 481284317Sbrgeneric_pcie_write_ivar(device_t dev, device_t child, int index, 482284317Sbr uintptr_t value) 483284317Sbr{ 484284317Sbr 485284317Sbr return (ENOENT); 486284317Sbr} 487284317Sbr 488284317Sbrstatic struct rman * 489284317Sbrgeneric_pcie_rman(struct generic_pcie_softc *sc, int type) 490284317Sbr{ 491284317Sbr 492284317Sbr switch (type) { 493284317Sbr case SYS_RES_IOPORT: 494284317Sbr return (&sc->io_rman); 495284317Sbr case SYS_RES_MEMORY: 496284317Sbr return (&sc->mem_rman); 497284317Sbr default: 498284317Sbr break; 499284317Sbr } 500284317Sbr 501284317Sbr return (NULL); 502284317Sbr} 503284317Sbr 504284317Sbrstatic int 505295962Swmageneric_pcie_release_resource_pcie(device_t dev, device_t child, int type, 506284317Sbr int rid, struct resource *res) 507284317Sbr{ 508284317Sbr struct generic_pcie_softc *sc; 509284317Sbr struct rman *rm; 510284317Sbr 511284317Sbr sc = device_get_softc(dev); 512284317Sbr 513284317Sbr rm = generic_pcie_rman(sc, type); 514284317Sbr if (rm != NULL) { 515284317Sbr KASSERT(rman_is_region_manager(res, rm), ("rman mismatch")); 516284317Sbr rman_release_resource(res); 517284317Sbr } 518284317Sbr 519284317Sbr return (bus_generic_release_resource(dev, child, type, rid, res)); 520284317Sbr} 521284317Sbr 522295962Swmastatic int 523295962Swmageneric_pcie_release_resource(device_t dev, device_t child, int type, 524295962Swma int rid, struct resource *res) 525295962Swma{ 526300290Sandrew#if defined(NEW_PCIB) && defined(PCI_RES_BUS) 527300290Sandrew struct generic_pcie_softc *sc; 528295962Swma 529300290Sandrew if (type == PCI_RES_BUS) { 530300290Sandrew sc = device_get_softc(dev); 531300290Sandrew return (pci_domain_release_bus(sc->ecam, child, rid, res)); 532300290Sandrew } 533300290Sandrew#endif 534295962Swma /* For PCIe devices that do not have FDT nodes, use PCIB method */ 535295962Swma if ((int)ofw_bus_get_node(child) <= 0) { 536295962Swma return (generic_pcie_release_resource_pcie(dev, 537295962Swma child, type, rid, res)); 538295962Swma } 539295962Swma 540295962Swma /* For other devices use OFW method */ 541295962Swma return (generic_pcie_release_resource_ofw(dev, 542295962Swma child, type, rid, res)); 543295962Swma} 544295962Swma 545296091Swmastruct resource * 546296091Swmapci_host_generic_alloc_resource(device_t dev, device_t child, int type, int *rid, 547294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 548284317Sbr{ 549300290Sandrew#if defined(NEW_PCIB) && defined(PCI_RES_BUS) 550300290Sandrew struct generic_pcie_softc *sc; 551295962Swma 552300290Sandrew if (type == PCI_RES_BUS) { 553300290Sandrew sc = device_get_softc(dev); 554300290Sandrew return (pci_domain_alloc_bus(sc->ecam, child, rid, start, end, 555300290Sandrew count, flags)); 556300290Sandrew } 557300290Sandrew#endif 558295962Swma /* For PCIe devices that do not have FDT nodes, use PCIB method */ 559295962Swma if ((int)ofw_bus_get_node(child) <= 0) 560295962Swma return (generic_pcie_alloc_resource_pcie(dev, child, type, rid, 561295962Swma start, end, count, flags)); 562295962Swma 563295962Swma /* For other devices use OFW method */ 564295962Swma return (generic_pcie_alloc_resource_ofw(dev, child, type, rid, 565295962Swma start, end, count, flags)); 566295962Swma} 567295962Swma 568295962Swmastatic struct resource * 569295962Swmageneric_pcie_alloc_resource_pcie(device_t dev, device_t child, int type, int *rid, 570295962Swma rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 571295962Swma{ 572284317Sbr struct generic_pcie_softc *sc; 573284317Sbr struct resource *res; 574284317Sbr struct rman *rm; 575284317Sbr 576284317Sbr sc = device_get_softc(dev); 577284317Sbr 578284317Sbr rm = generic_pcie_rman(sc, type); 579284317Sbr if (rm == NULL) 580284317Sbr return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 581284317Sbr type, rid, start, end, count, flags)); 582284317Sbr 583284317Sbr if (bootverbose) { 584284317Sbr device_printf(dev, 585297038Sbz "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n", 586284317Sbr start, end, count); 587284317Sbr } 588284317Sbr 589284317Sbr res = rman_reserve_resource(rm, start, end, count, flags, child); 590284317Sbr if (res == NULL) 591284317Sbr goto fail; 592284317Sbr 593284317Sbr rman_set_rid(res, *rid); 594284317Sbr 595284317Sbr if (flags & RF_ACTIVE) 596284317Sbr if (bus_activate_resource(child, type, *rid, res)) { 597284317Sbr rman_release_resource(res); 598284317Sbr goto fail; 599284317Sbr } 600284317Sbr 601284317Sbr return (res); 602284317Sbr 603284317Sbrfail: 604295962Swma device_printf(dev, "%s FAIL: type=%d, rid=%d, " 605297038Sbz "start=%016jx, end=%016jx, count=%016jx, flags=%x\n", 606295962Swma __func__, type, *rid, start, end, count, flags); 607284317Sbr 608284317Sbr return (NULL); 609284317Sbr} 610284317Sbr 611284317Sbrstatic int 612284317Sbrgeneric_pcie_adjust_resource(device_t dev, device_t child, int type, 613294883Sjhibbits struct resource *res, rman_res_t start, rman_res_t end) 614284317Sbr{ 615284317Sbr struct generic_pcie_softc *sc; 616284317Sbr struct rman *rm; 617284317Sbr 618284317Sbr sc = device_get_softc(dev); 619300290Sandrew#if defined(NEW_PCIB) && defined(PCI_RES_BUS) 620300290Sandrew if (type == PCI_RES_BUS) 621300290Sandrew return (pci_domain_adjust_bus(sc->ecam, child, res, start, 622300290Sandrew end)); 623300290Sandrew#endif 624284317Sbr 625284317Sbr rm = generic_pcie_rman(sc, type); 626284317Sbr if (rm != NULL) 627284317Sbr return (rman_adjust_resource(res, start, end)); 628284317Sbr return (bus_generic_adjust_resource(dev, child, type, res, start, end)); 629284317Sbr} 630284317Sbr 631284317Sbrstatic int 632284317Sbrgeneric_pcie_activate_resource(device_t dev, device_t child, int type, int rid, 633284317Sbr struct resource *r) 634284317Sbr{ 635284317Sbr struct generic_pcie_softc *sc; 636284317Sbr uint64_t phys_base; 637284317Sbr uint64_t pci_base; 638284317Sbr uint64_t size; 639284317Sbr int found; 640284317Sbr int res; 641284317Sbr int i; 642284317Sbr 643284317Sbr sc = device_get_softc(dev); 644284317Sbr 645284317Sbr if ((res = rman_activate_resource(r)) != 0) 646284317Sbr return (res); 647284317Sbr 648284317Sbr switch(type) { 649284317Sbr case SYS_RES_IOPORT: 650284317Sbr found = 0; 651284317Sbr for (i = 0; i < MAX_RANGES_TUPLES; i++) { 652284317Sbr pci_base = sc->ranges[i].pci_base; 653284317Sbr phys_base = sc->ranges[i].phys_base; 654284317Sbr size = sc->ranges[i].size; 655284317Sbr 656284317Sbr if ((rid > pci_base) && (rid < (pci_base + size))) { 657284317Sbr found = 1; 658284317Sbr break; 659284317Sbr } 660284317Sbr } 661284317Sbr if (found) { 662284317Sbr rman_set_start(r, rman_get_start(r) + phys_base); 663299658Sbz rman_set_end(r, rman_get_end(r) + phys_base); 664284317Sbr BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, 665284317Sbr type, rid, r); 666284317Sbr } else { 667284317Sbr device_printf(dev, "Failed to activate IOPORT resource\n"); 668284317Sbr res = 0; 669284317Sbr } 670284317Sbr break; 671284317Sbr case SYS_RES_MEMORY: 672284317Sbr BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type, rid, r); 673284317Sbr break; 674284317Sbr default: 675284317Sbr break; 676284317Sbr } 677284317Sbr 678284317Sbr return (res); 679284317Sbr} 680284317Sbr 681284317Sbrstatic int 682284317Sbrgeneric_pcie_deactivate_resource(device_t dev, device_t child, int type, int rid, 683284317Sbr struct resource *r) 684284317Sbr{ 685284317Sbr struct generic_pcie_softc *sc; 686284317Sbr vm_offset_t vaddr; 687284317Sbr int res; 688284317Sbr 689284317Sbr sc = device_get_softc(dev); 690284317Sbr 691284317Sbr if ((res = rman_deactivate_resource(r)) != 0) 692284317Sbr return (res); 693284317Sbr 694284317Sbr switch(type) { 695284317Sbr case SYS_RES_IOPORT: 696284317Sbr case SYS_RES_MEMORY: 697284317Sbr vaddr = (vm_offset_t)rman_get_virtual(r); 698284317Sbr pmap_unmapdev(vaddr, rman_get_size(r)); 699284317Sbr break; 700284317Sbr default: 701284317Sbr break; 702284317Sbr } 703284317Sbr 704284317Sbr return (res); 705284317Sbr} 706284317Sbr 707301031Sandrewstatic bus_dma_tag_t 708301031Sandrewgeneric_pcie_get_dma_tag(device_t dev, device_t child) 709301031Sandrew{ 710301031Sandrew struct generic_pcie_softc *sc; 711301031Sandrew 712301031Sandrew sc = device_get_softc(dev); 713301031Sandrew return (sc->dmat); 714301031Sandrew} 715301031Sandrew 716298202Sandrewstatic int 717298202Sandrewgeneric_pcie_alloc_msi(device_t pci, device_t child, int count, int maxcount, 718298202Sandrew int *irqs) 719298202Sandrew{ 720299928Sandrew#if defined(INTRNG) 721299941Sandrew phandle_t msi_parent; 722298202Sandrew 723299941Sandrew ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 724299941Sandrew NULL); 725299941Sandrew return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, 726299928Sandrew irqs)); 727298202Sandrew#else 728298202Sandrew return (ENXIO); 729298202Sandrew#endif 730298202Sandrew} 731298202Sandrew 732298202Sandrewstatic int 733298202Sandrewgeneric_pcie_release_msi(device_t pci, device_t child, int count, int *irqs) 734298202Sandrew{ 735299928Sandrew#if defined(INTRNG) 736299941Sandrew phandle_t msi_parent; 737298202Sandrew 738299941Sandrew ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 739299941Sandrew NULL); 740299941Sandrew return (intr_release_msi(pci, child, msi_parent, count, irqs)); 741298202Sandrew#else 742298202Sandrew return (ENXIO); 743298202Sandrew#endif 744298202Sandrew} 745298202Sandrew 746298202Sandrewstatic int 747298202Sandrewgeneric_pcie_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, 748298202Sandrew uint32_t *data) 749298202Sandrew{ 750299928Sandrew#if defined(INTRNG) 751299941Sandrew phandle_t msi_parent; 752298202Sandrew 753299941Sandrew ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 754299941Sandrew NULL); 755299941Sandrew return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); 756298202Sandrew#else 757298202Sandrew return (ENXIO); 758298202Sandrew#endif 759298202Sandrew} 760298202Sandrew 761298202Sandrewstatic int 762298202Sandrewgeneric_pcie_alloc_msix(device_t pci, device_t child, int *irq) 763298202Sandrew{ 764299928Sandrew#if defined(INTRNG) 765299941Sandrew phandle_t msi_parent; 766298202Sandrew 767299941Sandrew ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 768299941Sandrew NULL); 769299941Sandrew return (intr_alloc_msix(pci, child, msi_parent, irq)); 770298202Sandrew#else 771298202Sandrew return (ENXIO); 772298202Sandrew#endif 773298202Sandrew} 774298202Sandrew 775298202Sandrewstatic int 776298202Sandrewgeneric_pcie_release_msix(device_t pci, device_t child, int irq) 777298202Sandrew{ 778299928Sandrew#if defined(INTRNG) 779299941Sandrew phandle_t msi_parent; 780298202Sandrew 781299941Sandrew ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 782299941Sandrew NULL); 783299941Sandrew return (intr_release_msix(pci, child, msi_parent, irq)); 784298202Sandrew#else 785298202Sandrew return (ENXIO); 786298202Sandrew#endif 787298202Sandrew} 788298202Sandrew 789299932Sandrewint 790299932Sandrewgeneric_pcie_get_id(device_t pci, device_t child, enum pci_id_type type, 791299932Sandrew uintptr_t *id) 792299932Sandrew{ 793299932Sandrew phandle_t node; 794299932Sandrew uint32_t rid; 795299932Sandrew uint16_t pci_rid; 796299932Sandrew 797299932Sandrew if (type != PCI_ID_MSI) 798299932Sandrew return (pcib_get_id(pci, child, type, id)); 799299932Sandrew 800299932Sandrew node = ofw_bus_get_node(pci); 801299932Sandrew pci_rid = pci_get_rid(child); 802299932Sandrew 803299932Sandrew ofw_bus_msimap(node, pci_rid, NULL, &rid); 804299932Sandrew *id = rid; 805299932Sandrew 806299932Sandrew return (0); 807299932Sandrew} 808299932Sandrew 809284317Sbrstatic device_method_t generic_pcie_methods[] = { 810284317Sbr DEVMETHOD(device_probe, generic_pcie_probe), 811295962Swma DEVMETHOD(device_attach, pci_host_generic_attach), 812284317Sbr DEVMETHOD(bus_read_ivar, generic_pcie_read_ivar), 813284317Sbr DEVMETHOD(bus_write_ivar, generic_pcie_write_ivar), 814296091Swma DEVMETHOD(bus_alloc_resource, pci_host_generic_alloc_resource), 815284317Sbr DEVMETHOD(bus_adjust_resource, generic_pcie_adjust_resource), 816284317Sbr DEVMETHOD(bus_release_resource, generic_pcie_release_resource), 817284317Sbr DEVMETHOD(bus_activate_resource, generic_pcie_activate_resource), 818284317Sbr DEVMETHOD(bus_deactivate_resource, generic_pcie_deactivate_resource), 819284317Sbr DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 820284317Sbr DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 821292215Sandrew 822301031Sandrew DEVMETHOD(bus_get_dma_tag, generic_pcie_get_dma_tag), 823301031Sandrew 824292215Sandrew /* pcib interface */ 825284317Sbr DEVMETHOD(pcib_maxslots, generic_pcie_maxslots), 826292215Sandrew DEVMETHOD(pcib_route_interrupt, generic_pcie_route_interrupt), 827284317Sbr DEVMETHOD(pcib_read_config, generic_pcie_read_config), 828284317Sbr DEVMETHOD(pcib_write_config, generic_pcie_write_config), 829298202Sandrew DEVMETHOD(pcib_alloc_msi, generic_pcie_alloc_msi), 830298202Sandrew DEVMETHOD(pcib_release_msi, generic_pcie_release_msi), 831298202Sandrew DEVMETHOD(pcib_alloc_msix, generic_pcie_alloc_msix), 832298202Sandrew DEVMETHOD(pcib_release_msix, generic_pcie_release_msix), 833298202Sandrew DEVMETHOD(pcib_map_msi, generic_pcie_map_msi), 834299932Sandrew DEVMETHOD(pcib_get_id, generic_pcie_get_id), 835292215Sandrew 836295962Swma /* ofw_bus interface */ 837295962Swma DEVMETHOD(ofw_bus_get_devinfo, generic_pcie_ofw_get_devinfo), 838295962Swma DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 839295962Swma DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 840295962Swma DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 841295962Swma DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 842295962Swma DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 843295962Swma 844284317Sbr DEVMETHOD_END 845284317Sbr}; 846284317Sbr 847295962Swmastatic const struct ofw_bus_devinfo * 848295962Swmageneric_pcie_ofw_get_devinfo(device_t bus __unused, device_t child) 849295962Swma{ 850295962Swma struct generic_pcie_ofw_devinfo *di; 851284317Sbr 852295962Swma di = device_get_ivars(child); 853295962Swma return (&di->di_dinfo); 854295962Swma} 855284317Sbr 856295962Swmastatic struct resource * 857295962Swmageneric_pcie_alloc_resource_ofw(device_t bus, device_t child, int type, int *rid, 858295962Swma rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 859295962Swma{ 860295962Swma struct generic_pcie_softc *sc; 861295962Swma struct generic_pcie_ofw_devinfo *di; 862295962Swma struct resource_list_entry *rle; 863295962Swma int i; 864295962Swma 865295962Swma sc = device_get_softc(bus); 866295962Swma 867296298Sjhibbits if (RMAN_IS_DEFAULT_RANGE(start, end)) { 868295962Swma if ((di = device_get_ivars(child)) == NULL) 869295962Swma return (NULL); 870295962Swma if (type == SYS_RES_IOPORT) 871295962Swma type = SYS_RES_MEMORY; 872295962Swma 873295962Swma /* Find defaults for this rid */ 874295962Swma rle = resource_list_find(&di->di_rl, type, *rid); 875295962Swma if (rle == NULL) 876295962Swma return (NULL); 877295962Swma 878295962Swma start = rle->start; 879295962Swma end = rle->end; 880295962Swma count = rle->count; 881295962Swma } 882295962Swma 883295962Swma if (type == SYS_RES_MEMORY) { 884295962Swma /* Remap through ranges property */ 885295962Swma for (i = 0; i < MAX_RANGES_TUPLES; i++) { 886295962Swma if (start >= sc->ranges[i].phys_base && end < 887295962Swma sc->ranges[i].pci_base + sc->ranges[i].size) { 888295962Swma start -= sc->ranges[i].phys_base; 889295962Swma start += sc->ranges[i].pci_base; 890295962Swma end -= sc->ranges[i].phys_base; 891295962Swma end += sc->ranges[i].pci_base; 892295962Swma break; 893295962Swma } 894295962Swma } 895295962Swma 896295962Swma if (i == MAX_RANGES_TUPLES) { 897295962Swma device_printf(bus, "Could not map resource " 898297038Sbz "%#jx-%#jx\n", start, end); 899295962Swma return (NULL); 900295962Swma } 901295962Swma } 902295962Swma 903295962Swma return (bus_generic_alloc_resource(bus, child, type, rid, start, end, 904295962Swma count, flags)); 905295962Swma} 906295962Swma 907295962Swmastatic int 908295962Swmageneric_pcie_release_resource_ofw(device_t bus, device_t child, int type, int rid, 909295962Swma struct resource *res) 910295962Swma{ 911295962Swma 912295962Swma return (bus_generic_release_resource(bus, child, type, rid, res)); 913295962Swma} 914295962Swma 915295962Swma/* Helper functions */ 916295962Swma 917295962Swmastatic int 918295962Swmageneric_pcie_ofw_bus_attach(device_t dev) 919295962Swma{ 920295962Swma struct generic_pcie_ofw_devinfo *di; 921295962Swma device_t child; 922295962Swma phandle_t parent, node; 923295962Swma pcell_t addr_cells, size_cells; 924295962Swma 925295962Swma parent = ofw_bus_get_node(dev); 926295962Swma if (parent > 0) { 927295962Swma get_addr_size_cells(parent, &addr_cells, &size_cells); 928295962Swma /* Iterate through all bus subordinates */ 929295962Swma for (node = OF_child(parent); node > 0; node = OF_peer(node)) { 930295962Swma 931295962Swma /* Allocate and populate devinfo. */ 932295962Swma di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO); 933295962Swma if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node) != 0) { 934295962Swma free(di, M_DEVBUF); 935295962Swma continue; 936295962Swma } 937295962Swma 938295962Swma /* Initialize and populate resource list. */ 939295962Swma resource_list_init(&di->di_rl); 940295962Swma ofw_bus_reg_to_rl(dev, node, addr_cells, size_cells, 941295962Swma &di->di_rl); 942295962Swma ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL); 943295962Swma 944295962Swma /* Add newbus device for this FDT node */ 945295962Swma child = device_add_child(dev, NULL, -1); 946295962Swma if (child == NULL) { 947295962Swma resource_list_free(&di->di_rl); 948295962Swma ofw_bus_gen_destroy_devinfo(&di->di_dinfo); 949295962Swma free(di, M_DEVBUF); 950295962Swma continue; 951295962Swma } 952295962Swma 953295962Swma device_set_ivars(child, di); 954295962Swma } 955295962Swma } 956295962Swma 957295962Swma return (0); 958295962Swma} 959295962Swma 960295962SwmaDEFINE_CLASS_0(pcib, generic_pcie_driver, 961295962Swma generic_pcie_methods, sizeof(struct generic_pcie_softc)); 962295962Swma 963295962Swmadevclass_t generic_pcie_devclass; 964295962Swma 965284317SbrDRIVER_MODULE(pcib, simplebus, generic_pcie_driver, 966295962Swma generic_pcie_devclass, 0, 0); 967284317SbrDRIVER_MODULE(pcib, ofwbus, generic_pcie_driver, 968295962Swma generic_pcie_devclass, 0, 0); 969295962Swma 970