Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108273529
D23337.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
D23337.diff
View Options
Index: head/sys/conf/files.riscv
===================================================================
--- head/sys/conf/files.riscv
+++ head/sys/conf/files.riscv
@@ -14,6 +14,7 @@
dev/xilinx/axi_quad_spi.c optional xilinx_spi
dev/xilinx/axidma.c optional axidma xdma
dev/xilinx/if_xae.c optional xae
+dev/xilinx/xlnx_pcib.c optional pci fdt xlnx_pcib
kern/kern_clocksource.c standard
kern/msi_if.m standard
kern/pic_if.m standard
Index: head/sys/dev/xilinx/xlnx_pcib.h
===================================================================
--- head/sys/dev/xilinx/xlnx_pcib.h
+++ head/sys/dev/xilinx/xlnx_pcib.h
@@ -0,0 +1,84 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory (Department of Computer Science and
+ * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
+ * DARPA SSITH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_XILINX_XLNX_PCIB_H_
+#define _DEV_XILINX_XLNX_PCIB_H_
+
+#define XLNX_PCIE_VSEC 0x12c
+#define XLNX_PCIE_BIR 0x130 /* Bridge Info Register */
+#define XLNX_PCIE_BSCR 0x134 /* Bridge Status and Control */
+#define XLNX_PCIE_IDR 0x138 /* Interrupt Decode Register */
+#define XLNX_PCIE_IMR 0x13C /* Interrupt Mask Register */
+#define IMR_LINK_DOWN (1 << 0)
+#define IMR_HOT_RESET (1 << 3)
+#define IMR_CFG_COMPL_STATUS_S 5
+#define IMR_CFG_COMPL_STATUS_M (0x7 << IMR_CFG_COMPL_STATUS_S)
+#define IMR_CFG_TIMEOUT (1 << 8)
+#define IMR_CORRECTABLE (1 << 9)
+#define IMR_NON_FATAL (1 << 10)
+#define IMR_FATAL (1 << 11)
+#define IMR_INTX (1 << 16) /* INTx Interrupt Received */
+#define IMR_MSI (1 << 17) /* MSI Interrupt Received */
+#define IMR_SLAVE_UNSUPP_REQ (1 << 20)
+#define IMR_SLAVE_UNEXP_COMPL (1 << 21)
+#define IMR_SLAVE_COMPL_TIMOUT (1 << 22)
+#define IMR_SLAVE_ERROR_POISON (1 << 23)
+#define IMR_SLAVE_COMPL_ABORT (1 << 24)
+#define IMR_SLAVE_ILLEG_BURST (1 << 25)
+#define IMR_MASTER_DECERR (1 << 26)
+#define IMR_MASTER_SLVERR (1 << 27)
+#define XLNX_PCIE_BLR 0x140 /* Bus Location Register */
+#define XLNX_PCIE_PHYSCR 0x144 /* PHY Status/Control Register */
+#define PHYSCR_LINK_UP (1 << 11) /* Current PHY Link-up state */
+#define XLNX_PCIE_RPSCR 0x148 /* Root Port Status/Control Register */
+#define RPSCR_BE (1 << 0) /* Bridge Enable */
+#define XLNX_PCIE_RPMSIBR1 0x14C /* Root Port MSI Base Register 1 */
+#define XLNX_PCIE_RPMSIBR2 0x150 /* Root Port MSI Base Register 2 */
+#define XLNX_PCIE_RPERRFRR 0x154 /* Root Port Error FIFO Read */
+#define RPERRFRR_VALID (1 << 18) /* Indicates whether read succeeded.*/
+#define RPERRFRR_REQ_ID_S 0 /* Requester of the error message. */
+#define RPERRFRR_REQ_ID_M (0xffff << RPERRFRR_REQ_ID_S)
+#define XLNX_PCIE_RPIFRR1 0x158 /* Root Port Interrupt FIFO Read 1 */
+#define XLNX_PCIE_RPIFRR2 0x15C /* Root Port Interrupt FIFO Read 2 */
+#define XLNX_PCIE_RPID2 0x160 /* Root Port Interrupt Decode 2 */
+#define XLNX_PCIE_RPID2_MASK 0x164 /* Root Port Interrupt Decode 2 Mask */
+#define XLNX_PCIE_RPMSIID1 0x170 /* Root Port MSI Interrupt Decode 1 */
+#define XLNX_PCIE_RPMSIID2 0x174 /* Root Port MSI Interrupt Decode 2 */
+#define XLNX_PCIE_RPMSIID1_MASK 0x178 /* Root Port MSI Int. Decode 1 Mask */
+#define XLNX_PCIE_RPMSIID2_MASK 0x17C /* Root Port MSI Int. Decode 2 Mask */
+#define XLNX_PCIE_CCR 0x168 /* Configuration Control Register */
+#define XLNX_PCIE_VSEC_CR 0x200 /* VSEC Capability Register 2 */
+#define XLNX_PCIE_VSEC_HR 0x204 /* VSEC Header Register 2 */
+
+#endif /* !_DEV_XILINX_XLNX_PCIB_H_ */
Index: head/sys/dev/xilinx/xlnx_pcib.c
===================================================================
--- head/sys/dev/xilinx/xlnx_pcib.c
+++ head/sys/dev/xilinx/xlnx_pcib.c
@@ -0,0 +1,794 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory (Department of Computer Science and
+ * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
+ * DARPA SSITH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/cpuset.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_host_generic.h>
+#include <dev/pci/pci_host_generic_fdt.h>
+#include <dev/pci/pcib_private.h>
+
+#include "xlnx_pcib.h"
+
+#include "ofw_bus_if.h"
+#include "msi_if.h"
+#include "pcib_if.h"
+#include "pic_if.h"
+
+#define XLNX_PCIB_MAX_MSI 64
+
+static int xlnx_pcib_fdt_attach(device_t);
+static int xlnx_pcib_fdt_probe(device_t);
+static int xlnx_pcib_fdt_get_id(device_t, device_t, enum pci_id_type,
+ uintptr_t *);
+static void xlnx_pcib_msi_mask(device_t dev, struct intr_irqsrc *isrc,
+ bool mask);
+
+struct xlnx_pcib_softc {
+ struct generic_pcie_fdt_softc fdt_sc;
+ struct resource *res[4];
+ struct mtx mtx;
+ vm_offset_t msi_page;
+ struct xlnx_pcib_irqsrc *isrcs;
+ device_t dev;
+ void *intr_cookie[3];
+};
+
+static struct resource_spec xlnx_pcib_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE },
+ { -1, 0 }
+};
+
+struct xlnx_pcib_irqsrc {
+ struct intr_irqsrc isrc;
+ u_int irq;
+#define XLNX_IRQ_FLAG_USED (1 << 0)
+ u_int flags;
+};
+
+static void
+xlnx_pcib_clear_err_interrupts(struct generic_pcie_core_softc *sc)
+{
+ uint32_t reg;
+
+ reg = bus_read_4(sc->res, XLNX_PCIE_RPERRFRR);
+
+ if (reg & RPERRFRR_VALID) {
+ device_printf(sc->dev, "Requested ID: %x\n",
+ reg & RPERRFRR_REQ_ID_M);
+ bus_write_4(sc->res, XLNX_PCIE_RPERRFRR, ~0U);
+ }
+}
+
+static int
+xlnx_pcib_intr(void *arg)
+{
+ struct generic_pcie_fdt_softc *fdt_sc;
+ struct generic_pcie_core_softc *sc;
+ struct xlnx_pcib_softc *xlnx_sc;
+ uint32_t val, mask, status;
+
+ xlnx_sc = arg;
+ fdt_sc = &xlnx_sc->fdt_sc;
+ sc = &fdt_sc->base;
+
+ val = bus_read_4(sc->res, XLNX_PCIE_IDR);
+ mask = bus_read_4(sc->res, XLNX_PCIE_IMR);
+
+ status = val & mask;
+ if (!status)
+ return (FILTER_HANDLED);
+
+ if (status & IMR_LINK_DOWN)
+ device_printf(sc->dev, "Link down");
+
+ if (status & IMR_HOT_RESET)
+ device_printf(sc->dev, "Hot reset");
+
+ if (status & IMR_CORRECTABLE)
+ xlnx_pcib_clear_err_interrupts(sc);
+
+ if (status & IMR_FATAL)
+ xlnx_pcib_clear_err_interrupts(sc);
+
+ if (status & IMR_NON_FATAL)
+ xlnx_pcib_clear_err_interrupts(sc);
+
+ if (status & IMR_MSI) {
+ device_printf(sc->dev, "MSI interrupt");
+
+ /* FIFO mode MSI not implemented. */
+ }
+
+ if (status & IMR_INTX) {
+ device_printf(sc->dev, "INTx received");
+
+ /* Not implemented. */
+ }
+
+ if (status & IMR_SLAVE_UNSUPP_REQ)
+ device_printf(sc->dev, "Slave unsupported request");
+
+ if (status & IMR_SLAVE_UNEXP_COMPL)
+ device_printf(sc->dev, "Slave unexpected completion");
+
+ if (status & IMR_SLAVE_COMPL_TIMOUT)
+ device_printf(sc->dev, "Slave completion timeout");
+
+ if (status & IMR_SLAVE_ERROR_POISON)
+ device_printf(sc->dev, "Slave error poison");
+
+ if (status & IMR_SLAVE_COMPL_ABORT)
+ device_printf(sc->dev, "Slave completion abort");
+
+ if (status & IMR_SLAVE_ILLEG_BURST)
+ device_printf(sc->dev, "Slave illegal burst");
+
+ if (status & IMR_MASTER_DECERR)
+ device_printf(sc->dev, "Master decode error");
+
+ if (status & IMR_MASTER_SLVERR)
+ device_printf(sc->dev, "Master slave error");
+
+ bus_write_4(sc->res, XLNX_PCIE_IDR, val);
+
+ return (FILTER_HANDLED);
+}
+
+static void
+xlnx_pcib_handle_msi_intr(void *arg, int msireg)
+{
+ struct generic_pcie_fdt_softc *fdt_sc;
+ struct generic_pcie_core_softc *sc;
+ struct xlnx_pcib_softc *xlnx_sc;
+ struct xlnx_pcib_irqsrc *xi;
+ struct trapframe *tf;
+ int irq;
+ int reg;
+ int i;
+
+ xlnx_sc = arg;
+ fdt_sc = &xlnx_sc->fdt_sc;
+ sc = &fdt_sc->base;
+ tf = curthread->td_intr_frame;
+
+ do {
+ reg = bus_read_4(sc->res, msireg);
+
+ for (i = 0; i < sizeof(uint32_t) * 8; i++) {
+ if (reg & (1 << i)) {
+ bus_write_4(sc->res, msireg, (1 << i));
+
+ irq = i;
+ if (msireg == XLNX_PCIE_RPMSIID2)
+ irq += 32;
+
+ xi = &xlnx_sc->isrcs[irq];
+ if (intr_isrc_dispatch(&xi->isrc, tf) != 0) {
+ /* Disable stray. */
+ xlnx_pcib_msi_mask(sc->dev,
+ &xi->isrc, 1);
+ device_printf(sc->dev,
+ "Stray irq %u disabled\n", irq);
+ }
+ }
+ }
+ } while (reg != 0);
+}
+
+static int
+xlnx_pcib_msi0_intr(void *arg)
+{
+
+ xlnx_pcib_handle_msi_intr(arg, XLNX_PCIE_RPMSIID1);
+
+ return (FILTER_HANDLED);
+}
+
+static int
+xlnx_pcib_msi1_intr(void *arg)
+{
+
+ xlnx_pcib_handle_msi_intr(arg, XLNX_PCIE_RPMSIID2);
+
+ return (FILTER_HANDLED);
+}
+
+static int
+xlnx_pcib_register_msi(struct xlnx_pcib_softc *sc)
+{
+ const char *name;
+ int error;
+ int irq;
+
+ sc->isrcs = malloc(sizeof(*sc->isrcs) * XLNX_PCIB_MAX_MSI, M_DEVBUF,
+ M_WAITOK | M_ZERO);
+
+ name = device_get_nameunit(sc->dev);
+
+ for (irq = 0; irq < XLNX_PCIB_MAX_MSI; irq++) {
+ sc->isrcs[irq].irq = irq;
+ error = intr_isrc_register(&sc->isrcs[irq].isrc,
+ sc->dev, 0, "%s,%u", name, irq);
+ if (error != 0)
+ return (error); /* XXX deregister ISRCs */
+ }
+
+ if (intr_msi_register(sc->dev,
+ OF_xref_from_node(ofw_bus_get_node(sc->dev))) != 0)
+ return (ENXIO);
+
+ return (0);
+}
+
+static void
+xlnx_pcib_init(struct xlnx_pcib_softc *sc)
+{
+ bus_addr_t addr;
+ int reg;
+
+ /* Disable interrupts. */
+ bus_write_4(sc->res[0], XLNX_PCIE_IMR, 0);
+
+ /* Clear pending interrupts.*/
+ reg = bus_read_4(sc->res[0], XLNX_PCIE_IDR);
+ bus_write_4(sc->res[0], XLNX_PCIE_IDR, reg);
+
+ /* Setup an MSI page. */
+ sc->msi_page = kmem_alloc_contig(PAGE_SIZE, M_WAITOK, 0,
+ BUS_SPACE_MAXADDR, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+ addr = vtophys(sc->msi_page);
+ bus_write_4(sc->res[0], XLNX_PCIE_RPMSIBR1, (addr >> 32));
+ bus_write_4(sc->res[0], XLNX_PCIE_RPMSIBR2, (addr >> 0));
+
+ /* Enable the bridge. */
+ reg = bus_read_4(sc->res[0], XLNX_PCIE_RPSCR);
+ reg |= RPSCR_BE;
+ bus_write_4(sc->res[0], XLNX_PCIE_RPSCR, reg);
+
+ /* Enable interrupts. */
+ reg = IMR_LINK_DOWN
+ | IMR_HOT_RESET
+ | IMR_CFG_COMPL_STATUS_M
+ | IMR_CFG_TIMEOUT
+ | IMR_CORRECTABLE
+ | IMR_NON_FATAL
+ | IMR_FATAL
+ | IMR_INTX
+ | IMR_MSI
+ | IMR_SLAVE_UNSUPP_REQ
+ | IMR_SLAVE_UNEXP_COMPL
+ | IMR_SLAVE_COMPL_TIMOUT
+ | IMR_SLAVE_ERROR_POISON
+ | IMR_SLAVE_COMPL_ABORT
+ | IMR_SLAVE_ILLEG_BURST
+ | IMR_MASTER_DECERR
+ | IMR_MASTER_SLVERR;
+ bus_write_4(sc->res[0], XLNX_PCIE_IMR, reg);
+}
+
+static int
+xlnx_pcib_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_is_compatible(dev, "xlnx,xdma-host-3.00")) {
+ device_set_desc(dev, "Xilinx XDMA PCIe Controller");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+xlnx_pcib_fdt_attach(device_t dev)
+{
+ struct xlnx_pcib_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF);
+
+ if (bus_alloc_resources(dev, xlnx_pcib_spec, sc->res)) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ /* Setup MISC interrupt handler. */
+ error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
+ xlnx_pcib_intr, NULL, sc, &sc->intr_cookie[0]);
+ if (error != 0) {
+ device_printf(dev, "could not setup interrupt handler.\n");
+ return (ENXIO);
+ }
+
+ /* Setup MSI0 interrupt handler. */
+ error = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
+ xlnx_pcib_msi0_intr, NULL, sc, &sc->intr_cookie[1]);
+ if (error != 0) {
+ device_printf(dev, "could not setup interrupt handler.\n");
+ return (ENXIO);
+ }
+
+ /* Setup MSI1 interrupt handler. */
+ error = bus_setup_intr(dev, sc->res[3], INTR_TYPE_MISC | INTR_MPSAFE,
+ xlnx_pcib_msi1_intr, NULL, sc, &sc->intr_cookie[2]);
+ if (error != 0) {
+ device_printf(dev, "could not setup interrupt handler.\n");
+ return (ENXIO);
+ }
+
+ xlnx_pcib_init(sc);
+
+ /*
+ * Allow the core driver to map registers.
+ * We will be accessing the device memory using core_softc.
+ */
+ bus_release_resources(dev, xlnx_pcib_spec, sc->res);
+
+ error = xlnx_pcib_register_msi(sc);
+ if (error)
+ return (error);
+
+ return (pci_host_generic_attach(dev));
+}
+
+static int
+xlnx_pcib_fdt_get_id(device_t pci, device_t child, enum pci_id_type type,
+ uintptr_t *id)
+{
+ phandle_t node;
+ int bsf;
+
+ if (type != PCI_ID_MSI)
+ return (pcib_get_id(pci, child, type, id));
+
+ node = ofw_bus_get_node(pci);
+ if (OF_hasprop(node, "msi-map"))
+ return (generic_pcie_get_id(pci, child, type, id));
+
+ bsf = pci_get_rid(child);
+ *id = (pci_get_domain(child) << PCI_RID_DOMAIN_SHIFT) | bsf;
+
+ return (0);
+}
+
+static int
+xlnx_pcib_req_valid(struct generic_pcie_core_softc *sc,
+ u_int bus, u_int slot, u_int func, u_int reg)
+{
+ bus_space_handle_t h;
+ bus_space_tag_t t;
+ uint32_t val;
+
+ t = sc->bst;
+ h = sc->bsh;
+
+ if ((bus < sc->bus_start) || (bus > sc->bus_end))
+ return (0);
+ if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
+ (reg > PCIE_REGMAX))
+ return (0);
+
+ if (bus == 0 && slot > 0)
+ return (0);
+
+ val = bus_space_read_4(t, h, XLNX_PCIE_PHYSCR);
+ if ((val & PHYSCR_LINK_UP) == 0) {
+ /* Link is down */
+ return (0);
+ }
+
+ /* Valid */
+
+ return (1);
+}
+
+static uint32_t
+xlnx_pcib_read_config(device_t dev, u_int bus, u_int slot,
+ u_int func, u_int reg, int bytes)
+{
+ struct generic_pcie_fdt_softc *fdt_sc;
+ struct xlnx_pcib_softc *xlnx_sc;
+ struct generic_pcie_core_softc *sc;
+ bus_space_handle_t h;
+ bus_space_tag_t t;
+ uint64_t offset;
+ uint32_t data;
+
+ xlnx_sc = device_get_softc(dev);
+ fdt_sc = &xlnx_sc->fdt_sc;
+ sc = &fdt_sc->base;
+
+ if (!xlnx_pcib_req_valid(sc, bus, slot, func, reg))
+ return (~0U);
+
+ offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg);
+ t = sc->bst;
+ h = sc->bsh;
+
+ data = bus_space_read_4(t, h, offset & ~3);
+
+ switch (bytes) {
+ case 1:
+ data >>= (offset & 3) * 8;
+ data &= 0xff;
+ break;
+ case 2:
+ data >>= (offset & 3) * 8;
+ data = le16toh(data);
+ break;
+ case 4:
+ data = le32toh(data);
+ break;
+ default:
+ return (~0U);
+ }
+
+ return (data);
+}
+
+static void
+xlnx_pcib_write_config(device_t dev, u_int bus, u_int slot,
+ u_int func, u_int reg, uint32_t val, int bytes)
+{
+ struct generic_pcie_fdt_softc *fdt_sc;
+ struct xlnx_pcib_softc *xlnx_sc;
+ struct generic_pcie_core_softc *sc;
+ bus_space_handle_t h;
+ bus_space_tag_t t;
+ uint64_t offset;
+ uint32_t data;
+
+ xlnx_sc = device_get_softc(dev);
+ fdt_sc = &xlnx_sc->fdt_sc;
+ sc = &fdt_sc->base;
+
+ if (!xlnx_pcib_req_valid(sc, bus, slot, func, reg))
+ return;
+
+ offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg);
+
+ t = sc->bst;
+ h = sc->bsh;
+
+ /*
+ * 32-bit access used due to a bug in the Xilinx bridge that
+ * requires to write primary and secondary buses in one blast.
+ *
+ * TODO: This is probably wrong on big-endian.
+ */
+ switch (bytes) {
+ case 1:
+ data = bus_space_read_4(t, h, offset & ~3);
+ data &= ~(0xff << ((offset & 3) * 8));
+ data |= (val & 0xff) << ((offset & 3) * 8);
+ bus_space_write_4(t, h, offset & ~3, htole32(data));
+ break;
+ case 2:
+ data = bus_space_read_4(t, h, offset & ~3);
+ data &= ~(0xffff << ((offset & 3) * 8));
+ data |= (val & 0xffff) << ((offset & 3) * 8);
+ bus_space_write_4(t, h, offset & ~3, htole32(data));
+ break;
+ case 4:
+ bus_space_write_4(t, h, offset, htole32(val));
+ break;
+ default:
+ return;
+ }
+}
+
+static int
+xlnx_pcib_alloc_msi(device_t pci, device_t child, int count, int maxcount,
+ int *irqs)
+{
+ phandle_t msi_parent;
+
+ ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
+ NULL);
+ msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
+ return (intr_alloc_msi(pci, child, msi_parent, count, maxcount,
+ irqs));
+}
+
+static int
+xlnx_pcib_release_msi(device_t pci, device_t child, int count, int *irqs)
+{
+ phandle_t msi_parent;
+
+ ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
+ NULL);
+ msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
+ return (intr_release_msi(pci, child, msi_parent, count, irqs));
+}
+
+static int
+xlnx_pcib_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,
+ uint32_t *data)
+{
+ phandle_t msi_parent;
+
+ ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
+ NULL);
+ msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
+ return (intr_map_msi(pci, child, msi_parent, irq, addr, data));
+}
+
+static int
+xlnx_pcib_msi_alloc_msi(device_t dev, device_t child, int count, int maxcount,
+ device_t *pic, struct intr_irqsrc **srcs)
+{
+ struct xlnx_pcib_softc *sc;
+ int irq, end_irq, i;
+ bool found;
+
+ sc = device_get_softc(dev);
+
+ mtx_lock(&sc->mtx);
+
+ found = false;
+
+ for (irq = 0; (irq + count - 1) < XLNX_PCIB_MAX_MSI; irq++) {
+
+ /* Assume the range is valid. */
+ found = true;
+
+ /* Check this range is valid. */
+ for (end_irq = irq; end_irq < irq + count; end_irq++) {
+ if (sc->isrcs[end_irq].flags & XLNX_IRQ_FLAG_USED) {
+ /* This is already used. */
+ found = false;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ }
+
+ if (!found || irq == (XLNX_PCIB_MAX_MSI - 1)) {
+ /* Not enough interrupts were found. */
+ mtx_unlock(&sc->mtx);
+ return (ENXIO);
+ }
+
+ /* Mark the interrupt as used. */
+ for (i = 0; i < count; i++)
+ sc->isrcs[irq + i].flags |= XLNX_IRQ_FLAG_USED;
+
+ mtx_unlock(&sc->mtx);
+
+ for (i = 0; i < count; i++)
+ srcs[i] = (struct intr_irqsrc *)&sc->isrcs[irq + i];
+
+ *pic = device_get_parent(dev);
+
+ return (0);
+}
+
+static int
+xlnx_pcib_msi_release_msi(device_t dev, device_t child, int count,
+ struct intr_irqsrc **isrc)
+{
+ struct xlnx_pcib_softc *sc;
+ struct xlnx_pcib_irqsrc *xi;
+ int i;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+ for (i = 0; i < count; i++) {
+ xi = (struct xlnx_pcib_irqsrc *)isrc[i];
+
+ KASSERT(xi->flags & XLNX_IRQ_FLAG_USED,
+ ("%s: Releasing an unused MSI interrupt", __func__));
+
+ xi->flags &= ~XLNX_IRQ_FLAG_USED;
+ }
+
+ mtx_unlock(&sc->mtx);
+ return (0);
+}
+
+static int
+xlnx_pcib_msi_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
+ uint64_t *addr, uint32_t *data)
+{
+ struct xlnx_pcib_softc *sc;
+ struct xlnx_pcib_irqsrc *xi;
+
+ sc = device_get_softc(dev);
+ xi = (struct xlnx_pcib_irqsrc *)isrc;
+
+ *addr = vtophys(sc->msi_page);
+ *data = xi->irq;
+
+ return (0);
+}
+
+static void
+xlnx_pcib_msi_mask(device_t dev, struct intr_irqsrc *isrc, bool mask)
+{
+ struct generic_pcie_fdt_softc *fdt_sc;
+ struct generic_pcie_core_softc *sc;
+ struct xlnx_pcib_softc *xlnx_sc;
+ struct xlnx_pcib_irqsrc *xi;
+ uint32_t msireg, irq;
+ uint32_t reg;
+
+ xlnx_sc = device_get_softc(dev);
+ fdt_sc = &xlnx_sc->fdt_sc;
+ sc = &fdt_sc->base;
+
+ xi = (struct xlnx_pcib_irqsrc *)isrc;
+
+ irq = xi->irq;
+ if (irq < 32)
+ msireg = XLNX_PCIE_RPMSIID1_MASK;
+ else
+ msireg = XLNX_PCIE_RPMSIID2_MASK;
+
+ reg = bus_read_4(sc->res, msireg);
+ if (mask)
+ reg &= ~(1 << irq);
+ else
+ reg |= (1 << irq);
+ bus_write_4(sc->res, msireg, reg);
+}
+
+static void
+xlnx_pcib_msi_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ xlnx_pcib_msi_mask(dev, isrc, true);
+}
+
+static void
+xlnx_pcib_msi_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ xlnx_pcib_msi_mask(dev, isrc, false);
+}
+
+static void
+xlnx_pcib_msi_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+
+}
+
+static void
+xlnx_pcib_msi_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ xlnx_pcib_msi_mask(dev, isrc, false);
+}
+
+static void
+xlnx_pcib_msi_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ xlnx_pcib_msi_mask(dev, isrc, true);
+}
+
+static int
+xlnx_pcib_msi_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+
+ return (0);
+}
+
+static int
+xlnx_pcib_msi_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+
+ return (0);
+}
+
+static device_method_t xlnx_pcib_fdt_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, xlnx_pcib_fdt_probe),
+ DEVMETHOD(device_attach, xlnx_pcib_fdt_attach),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_get_id, xlnx_pcib_fdt_get_id),
+ DEVMETHOD(pcib_read_config, xlnx_pcib_read_config),
+ DEVMETHOD(pcib_write_config, xlnx_pcib_write_config),
+ DEVMETHOD(pcib_alloc_msi, xlnx_pcib_alloc_msi),
+ DEVMETHOD(pcib_release_msi, xlnx_pcib_release_msi),
+ DEVMETHOD(pcib_map_msi, xlnx_pcib_map_msi),
+
+ /* MSI interface */
+ DEVMETHOD(msi_alloc_msi, xlnx_pcib_msi_alloc_msi),
+ DEVMETHOD(msi_release_msi, xlnx_pcib_msi_release_msi),
+ DEVMETHOD(msi_map_msi, xlnx_pcib_msi_map_msi),
+
+ /* Interrupt controller interface */
+ DEVMETHOD(pic_disable_intr, xlnx_pcib_msi_disable_intr),
+ DEVMETHOD(pic_enable_intr, xlnx_pcib_msi_enable_intr),
+ DEVMETHOD(pic_setup_intr, xlnx_pcib_msi_setup_intr),
+ DEVMETHOD(pic_teardown_intr, xlnx_pcib_msi_teardown_intr),
+ DEVMETHOD(pic_post_filter, xlnx_pcib_msi_post_filter),
+ DEVMETHOD(pic_post_ithread, xlnx_pcib_msi_post_ithread),
+ DEVMETHOD(pic_pre_ithread, xlnx_pcib_msi_pre_ithread),
+
+ /* End */
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(pcib, xlnx_pcib_fdt_driver, xlnx_pcib_fdt_methods,
+ sizeof(struct xlnx_pcib_softc), generic_pcie_fdt_driver);
+
+static devclass_t xlnx_pcib_fdt_devclass;
+
+DRIVER_MODULE(xlnx_pcib, simplebus, xlnx_pcib_fdt_driver,
+ xlnx_pcib_fdt_devclass, 0, 0);
+DRIVER_MODULE(xlnx_pcib, ofwbus, xlnx_pcib_fdt_driver,
+ xlnx_pcib_fdt_devclass, 0, 0);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 24, 9:10 AM (16 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16082797
Default Alt Text
D23337.diff (24 KB)
Attached To
Mode
D23337: Xilinx XDMA PCIe Controller driver
Attached
Detach File
Event Timeline
Log In to Comment