1*ba7319e9SDmitry Salychev /*- 2*ba7319e9SDmitry Salychev * SPDX-License-Identifier: BSD-2-Clause 3*ba7319e9SDmitry Salychev * 4*ba7319e9SDmitry Salychev * Copyright © 2021-2022 Dmitry Salychev 5*ba7319e9SDmitry Salychev * 6*ba7319e9SDmitry Salychev * Redistribution and use in source and binary forms, with or without 7*ba7319e9SDmitry Salychev * modification, are permitted provided that the following conditions 8*ba7319e9SDmitry Salychev * are met: 9*ba7319e9SDmitry Salychev * 1. Redistributions of source code must retain the above copyright 10*ba7319e9SDmitry Salychev * notice, this list of conditions and the following disclaimer. 11*ba7319e9SDmitry Salychev * 2. Redistributions in binary form must reproduce the above copyright 12*ba7319e9SDmitry Salychev * notice, this list of conditions and the following disclaimer in the 13*ba7319e9SDmitry Salychev * documentation and/or other materials provided with the distribution. 14*ba7319e9SDmitry Salychev * 15*ba7319e9SDmitry Salychev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*ba7319e9SDmitry Salychev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*ba7319e9SDmitry Salychev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*ba7319e9SDmitry Salychev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*ba7319e9SDmitry Salychev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*ba7319e9SDmitry Salychev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*ba7319e9SDmitry Salychev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*ba7319e9SDmitry Salychev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*ba7319e9SDmitry Salychev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*ba7319e9SDmitry Salychev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*ba7319e9SDmitry Salychev * SUCH DAMAGE. 26*ba7319e9SDmitry Salychev */ 27*ba7319e9SDmitry Salychev 28*ba7319e9SDmitry Salychev #include <sys/cdefs.h> 29*ba7319e9SDmitry Salychev __FBSDID("$FreeBSD$"); 30*ba7319e9SDmitry Salychev 31*ba7319e9SDmitry Salychev /* 32*ba7319e9SDmitry Salychev * The DPAA2 Concentrator (DPCON) driver. 33*ba7319e9SDmitry Salychev * 34*ba7319e9SDmitry Salychev * Supports configuration of QBMan channels for advanced scheduling of ingress 35*ba7319e9SDmitry Salychev * packets from one or more network interfaces. 36*ba7319e9SDmitry Salychev * 37*ba7319e9SDmitry Salychev * DPCONs are used to distribute Rx or Tx Confirmation traffic to different 38*ba7319e9SDmitry Salychev * cores, via affine DPIO objects. The implication is that one DPCON must be 39*ba7319e9SDmitry Salychev * available for each core where Rx or Tx Confirmation traffic should be 40*ba7319e9SDmitry Salychev * distributed to. 41*ba7319e9SDmitry Salychev * 42*ba7319e9SDmitry Salychev * QBMan channel contains several work queues. The WQs within a channel have a 43*ba7319e9SDmitry Salychev * priority relative to each other. Each channel consists of either eight or two 44*ba7319e9SDmitry Salychev * WQs, and thus, there are either eight or two possible priorities in a channel. 45*ba7319e9SDmitry Salychev */ 46*ba7319e9SDmitry Salychev 47*ba7319e9SDmitry Salychev #include <sys/param.h> 48*ba7319e9SDmitry Salychev #include <sys/kernel.h> 49*ba7319e9SDmitry Salychev #include <sys/bus.h> 50*ba7319e9SDmitry Salychev #include <sys/rman.h> 51*ba7319e9SDmitry Salychev #include <sys/module.h> 52*ba7319e9SDmitry Salychev #include <sys/malloc.h> 53*ba7319e9SDmitry Salychev #include <sys/mutex.h> 54*ba7319e9SDmitry Salychev 55*ba7319e9SDmitry Salychev #include <vm/vm.h> 56*ba7319e9SDmitry Salychev 57*ba7319e9SDmitry Salychev #include <machine/bus.h> 58*ba7319e9SDmitry Salychev #include <machine/resource.h> 59*ba7319e9SDmitry Salychev 60*ba7319e9SDmitry Salychev #include <dev/pci/pcivar.h> 61*ba7319e9SDmitry Salychev 62*ba7319e9SDmitry Salychev #include "pcib_if.h" 63*ba7319e9SDmitry Salychev #include "pci_if.h" 64*ba7319e9SDmitry Salychev 65*ba7319e9SDmitry Salychev #include "dpaa2_mcp.h" 66*ba7319e9SDmitry Salychev #include "dpaa2_swp.h" 67*ba7319e9SDmitry Salychev #include "dpaa2_mc.h" 68*ba7319e9SDmitry Salychev #include "dpaa2_cmd_if.h" 69*ba7319e9SDmitry Salychev 70*ba7319e9SDmitry Salychev /* DPAA2 Concentrator resource specification. */ 71*ba7319e9SDmitry Salychev struct resource_spec dpaa2_con_spec[] = { 72*ba7319e9SDmitry Salychev /* 73*ba7319e9SDmitry Salychev * DPMCP resources. 74*ba7319e9SDmitry Salychev * 75*ba7319e9SDmitry Salychev * NOTE: MC command portals (MCPs) are used to send commands to, and 76*ba7319e9SDmitry Salychev * receive responses from, the MC firmware. One portal per DPCON. 77*ba7319e9SDmitry Salychev */ 78*ba7319e9SDmitry Salychev #define MCP_RES_NUM (1u) 79*ba7319e9SDmitry Salychev #define MCP_RID_OFF (0u) 80*ba7319e9SDmitry Salychev #define MCP_RID(rid) ((rid) + MCP_RID_OFF) 81*ba7319e9SDmitry Salychev /* --- */ 82*ba7319e9SDmitry Salychev { DPAA2_DEV_MCP, MCP_RID(0), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 83*ba7319e9SDmitry Salychev /* --- */ 84*ba7319e9SDmitry Salychev RESOURCE_SPEC_END 85*ba7319e9SDmitry Salychev }; 86*ba7319e9SDmitry Salychev 87*ba7319e9SDmitry Salychev static int dpaa2_con_detach(device_t dev); 88*ba7319e9SDmitry Salychev 89*ba7319e9SDmitry Salychev /* 90*ba7319e9SDmitry Salychev * Device interface. 91*ba7319e9SDmitry Salychev */ 92*ba7319e9SDmitry Salychev 93*ba7319e9SDmitry Salychev static int 94*ba7319e9SDmitry Salychev dpaa2_con_probe(device_t dev) 95*ba7319e9SDmitry Salychev { 96*ba7319e9SDmitry Salychev /* DPCON device will be added by a parent resource container itself. */ 97*ba7319e9SDmitry Salychev device_set_desc(dev, "DPAA2 Concentrator"); 98*ba7319e9SDmitry Salychev return (BUS_PROBE_DEFAULT); 99*ba7319e9SDmitry Salychev } 100*ba7319e9SDmitry Salychev 101*ba7319e9SDmitry Salychev static int 102*ba7319e9SDmitry Salychev dpaa2_con_detach(device_t dev) 103*ba7319e9SDmitry Salychev { 104*ba7319e9SDmitry Salychev device_t child = dev; 105*ba7319e9SDmitry Salychev struct dpaa2_con_softc *sc = device_get_softc(dev); 106*ba7319e9SDmitry Salychev 107*ba7319e9SDmitry Salychev DPAA2_CMD_CON_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->con_token)); 108*ba7319e9SDmitry Salychev DPAA2_CMD_RC_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->rc_token)); 109*ba7319e9SDmitry Salychev dpaa2_mcp_free_command(sc->cmd); 110*ba7319e9SDmitry Salychev 111*ba7319e9SDmitry Salychev sc->cmd = NULL; 112*ba7319e9SDmitry Salychev sc->con_token = 0; 113*ba7319e9SDmitry Salychev sc->rc_token = 0; 114*ba7319e9SDmitry Salychev 115*ba7319e9SDmitry Salychev return (0); 116*ba7319e9SDmitry Salychev } 117*ba7319e9SDmitry Salychev 118*ba7319e9SDmitry Salychev static int 119*ba7319e9SDmitry Salychev dpaa2_con_attach(device_t dev) 120*ba7319e9SDmitry Salychev { 121*ba7319e9SDmitry Salychev device_t pdev = device_get_parent(dev); 122*ba7319e9SDmitry Salychev device_t child = dev; 123*ba7319e9SDmitry Salychev device_t mcp_dev; 124*ba7319e9SDmitry Salychev struct dpaa2_con_softc *sc = device_get_softc(dev); 125*ba7319e9SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 126*ba7319e9SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 127*ba7319e9SDmitry Salychev struct dpaa2_devinfo *mcp_dinfo; 128*ba7319e9SDmitry Salychev int error; 129*ba7319e9SDmitry Salychev 130*ba7319e9SDmitry Salychev sc->dev = dev; 131*ba7319e9SDmitry Salychev 132*ba7319e9SDmitry Salychev error = bus_alloc_resources(sc->dev, dpaa2_con_spec, sc->res); 133*ba7319e9SDmitry Salychev if (error) { 134*ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to allocate resources: " 135*ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 136*ba7319e9SDmitry Salychev return (ENXIO); 137*ba7319e9SDmitry Salychev } 138*ba7319e9SDmitry Salychev 139*ba7319e9SDmitry Salychev /* Obtain MC portal. */ 140*ba7319e9SDmitry Salychev mcp_dev = (device_t) rman_get_start(sc->res[MCP_RID(0)]); 141*ba7319e9SDmitry Salychev mcp_dinfo = device_get_ivars(mcp_dev); 142*ba7319e9SDmitry Salychev dinfo->portal = mcp_dinfo->portal; 143*ba7319e9SDmitry Salychev 144*ba7319e9SDmitry Salychev /* Allocate a command to send to MC hardware. */ 145*ba7319e9SDmitry Salychev error = dpaa2_mcp_init_command(&sc->cmd, DPAA2_CMD_DEF); 146*ba7319e9SDmitry Salychev if (error) { 147*ba7319e9SDmitry Salychev device_printf(dev, "Failed to allocate dpaa2_cmd: error=%d\n", 148*ba7319e9SDmitry Salychev error); 149*ba7319e9SDmitry Salychev goto err_exit; 150*ba7319e9SDmitry Salychev } 151*ba7319e9SDmitry Salychev 152*ba7319e9SDmitry Salychev /* Open resource container and DPCON object. */ 153*ba7319e9SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, sc->cmd, rcinfo->id, 154*ba7319e9SDmitry Salychev &sc->rc_token); 155*ba7319e9SDmitry Salychev if (error) { 156*ba7319e9SDmitry Salychev device_printf(dev, "Failed to open DPRC: error=%d\n", error); 157*ba7319e9SDmitry Salychev goto err_free_cmd; 158*ba7319e9SDmitry Salychev } 159*ba7319e9SDmitry Salychev error = DPAA2_CMD_CON_OPEN(dev, child, sc->cmd, dinfo->id, 160*ba7319e9SDmitry Salychev &sc->con_token); 161*ba7319e9SDmitry Salychev if (error) { 162*ba7319e9SDmitry Salychev device_printf(dev, "Failed to open DPCON: id=%d, error=%d\n", 163*ba7319e9SDmitry Salychev dinfo->id, error); 164*ba7319e9SDmitry Salychev goto err_close_rc; 165*ba7319e9SDmitry Salychev } 166*ba7319e9SDmitry Salychev 167*ba7319e9SDmitry Salychev /* Prepare DPCON object. */ 168*ba7319e9SDmitry Salychev error = DPAA2_CMD_CON_RESET(dev, child, sc->cmd); 169*ba7319e9SDmitry Salychev if (error) { 170*ba7319e9SDmitry Salychev device_printf(dev, "Failed to reset DPCON: id=%d, error=%d\n", 171*ba7319e9SDmitry Salychev dinfo->id, error); 172*ba7319e9SDmitry Salychev goto err_close_con; 173*ba7319e9SDmitry Salychev } 174*ba7319e9SDmitry Salychev error = DPAA2_CMD_CON_GET_ATTRIBUTES(dev, child, sc->cmd, &sc->attr); 175*ba7319e9SDmitry Salychev if (error) { 176*ba7319e9SDmitry Salychev device_printf(dev, "Failed to get DPCON attributes: id=%d, " 177*ba7319e9SDmitry Salychev "error=%d\n", dinfo->id, error); 178*ba7319e9SDmitry Salychev goto err_close_con; 179*ba7319e9SDmitry Salychev } 180*ba7319e9SDmitry Salychev 181*ba7319e9SDmitry Salychev /* TODO: Enable debug output via sysctl (to reduce output). */ 182*ba7319e9SDmitry Salychev if (bootverbose) 183*ba7319e9SDmitry Salychev device_printf(dev, "chan_id=%d, priorities=%d\n", 184*ba7319e9SDmitry Salychev sc->attr.chan_id, sc->attr.prior_num); 185*ba7319e9SDmitry Salychev 186*ba7319e9SDmitry Salychev return (0); 187*ba7319e9SDmitry Salychev 188*ba7319e9SDmitry Salychev err_close_con: 189*ba7319e9SDmitry Salychev DPAA2_CMD_CON_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->con_token)); 190*ba7319e9SDmitry Salychev err_close_rc: 191*ba7319e9SDmitry Salychev DPAA2_CMD_RC_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->rc_token)); 192*ba7319e9SDmitry Salychev err_free_cmd: 193*ba7319e9SDmitry Salychev dpaa2_mcp_free_command(sc->cmd); 194*ba7319e9SDmitry Salychev err_exit: 195*ba7319e9SDmitry Salychev return (ENXIO); 196*ba7319e9SDmitry Salychev } 197*ba7319e9SDmitry Salychev 198*ba7319e9SDmitry Salychev static device_method_t dpaa2_con_methods[] = { 199*ba7319e9SDmitry Salychev /* Device interface */ 200*ba7319e9SDmitry Salychev DEVMETHOD(device_probe, dpaa2_con_probe), 201*ba7319e9SDmitry Salychev DEVMETHOD(device_attach, dpaa2_con_attach), 202*ba7319e9SDmitry Salychev DEVMETHOD(device_detach, dpaa2_con_detach), 203*ba7319e9SDmitry Salychev 204*ba7319e9SDmitry Salychev DEVMETHOD_END 205*ba7319e9SDmitry Salychev }; 206*ba7319e9SDmitry Salychev 207*ba7319e9SDmitry Salychev static driver_t dpaa2_con_driver = { 208*ba7319e9SDmitry Salychev "dpaa2_con", 209*ba7319e9SDmitry Salychev dpaa2_con_methods, 210*ba7319e9SDmitry Salychev sizeof(struct dpaa2_con_softc), 211*ba7319e9SDmitry Salychev }; 212*ba7319e9SDmitry Salychev 213*ba7319e9SDmitry Salychev DRIVER_MODULE(dpaa2_con, dpaa2_rc, dpaa2_con_driver, 0, 0); 214