1ba7319e9SDmitry Salychev /*- 2ba7319e9SDmitry Salychev * SPDX-License-Identifier: BSD-2-Clause 3ba7319e9SDmitry Salychev * 4ba7319e9SDmitry Salychev * Copyright © 2021-2022 Dmitry Salychev 5ba7319e9SDmitry Salychev * 6ba7319e9SDmitry Salychev * Redistribution and use in source and binary forms, with or without 7ba7319e9SDmitry Salychev * modification, are permitted provided that the following conditions 8ba7319e9SDmitry Salychev * are met: 9ba7319e9SDmitry Salychev * 1. Redistributions of source code must retain the above copyright 10ba7319e9SDmitry Salychev * notice, this list of conditions and the following disclaimer. 11ba7319e9SDmitry Salychev * 2. Redistributions in binary form must reproduce the above copyright 12ba7319e9SDmitry Salychev * notice, this list of conditions and the following disclaimer in the 13ba7319e9SDmitry Salychev * documentation and/or other materials provided with the distribution. 14ba7319e9SDmitry Salychev * 15ba7319e9SDmitry Salychev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16ba7319e9SDmitry Salychev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17ba7319e9SDmitry Salychev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18ba7319e9SDmitry Salychev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19ba7319e9SDmitry Salychev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20ba7319e9SDmitry Salychev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21ba7319e9SDmitry Salychev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22ba7319e9SDmitry Salychev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23ba7319e9SDmitry Salychev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24ba7319e9SDmitry Salychev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25ba7319e9SDmitry Salychev * SUCH DAMAGE. 26ba7319e9SDmitry Salychev */ 27ba7319e9SDmitry Salychev 28ba7319e9SDmitry Salychev #include <sys/cdefs.h> 29ba7319e9SDmitry Salychev __FBSDID("$FreeBSD$"); 30ba7319e9SDmitry Salychev 31ba7319e9SDmitry Salychev /* 32ba7319e9SDmitry Salychev * DPAA2 MC command portal and helper routines. 33ba7319e9SDmitry Salychev */ 34ba7319e9SDmitry Salychev 35ba7319e9SDmitry Salychev #include <sys/param.h> 36ba7319e9SDmitry Salychev #include <sys/kernel.h> 37ba7319e9SDmitry Salychev #include <sys/bus.h> 38ba7319e9SDmitry Salychev #include <sys/rman.h> 39ba7319e9SDmitry Salychev #include <sys/module.h> 40ba7319e9SDmitry Salychev #include <sys/malloc.h> 41ba7319e9SDmitry Salychev #include <sys/mutex.h> 42ba7319e9SDmitry Salychev #include <sys/time.h> 43ba7319e9SDmitry Salychev #include <sys/types.h> 44ba7319e9SDmitry Salychev #include <sys/systm.h> 45ba7319e9SDmitry Salychev #include <sys/condvar.h> 46ba7319e9SDmitry Salychev #include <sys/lock.h> 47ba7319e9SDmitry Salychev 48ba7319e9SDmitry Salychev #include <machine/bus.h> 49ba7319e9SDmitry Salychev #include <machine/resource.h> 50ba7319e9SDmitry Salychev 51ba7319e9SDmitry Salychev #include "pcib_if.h" 52ba7319e9SDmitry Salychev #include "pci_if.h" 53ba7319e9SDmitry Salychev 54ba7319e9SDmitry Salychev #include "dpaa2_mcp.h" 55ba7319e9SDmitry Salychev #include "dpaa2_mc.h" 56ba7319e9SDmitry Salychev #include "dpaa2_cmd_if.h" 57ba7319e9SDmitry Salychev 58ba7319e9SDmitry Salychev MALLOC_DEFINE(M_DPAA2_MCP, "dpaa2_mcp", "DPAA2 Management Complex Portal"); 59ba7319e9SDmitry Salychev 60ba7319e9SDmitry Salychev static struct resource_spec dpaa2_mcp_spec[] = { 61ba7319e9SDmitry Salychev { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_UNMAPPED }, 62ba7319e9SDmitry Salychev RESOURCE_SPEC_END 63ba7319e9SDmitry Salychev }; 64ba7319e9SDmitry Salychev 65ba7319e9SDmitry Salychev int 66ba7319e9SDmitry Salychev dpaa2_mcp_init_portal(struct dpaa2_mcp **mcp, struct resource *res, 67ba7319e9SDmitry Salychev struct resource_map *map, uint16_t flags) 68ba7319e9SDmitry Salychev { 69ba7319e9SDmitry Salychev const int mflags = flags & DPAA2_PORTAL_NOWAIT_ALLOC 70ba7319e9SDmitry Salychev ? (M_NOWAIT | M_ZERO) : (M_WAITOK | M_ZERO); 71ba7319e9SDmitry Salychev struct dpaa2_mcp *p; 72ba7319e9SDmitry Salychev 73ba7319e9SDmitry Salychev if (!mcp || !res || !map) 74ba7319e9SDmitry Salychev return (DPAA2_CMD_STAT_EINVAL); 75ba7319e9SDmitry Salychev 76ba7319e9SDmitry Salychev p = malloc(sizeof(struct dpaa2_mcp), M_DPAA2_MCP, mflags); 77ba7319e9SDmitry Salychev if (p == NULL) 78ba7319e9SDmitry Salychev return (DPAA2_CMD_STAT_NO_MEMORY); 79ba7319e9SDmitry Salychev 80ba7319e9SDmitry Salychev mtx_init(&p->lock, "mcp_sleep_lock", NULL, MTX_DEF); 81ba7319e9SDmitry Salychev 82ba7319e9SDmitry Salychev p->res = res; 83ba7319e9SDmitry Salychev p->map = map; 84ba7319e9SDmitry Salychev p->flags = flags; 85ba7319e9SDmitry Salychev p->rc_api_major = 0; /* DPRC API version to be cached later. */ 86ba7319e9SDmitry Salychev p->rc_api_minor = 0; 87ba7319e9SDmitry Salychev 88ba7319e9SDmitry Salychev *mcp = p; 89ba7319e9SDmitry Salychev 90ba7319e9SDmitry Salychev return (0); 91ba7319e9SDmitry Salychev } 92ba7319e9SDmitry Salychev 93ba7319e9SDmitry Salychev void 94ba7319e9SDmitry Salychev dpaa2_mcp_free_portal(struct dpaa2_mcp *mcp) 95ba7319e9SDmitry Salychev { 96ba7319e9SDmitry Salychev uint16_t flags; 97ba7319e9SDmitry Salychev 98ba7319e9SDmitry Salychev KASSERT(mcp != NULL, ("%s: mcp is NULL", __func__)); 99ba7319e9SDmitry Salychev 100ba7319e9SDmitry Salychev DPAA2_MCP_LOCK(mcp, &flags); 101ba7319e9SDmitry Salychev mcp->flags |= DPAA2_PORTAL_DESTROYED; 102ba7319e9SDmitry Salychev DPAA2_MCP_UNLOCK(mcp); 103ba7319e9SDmitry Salychev 104ba7319e9SDmitry Salychev /* Let threads stop using this portal. */ 105ba7319e9SDmitry Salychev DELAY(DPAA2_PORTAL_TIMEOUT); 106ba7319e9SDmitry Salychev 107ba7319e9SDmitry Salychev mtx_destroy(&mcp->lock); 108ba7319e9SDmitry Salychev free(mcp, M_DPAA2_MCP); 109ba7319e9SDmitry Salychev } 110ba7319e9SDmitry Salychev 111ba7319e9SDmitry Salychev struct dpaa2_cmd * 112ba7319e9SDmitry Salychev dpaa2_mcp_tk(struct dpaa2_cmd *cmd, uint16_t token) 113ba7319e9SDmitry Salychev { 114ba7319e9SDmitry Salychev struct dpaa2_cmd_header *hdr; 115*4cd96614SDmitry Salychev KASSERT(cmd != NULL, ("%s: cmd is NULL", __func__)); 116*4cd96614SDmitry Salychev 117ba7319e9SDmitry Salychev hdr = (struct dpaa2_cmd_header *) &cmd->header; 118ba7319e9SDmitry Salychev hdr->token = token; 119ba7319e9SDmitry Salychev return (cmd); 120ba7319e9SDmitry Salychev } 121ba7319e9SDmitry Salychev 122ba7319e9SDmitry Salychev struct dpaa2_cmd * 123ba7319e9SDmitry Salychev dpaa2_mcp_f(struct dpaa2_cmd *cmd, uint16_t flags) 124ba7319e9SDmitry Salychev { 125ba7319e9SDmitry Salychev struct dpaa2_cmd_header *hdr; 126*4cd96614SDmitry Salychev KASSERT(cmd != NULL, ("%s: cmd is NULL", __func__)); 127*4cd96614SDmitry Salychev 128ba7319e9SDmitry Salychev hdr = (struct dpaa2_cmd_header *) &cmd->header; 129ba7319e9SDmitry Salychev hdr->flags_hw = DPAA2_CMD_DEF; 130ba7319e9SDmitry Salychev hdr->flags_sw = DPAA2_CMD_DEF; 131*4cd96614SDmitry Salychev if (flags & DPAA2_CMD_HIGH_PRIO) { 132ba7319e9SDmitry Salychev hdr->flags_hw |= DPAA2_HW_FLAG_HIGH_PRIO; 133*4cd96614SDmitry Salychev } 134*4cd96614SDmitry Salychev if (flags & DPAA2_CMD_INTR_DIS) { 135ba7319e9SDmitry Salychev hdr->flags_sw |= DPAA2_SW_FLAG_INTR_DIS; 136ba7319e9SDmitry Salychev } 137ba7319e9SDmitry Salychev return (cmd); 138ba7319e9SDmitry Salychev } 139ba7319e9SDmitry Salychev 140ba7319e9SDmitry Salychev static int 141ba7319e9SDmitry Salychev dpaa2_mcp_probe(device_t dev) 142ba7319e9SDmitry Salychev { 143ba7319e9SDmitry Salychev /* DPMCP device will be added by the parent resource container. */ 144ba7319e9SDmitry Salychev device_set_desc(dev, "DPAA2 MC portal"); 145ba7319e9SDmitry Salychev return (BUS_PROBE_DEFAULT); 146ba7319e9SDmitry Salychev } 147ba7319e9SDmitry Salychev 148ba7319e9SDmitry Salychev static int 149ba7319e9SDmitry Salychev dpaa2_mcp_detach(device_t dev) 150ba7319e9SDmitry Salychev { 151ba7319e9SDmitry Salychev return (0); 152ba7319e9SDmitry Salychev } 153ba7319e9SDmitry Salychev 154ba7319e9SDmitry Salychev static int 155ba7319e9SDmitry Salychev dpaa2_mcp_attach(device_t dev) 156ba7319e9SDmitry Salychev { 157ba7319e9SDmitry Salychev device_t pdev = device_get_parent(dev); 158ba7319e9SDmitry Salychev device_t child = dev; 159ba7319e9SDmitry Salychev struct dpaa2_mcp_softc *sc = device_get_softc(dev); 160ba7319e9SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 161ba7319e9SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 162*4cd96614SDmitry Salychev struct dpaa2_cmd cmd; 163ba7319e9SDmitry Salychev struct dpaa2_mcp *portal; 164ba7319e9SDmitry Salychev struct resource_map_request req; 165ba7319e9SDmitry Salychev uint16_t rc_token, mcp_token; 166ba7319e9SDmitry Salychev int error; 167ba7319e9SDmitry Salychev 168ba7319e9SDmitry Salychev sc->dev = dev; 169ba7319e9SDmitry Salychev 170ba7319e9SDmitry Salychev error = bus_alloc_resources(sc->dev, dpaa2_mcp_spec, sc->res); 171ba7319e9SDmitry Salychev if (error) { 172ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to allocate resources\n", 173ba7319e9SDmitry Salychev __func__); 174ba7319e9SDmitry Salychev goto err_exit; 175ba7319e9SDmitry Salychev } 176ba7319e9SDmitry Salychev 177ba7319e9SDmitry Salychev /* At least 64 bytes of the command portal should be available. */ 178ba7319e9SDmitry Salychev if (rman_get_size(sc->res[0]) < DPAA2_MCP_MEM_WIDTH) { 179ba7319e9SDmitry Salychev device_printf(dev, "%s: MC portal memory region too small: " 180ba7319e9SDmitry Salychev "%jd\n", __func__, rman_get_size(sc->res[0])); 181ba7319e9SDmitry Salychev goto err_exit; 182ba7319e9SDmitry Salychev } 183ba7319e9SDmitry Salychev 184ba7319e9SDmitry Salychev /* Map MC portal memory resource. */ 185ba7319e9SDmitry Salychev resource_init_map_request(&req); 186ba7319e9SDmitry Salychev req.memattr = VM_MEMATTR_DEVICE; 187ba7319e9SDmitry Salychev error = bus_map_resource(sc->dev, SYS_RES_MEMORY, sc->res[0], &req, 188ba7319e9SDmitry Salychev &sc->map[0]); 189ba7319e9SDmitry Salychev if (error) { 190ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to map MC portal memory\n", 191ba7319e9SDmitry Salychev __func__); 192ba7319e9SDmitry Salychev goto err_exit; 193ba7319e9SDmitry Salychev } 194ba7319e9SDmitry Salychev 195ba7319e9SDmitry Salychev /* Initialize portal to send commands to MC. */ 196ba7319e9SDmitry Salychev error = dpaa2_mcp_init_portal(&portal, sc->res[0], &sc->map[0], 197ba7319e9SDmitry Salychev DPAA2_PORTAL_DEF); 198ba7319e9SDmitry Salychev if (error) { 199ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to initialize dpaa2_mcp: " 200ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 201ba7319e9SDmitry Salychev goto err_exit; 202ba7319e9SDmitry Salychev } 203ba7319e9SDmitry Salychev 204*4cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 205ba7319e9SDmitry Salychev 206ba7319e9SDmitry Salychev /* Open resource container and DPMCP object. */ 207*4cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 208ba7319e9SDmitry Salychev if (error) { 209ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to open DPRC: error=%d\n", 210ba7319e9SDmitry Salychev __func__, error); 211*4cd96614SDmitry Salychev goto err_exit; 212ba7319e9SDmitry Salychev } 213*4cd96614SDmitry Salychev error = DPAA2_CMD_MCP_OPEN(dev, child, &cmd, dinfo->id, &mcp_token); 214ba7319e9SDmitry Salychev if (error) { 215ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to open DPMCP: id=%d, error=%d\n", 216ba7319e9SDmitry Salychev __func__, dinfo->id, error); 217*4cd96614SDmitry Salychev goto close_rc; 218ba7319e9SDmitry Salychev } 219ba7319e9SDmitry Salychev 220ba7319e9SDmitry Salychev /* Prepare DPMCP object. */ 221*4cd96614SDmitry Salychev error = DPAA2_CMD_MCP_RESET(dev, child, &cmd); 222ba7319e9SDmitry Salychev if (error) { 223ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to reset DPMCP: id=%d, " 224ba7319e9SDmitry Salychev "error=%d\n", __func__, dinfo->id, error); 225*4cd96614SDmitry Salychev goto close_mcp; 226ba7319e9SDmitry Salychev } 227ba7319e9SDmitry Salychev 228*4cd96614SDmitry Salychev (void)DPAA2_CMD_MCP_CLOSE(dev, child, &cmd); 229*4cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 230ba7319e9SDmitry Salychev dinfo->portal = portal; 231ba7319e9SDmitry Salychev 232ba7319e9SDmitry Salychev return (0); 233ba7319e9SDmitry Salychev 234*4cd96614SDmitry Salychev close_mcp: 235*4cd96614SDmitry Salychev (void)DPAA2_CMD_MCP_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, mcp_token)); 236*4cd96614SDmitry Salychev close_rc: 237*4cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 238ba7319e9SDmitry Salychev err_exit: 239ba7319e9SDmitry Salychev dpaa2_mcp_detach(dev); 240ba7319e9SDmitry Salychev return (ENXIO); 241ba7319e9SDmitry Salychev } 242ba7319e9SDmitry Salychev 243ba7319e9SDmitry Salychev static device_method_t dpaa2_mcp_methods[] = { 244ba7319e9SDmitry Salychev /* Device interface */ 245ba7319e9SDmitry Salychev DEVMETHOD(device_probe, dpaa2_mcp_probe), 246ba7319e9SDmitry Salychev DEVMETHOD(device_attach, dpaa2_mcp_attach), 247ba7319e9SDmitry Salychev DEVMETHOD(device_detach, dpaa2_mcp_detach), 248ba7319e9SDmitry Salychev 249ba7319e9SDmitry Salychev DEVMETHOD_END 250ba7319e9SDmitry Salychev }; 251ba7319e9SDmitry Salychev 252ba7319e9SDmitry Salychev static driver_t dpaa2_mcp_driver = { 253ba7319e9SDmitry Salychev "dpaa2_mcp", 254ba7319e9SDmitry Salychev dpaa2_mcp_methods, 255ba7319e9SDmitry Salychev sizeof(struct dpaa2_mcp_softc), 256ba7319e9SDmitry Salychev }; 257ba7319e9SDmitry Salychev 258ba7319e9SDmitry Salychev DRIVER_MODULE(dpaa2_mcp, dpaa2_rc, dpaa2_mcp_driver, 0, 0); 259