1dee4c1d2SRuslan Bukin /*- 2dee4c1d2SRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause 3dee4c1d2SRuslan Bukin * 4dee4c1d2SRuslan Bukin * Copyright (c) 2020 Ruslan Bukin <br@bsdpad.com> 5dee4c1d2SRuslan Bukin * 6dee4c1d2SRuslan Bukin * This software was developed by SRI International and the University of 7dee4c1d2SRuslan Bukin * Cambridge Computer Laboratory (Department of Computer Science and 8dee4c1d2SRuslan Bukin * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 9dee4c1d2SRuslan Bukin * DARPA SSITH research programme. 10dee4c1d2SRuslan Bukin * 11dee4c1d2SRuslan Bukin * Redistribution and use in source and binary forms, with or without 12dee4c1d2SRuslan Bukin * modification, are permitted provided that the following conditions 13dee4c1d2SRuslan Bukin * are met: 14dee4c1d2SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 15dee4c1d2SRuslan Bukin * notice, this list of conditions and the following disclaimer. 16dee4c1d2SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 17dee4c1d2SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 18dee4c1d2SRuslan Bukin * documentation and/or other materials provided with the distribution. 19dee4c1d2SRuslan Bukin * 20dee4c1d2SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21dee4c1d2SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22dee4c1d2SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23dee4c1d2SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24dee4c1d2SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25dee4c1d2SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26dee4c1d2SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27dee4c1d2SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28dee4c1d2SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29dee4c1d2SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30dee4c1d2SRuslan Bukin * SUCH DAMAGE. 31dee4c1d2SRuslan Bukin */ 32dee4c1d2SRuslan Bukin 33dee4c1d2SRuslan Bukin #include "opt_platform.h" 34dee4c1d2SRuslan Bukin 35dee4c1d2SRuslan Bukin #include <sys/cdefs.h> 36dee4c1d2SRuslan Bukin __FBSDID("$FreeBSD$"); 37dee4c1d2SRuslan Bukin 38dee4c1d2SRuslan Bukin #include <sys/param.h> 39dee4c1d2SRuslan Bukin #include <sys/systm.h> 40dee4c1d2SRuslan Bukin #include <sys/malloc.h> 41dee4c1d2SRuslan Bukin #include <sys/types.h> 42dee4c1d2SRuslan Bukin #include <sys/sysctl.h> 43dee4c1d2SRuslan Bukin #include <sys/kernel.h> 44dee4c1d2SRuslan Bukin #include <sys/rman.h> 45dee4c1d2SRuslan Bukin #include <sys/module.h> 46dee4c1d2SRuslan Bukin #include <sys/bus.h> 47dee4c1d2SRuslan Bukin #include <sys/endian.h> 48dee4c1d2SRuslan Bukin #include <sys/cpuset.h> 49dee4c1d2SRuslan Bukin #include <sys/mutex.h> 50dee4c1d2SRuslan Bukin #include <sys/proc.h> 51dee4c1d2SRuslan Bukin 52dee4c1d2SRuslan Bukin #include <machine/intr.h> 53dee4c1d2SRuslan Bukin #include <machine/bus.h> 54dee4c1d2SRuslan Bukin 55dee4c1d2SRuslan Bukin #include <vm/vm.h> 56dee4c1d2SRuslan Bukin #include <vm/vm_extern.h> 57dee4c1d2SRuslan Bukin #include <vm/vm_kern.h> 58dee4c1d2SRuslan Bukin #include <vm/pmap.h> 59dee4c1d2SRuslan Bukin 60dee4c1d2SRuslan Bukin #include <dev/ofw/openfirm.h> 61dee4c1d2SRuslan Bukin #include <dev/ofw/ofw_bus.h> 62dee4c1d2SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 63dee4c1d2SRuslan Bukin 64dee4c1d2SRuslan Bukin #include <dev/pci/pcireg.h> 65dee4c1d2SRuslan Bukin #include <dev/pci/pcivar.h> 66dee4c1d2SRuslan Bukin #include <dev/pci/pci_host_generic.h> 67dee4c1d2SRuslan Bukin #include <dev/pci/pci_host_generic_fdt.h> 68dee4c1d2SRuslan Bukin #include <dev/pci/pcib_private.h> 69dee4c1d2SRuslan Bukin 70dee4c1d2SRuslan Bukin #include "xlnx_pcib.h" 71dee4c1d2SRuslan Bukin 72dee4c1d2SRuslan Bukin #include "ofw_bus_if.h" 73dee4c1d2SRuslan Bukin #include "msi_if.h" 74dee4c1d2SRuslan Bukin #include "pcib_if.h" 75dee4c1d2SRuslan Bukin #include "pic_if.h" 76dee4c1d2SRuslan Bukin 77dee4c1d2SRuslan Bukin #define XLNX_PCIB_MAX_MSI 64 78dee4c1d2SRuslan Bukin 79dee4c1d2SRuslan Bukin static int xlnx_pcib_fdt_attach(device_t); 80dee4c1d2SRuslan Bukin static int xlnx_pcib_fdt_probe(device_t); 81dee4c1d2SRuslan Bukin static int xlnx_pcib_fdt_get_id(device_t, device_t, enum pci_id_type, 82dee4c1d2SRuslan Bukin uintptr_t *); 83dee4c1d2SRuslan Bukin static void xlnx_pcib_msi_mask(device_t dev, struct intr_irqsrc *isrc, 84dee4c1d2SRuslan Bukin bool mask); 85dee4c1d2SRuslan Bukin 86dee4c1d2SRuslan Bukin struct xlnx_pcib_softc { 87dee4c1d2SRuslan Bukin struct generic_pcie_fdt_softc fdt_sc; 88dee4c1d2SRuslan Bukin struct resource *res[4]; 89dee4c1d2SRuslan Bukin struct mtx mtx; 90dee4c1d2SRuslan Bukin vm_offset_t msi_page; 91dee4c1d2SRuslan Bukin struct xlnx_pcib_irqsrc *isrcs; 92dee4c1d2SRuslan Bukin device_t dev; 93dee4c1d2SRuslan Bukin void *intr_cookie[3]; 94dee4c1d2SRuslan Bukin }; 95dee4c1d2SRuslan Bukin 96dee4c1d2SRuslan Bukin static struct resource_spec xlnx_pcib_spec[] = { 97dee4c1d2SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 98dee4c1d2SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 99dee4c1d2SRuslan Bukin { SYS_RES_IRQ, 1, RF_ACTIVE }, 100dee4c1d2SRuslan Bukin { SYS_RES_IRQ, 2, RF_ACTIVE }, 101dee4c1d2SRuslan Bukin { -1, 0 } 102dee4c1d2SRuslan Bukin }; 103dee4c1d2SRuslan Bukin 104dee4c1d2SRuslan Bukin struct xlnx_pcib_irqsrc { 105dee4c1d2SRuslan Bukin struct intr_irqsrc isrc; 106dee4c1d2SRuslan Bukin u_int irq; 107dee4c1d2SRuslan Bukin #define XLNX_IRQ_FLAG_USED (1 << 0) 108dee4c1d2SRuslan Bukin u_int flags; 109dee4c1d2SRuslan Bukin }; 110dee4c1d2SRuslan Bukin 111dee4c1d2SRuslan Bukin static void 112dee4c1d2SRuslan Bukin xlnx_pcib_clear_err_interrupts(struct generic_pcie_core_softc *sc) 113dee4c1d2SRuslan Bukin { 114dee4c1d2SRuslan Bukin uint32_t reg; 115dee4c1d2SRuslan Bukin 116dee4c1d2SRuslan Bukin reg = bus_read_4(sc->res, XLNX_PCIE_RPERRFRR); 117dee4c1d2SRuslan Bukin 118dee4c1d2SRuslan Bukin if (reg & RPERRFRR_VALID) { 119dee4c1d2SRuslan Bukin device_printf(sc->dev, "Requested ID: %x\n", 120dee4c1d2SRuslan Bukin reg & RPERRFRR_REQ_ID_M); 121dee4c1d2SRuslan Bukin bus_write_4(sc->res, XLNX_PCIE_RPERRFRR, ~0U); 122dee4c1d2SRuslan Bukin } 123dee4c1d2SRuslan Bukin } 124dee4c1d2SRuslan Bukin 125dee4c1d2SRuslan Bukin static int 126dee4c1d2SRuslan Bukin xlnx_pcib_intr(void *arg) 127dee4c1d2SRuslan Bukin { 128dee4c1d2SRuslan Bukin struct generic_pcie_fdt_softc *fdt_sc; 129dee4c1d2SRuslan Bukin struct generic_pcie_core_softc *sc; 130dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *xlnx_sc; 131dee4c1d2SRuslan Bukin uint32_t val, mask, status; 132dee4c1d2SRuslan Bukin 133dee4c1d2SRuslan Bukin xlnx_sc = arg; 134dee4c1d2SRuslan Bukin fdt_sc = &xlnx_sc->fdt_sc; 135dee4c1d2SRuslan Bukin sc = &fdt_sc->base; 136dee4c1d2SRuslan Bukin 137dee4c1d2SRuslan Bukin val = bus_read_4(sc->res, XLNX_PCIE_IDR); 138dee4c1d2SRuslan Bukin mask = bus_read_4(sc->res, XLNX_PCIE_IMR); 139dee4c1d2SRuslan Bukin 140dee4c1d2SRuslan Bukin status = val & mask; 141dee4c1d2SRuslan Bukin if (!status) 142dee4c1d2SRuslan Bukin return (FILTER_HANDLED); 143dee4c1d2SRuslan Bukin 144dee4c1d2SRuslan Bukin if (status & IMR_LINK_DOWN) 145dee4c1d2SRuslan Bukin device_printf(sc->dev, "Link down"); 146dee4c1d2SRuslan Bukin 147dee4c1d2SRuslan Bukin if (status & IMR_HOT_RESET) 148dee4c1d2SRuslan Bukin device_printf(sc->dev, "Hot reset"); 149dee4c1d2SRuslan Bukin 150dee4c1d2SRuslan Bukin if (status & IMR_CORRECTABLE) 151dee4c1d2SRuslan Bukin xlnx_pcib_clear_err_interrupts(sc); 152dee4c1d2SRuslan Bukin 153dee4c1d2SRuslan Bukin if (status & IMR_FATAL) 154dee4c1d2SRuslan Bukin xlnx_pcib_clear_err_interrupts(sc); 155dee4c1d2SRuslan Bukin 156dee4c1d2SRuslan Bukin if (status & IMR_NON_FATAL) 157dee4c1d2SRuslan Bukin xlnx_pcib_clear_err_interrupts(sc); 158dee4c1d2SRuslan Bukin 159dee4c1d2SRuslan Bukin if (status & IMR_MSI) { 160dee4c1d2SRuslan Bukin device_printf(sc->dev, "MSI interrupt"); 161dee4c1d2SRuslan Bukin 162dee4c1d2SRuslan Bukin /* FIFO mode MSI not implemented. */ 163dee4c1d2SRuslan Bukin } 164dee4c1d2SRuslan Bukin 165dee4c1d2SRuslan Bukin if (status & IMR_INTX) { 166dee4c1d2SRuslan Bukin device_printf(sc->dev, "INTx received"); 167dee4c1d2SRuslan Bukin 168dee4c1d2SRuslan Bukin /* Not implemented. */ 169dee4c1d2SRuslan Bukin } 170dee4c1d2SRuslan Bukin 171dee4c1d2SRuslan Bukin if (status & IMR_SLAVE_UNSUPP_REQ) 172dee4c1d2SRuslan Bukin device_printf(sc->dev, "Slave unsupported request"); 173dee4c1d2SRuslan Bukin 174dee4c1d2SRuslan Bukin if (status & IMR_SLAVE_UNEXP_COMPL) 175dee4c1d2SRuslan Bukin device_printf(sc->dev, "Slave unexpected completion"); 176dee4c1d2SRuslan Bukin 177dee4c1d2SRuslan Bukin if (status & IMR_SLAVE_COMPL_TIMOUT) 178dee4c1d2SRuslan Bukin device_printf(sc->dev, "Slave completion timeout"); 179dee4c1d2SRuslan Bukin 180dee4c1d2SRuslan Bukin if (status & IMR_SLAVE_ERROR_POISON) 181dee4c1d2SRuslan Bukin device_printf(sc->dev, "Slave error poison"); 182dee4c1d2SRuslan Bukin 183dee4c1d2SRuslan Bukin if (status & IMR_SLAVE_COMPL_ABORT) 184dee4c1d2SRuslan Bukin device_printf(sc->dev, "Slave completion abort"); 185dee4c1d2SRuslan Bukin 186dee4c1d2SRuslan Bukin if (status & IMR_SLAVE_ILLEG_BURST) 187dee4c1d2SRuslan Bukin device_printf(sc->dev, "Slave illegal burst"); 188dee4c1d2SRuslan Bukin 189dee4c1d2SRuslan Bukin if (status & IMR_MASTER_DECERR) 190dee4c1d2SRuslan Bukin device_printf(sc->dev, "Master decode error"); 191dee4c1d2SRuslan Bukin 192dee4c1d2SRuslan Bukin if (status & IMR_MASTER_SLVERR) 193dee4c1d2SRuslan Bukin device_printf(sc->dev, "Master slave error"); 194dee4c1d2SRuslan Bukin 195dee4c1d2SRuslan Bukin bus_write_4(sc->res, XLNX_PCIE_IDR, val); 196dee4c1d2SRuslan Bukin 197dee4c1d2SRuslan Bukin return (FILTER_HANDLED); 198dee4c1d2SRuslan Bukin } 199dee4c1d2SRuslan Bukin 200dee4c1d2SRuslan Bukin static void 201dee4c1d2SRuslan Bukin xlnx_pcib_handle_msi_intr(void *arg, int msireg) 202dee4c1d2SRuslan Bukin { 203dee4c1d2SRuslan Bukin struct generic_pcie_fdt_softc *fdt_sc; 204dee4c1d2SRuslan Bukin struct generic_pcie_core_softc *sc; 205dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *xlnx_sc; 206dee4c1d2SRuslan Bukin struct xlnx_pcib_irqsrc *xi; 207dee4c1d2SRuslan Bukin struct trapframe *tf; 208dee4c1d2SRuslan Bukin int irq; 209dee4c1d2SRuslan Bukin int reg; 210dee4c1d2SRuslan Bukin int i; 211dee4c1d2SRuslan Bukin 212dee4c1d2SRuslan Bukin xlnx_sc = arg; 213dee4c1d2SRuslan Bukin fdt_sc = &xlnx_sc->fdt_sc; 214dee4c1d2SRuslan Bukin sc = &fdt_sc->base; 215dee4c1d2SRuslan Bukin tf = curthread->td_intr_frame; 216dee4c1d2SRuslan Bukin 217dee4c1d2SRuslan Bukin do { 218dee4c1d2SRuslan Bukin reg = bus_read_4(sc->res, msireg); 219dee4c1d2SRuslan Bukin 220dee4c1d2SRuslan Bukin for (i = 0; i < sizeof(uint32_t) * 8; i++) { 221dee4c1d2SRuslan Bukin if (reg & (1 << i)) { 222dee4c1d2SRuslan Bukin bus_write_4(sc->res, msireg, (1 << i)); 223dee4c1d2SRuslan Bukin 224dee4c1d2SRuslan Bukin irq = i; 225dee4c1d2SRuslan Bukin if (msireg == XLNX_PCIE_RPMSIID2) 226dee4c1d2SRuslan Bukin irq += 32; 227dee4c1d2SRuslan Bukin 228dee4c1d2SRuslan Bukin xi = &xlnx_sc->isrcs[irq]; 229dee4c1d2SRuslan Bukin if (intr_isrc_dispatch(&xi->isrc, tf) != 0) { 230dee4c1d2SRuslan Bukin /* Disable stray. */ 231dee4c1d2SRuslan Bukin xlnx_pcib_msi_mask(sc->dev, 232dee4c1d2SRuslan Bukin &xi->isrc, 1); 233dee4c1d2SRuslan Bukin device_printf(sc->dev, 234dee4c1d2SRuslan Bukin "Stray irq %u disabled\n", irq); 235dee4c1d2SRuslan Bukin } 236dee4c1d2SRuslan Bukin } 237dee4c1d2SRuslan Bukin } 238dee4c1d2SRuslan Bukin } while (reg != 0); 239dee4c1d2SRuslan Bukin } 240dee4c1d2SRuslan Bukin 241dee4c1d2SRuslan Bukin static int 242dee4c1d2SRuslan Bukin xlnx_pcib_msi0_intr(void *arg) 243dee4c1d2SRuslan Bukin { 244dee4c1d2SRuslan Bukin 245dee4c1d2SRuslan Bukin xlnx_pcib_handle_msi_intr(arg, XLNX_PCIE_RPMSIID1); 246dee4c1d2SRuslan Bukin 247dee4c1d2SRuslan Bukin return (FILTER_HANDLED); 248dee4c1d2SRuslan Bukin } 249dee4c1d2SRuslan Bukin 250dee4c1d2SRuslan Bukin static int 251dee4c1d2SRuslan Bukin xlnx_pcib_msi1_intr(void *arg) 252dee4c1d2SRuslan Bukin { 253dee4c1d2SRuslan Bukin 254dee4c1d2SRuslan Bukin xlnx_pcib_handle_msi_intr(arg, XLNX_PCIE_RPMSIID2); 255dee4c1d2SRuslan Bukin 256dee4c1d2SRuslan Bukin return (FILTER_HANDLED); 257dee4c1d2SRuslan Bukin } 258dee4c1d2SRuslan Bukin 259dee4c1d2SRuslan Bukin static int 260dee4c1d2SRuslan Bukin xlnx_pcib_register_msi(struct xlnx_pcib_softc *sc) 261dee4c1d2SRuslan Bukin { 262dee4c1d2SRuslan Bukin const char *name; 263dee4c1d2SRuslan Bukin int error; 264dee4c1d2SRuslan Bukin int irq; 265dee4c1d2SRuslan Bukin 266dee4c1d2SRuslan Bukin sc->isrcs = malloc(sizeof(*sc->isrcs) * XLNX_PCIB_MAX_MSI, M_DEVBUF, 267dee4c1d2SRuslan Bukin M_WAITOK | M_ZERO); 268dee4c1d2SRuslan Bukin 269dee4c1d2SRuslan Bukin name = device_get_nameunit(sc->dev); 270dee4c1d2SRuslan Bukin 271dee4c1d2SRuslan Bukin for (irq = 0; irq < XLNX_PCIB_MAX_MSI; irq++) { 272dee4c1d2SRuslan Bukin sc->isrcs[irq].irq = irq; 273dee4c1d2SRuslan Bukin error = intr_isrc_register(&sc->isrcs[irq].isrc, 274dee4c1d2SRuslan Bukin sc->dev, 0, "%s,%u", name, irq); 275dee4c1d2SRuslan Bukin if (error != 0) 276dee4c1d2SRuslan Bukin return (error); /* XXX deregister ISRCs */ 277dee4c1d2SRuslan Bukin } 278dee4c1d2SRuslan Bukin 279dee4c1d2SRuslan Bukin if (intr_msi_register(sc->dev, 280dee4c1d2SRuslan Bukin OF_xref_from_node(ofw_bus_get_node(sc->dev))) != 0) 281dee4c1d2SRuslan Bukin return (ENXIO); 282dee4c1d2SRuslan Bukin 283dee4c1d2SRuslan Bukin return (0); 284dee4c1d2SRuslan Bukin } 285dee4c1d2SRuslan Bukin 286dee4c1d2SRuslan Bukin static void 287dee4c1d2SRuslan Bukin xlnx_pcib_init(struct xlnx_pcib_softc *sc) 288dee4c1d2SRuslan Bukin { 289dee4c1d2SRuslan Bukin bus_addr_t addr; 290dee4c1d2SRuslan Bukin int reg; 291dee4c1d2SRuslan Bukin 292dee4c1d2SRuslan Bukin /* Disable interrupts. */ 293dee4c1d2SRuslan Bukin bus_write_4(sc->res[0], XLNX_PCIE_IMR, 0); 294dee4c1d2SRuslan Bukin 295dee4c1d2SRuslan Bukin /* Clear pending interrupts.*/ 296dee4c1d2SRuslan Bukin reg = bus_read_4(sc->res[0], XLNX_PCIE_IDR); 297dee4c1d2SRuslan Bukin bus_write_4(sc->res[0], XLNX_PCIE_IDR, reg); 298dee4c1d2SRuslan Bukin 299dee4c1d2SRuslan Bukin /* Setup an MSI page. */ 300dee4c1d2SRuslan Bukin sc->msi_page = kmem_alloc_contig(PAGE_SIZE, M_WAITOK, 0, 301dee4c1d2SRuslan Bukin BUS_SPACE_MAXADDR, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT); 302dee4c1d2SRuslan Bukin addr = vtophys(sc->msi_page); 303dee4c1d2SRuslan Bukin bus_write_4(sc->res[0], XLNX_PCIE_RPMSIBR1, (addr >> 32)); 304dee4c1d2SRuslan Bukin bus_write_4(sc->res[0], XLNX_PCIE_RPMSIBR2, (addr >> 0)); 305dee4c1d2SRuslan Bukin 306dee4c1d2SRuslan Bukin /* Enable the bridge. */ 307dee4c1d2SRuslan Bukin reg = bus_read_4(sc->res[0], XLNX_PCIE_RPSCR); 308dee4c1d2SRuslan Bukin reg |= RPSCR_BE; 309dee4c1d2SRuslan Bukin bus_write_4(sc->res[0], XLNX_PCIE_RPSCR, reg); 310dee4c1d2SRuslan Bukin 311dee4c1d2SRuslan Bukin /* Enable interrupts. */ 312dee4c1d2SRuslan Bukin reg = IMR_LINK_DOWN 313dee4c1d2SRuslan Bukin | IMR_HOT_RESET 314dee4c1d2SRuslan Bukin | IMR_CFG_COMPL_STATUS_M 315dee4c1d2SRuslan Bukin | IMR_CFG_TIMEOUT 316dee4c1d2SRuslan Bukin | IMR_CORRECTABLE 317dee4c1d2SRuslan Bukin | IMR_NON_FATAL 318dee4c1d2SRuslan Bukin | IMR_FATAL 319dee4c1d2SRuslan Bukin | IMR_INTX 320dee4c1d2SRuslan Bukin | IMR_MSI 321dee4c1d2SRuslan Bukin | IMR_SLAVE_UNSUPP_REQ 322dee4c1d2SRuslan Bukin | IMR_SLAVE_UNEXP_COMPL 323dee4c1d2SRuslan Bukin | IMR_SLAVE_COMPL_TIMOUT 324dee4c1d2SRuslan Bukin | IMR_SLAVE_ERROR_POISON 325dee4c1d2SRuslan Bukin | IMR_SLAVE_COMPL_ABORT 326dee4c1d2SRuslan Bukin | IMR_SLAVE_ILLEG_BURST 327dee4c1d2SRuslan Bukin | IMR_MASTER_DECERR 328dee4c1d2SRuslan Bukin | IMR_MASTER_SLVERR; 329dee4c1d2SRuslan Bukin bus_write_4(sc->res[0], XLNX_PCIE_IMR, reg); 330dee4c1d2SRuslan Bukin } 331dee4c1d2SRuslan Bukin 332dee4c1d2SRuslan Bukin static int 333dee4c1d2SRuslan Bukin xlnx_pcib_fdt_probe(device_t dev) 334dee4c1d2SRuslan Bukin { 335dee4c1d2SRuslan Bukin 336dee4c1d2SRuslan Bukin if (!ofw_bus_status_okay(dev)) 337dee4c1d2SRuslan Bukin return (ENXIO); 338dee4c1d2SRuslan Bukin 339dee4c1d2SRuslan Bukin if (ofw_bus_is_compatible(dev, "xlnx,xdma-host-3.00")) { 340dee4c1d2SRuslan Bukin device_set_desc(dev, "Xilinx XDMA PCIe Controller"); 341dee4c1d2SRuslan Bukin return (BUS_PROBE_DEFAULT); 342dee4c1d2SRuslan Bukin } 343dee4c1d2SRuslan Bukin 344dee4c1d2SRuslan Bukin return (ENXIO); 345dee4c1d2SRuslan Bukin } 346dee4c1d2SRuslan Bukin 347dee4c1d2SRuslan Bukin static int 348dee4c1d2SRuslan Bukin xlnx_pcib_fdt_attach(device_t dev) 349dee4c1d2SRuslan Bukin { 350dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *sc; 351dee4c1d2SRuslan Bukin int error; 352dee4c1d2SRuslan Bukin 353dee4c1d2SRuslan Bukin sc = device_get_softc(dev); 354dee4c1d2SRuslan Bukin sc->dev = dev; 355dee4c1d2SRuslan Bukin 356dee4c1d2SRuslan Bukin mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF); 357dee4c1d2SRuslan Bukin 358dee4c1d2SRuslan Bukin if (bus_alloc_resources(dev, xlnx_pcib_spec, sc->res)) { 359dee4c1d2SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 360dee4c1d2SRuslan Bukin return (ENXIO); 361dee4c1d2SRuslan Bukin } 362dee4c1d2SRuslan Bukin 363dee4c1d2SRuslan Bukin /* Setup MISC interrupt handler. */ 364dee4c1d2SRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE, 365dee4c1d2SRuslan Bukin xlnx_pcib_intr, NULL, sc, &sc->intr_cookie[0]); 366dee4c1d2SRuslan Bukin if (error != 0) { 367dee4c1d2SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 368dee4c1d2SRuslan Bukin return (ENXIO); 369dee4c1d2SRuslan Bukin } 370dee4c1d2SRuslan Bukin 371dee4c1d2SRuslan Bukin /* Setup MSI0 interrupt handler. */ 372dee4c1d2SRuslan Bukin error = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE, 373dee4c1d2SRuslan Bukin xlnx_pcib_msi0_intr, NULL, sc, &sc->intr_cookie[1]); 374dee4c1d2SRuslan Bukin if (error != 0) { 375dee4c1d2SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 376dee4c1d2SRuslan Bukin return (ENXIO); 377dee4c1d2SRuslan Bukin } 378dee4c1d2SRuslan Bukin 379dee4c1d2SRuslan Bukin /* Setup MSI1 interrupt handler. */ 380dee4c1d2SRuslan Bukin error = bus_setup_intr(dev, sc->res[3], INTR_TYPE_MISC | INTR_MPSAFE, 381dee4c1d2SRuslan Bukin xlnx_pcib_msi1_intr, NULL, sc, &sc->intr_cookie[2]); 382dee4c1d2SRuslan Bukin if (error != 0) { 383dee4c1d2SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 384dee4c1d2SRuslan Bukin return (ENXIO); 385dee4c1d2SRuslan Bukin } 386dee4c1d2SRuslan Bukin 387dee4c1d2SRuslan Bukin xlnx_pcib_init(sc); 388dee4c1d2SRuslan Bukin 389dee4c1d2SRuslan Bukin /* 390dee4c1d2SRuslan Bukin * Allow the core driver to map registers. 391dee4c1d2SRuslan Bukin * We will be accessing the device memory using core_softc. 392dee4c1d2SRuslan Bukin */ 393dee4c1d2SRuslan Bukin bus_release_resources(dev, xlnx_pcib_spec, sc->res); 394dee4c1d2SRuslan Bukin 395dee4c1d2SRuslan Bukin error = xlnx_pcib_register_msi(sc); 396dee4c1d2SRuslan Bukin if (error) 397dee4c1d2SRuslan Bukin return (error); 398dee4c1d2SRuslan Bukin 399*ad52fba1SAndrew Turner return (pci_host_generic_fdt_attach(dev)); 400dee4c1d2SRuslan Bukin } 401dee4c1d2SRuslan Bukin 402dee4c1d2SRuslan Bukin static int 403dee4c1d2SRuslan Bukin xlnx_pcib_fdt_get_id(device_t pci, device_t child, enum pci_id_type type, 404dee4c1d2SRuslan Bukin uintptr_t *id) 405dee4c1d2SRuslan Bukin { 406dee4c1d2SRuslan Bukin phandle_t node; 407dee4c1d2SRuslan Bukin int bsf; 408dee4c1d2SRuslan Bukin 409dee4c1d2SRuslan Bukin if (type != PCI_ID_MSI) 410dee4c1d2SRuslan Bukin return (pcib_get_id(pci, child, type, id)); 411dee4c1d2SRuslan Bukin 412dee4c1d2SRuslan Bukin node = ofw_bus_get_node(pci); 413dee4c1d2SRuslan Bukin if (OF_hasprop(node, "msi-map")) 414dee4c1d2SRuslan Bukin return (generic_pcie_get_id(pci, child, type, id)); 415dee4c1d2SRuslan Bukin 416dee4c1d2SRuslan Bukin bsf = pci_get_rid(child); 417dee4c1d2SRuslan Bukin *id = (pci_get_domain(child) << PCI_RID_DOMAIN_SHIFT) | bsf; 418dee4c1d2SRuslan Bukin 419dee4c1d2SRuslan Bukin return (0); 420dee4c1d2SRuslan Bukin } 421dee4c1d2SRuslan Bukin 422dee4c1d2SRuslan Bukin static int 423dee4c1d2SRuslan Bukin xlnx_pcib_req_valid(struct generic_pcie_core_softc *sc, 424dee4c1d2SRuslan Bukin u_int bus, u_int slot, u_int func, u_int reg) 425dee4c1d2SRuslan Bukin { 426dee4c1d2SRuslan Bukin bus_space_handle_t h; 427dee4c1d2SRuslan Bukin bus_space_tag_t t; 428dee4c1d2SRuslan Bukin uint32_t val; 429dee4c1d2SRuslan Bukin 430dee4c1d2SRuslan Bukin t = sc->bst; 431dee4c1d2SRuslan Bukin h = sc->bsh; 432dee4c1d2SRuslan Bukin 433dee4c1d2SRuslan Bukin if ((bus < sc->bus_start) || (bus > sc->bus_end)) 434dee4c1d2SRuslan Bukin return (0); 435dee4c1d2SRuslan Bukin if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || 436dee4c1d2SRuslan Bukin (reg > PCIE_REGMAX)) 437dee4c1d2SRuslan Bukin return (0); 438dee4c1d2SRuslan Bukin 439dee4c1d2SRuslan Bukin if (bus == 0 && slot > 0) 440dee4c1d2SRuslan Bukin return (0); 441dee4c1d2SRuslan Bukin 442dee4c1d2SRuslan Bukin val = bus_space_read_4(t, h, XLNX_PCIE_PHYSCR); 443dee4c1d2SRuslan Bukin if ((val & PHYSCR_LINK_UP) == 0) { 444dee4c1d2SRuslan Bukin /* Link is down */ 445dee4c1d2SRuslan Bukin return (0); 446dee4c1d2SRuslan Bukin } 447dee4c1d2SRuslan Bukin 448dee4c1d2SRuslan Bukin /* Valid */ 449dee4c1d2SRuslan Bukin 450dee4c1d2SRuslan Bukin return (1); 451dee4c1d2SRuslan Bukin } 452dee4c1d2SRuslan Bukin 453dee4c1d2SRuslan Bukin static uint32_t 454dee4c1d2SRuslan Bukin xlnx_pcib_read_config(device_t dev, u_int bus, u_int slot, 455dee4c1d2SRuslan Bukin u_int func, u_int reg, int bytes) 456dee4c1d2SRuslan Bukin { 457dee4c1d2SRuslan Bukin struct generic_pcie_fdt_softc *fdt_sc; 458dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *xlnx_sc; 459dee4c1d2SRuslan Bukin struct generic_pcie_core_softc *sc; 460dee4c1d2SRuslan Bukin bus_space_handle_t h; 461dee4c1d2SRuslan Bukin bus_space_tag_t t; 462dee4c1d2SRuslan Bukin uint64_t offset; 463dee4c1d2SRuslan Bukin uint32_t data; 464dee4c1d2SRuslan Bukin 465dee4c1d2SRuslan Bukin xlnx_sc = device_get_softc(dev); 466dee4c1d2SRuslan Bukin fdt_sc = &xlnx_sc->fdt_sc; 467dee4c1d2SRuslan Bukin sc = &fdt_sc->base; 468dee4c1d2SRuslan Bukin 469dee4c1d2SRuslan Bukin if (!xlnx_pcib_req_valid(sc, bus, slot, func, reg)) 470dee4c1d2SRuslan Bukin return (~0U); 471dee4c1d2SRuslan Bukin 472dee4c1d2SRuslan Bukin offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg); 473dee4c1d2SRuslan Bukin t = sc->bst; 474dee4c1d2SRuslan Bukin h = sc->bsh; 475dee4c1d2SRuslan Bukin 476dee4c1d2SRuslan Bukin data = bus_space_read_4(t, h, offset & ~3); 477dee4c1d2SRuslan Bukin 478dee4c1d2SRuslan Bukin switch (bytes) { 479dee4c1d2SRuslan Bukin case 1: 480dee4c1d2SRuslan Bukin data >>= (offset & 3) * 8; 481dee4c1d2SRuslan Bukin data &= 0xff; 482dee4c1d2SRuslan Bukin break; 483dee4c1d2SRuslan Bukin case 2: 484dee4c1d2SRuslan Bukin data >>= (offset & 3) * 8; 485dee4c1d2SRuslan Bukin data = le16toh(data); 486dee4c1d2SRuslan Bukin break; 487dee4c1d2SRuslan Bukin case 4: 488dee4c1d2SRuslan Bukin data = le32toh(data); 489dee4c1d2SRuslan Bukin break; 490dee4c1d2SRuslan Bukin default: 491dee4c1d2SRuslan Bukin return (~0U); 492dee4c1d2SRuslan Bukin } 493dee4c1d2SRuslan Bukin 494dee4c1d2SRuslan Bukin return (data); 495dee4c1d2SRuslan Bukin } 496dee4c1d2SRuslan Bukin 497dee4c1d2SRuslan Bukin static void 498dee4c1d2SRuslan Bukin xlnx_pcib_write_config(device_t dev, u_int bus, u_int slot, 499dee4c1d2SRuslan Bukin u_int func, u_int reg, uint32_t val, int bytes) 500dee4c1d2SRuslan Bukin { 501dee4c1d2SRuslan Bukin struct generic_pcie_fdt_softc *fdt_sc; 502dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *xlnx_sc; 503dee4c1d2SRuslan Bukin struct generic_pcie_core_softc *sc; 504dee4c1d2SRuslan Bukin bus_space_handle_t h; 505dee4c1d2SRuslan Bukin bus_space_tag_t t; 506dee4c1d2SRuslan Bukin uint64_t offset; 507dee4c1d2SRuslan Bukin uint32_t data; 508dee4c1d2SRuslan Bukin 509dee4c1d2SRuslan Bukin xlnx_sc = device_get_softc(dev); 510dee4c1d2SRuslan Bukin fdt_sc = &xlnx_sc->fdt_sc; 511dee4c1d2SRuslan Bukin sc = &fdt_sc->base; 512dee4c1d2SRuslan Bukin 513dee4c1d2SRuslan Bukin if (!xlnx_pcib_req_valid(sc, bus, slot, func, reg)) 514dee4c1d2SRuslan Bukin return; 515dee4c1d2SRuslan Bukin 516dee4c1d2SRuslan Bukin offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg); 517dee4c1d2SRuslan Bukin 518dee4c1d2SRuslan Bukin t = sc->bst; 519dee4c1d2SRuslan Bukin h = sc->bsh; 520dee4c1d2SRuslan Bukin 521dee4c1d2SRuslan Bukin /* 522dee4c1d2SRuslan Bukin * 32-bit access used due to a bug in the Xilinx bridge that 523dee4c1d2SRuslan Bukin * requires to write primary and secondary buses in one blast. 524dee4c1d2SRuslan Bukin * 525dee4c1d2SRuslan Bukin * TODO: This is probably wrong on big-endian. 526dee4c1d2SRuslan Bukin */ 527dee4c1d2SRuslan Bukin switch (bytes) { 528dee4c1d2SRuslan Bukin case 1: 529dee4c1d2SRuslan Bukin data = bus_space_read_4(t, h, offset & ~3); 530dee4c1d2SRuslan Bukin data &= ~(0xff << ((offset & 3) * 8)); 531dee4c1d2SRuslan Bukin data |= (val & 0xff) << ((offset & 3) * 8); 532dee4c1d2SRuslan Bukin bus_space_write_4(t, h, offset & ~3, htole32(data)); 533dee4c1d2SRuslan Bukin break; 534dee4c1d2SRuslan Bukin case 2: 535dee4c1d2SRuslan Bukin data = bus_space_read_4(t, h, offset & ~3); 536dee4c1d2SRuslan Bukin data &= ~(0xffff << ((offset & 3) * 8)); 537dee4c1d2SRuslan Bukin data |= (val & 0xffff) << ((offset & 3) * 8); 538dee4c1d2SRuslan Bukin bus_space_write_4(t, h, offset & ~3, htole32(data)); 539dee4c1d2SRuslan Bukin break; 540dee4c1d2SRuslan Bukin case 4: 541dee4c1d2SRuslan Bukin bus_space_write_4(t, h, offset, htole32(val)); 542dee4c1d2SRuslan Bukin break; 543dee4c1d2SRuslan Bukin default: 544dee4c1d2SRuslan Bukin return; 545dee4c1d2SRuslan Bukin } 546dee4c1d2SRuslan Bukin } 547dee4c1d2SRuslan Bukin 548dee4c1d2SRuslan Bukin static int 549dee4c1d2SRuslan Bukin xlnx_pcib_alloc_msi(device_t pci, device_t child, int count, int maxcount, 550dee4c1d2SRuslan Bukin int *irqs) 551dee4c1d2SRuslan Bukin { 552dee4c1d2SRuslan Bukin phandle_t msi_parent; 553dee4c1d2SRuslan Bukin 554dee4c1d2SRuslan Bukin ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 555dee4c1d2SRuslan Bukin NULL); 556dee4c1d2SRuslan Bukin msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); 557dee4c1d2SRuslan Bukin return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, 558dee4c1d2SRuslan Bukin irqs)); 559dee4c1d2SRuslan Bukin } 560dee4c1d2SRuslan Bukin 561dee4c1d2SRuslan Bukin static int 562dee4c1d2SRuslan Bukin xlnx_pcib_release_msi(device_t pci, device_t child, int count, int *irqs) 563dee4c1d2SRuslan Bukin { 564dee4c1d2SRuslan Bukin phandle_t msi_parent; 565dee4c1d2SRuslan Bukin 566dee4c1d2SRuslan Bukin ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 567dee4c1d2SRuslan Bukin NULL); 568dee4c1d2SRuslan Bukin msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); 569dee4c1d2SRuslan Bukin return (intr_release_msi(pci, child, msi_parent, count, irqs)); 570dee4c1d2SRuslan Bukin } 571dee4c1d2SRuslan Bukin 572dee4c1d2SRuslan Bukin static int 573dee4c1d2SRuslan Bukin xlnx_pcib_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, 574dee4c1d2SRuslan Bukin uint32_t *data) 575dee4c1d2SRuslan Bukin { 576dee4c1d2SRuslan Bukin phandle_t msi_parent; 577dee4c1d2SRuslan Bukin 578dee4c1d2SRuslan Bukin ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, 579dee4c1d2SRuslan Bukin NULL); 580dee4c1d2SRuslan Bukin msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); 581dee4c1d2SRuslan Bukin return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); 582dee4c1d2SRuslan Bukin } 583dee4c1d2SRuslan Bukin 584dee4c1d2SRuslan Bukin static int 585dee4c1d2SRuslan Bukin xlnx_pcib_msi_alloc_msi(device_t dev, device_t child, int count, int maxcount, 586dee4c1d2SRuslan Bukin device_t *pic, struct intr_irqsrc **srcs) 587dee4c1d2SRuslan Bukin { 588dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *sc; 589dee4c1d2SRuslan Bukin int irq, end_irq, i; 590dee4c1d2SRuslan Bukin bool found; 591dee4c1d2SRuslan Bukin 592dee4c1d2SRuslan Bukin sc = device_get_softc(dev); 593dee4c1d2SRuslan Bukin 594dee4c1d2SRuslan Bukin mtx_lock(&sc->mtx); 595dee4c1d2SRuslan Bukin 596dee4c1d2SRuslan Bukin found = false; 597dee4c1d2SRuslan Bukin 598dee4c1d2SRuslan Bukin for (irq = 0; (irq + count - 1) < XLNX_PCIB_MAX_MSI; irq++) { 599dee4c1d2SRuslan Bukin /* Assume the range is valid. */ 600dee4c1d2SRuslan Bukin found = true; 601dee4c1d2SRuslan Bukin 602dee4c1d2SRuslan Bukin /* Check this range is valid. */ 603dee4c1d2SRuslan Bukin for (end_irq = irq; end_irq < irq + count; end_irq++) { 604dee4c1d2SRuslan Bukin if (sc->isrcs[end_irq].flags & XLNX_IRQ_FLAG_USED) { 605dee4c1d2SRuslan Bukin /* This is already used. */ 606dee4c1d2SRuslan Bukin found = false; 607dee4c1d2SRuslan Bukin break; 608dee4c1d2SRuslan Bukin } 609dee4c1d2SRuslan Bukin } 610dee4c1d2SRuslan Bukin 611dee4c1d2SRuslan Bukin if (found) 612dee4c1d2SRuslan Bukin break; 613dee4c1d2SRuslan Bukin } 614dee4c1d2SRuslan Bukin 615dee4c1d2SRuslan Bukin if (!found || irq == (XLNX_PCIB_MAX_MSI - 1)) { 616dee4c1d2SRuslan Bukin /* Not enough interrupts were found. */ 617dee4c1d2SRuslan Bukin mtx_unlock(&sc->mtx); 618dee4c1d2SRuslan Bukin return (ENXIO); 619dee4c1d2SRuslan Bukin } 620dee4c1d2SRuslan Bukin 621dee4c1d2SRuslan Bukin /* Mark the interrupt as used. */ 622dee4c1d2SRuslan Bukin for (i = 0; i < count; i++) 623dee4c1d2SRuslan Bukin sc->isrcs[irq + i].flags |= XLNX_IRQ_FLAG_USED; 624dee4c1d2SRuslan Bukin 625dee4c1d2SRuslan Bukin mtx_unlock(&sc->mtx); 626dee4c1d2SRuslan Bukin 627dee4c1d2SRuslan Bukin for (i = 0; i < count; i++) 628dee4c1d2SRuslan Bukin srcs[i] = (struct intr_irqsrc *)&sc->isrcs[irq + i]; 629dee4c1d2SRuslan Bukin 630dee4c1d2SRuslan Bukin *pic = device_get_parent(dev); 631dee4c1d2SRuslan Bukin 632dee4c1d2SRuslan Bukin return (0); 633dee4c1d2SRuslan Bukin } 634dee4c1d2SRuslan Bukin 635dee4c1d2SRuslan Bukin static int 636dee4c1d2SRuslan Bukin xlnx_pcib_msi_release_msi(device_t dev, device_t child, int count, 637dee4c1d2SRuslan Bukin struct intr_irqsrc **isrc) 638dee4c1d2SRuslan Bukin { 639dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *sc; 640dee4c1d2SRuslan Bukin struct xlnx_pcib_irqsrc *xi; 641dee4c1d2SRuslan Bukin int i; 642dee4c1d2SRuslan Bukin 643dee4c1d2SRuslan Bukin sc = device_get_softc(dev); 644dee4c1d2SRuslan Bukin mtx_lock(&sc->mtx); 645dee4c1d2SRuslan Bukin for (i = 0; i < count; i++) { 646dee4c1d2SRuslan Bukin xi = (struct xlnx_pcib_irqsrc *)isrc[i]; 647dee4c1d2SRuslan Bukin 648dee4c1d2SRuslan Bukin KASSERT(xi->flags & XLNX_IRQ_FLAG_USED, 649dee4c1d2SRuslan Bukin ("%s: Releasing an unused MSI interrupt", __func__)); 650dee4c1d2SRuslan Bukin 651dee4c1d2SRuslan Bukin xi->flags &= ~XLNX_IRQ_FLAG_USED; 652dee4c1d2SRuslan Bukin } 653dee4c1d2SRuslan Bukin 654dee4c1d2SRuslan Bukin mtx_unlock(&sc->mtx); 655dee4c1d2SRuslan Bukin return (0); 656dee4c1d2SRuslan Bukin } 657dee4c1d2SRuslan Bukin 658dee4c1d2SRuslan Bukin static int 659dee4c1d2SRuslan Bukin xlnx_pcib_msi_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, 660dee4c1d2SRuslan Bukin uint64_t *addr, uint32_t *data) 661dee4c1d2SRuslan Bukin { 662dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *sc; 663dee4c1d2SRuslan Bukin struct xlnx_pcib_irqsrc *xi; 664dee4c1d2SRuslan Bukin 665dee4c1d2SRuslan Bukin sc = device_get_softc(dev); 666dee4c1d2SRuslan Bukin xi = (struct xlnx_pcib_irqsrc *)isrc; 667dee4c1d2SRuslan Bukin 668dee4c1d2SRuslan Bukin *addr = vtophys(sc->msi_page); 669dee4c1d2SRuslan Bukin *data = xi->irq; 670dee4c1d2SRuslan Bukin 671dee4c1d2SRuslan Bukin return (0); 672dee4c1d2SRuslan Bukin } 673dee4c1d2SRuslan Bukin 674dee4c1d2SRuslan Bukin static void 675dee4c1d2SRuslan Bukin xlnx_pcib_msi_mask(device_t dev, struct intr_irqsrc *isrc, bool mask) 676dee4c1d2SRuslan Bukin { 677dee4c1d2SRuslan Bukin struct generic_pcie_fdt_softc *fdt_sc; 678dee4c1d2SRuslan Bukin struct generic_pcie_core_softc *sc; 679dee4c1d2SRuslan Bukin struct xlnx_pcib_softc *xlnx_sc; 680dee4c1d2SRuslan Bukin struct xlnx_pcib_irqsrc *xi; 681dee4c1d2SRuslan Bukin uint32_t msireg, irq; 682dee4c1d2SRuslan Bukin uint32_t reg; 683dee4c1d2SRuslan Bukin 684dee4c1d2SRuslan Bukin xlnx_sc = device_get_softc(dev); 685dee4c1d2SRuslan Bukin fdt_sc = &xlnx_sc->fdt_sc; 686dee4c1d2SRuslan Bukin sc = &fdt_sc->base; 687dee4c1d2SRuslan Bukin 688dee4c1d2SRuslan Bukin xi = (struct xlnx_pcib_irqsrc *)isrc; 689dee4c1d2SRuslan Bukin 690dee4c1d2SRuslan Bukin irq = xi->irq; 691dee4c1d2SRuslan Bukin if (irq < 32) 692dee4c1d2SRuslan Bukin msireg = XLNX_PCIE_RPMSIID1_MASK; 693dee4c1d2SRuslan Bukin else 694dee4c1d2SRuslan Bukin msireg = XLNX_PCIE_RPMSIID2_MASK; 695dee4c1d2SRuslan Bukin 696dee4c1d2SRuslan Bukin reg = bus_read_4(sc->res, msireg); 697dee4c1d2SRuslan Bukin if (mask) 698dee4c1d2SRuslan Bukin reg &= ~(1 << irq); 699dee4c1d2SRuslan Bukin else 700dee4c1d2SRuslan Bukin reg |= (1 << irq); 701dee4c1d2SRuslan Bukin bus_write_4(sc->res, msireg, reg); 702dee4c1d2SRuslan Bukin } 703dee4c1d2SRuslan Bukin 704dee4c1d2SRuslan Bukin static void 705dee4c1d2SRuslan Bukin xlnx_pcib_msi_disable_intr(device_t dev, struct intr_irqsrc *isrc) 706dee4c1d2SRuslan Bukin { 707dee4c1d2SRuslan Bukin 708dee4c1d2SRuslan Bukin xlnx_pcib_msi_mask(dev, isrc, true); 709dee4c1d2SRuslan Bukin } 710dee4c1d2SRuslan Bukin 711dee4c1d2SRuslan Bukin static void 712dee4c1d2SRuslan Bukin xlnx_pcib_msi_enable_intr(device_t dev, struct intr_irqsrc *isrc) 713dee4c1d2SRuslan Bukin { 714dee4c1d2SRuslan Bukin 715dee4c1d2SRuslan Bukin xlnx_pcib_msi_mask(dev, isrc, false); 716dee4c1d2SRuslan Bukin } 717dee4c1d2SRuslan Bukin 718dee4c1d2SRuslan Bukin static void 719dee4c1d2SRuslan Bukin xlnx_pcib_msi_post_filter(device_t dev, struct intr_irqsrc *isrc) 720dee4c1d2SRuslan Bukin { 721dee4c1d2SRuslan Bukin 722dee4c1d2SRuslan Bukin } 723dee4c1d2SRuslan Bukin 724dee4c1d2SRuslan Bukin static void 725dee4c1d2SRuslan Bukin xlnx_pcib_msi_post_ithread(device_t dev, struct intr_irqsrc *isrc) 726dee4c1d2SRuslan Bukin { 727dee4c1d2SRuslan Bukin 728dee4c1d2SRuslan Bukin xlnx_pcib_msi_mask(dev, isrc, false); 729dee4c1d2SRuslan Bukin } 730dee4c1d2SRuslan Bukin 731dee4c1d2SRuslan Bukin static void 732dee4c1d2SRuslan Bukin xlnx_pcib_msi_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 733dee4c1d2SRuslan Bukin { 734dee4c1d2SRuslan Bukin 735dee4c1d2SRuslan Bukin xlnx_pcib_msi_mask(dev, isrc, true); 736dee4c1d2SRuslan Bukin } 737dee4c1d2SRuslan Bukin 738dee4c1d2SRuslan Bukin static int 739dee4c1d2SRuslan Bukin xlnx_pcib_msi_setup_intr(device_t dev, struct intr_irqsrc *isrc, 740dee4c1d2SRuslan Bukin struct resource *res, struct intr_map_data *data) 741dee4c1d2SRuslan Bukin { 742dee4c1d2SRuslan Bukin 743dee4c1d2SRuslan Bukin return (0); 744dee4c1d2SRuslan Bukin } 745dee4c1d2SRuslan Bukin 746dee4c1d2SRuslan Bukin static int 747dee4c1d2SRuslan Bukin xlnx_pcib_msi_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 748dee4c1d2SRuslan Bukin struct resource *res, struct intr_map_data *data) 749dee4c1d2SRuslan Bukin { 750dee4c1d2SRuslan Bukin 751dee4c1d2SRuslan Bukin return (0); 752dee4c1d2SRuslan Bukin } 753dee4c1d2SRuslan Bukin 754dee4c1d2SRuslan Bukin static device_method_t xlnx_pcib_fdt_methods[] = { 755dee4c1d2SRuslan Bukin /* Device interface */ 756dee4c1d2SRuslan Bukin DEVMETHOD(device_probe, xlnx_pcib_fdt_probe), 757dee4c1d2SRuslan Bukin DEVMETHOD(device_attach, xlnx_pcib_fdt_attach), 758dee4c1d2SRuslan Bukin 759dee4c1d2SRuslan Bukin /* pcib interface */ 760dee4c1d2SRuslan Bukin DEVMETHOD(pcib_get_id, xlnx_pcib_fdt_get_id), 761dee4c1d2SRuslan Bukin DEVMETHOD(pcib_read_config, xlnx_pcib_read_config), 762dee4c1d2SRuslan Bukin DEVMETHOD(pcib_write_config, xlnx_pcib_write_config), 763dee4c1d2SRuslan Bukin DEVMETHOD(pcib_alloc_msi, xlnx_pcib_alloc_msi), 764dee4c1d2SRuslan Bukin DEVMETHOD(pcib_release_msi, xlnx_pcib_release_msi), 765dee4c1d2SRuslan Bukin DEVMETHOD(pcib_map_msi, xlnx_pcib_map_msi), 766dee4c1d2SRuslan Bukin 767dee4c1d2SRuslan Bukin /* MSI interface */ 768dee4c1d2SRuslan Bukin DEVMETHOD(msi_alloc_msi, xlnx_pcib_msi_alloc_msi), 769dee4c1d2SRuslan Bukin DEVMETHOD(msi_release_msi, xlnx_pcib_msi_release_msi), 770dee4c1d2SRuslan Bukin DEVMETHOD(msi_map_msi, xlnx_pcib_msi_map_msi), 771dee4c1d2SRuslan Bukin 772dee4c1d2SRuslan Bukin /* Interrupt controller interface */ 773dee4c1d2SRuslan Bukin DEVMETHOD(pic_disable_intr, xlnx_pcib_msi_disable_intr), 774dee4c1d2SRuslan Bukin DEVMETHOD(pic_enable_intr, xlnx_pcib_msi_enable_intr), 775dee4c1d2SRuslan Bukin DEVMETHOD(pic_setup_intr, xlnx_pcib_msi_setup_intr), 776dee4c1d2SRuslan Bukin DEVMETHOD(pic_teardown_intr, xlnx_pcib_msi_teardown_intr), 777dee4c1d2SRuslan Bukin DEVMETHOD(pic_post_filter, xlnx_pcib_msi_post_filter), 778dee4c1d2SRuslan Bukin DEVMETHOD(pic_post_ithread, xlnx_pcib_msi_post_ithread), 779dee4c1d2SRuslan Bukin DEVMETHOD(pic_pre_ithread, xlnx_pcib_msi_pre_ithread), 780dee4c1d2SRuslan Bukin 781dee4c1d2SRuslan Bukin /* End */ 782dee4c1d2SRuslan Bukin DEVMETHOD_END 783dee4c1d2SRuslan Bukin }; 784dee4c1d2SRuslan Bukin 785dee4c1d2SRuslan Bukin DEFINE_CLASS_1(pcib, xlnx_pcib_fdt_driver, xlnx_pcib_fdt_methods, 786dee4c1d2SRuslan Bukin sizeof(struct xlnx_pcib_softc), generic_pcie_fdt_driver); 787dee4c1d2SRuslan Bukin 78890b8b224SJohn Baldwin DRIVER_MODULE(xlnx_pcib, simplebus, xlnx_pcib_fdt_driver, 0, 0); 78990b8b224SJohn Baldwin DRIVER_MODULE(xlnx_pcib, ofwbus, xlnx_pcib_fdt_driver, 0, 0); 790