mirror of
https://github.com/opnsense/src.git
synced 2026-02-27 03:40:37 -05:00
DPAA2 is a hardware-level networking architecture found in some NXP SoCs which contain hardware blocks including Management Complex (MC, a command interface to manipulate DPAA2 objects), Wire Rate I/O processor (WRIOP, packets distribution, queuing, drop decisions), Queues and Buffers Manager (QBMan, Rx/Tx queues control, Rx buffer pools) and the others. The Management Complex runs NXP-supplied firmware which provides DPAA2 objects as an abstraction layer over those blocks to simplify an access to the underlying hardware. Each DPAA2 object has its own driver (to perform an initialization at least) and will be visible as a separate device in the device tree. Two new drivers (dpaa2_mc and dpaa2_rc) act like firmware buses in order to form a hierarchy of the DPAA2 devices: acpiX (or simplebusX) dpaa2_mcX dpaa2_rcX dpaa2_mcp0 ... dpaa2_mcpN dpaa2_bpX dpaa2_macX dpaa2_io0 ... dpaa2_ioM dpaa2_niX dpaa2_mc is suppossed to be a root of the hierarchy, comes in ACPI and FDT flavours and implements helper interfaces to allocate and assign bus resources, MSI and "managed" DPAA2 devices (NXP treats some of the objects as resources for the other DPAA2 objects to let them function properly). Almost all of the DPAA2 objects are assigned to the resource containers (dpaa2_rc) to implement isolation. The initial implementation focuses on the DPAA2 network interface to be operational. It is the most complex object in terms of dependencies which uses I/O objects to transmit/receive packets. Approved by: bz (mentor) Tested by: manu, bz MFC after: 3 months Differential Revision: https://reviews.freebsd.org/D36638
3585 lines
96 KiB
C
3585 lines
96 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright © 2021-2022 Dmitry Salychev
|
|
*
|
|
* 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 <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
/*
|
|
* The DPAA2 Resource Container (DPRC) bus driver.
|
|
*
|
|
* DPRC holds all the resources and object information that a software context
|
|
* (kernel, virtual machine, etc.) can access or use.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/bus.h>
|
|
#include <sys/rman.h>
|
|
#include <sys/module.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/mutex.h>
|
|
#include <sys/condvar.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/smp.h>
|
|
|
|
#include <machine/bus.h>
|
|
#include <machine/resource.h>
|
|
|
|
#include "pcib_if.h"
|
|
#include "pci_if.h"
|
|
|
|
#include "dpaa2_mcp.h"
|
|
#include "dpaa2_mc.h"
|
|
#include "dpaa2_ni.h"
|
|
#include "dpaa2_mc_if.h"
|
|
#include "dpaa2_cmd_if.h"
|
|
|
|
/* Timeouts to wait for a command response from MC. */
|
|
#define CMD_SPIN_TIMEOUT 100u /* us */
|
|
#define CMD_SPIN_ATTEMPTS 2000u /* max. 200 ms */
|
|
|
|
#define TYPE_LEN_MAX 16u
|
|
#define LABEL_LEN_MAX 16u
|
|
|
|
MALLOC_DEFINE(M_DPAA2_RC, "dpaa2_rc", "DPAA2 Resource Container");
|
|
|
|
/* Discover and add devices to the resource container. */
|
|
static int dpaa2_rc_discover(struct dpaa2_rc_softc *);
|
|
static int dpaa2_rc_add_child(struct dpaa2_rc_softc *, struct dpaa2_cmd *,
|
|
struct dpaa2_obj *);
|
|
static int dpaa2_rc_add_managed_child(struct dpaa2_rc_softc *,
|
|
struct dpaa2_cmd *, struct dpaa2_obj *);
|
|
|
|
/* Helper routines. */
|
|
static int dpaa2_rc_enable_irq(struct dpaa2_mcp *, struct dpaa2_cmd *, uint8_t,
|
|
bool, uint16_t);
|
|
static int dpaa2_rc_configure_irq(device_t, device_t, int, uint64_t, uint32_t);
|
|
static int dpaa2_rc_add_res(device_t, device_t, enum dpaa2_dev_type, int *, int);
|
|
static int dpaa2_rc_print_type(struct resource_list *, enum dpaa2_dev_type);
|
|
static struct dpaa2_mcp *dpaa2_rc_select_portal(device_t, device_t);
|
|
|
|
/* Routines to send commands to MC. */
|
|
static int dpaa2_rc_exec_cmd(struct dpaa2_mcp *, struct dpaa2_cmd *, uint16_t);
|
|
static int dpaa2_rc_send_cmd(struct dpaa2_mcp *, struct dpaa2_cmd *);
|
|
static int dpaa2_rc_wait_for_cmd(struct dpaa2_mcp *, struct dpaa2_cmd *);
|
|
static int dpaa2_rc_reset_cmd_params(struct dpaa2_cmd *);
|
|
|
|
static int
|
|
dpaa2_rc_probe(device_t dev)
|
|
{
|
|
/* DPRC device will be added by the parent DPRC or MC bus itself. */
|
|
device_set_desc(dev, "DPAA2 Resource Container");
|
|
return (BUS_PROBE_DEFAULT);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_detach(device_t dev)
|
|
{
|
|
struct dpaa2_devinfo *dinfo;
|
|
int error;
|
|
|
|
error = bus_generic_detach(dev);
|
|
if (error)
|
|
return (error);
|
|
|
|
dinfo = device_get_ivars(dev);
|
|
|
|
if (dinfo->portal)
|
|
dpaa2_mcp_free_portal(dinfo->portal);
|
|
if (dinfo)
|
|
free(dinfo, M_DPAA2_RC);
|
|
|
|
return (device_delete_children(dev));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_attach(device_t dev)
|
|
{
|
|
device_t pdev;
|
|
struct dpaa2_mc_softc *mcsc;
|
|
struct dpaa2_rc_softc *sc;
|
|
struct dpaa2_devinfo *dinfo = NULL;
|
|
int error;
|
|
|
|
sc = device_get_softc(dev);
|
|
sc->dev = dev;
|
|
sc->unit = device_get_unit(dev);
|
|
|
|
if (sc->unit == 0) {
|
|
/* Root DPRC should be attached directly to the MC bus. */
|
|
pdev = device_get_parent(dev);
|
|
mcsc = device_get_softc(pdev);
|
|
|
|
KASSERT(strcmp(device_get_name(pdev), "dpaa2_mc") == 0,
|
|
("root DPRC should be attached to the MC bus"));
|
|
|
|
/*
|
|
* Allocate devinfo to let the parent MC bus access ICID of the
|
|
* DPRC object.
|
|
*/
|
|
dinfo = malloc(sizeof(struct dpaa2_devinfo), M_DPAA2_RC,
|
|
M_WAITOK | M_ZERO);
|
|
if (!dinfo) {
|
|
device_printf(dev, "%s: failed to allocate "
|
|
"dpaa2_devinfo\n", __func__);
|
|
dpaa2_rc_detach(dev);
|
|
return (ENXIO);
|
|
}
|
|
device_set_ivars(dev, dinfo);
|
|
|
|
dinfo->pdev = pdev;
|
|
dinfo->dev = dev;
|
|
dinfo->dtype = DPAA2_DEV_RC;
|
|
dinfo->portal = NULL;
|
|
|
|
/* Prepare helper portal object to send commands to MC. */
|
|
error = dpaa2_mcp_init_portal(&dinfo->portal, mcsc->res[0],
|
|
&mcsc->map[0], DPAA2_PORTAL_DEF);
|
|
if (error) {
|
|
device_printf(dev, "%s: failed to initialize dpaa2_mcp: "
|
|
"error=%d\n", __func__, error);
|
|
dpaa2_rc_detach(dev);
|
|
return (ENXIO);
|
|
}
|
|
} else {
|
|
/* TODO: Child DPRCs aren't supported yet. */
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* Create DPAA2 devices for objects in this container. */
|
|
error = dpaa2_rc_discover(sc);
|
|
if (error) {
|
|
device_printf(dev, "%s: failed to discover objects in "
|
|
"container: error=%d\n", __func__, error);
|
|
dpaa2_rc_detach(dev);
|
|
return (error);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Bus interface.
|
|
*/
|
|
|
|
static struct resource_list *
|
|
dpaa2_rc_get_resource_list(device_t rcdev, device_t child)
|
|
{
|
|
struct dpaa2_devinfo *dinfo = device_get_ivars(child);
|
|
|
|
return (&dinfo->resources);
|
|
}
|
|
|
|
static void
|
|
dpaa2_rc_delete_resource(device_t rcdev, device_t child, int type, int rid)
|
|
{
|
|
struct resource_list *rl;
|
|
struct resource_list_entry *rle;
|
|
struct dpaa2_devinfo *dinfo;
|
|
|
|
if (device_get_parent(child) != rcdev)
|
|
return;
|
|
|
|
dinfo = device_get_ivars(child);
|
|
rl = &dinfo->resources;
|
|
rle = resource_list_find(rl, type, rid);
|
|
if (rle == NULL)
|
|
return;
|
|
|
|
if (rle->res) {
|
|
if (rman_get_flags(rle->res) & RF_ACTIVE ||
|
|
resource_list_busy(rl, type, rid)) {
|
|
device_printf(rcdev, "%s: resource still owned by "
|
|
"child: type=%d, rid=%d, start=%jx\n", __func__,
|
|
type, rid, rman_get_start(rle->res));
|
|
return;
|
|
}
|
|
resource_list_unreserve(rl, rcdev, child, type, rid);
|
|
}
|
|
resource_list_delete(rl, type, rid);
|
|
}
|
|
|
|
static struct resource *
|
|
dpaa2_rc_alloc_multi_resource(device_t rcdev, device_t child, int type, int *rid,
|
|
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
|
|
{
|
|
struct resource_list *rl;
|
|
struct dpaa2_devinfo *dinfo;
|
|
|
|
dinfo = device_get_ivars(child);
|
|
rl = &dinfo->resources;
|
|
|
|
/*
|
|
* By default, software portal interrupts are message-based, that is,
|
|
* they are issued from QMan using a 4 byte write.
|
|
*
|
|
* TODO: However this default behavior can be changed by programming one
|
|
* or more software portals to issue their interrupts via a
|
|
* dedicated software portal interrupt wire.
|
|
* See registers SWP_INTW0_CFG to SWP_INTW3_CFG for details.
|
|
*/
|
|
if (type == SYS_RES_IRQ && *rid == 0)
|
|
return (NULL);
|
|
|
|
return (resource_list_alloc(rl, rcdev, child, type, rid,
|
|
start, end, count, flags));
|
|
}
|
|
|
|
static struct resource *
|
|
dpaa2_rc_alloc_resource(device_t rcdev, device_t child, int type, int *rid,
|
|
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
|
|
{
|
|
if (device_get_parent(child) != rcdev)
|
|
return (BUS_ALLOC_RESOURCE(device_get_parent(rcdev), child,
|
|
type, rid, start, end, count, flags));
|
|
|
|
return (dpaa2_rc_alloc_multi_resource(rcdev, child, type, rid, start,
|
|
end, count, flags));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_release_resource(device_t rcdev, device_t child, int type, int rid,
|
|
struct resource *r)
|
|
{
|
|
struct resource_list *rl;
|
|
struct dpaa2_devinfo *dinfo;
|
|
|
|
if (device_get_parent(child) != rcdev)
|
|
return (BUS_RELEASE_RESOURCE(device_get_parent(rcdev), child,
|
|
type, rid, r));
|
|
|
|
dinfo = device_get_ivars(child);
|
|
rl = &dinfo->resources;
|
|
return (resource_list_release(rl, rcdev, child, type, rid, r));
|
|
}
|
|
|
|
static void
|
|
dpaa2_rc_child_deleted(device_t rcdev, device_t child)
|
|
{
|
|
struct dpaa2_devinfo *dinfo;
|
|
struct resource_list *rl;
|
|
struct resource_list_entry *rle;
|
|
|
|
dinfo = device_get_ivars(child);
|
|
rl = &dinfo->resources;
|
|
|
|
/* Free all allocated resources */
|
|
STAILQ_FOREACH(rle, rl, link) {
|
|
if (rle->res) {
|
|
if (rman_get_flags(rle->res) & RF_ACTIVE ||
|
|
resource_list_busy(rl, rle->type, rle->rid)) {
|
|
device_printf(child, "%s: resource still owned: "
|
|
"type=%d, rid=%d, addr=%lx\n", __func__,
|
|
rle->type, rle->rid,
|
|
rman_get_start(rle->res));
|
|
bus_release_resource(child, rle->type, rle->rid,
|
|
rle->res);
|
|
}
|
|
resource_list_unreserve(rl, rcdev, child, rle->type,
|
|
rle->rid);
|
|
}
|
|
}
|
|
resource_list_free(rl);
|
|
|
|
if (dinfo)
|
|
free(dinfo, M_DPAA2_RC);
|
|
}
|
|
|
|
static void
|
|
dpaa2_rc_child_detached(device_t rcdev, device_t child)
|
|
{
|
|
struct dpaa2_devinfo *dinfo;
|
|
struct resource_list *rl;
|
|
|
|
dinfo = device_get_ivars(child);
|
|
rl = &dinfo->resources;
|
|
|
|
if (resource_list_release_active(rl, rcdev, child, SYS_RES_IRQ) != 0)
|
|
device_printf(child, "%s: leaked IRQ resources!\n", __func__);
|
|
if (dinfo->msi.msi_alloc != 0) {
|
|
device_printf(child, "%s: leaked %d MSI vectors!\n", __func__,
|
|
dinfo->msi.msi_alloc);
|
|
PCI_RELEASE_MSI(rcdev, child);
|
|
}
|
|
if (resource_list_release_active(rl, rcdev, child, SYS_RES_MEMORY) != 0)
|
|
device_printf(child, "%s: leaked memory resources!\n", __func__);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_setup_intr(device_t rcdev, device_t child, struct resource *irq,
|
|
int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
|
|
void **cookiep)
|
|
{
|
|
struct dpaa2_devinfo *dinfo;
|
|
uint64_t addr;
|
|
uint32_t data;
|
|
void *cookie;
|
|
int error, rid;
|
|
|
|
error = bus_generic_setup_intr(rcdev, child, irq, flags, filter, intr,
|
|
arg, &cookie);
|
|
if (error) {
|
|
device_printf(rcdev, "%s: bus_generic_setup_intr() failed: "
|
|
"error=%d\n", __func__, error);
|
|
return (error);
|
|
}
|
|
|
|
/* If this is not a direct child, just bail out. */
|
|
if (device_get_parent(child) != rcdev) {
|
|
*cookiep = cookie;
|
|
return (0);
|
|
}
|
|
|
|
rid = rman_get_rid(irq);
|
|
if (rid == 0) {
|
|
if (bootverbose)
|
|
device_printf(rcdev, "%s: cannot setup interrupt with "
|
|
"rid=0: INTx are not supported by DPAA2 objects "
|
|
"yet\n", __func__);
|
|
return (EINVAL);
|
|
} else {
|
|
dinfo = device_get_ivars(child);
|
|
KASSERT(dinfo->msi.msi_alloc > 0,
|
|
("No MSI interrupts allocated"));
|
|
|
|
/*
|
|
* Ask our parent to map the MSI and give us the address and
|
|
* data register values. If we fail for some reason, teardown
|
|
* the interrupt handler.
|
|
*/
|
|
error = PCIB_MAP_MSI(device_get_parent(rcdev), child,
|
|
rman_get_start(irq), &addr, &data);
|
|
if (error) {
|
|
device_printf(rcdev, "%s: PCIB_MAP_MSI failed: "
|
|
"error=%d\n", __func__, error);
|
|
(void)bus_generic_teardown_intr(rcdev, child, irq,
|
|
cookie);
|
|
return (error);
|
|
}
|
|
|
|
/* Configure MSI for this DPAA2 object. */
|
|
error = dpaa2_rc_configure_irq(rcdev, child, rid, addr, data);
|
|
if (error) {
|
|
device_printf(rcdev, "%s: failed to configure IRQ for "
|
|
"DPAA2 object: rid=%d, type=%s, unit=%d\n", __func__,
|
|
rid, dpaa2_ttos(dinfo->dtype),
|
|
device_get_unit(child));
|
|
return (error);
|
|
}
|
|
dinfo->msi.msi_handlers++;
|
|
}
|
|
*cookiep = cookie;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_teardown_intr(device_t rcdev, device_t child, struct resource *irq,
|
|
void *cookie)
|
|
{
|
|
struct resource_list_entry *rle;
|
|
struct dpaa2_devinfo *dinfo;
|
|
int error, rid;
|
|
|
|
if (irq == NULL || !(rman_get_flags(irq) & RF_ACTIVE))
|
|
return (EINVAL);
|
|
|
|
/* If this isn't a direct child, just bail out */
|
|
if (device_get_parent(child) != rcdev)
|
|
return(bus_generic_teardown_intr(rcdev, child, irq, cookie));
|
|
|
|
rid = rman_get_rid(irq);
|
|
if (rid == 0) {
|
|
if (bootverbose)
|
|
device_printf(rcdev, "%s: cannot teardown interrupt "
|
|
"with rid=0: INTx are not supported by DPAA2 "
|
|
"objects yet\n", __func__);
|
|
return (EINVAL);
|
|
} else {
|
|
dinfo = device_get_ivars(child);
|
|
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid);
|
|
if (rle->res != irq)
|
|
return (EINVAL);
|
|
dinfo->msi.msi_handlers--;
|
|
}
|
|
|
|
error = bus_generic_teardown_intr(rcdev, child, irq, cookie);
|
|
if (rid > 0)
|
|
KASSERT(error == 0,
|
|
("%s: generic teardown failed for MSI", __func__));
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_print_child(device_t rcdev, device_t child)
|
|
{
|
|
struct dpaa2_devinfo *dinfo = device_get_ivars(child);
|
|
struct resource_list *rl = &dinfo->resources;
|
|
int retval = 0;
|
|
|
|
retval += bus_print_child_header(rcdev, child);
|
|
|
|
retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
|
|
retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
|
|
retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
|
|
|
|
/* Print DPAA2-specific resources. */
|
|
retval += dpaa2_rc_print_type(rl, DPAA2_DEV_IO);
|
|
retval += dpaa2_rc_print_type(rl, DPAA2_DEV_BP);
|
|
retval += dpaa2_rc_print_type(rl, DPAA2_DEV_CON);
|
|
retval += dpaa2_rc_print_type(rl, DPAA2_DEV_MCP);
|
|
|
|
retval += printf(" at %s (id=%u)", dpaa2_ttos(dinfo->dtype), dinfo->id);
|
|
|
|
retval += bus_print_child_domain(rcdev, child);
|
|
retval += bus_print_child_footer(rcdev, child);
|
|
|
|
return (retval);
|
|
}
|
|
|
|
/*
|
|
* Pseudo-PCI interface.
|
|
*/
|
|
|
|
/*
|
|
* Attempt to allocate *count MSI messages. The actual number allocated is
|
|
* returned in *count. After this function returns, each message will be
|
|
* available to the driver as SYS_RES_IRQ resources starting at a rid 1.
|
|
*
|
|
* NOTE: Implementation is similar to sys/dev/pci/pci.c.
|
|
*/
|
|
static int
|
|
dpaa2_rc_alloc_msi(device_t rcdev, device_t child, int *count)
|
|
{
|
|
struct dpaa2_devinfo *rcinfo = device_get_ivars(rcdev);
|
|
struct dpaa2_devinfo *dinfo = device_get_ivars(child);
|
|
int error, actual, i, run, irqs[32];
|
|
|
|
/* Don't let count == 0 get us into trouble. */
|
|
if (*count == 0)
|
|
return (EINVAL);
|
|
|
|
/* MSI should be allocated by the resource container. */
|
|
if (rcinfo->dtype != DPAA2_DEV_RC)
|
|
return (ENODEV);
|
|
|
|
/* Already have allocated messages? */
|
|
if (dinfo->msi.msi_alloc != 0)
|
|
return (ENXIO);
|
|
|
|
/* Don't ask for more than the device supports. */
|
|
actual = min(*count, dinfo->msi.msi_msgnum);
|
|
|
|
/* Don't ask for more than 32 messages. */
|
|
actual = min(actual, 32);
|
|
|
|
/* MSI requires power of 2 number of messages. */
|
|
if (!powerof2(actual))
|
|
return (EINVAL);
|
|
|
|
for (;;) {
|
|
/* Try to allocate N messages. */
|
|
error = PCIB_ALLOC_MSI(device_get_parent(rcdev), child, actual,
|
|
actual, irqs);
|
|
if (error == 0)
|
|
break;
|
|
if (actual == 1)
|
|
return (error);
|
|
|
|
/* Try N / 2. */
|
|
actual >>= 1;
|
|
}
|
|
|
|
/*
|
|
* We now have N actual messages mapped onto SYS_RES_IRQ resources in
|
|
* the irqs[] array, so add new resources starting at rid 1.
|
|
*/
|
|
for (i = 0; i < actual; i++)
|
|
resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1,
|
|
irqs[i], irqs[i], 1);
|
|
|
|
if (bootverbose) {
|
|
if (actual == 1) {
|
|
device_printf(child, "using IRQ %d for MSI\n", irqs[0]);
|
|
} else {
|
|
/*
|
|
* Be fancy and try to print contiguous runs
|
|
* of IRQ values as ranges. 'run' is true if
|
|
* we are in a range.
|
|
*/
|
|
device_printf(child, "using IRQs %d", irqs[0]);
|
|
run = 0;
|
|
for (i = 1; i < actual; i++) {
|
|
/* Still in a run? */
|
|
if (irqs[i] == irqs[i - 1] + 1) {
|
|
run = 1;
|
|
continue;
|
|
}
|
|
|
|
/* Finish previous range. */
|
|
if (run) {
|
|
printf("-%d", irqs[i - 1]);
|
|
run = 0;
|
|
}
|
|
|
|
/* Start new range. */
|
|
printf(",%d", irqs[i]);
|
|
}
|
|
|
|
/* Unfinished range? */
|
|
if (run)
|
|
printf("-%d", irqs[actual - 1]);
|
|
printf(" for MSI\n");
|
|
}
|
|
}
|
|
|
|
/* Update counts of alloc'd messages. */
|
|
dinfo->msi.msi_alloc = actual;
|
|
dinfo->msi.msi_handlers = 0;
|
|
*count = actual;
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Release the MSI messages associated with this DPAA2 device.
|
|
*
|
|
* NOTE: Implementation is similar to sys/dev/pci/pci.c.
|
|
*/
|
|
static int
|
|
dpaa2_rc_release_msi(device_t rcdev, device_t child)
|
|
{
|
|
struct dpaa2_devinfo *rcinfo = device_get_ivars(rcdev);
|
|
struct dpaa2_devinfo *dinfo = device_get_ivars(child);
|
|
struct resource_list_entry *rle;
|
|
int i, irqs[32];
|
|
|
|
/* MSI should be released by the resource container. */
|
|
if (rcinfo->dtype != DPAA2_DEV_RC)
|
|
return (ENODEV);
|
|
|
|
/* Do we have any messages to release? */
|
|
if (dinfo->msi.msi_alloc == 0)
|
|
return (ENODEV);
|
|
KASSERT(dinfo->msi.msi_alloc <= 32,
|
|
("more than 32 alloc'd MSI messages"));
|
|
|
|
/* Make sure none of the resources are allocated. */
|
|
if (dinfo->msi.msi_handlers > 0)
|
|
return (EBUSY);
|
|
for (i = 0; i < dinfo->msi.msi_alloc; i++) {
|
|
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
|
|
KASSERT(rle != NULL, ("missing MSI resource"));
|
|
if (rle->res != NULL)
|
|
return (EBUSY);
|
|
irqs[i] = rle->start;
|
|
}
|
|
|
|
/* Release the messages. */
|
|
PCIB_RELEASE_MSI(device_get_parent(rcdev), child, dinfo->msi.msi_alloc,
|
|
irqs);
|
|
for (i = 0; i < dinfo->msi.msi_alloc; i++)
|
|
resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1);
|
|
|
|
/* Update alloc count. */
|
|
dinfo->msi.msi_alloc = 0;
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* @brief Return the maximum number of the MSI supported by this DPAA2 device.
|
|
*/
|
|
static int
|
|
dpaa2_rc_msi_count(device_t rcdev, device_t child)
|
|
{
|
|
struct dpaa2_devinfo *dinfo = device_get_ivars(child);
|
|
|
|
return (dinfo->msi.msi_msgnum);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_id(device_t rcdev, device_t child, enum pci_id_type type,
|
|
uintptr_t *id)
|
|
{
|
|
struct dpaa2_devinfo *rcinfo = device_get_ivars(rcdev);
|
|
|
|
if (rcinfo->dtype != DPAA2_DEV_RC)
|
|
return (ENODEV);
|
|
|
|
return (PCIB_GET_ID(device_get_parent(rcdev), child, type, id));
|
|
}
|
|
|
|
/*
|
|
* DPAA2 MC command interface.
|
|
*/
|
|
|
|
static int
|
|
dpaa2_rc_mng_get_version(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t *major, uint32_t *minor, uint32_t *rev)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || major == NULL || minor == NULL ||
|
|
rev == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MNG_GET_VER);
|
|
if (!error) {
|
|
*major = cmd->params[0] >> 32;
|
|
*minor = cmd->params[1] & 0xFFFFFFFF;
|
|
*rev = cmd->params[0] & 0xFFFFFFFF;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mng_get_soc_version(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t *pvr, uint32_t *svr)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || pvr == NULL || svr == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MNG_GET_SOC_VER);
|
|
if (!error) {
|
|
*pvr = cmd->params[0] >> 32;
|
|
*svr = cmd->params[0] & 0xFFFFFFFF;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mng_get_container_id(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, uint32_t *cont_id)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || cont_id == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MNG_GET_CONT_ID);
|
|
if (!error)
|
|
*cont_id = cmd->params[0] & 0xFFFFFFFF;
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_open(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t cont_id, uint16_t *token)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
struct dpaa2_cmd_header *hdr;
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || token == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = cont_id;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_OPEN);
|
|
if (!error) {
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
*token = hdr->token;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_close(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_CLOSE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_obj_count(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t *obj_count)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || obj_count == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_GET_OBJ_COUNT);
|
|
if (!error)
|
|
*obj_count = (uint32_t)(cmd->params[0] >> 32);
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_obj(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t obj_idx, struct dpaa2_obj *obj)
|
|
{
|
|
struct __packed dpaa2_obj_resp {
|
|
uint32_t _reserved1;
|
|
uint32_t id;
|
|
uint16_t vendor;
|
|
uint8_t irq_count;
|
|
uint8_t reg_count;
|
|
uint32_t state;
|
|
uint16_t ver_major;
|
|
uint16_t ver_minor;
|
|
uint16_t flags;
|
|
uint16_t _reserved2;
|
|
uint8_t type[16];
|
|
uint8_t label[16];
|
|
} *pobj;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || obj == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = obj_idx;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_GET_OBJ);
|
|
if (!error) {
|
|
pobj = (struct dpaa2_obj_resp *) &cmd->params[0];
|
|
obj->id = pobj->id;
|
|
obj->vendor = pobj->vendor;
|
|
obj->irq_count = pobj->irq_count;
|
|
obj->reg_count = pobj->reg_count;
|
|
obj->state = pobj->state;
|
|
obj->ver_major = pobj->ver_major;
|
|
obj->ver_minor = pobj->ver_minor;
|
|
obj->flags = pobj->flags;
|
|
obj->type = dpaa2_stot((const char *) pobj->type);
|
|
memcpy(obj->label, pobj->label, sizeof(pobj->label));
|
|
}
|
|
|
|
/* Some DPAA2 objects might not be supported by the driver yet. */
|
|
if (obj->type == DPAA2_DEV_NOTYPE)
|
|
error = DPAA2_CMD_STAT_UNKNOWN_OBJ;
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_obj_descriptor(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, uint32_t obj_id, enum dpaa2_dev_type dtype,
|
|
struct dpaa2_obj *obj)
|
|
{
|
|
struct __packed get_obj_desc_args {
|
|
uint32_t obj_id;
|
|
uint32_t _reserved1;
|
|
uint8_t type[16];
|
|
} *args;
|
|
struct __packed dpaa2_obj_resp {
|
|
uint32_t _reserved1;
|
|
uint32_t id;
|
|
uint16_t vendor;
|
|
uint8_t irq_count;
|
|
uint8_t reg_count;
|
|
uint32_t state;
|
|
uint16_t ver_major;
|
|
uint16_t ver_minor;
|
|
uint16_t flags;
|
|
uint16_t _reserved2;
|
|
uint8_t type[16];
|
|
uint8_t label[16];
|
|
} *pobj;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
const char *type = dpaa2_ttos(dtype);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || obj == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct get_obj_desc_args *) &cmd->params[0];
|
|
args->obj_id = obj_id;
|
|
memcpy(args->type, type, min(strlen(type) + 1, TYPE_LEN_MAX));
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_GET_OBJ_DESC);
|
|
if (!error) {
|
|
pobj = (struct dpaa2_obj_resp *) &cmd->params[0];
|
|
obj->id = pobj->id;
|
|
obj->vendor = pobj->vendor;
|
|
obj->irq_count = pobj->irq_count;
|
|
obj->reg_count = pobj->reg_count;
|
|
obj->state = pobj->state;
|
|
obj->ver_major = pobj->ver_major;
|
|
obj->ver_minor = pobj->ver_minor;
|
|
obj->flags = pobj->flags;
|
|
obj->type = dpaa2_stot((const char *) pobj->type);
|
|
memcpy(obj->label, pobj->label, sizeof(pobj->label));
|
|
}
|
|
|
|
/* Some DPAA2 objects might not be supported by the driver yet. */
|
|
if (obj->type == DPAA2_DEV_NOTYPE)
|
|
error = DPAA2_CMD_STAT_UNKNOWN_OBJ;
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_attributes(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_rc_attr *attr)
|
|
{
|
|
struct __packed dpaa2_rc_attr {
|
|
uint32_t cont_id;
|
|
uint32_t icid;
|
|
uint32_t options;
|
|
uint32_t portal_id;
|
|
} *pattr;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || attr == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_GET_ATTR);
|
|
if (!error) {
|
|
pattr = (struct dpaa2_rc_attr *) &cmd->params[0];
|
|
attr->cont_id = pattr->cont_id;
|
|
attr->portal_id = pattr->portal_id;
|
|
attr->options = pattr->options;
|
|
attr->icid = pattr->icid;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_obj_region(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t obj_id, uint8_t reg_idx, enum dpaa2_dev_type dtype,
|
|
struct dpaa2_rc_obj_region *reg)
|
|
{
|
|
struct __packed obj_region_args {
|
|
uint32_t obj_id;
|
|
uint16_t _reserved1;
|
|
uint8_t reg_idx;
|
|
uint8_t _reserved2;
|
|
uint64_t _reserved3;
|
|
uint64_t _reserved4;
|
|
uint8_t type[16];
|
|
} *args;
|
|
struct __packed obj_region {
|
|
uint64_t _reserved1;
|
|
uint64_t base_offset;
|
|
uint32_t size;
|
|
uint32_t type;
|
|
uint32_t flags;
|
|
uint32_t _reserved2;
|
|
uint64_t base_paddr;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
uint16_t cmdid, api_major, api_minor;
|
|
const char *type = dpaa2_ttos(dtype);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || reg == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
/*
|
|
* If the DPRC object version was not yet cached, cache it now.
|
|
* Otherwise use the already cached value.
|
|
*/
|
|
if (!portal->rc_api_major && !portal->rc_api_minor) {
|
|
error = DPAA2_CMD_RC_GET_API_VERSION(dev, child, cmd,
|
|
&api_major, &api_minor);
|
|
if (error)
|
|
return (error);
|
|
portal->rc_api_major = api_major;
|
|
portal->rc_api_minor = api_minor;
|
|
} else {
|
|
api_major = portal->rc_api_major;
|
|
api_minor = portal->rc_api_minor;
|
|
}
|
|
|
|
/* TODO: Remove magic numbers. */
|
|
if (api_major > 6u || (api_major == 6u && api_minor >= 6u))
|
|
/*
|
|
* MC API version 6.6 changed the size of the MC portals and
|
|
* software portals to 64K (as implemented by hardware).
|
|
*/
|
|
cmdid = CMDID_RC_GET_OBJ_REG_V3;
|
|
else if (api_major == 6u && api_minor >= 3u)
|
|
/*
|
|
* MC API version 6.3 introduced a new field to the region
|
|
* descriptor: base_address.
|
|
*/
|
|
cmdid = CMDID_RC_GET_OBJ_REG_V2;
|
|
else
|
|
cmdid = CMDID_RC_GET_OBJ_REG;
|
|
|
|
args = (struct obj_region_args *) &cmd->params[0];
|
|
args->obj_id = obj_id;
|
|
args->reg_idx = reg_idx;
|
|
memcpy(args->type, type, min(strlen(type) + 1, TYPE_LEN_MAX));
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, cmdid);
|
|
if (!error) {
|
|
resp = (struct obj_region *) &cmd->params[0];
|
|
reg->base_paddr = resp->base_paddr;
|
|
reg->base_offset = resp->base_offset;
|
|
reg->size = resp->size;
|
|
reg->flags = resp->flags;
|
|
reg->type = resp->type & 0xFu;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_api_version(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint16_t *major, uint16_t *minor)
|
|
{
|
|
struct __packed rc_api_version {
|
|
uint16_t major;
|
|
uint16_t minor;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || major == NULL || minor == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_GET_API_VERSION);
|
|
if (!error) {
|
|
resp = (struct rc_api_version *) &cmd->params[0];
|
|
*major = resp->major;
|
|
*minor = resp->minor;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_set_irq_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint8_t enable)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_enable_irq(portal, cmd, irq_idx, enable,
|
|
CMDID_RC_SET_IRQ_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_set_obj_irq(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint64_t addr, uint32_t data, uint32_t irq_usr,
|
|
uint32_t obj_id, enum dpaa2_dev_type dtype)
|
|
{
|
|
struct __packed set_obj_irq_args {
|
|
uint32_t data;
|
|
uint8_t irq_idx;
|
|
uint8_t _reserved1[3];
|
|
uint64_t addr;
|
|
uint32_t irq_usr;
|
|
uint32_t obj_id;
|
|
uint8_t type[16];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
const char *type = dpaa2_ttos(dtype);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct set_obj_irq_args *) &cmd->params[0];
|
|
args->irq_idx = irq_idx;
|
|
args->addr = addr;
|
|
args->data = data;
|
|
args->irq_usr = irq_usr;
|
|
args->obj_id = obj_id;
|
|
memcpy(args->type, type, min(strlen(type) + 1, TYPE_LEN_MAX));
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_SET_OBJ_IRQ));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_get_conn(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ep_desc *ep1_desc, struct dpaa2_ep_desc *ep2_desc,
|
|
uint32_t *link_stat)
|
|
{
|
|
struct __packed get_conn_args {
|
|
uint32_t ep1_id;
|
|
uint32_t ep1_ifid;
|
|
uint8_t ep1_type[16];
|
|
uint64_t _reserved[4];
|
|
} *args;
|
|
struct __packed get_conn_resp {
|
|
uint64_t _reserved1[3];
|
|
uint32_t ep2_id;
|
|
uint32_t ep2_ifid;
|
|
uint8_t ep2_type[16];
|
|
uint32_t link_stat;
|
|
uint32_t _reserved2;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || ep1_desc == NULL ||
|
|
ep2_desc == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct get_conn_args *) &cmd->params[0];
|
|
args->ep1_id = ep1_desc->obj_id;
|
|
args->ep1_ifid = ep1_desc->if_id;
|
|
/* TODO: Remove magic number. */
|
|
strncpy(args->ep1_type, dpaa2_ttos(ep1_desc->type), 16);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_RC_GET_CONN);
|
|
if (!error) {
|
|
resp = (struct get_conn_resp *) &cmd->params[0];
|
|
ep2_desc->obj_id = resp->ep2_id;
|
|
ep2_desc->if_id = resp->ep2_ifid;
|
|
ep2_desc->type = dpaa2_stot((const char *) resp->ep2_type);
|
|
if (link_stat != NULL)
|
|
*link_stat = resp->link_stat;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_open(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t dpni_id, uint16_t *token)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
struct dpaa2_cmd_header *hdr;
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || token == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = dpni_id;
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_OPEN);
|
|
if (!error) {
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
*token = hdr->token;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_close(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_CLOSE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_disable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_DISABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_api_version(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint16_t *major, uint16_t *minor)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || major == NULL || minor == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_API_VER);
|
|
if (!error) {
|
|
*major = cmd->params[0] & 0xFFFFU;
|
|
*minor = (cmd->params[0] >> 16) & 0xFFFFU;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_reset(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_RESET));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_attributes(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_attr *attr)
|
|
{
|
|
struct __packed ni_attr {
|
|
uint32_t options;
|
|
uint8_t num_queues;
|
|
uint8_t num_rx_tcs;
|
|
uint8_t mac_entries;
|
|
uint8_t num_tx_tcs;
|
|
uint8_t vlan_entries;
|
|
uint8_t num_channels;
|
|
uint8_t qos_entries;
|
|
uint8_t _reserved1;
|
|
uint16_t fs_entries;
|
|
uint16_t _reserved2;
|
|
uint8_t qos_key_size;
|
|
uint8_t fs_key_size;
|
|
uint16_t wriop_ver;
|
|
uint8_t num_cgs;
|
|
uint8_t _reserved3;
|
|
uint16_t _reserved4;
|
|
uint64_t _reserved5[4];
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || attr == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_ATTR);
|
|
if (!error) {
|
|
resp = (struct ni_attr *) &cmd->params[0];
|
|
|
|
attr->options = resp->options;
|
|
attr->wriop_ver = resp->wriop_ver;
|
|
|
|
attr->entries.fs = resp->fs_entries;
|
|
attr->entries.mac = resp->mac_entries;
|
|
attr->entries.vlan = resp->vlan_entries;
|
|
attr->entries.qos = resp->qos_entries;
|
|
|
|
attr->num.queues = resp->num_queues;
|
|
attr->num.rx_tcs = resp->num_rx_tcs;
|
|
attr->num.tx_tcs = resp->num_tx_tcs;
|
|
attr->num.channels = resp->num_channels;
|
|
attr->num.cgs = resp->num_cgs;
|
|
|
|
attr->key_size.fs = resp->fs_key_size;
|
|
attr->key_size.qos = resp->qos_key_size;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_buf_layout(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_buf_layout *bl)
|
|
{
|
|
struct __packed set_buf_layout_args {
|
|
uint8_t queue_type;
|
|
uint8_t _reserved1;
|
|
uint16_t _reserved2;
|
|
uint16_t options;
|
|
uint8_t params;
|
|
uint8_t _reserved3;
|
|
uint16_t priv_data_size;
|
|
uint16_t data_align;
|
|
uint16_t head_room;
|
|
uint16_t tail_room;
|
|
uint64_t _reserved4[5];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || bl == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct set_buf_layout_args *) &cmd->params[0];
|
|
args->queue_type = (uint8_t) bl->queue_type;
|
|
args->options = bl->options;
|
|
args->params = 0;
|
|
args->priv_data_size = bl->pd_size;
|
|
args->data_align = bl->fd_align;
|
|
args->head_room = bl->head_size;
|
|
args->tail_room = bl->tail_size;
|
|
|
|
args->params |= bl->pass_timestamp ? 1U : 0U;
|
|
args->params |= bl->pass_parser_result ? 2U : 0U;
|
|
args->params |= bl->pass_frame_status ? 4U : 0U;
|
|
args->params |= bl->pass_sw_opaque ? 8U : 0U;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_BUF_LAYOUT));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_tx_data_offset(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, uint16_t *offset)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || offset == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_TX_DATA_OFF);
|
|
if (!error)
|
|
*offset = cmd->params[0] & 0xFFFFU;
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_port_mac_addr(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, uint8_t *mac)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || mac == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_PORT_MAC_ADDR);
|
|
if (!error) {
|
|
mac[0] = (cmd->params[0] >> 56) & 0xFFU;
|
|
mac[1] = (cmd->params[0] >> 48) & 0xFFU;
|
|
mac[2] = (cmd->params[0] >> 40) & 0xFFU;
|
|
mac[3] = (cmd->params[0] >> 32) & 0xFFU;
|
|
mac[4] = (cmd->params[0] >> 24) & 0xFFU;
|
|
mac[5] = (cmd->params[0] >> 16) & 0xFFU;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_prim_mac_addr(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, uint8_t *mac)
|
|
{
|
|
struct __packed set_prim_mac_args {
|
|
uint8_t _reserved[2];
|
|
uint8_t mac[ETHER_ADDR_LEN];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || mac == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
args = (struct set_prim_mac_args *) &cmd->params[0];
|
|
for (int i = 1; i <= ETHER_ADDR_LEN; i++)
|
|
args->mac[i - 1] = mac[ETHER_ADDR_LEN - i];
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_PRIM_MAC_ADDR));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_prim_mac_addr(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, uint8_t *mac)
|
|
{
|
|
struct __packed get_prim_mac_resp {
|
|
uint8_t _reserved[2];
|
|
uint8_t mac[ETHER_ADDR_LEN];
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || mac == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_PRIM_MAC_ADDR);
|
|
if (!error) {
|
|
resp = (struct get_prim_mac_resp *) &cmd->params[0];
|
|
for (int i = 1; i <= ETHER_ADDR_LEN; i++)
|
|
mac[ETHER_ADDR_LEN - i] = resp->mac[i - 1];
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_link_cfg(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_link_cfg *cfg)
|
|
{
|
|
struct __packed link_cfg_args {
|
|
uint64_t _reserved1;
|
|
uint32_t rate;
|
|
uint32_t _reserved2;
|
|
uint64_t options;
|
|
uint64_t adv_speeds;
|
|
uint64_t _reserved3[3];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || cfg == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
args = (struct link_cfg_args *) &cmd->params[0];
|
|
args->rate = cfg->rate;
|
|
args->options = cfg->options;
|
|
args->adv_speeds = cfg->adv_speeds;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_LINK_CFG));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_link_cfg(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_link_cfg *cfg)
|
|
{
|
|
struct __packed link_cfg_resp {
|
|
uint64_t _reserved1;
|
|
uint32_t rate;
|
|
uint32_t _reserved2;
|
|
uint64_t options;
|
|
uint64_t adv_speeds;
|
|
uint64_t _reserved3[3];
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || cfg == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_LINK_CFG);
|
|
if (!error) {
|
|
resp = (struct link_cfg_resp *) &cmd->params[0];
|
|
cfg->rate = resp->rate;
|
|
cfg->options = resp->options;
|
|
cfg->adv_speeds = resp->adv_speeds;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_link_state(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_link_state *state)
|
|
{
|
|
struct __packed link_state_resp {
|
|
uint32_t _reserved1;
|
|
uint32_t flags;
|
|
uint32_t rate;
|
|
uint32_t _reserved2;
|
|
uint64_t options;
|
|
uint64_t supported;
|
|
uint64_t advert;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || state == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_LINK_STATE);
|
|
if (!error) {
|
|
resp = (struct link_state_resp *) &cmd->params[0];
|
|
state->options = resp->options;
|
|
state->adv_speeds = resp->advert;
|
|
state->sup_speeds = resp->supported;
|
|
state->rate = resp->rate;
|
|
|
|
state->link_up = resp->flags & 0x1u ? true : false;
|
|
state->state_valid = resp->flags & 0x2u ? true : false;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_qos_table(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_qos_table *tbl)
|
|
{
|
|
struct __packed qos_table_args {
|
|
uint32_t _reserved1;
|
|
uint8_t default_tc;
|
|
uint8_t options;
|
|
uint16_t _reserved2;
|
|
uint64_t _reserved[5];
|
|
uint64_t kcfg_busaddr;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || tbl == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct qos_table_args *) &cmd->params[0];
|
|
args->default_tc = tbl->default_tc;
|
|
args->kcfg_busaddr = tbl->kcfg_busaddr;
|
|
|
|
args->options |= tbl->discard_on_miss ? 1U : 0U;
|
|
args->options |= tbl->keep_entries ? 2U : 0U;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_QOS_TABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_clear_qos_table(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_CLEAR_QOS_TABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_pools(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_pools_cfg *cfg)
|
|
{
|
|
struct __packed set_pools_args {
|
|
uint8_t pools_num;
|
|
uint8_t backup_pool_mask;
|
|
uint8_t _reserved1;
|
|
uint8_t pool_as; /* assigning: 0 - QPRI, 1 - QDBIN */
|
|
uint32_t bp_obj_id[DPAA2_NI_MAX_POOLS];
|
|
uint16_t buf_sz[DPAA2_NI_MAX_POOLS];
|
|
uint32_t _reserved2;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || cfg == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_pools_args *) &cmd->params[0];
|
|
args->pools_num = cfg->pools_num < DPAA2_NI_MAX_POOLS
|
|
? cfg->pools_num : DPAA2_NI_MAX_POOLS;
|
|
for (uint32_t i = 0; i < args->pools_num; i++) {
|
|
args->bp_obj_id[i] = cfg->pools[i].bp_obj_id;
|
|
args->buf_sz[i] = cfg->pools[i].buf_sz;
|
|
args->backup_pool_mask |= (cfg->pools[i].backup_flag & 1) << i;
|
|
}
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_POOLS));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_err_behavior(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_err_cfg *cfg)
|
|
{
|
|
struct __packed err_behavior_args {
|
|
uint32_t err_mask;
|
|
uint8_t flags;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || cfg == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct err_behavior_args *) &cmd->params[0];
|
|
args->err_mask = cfg->err_mask;
|
|
|
|
args->flags |= cfg->set_err_fas ? 0x10u : 0u;
|
|
args->flags |= ((uint8_t) cfg->action) & 0x0Fu;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_ERR_BEHAVIOR));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_queue(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_queue_cfg *cfg)
|
|
{
|
|
struct __packed get_queue_args {
|
|
uint8_t queue_type;
|
|
uint8_t tc;
|
|
uint8_t idx;
|
|
uint8_t chan_id;
|
|
} *args;
|
|
struct __packed get_queue_resp {
|
|
uint64_t _reserved1;
|
|
uint32_t dest_id;
|
|
uint16_t _reserved2;
|
|
uint8_t priority;
|
|
uint8_t flags;
|
|
uint64_t flc;
|
|
uint64_t user_ctx;
|
|
uint32_t fqid;
|
|
uint16_t qdbin;
|
|
uint16_t _reserved3;
|
|
uint8_t cgid;
|
|
uint8_t _reserved[15];
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || cfg == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct get_queue_args *) &cmd->params[0];
|
|
args->queue_type = (uint8_t) cfg->type;
|
|
args->tc = cfg->tc;
|
|
args->idx = cfg->idx;
|
|
args->chan_id = cfg->chan_id;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_QUEUE);
|
|
if (!error) {
|
|
resp = (struct get_queue_resp *) &cmd->params[0];
|
|
|
|
cfg->dest_id = resp->dest_id;
|
|
cfg->priority = resp->priority;
|
|
cfg->flow_ctx = resp->flc;
|
|
cfg->user_ctx = resp->user_ctx;
|
|
cfg->fqid = resp->fqid;
|
|
cfg->qdbin = resp->qdbin;
|
|
cfg->cgid = resp->cgid;
|
|
|
|
cfg->dest_type = (enum dpaa2_ni_dest_type) resp->flags & 0x0Fu;
|
|
cfg->cgid_valid = (resp->flags & 0x20u) > 0u ? true : false;
|
|
cfg->stash_control = (resp->flags & 0x40u) > 0u ? true : false;
|
|
cfg->hold_active = (resp->flags & 0x80u) > 0u ? true : false;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_queue(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_ni_queue_cfg *cfg)
|
|
{
|
|
struct __packed set_queue_args {
|
|
uint8_t queue_type;
|
|
uint8_t tc;
|
|
uint8_t idx;
|
|
uint8_t options;
|
|
uint32_t _reserved1;
|
|
uint32_t dest_id;
|
|
uint16_t _reserved2;
|
|
uint8_t priority;
|
|
uint8_t flags;
|
|
uint64_t flc;
|
|
uint64_t user_ctx;
|
|
uint8_t cgid;
|
|
uint8_t chan_id;
|
|
uint8_t _reserved[23];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || cfg == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_queue_args *) &cmd->params[0];
|
|
args->queue_type = (uint8_t) cfg->type;
|
|
args->tc = cfg->tc;
|
|
args->idx = cfg->idx;
|
|
args->options = cfg->options;
|
|
args->dest_id = cfg->dest_id;
|
|
args->priority = cfg->priority;
|
|
args->flc = cfg->flow_ctx;
|
|
args->user_ctx = cfg->user_ctx;
|
|
args->cgid = cfg->cgid;
|
|
args->chan_id = cfg->chan_id;
|
|
|
|
args->flags |= (uint8_t)(cfg->dest_type & 0x0Fu);
|
|
args->flags |= cfg->stash_control ? 0x40u : 0u;
|
|
args->flags |= cfg->hold_active ? 0x80u : 0u;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_QUEUE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_qdid(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
enum dpaa2_ni_queue_type type, uint16_t *qdid)
|
|
{
|
|
struct __packed get_qdid_args {
|
|
uint8_t queue_type;
|
|
} *args;
|
|
struct __packed get_qdid_resp {
|
|
uint16_t qdid;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || qdid == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct get_qdid_args *) &cmd->params[0];
|
|
args->queue_type = (uint8_t) type;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_QDID);
|
|
if (!error) {
|
|
resp = (struct get_qdid_resp *) &cmd->params[0];
|
|
*qdid = resp->qdid;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_add_mac_addr(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t *mac)
|
|
{
|
|
struct __packed add_mac_args {
|
|
uint8_t flags;
|
|
uint8_t _reserved;
|
|
uint8_t mac[ETHER_ADDR_LEN];
|
|
uint8_t tc_id;
|
|
uint8_t fq_id;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || mac == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct add_mac_args *) &cmd->params[0];
|
|
for (int i = 1; i <= ETHER_ADDR_LEN; i++)
|
|
args->mac[i - 1] = mac[ETHER_ADDR_LEN - i];
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_ADD_MAC_ADDR));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_remove_mac_addr(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t *mac)
|
|
{
|
|
struct __packed rem_mac_args {
|
|
uint16_t _reserved;
|
|
uint8_t mac[ETHER_ADDR_LEN];
|
|
uint64_t _reserved1[6];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || mac == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct rem_mac_args *) &cmd->params[0];
|
|
for (int i = 1; i <= ETHER_ADDR_LEN; i++)
|
|
args->mac[i - 1] = mac[ETHER_ADDR_LEN - i];
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_REMOVE_MAC_ADDR));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_clear_mac_filters(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, bool rm_uni, bool rm_multi)
|
|
{
|
|
struct __packed clear_mac_filters_args {
|
|
uint8_t flags;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct clear_mac_filters_args *) &cmd->params[0];
|
|
args->flags |= rm_uni ? 0x1 : 0x0;
|
|
args->flags |= rm_multi ? 0x2 : 0x0;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_CLEAR_MAC_FILTERS));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_mfl(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint16_t length)
|
|
{
|
|
struct __packed set_mfl_args {
|
|
uint16_t length;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_mfl_args *) &cmd->params[0];
|
|
args->length = length;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_MFL));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_offload(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
enum dpaa2_ni_ofl_type ofl_type, bool en)
|
|
{
|
|
struct __packed set_ofl_args {
|
|
uint8_t _reserved[3];
|
|
uint8_t ofl_type;
|
|
uint32_t config;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_ofl_args *) &cmd->params[0];
|
|
args->ofl_type = (uint8_t) ofl_type;
|
|
args->config = en ? 1u : 0u;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_OFFLOAD));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_irq_mask(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint32_t mask)
|
|
{
|
|
struct __packed set_irq_mask_args {
|
|
uint32_t mask;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_irq_mask_args *) &cmd->params[0];
|
|
args->mask = mask;
|
|
args->irq_idx = irq_idx;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_IRQ_MASK));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_irq_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, bool en)
|
|
{
|
|
struct __packed set_irq_enable_args {
|
|
uint32_t en;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_irq_enable_args *) &cmd->params[0];
|
|
args->en = en ? 1u : 0u;
|
|
args->irq_idx = irq_idx;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_IRQ_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_irq_status(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint32_t *status)
|
|
{
|
|
struct __packed get_irq_stat_args {
|
|
uint32_t status;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct __packed get_irq_stat_resp {
|
|
uint32_t status;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || status == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct get_irq_stat_args *) &cmd->params[0];
|
|
args->status = *status;
|
|
args->irq_idx = irq_idx;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_IRQ_STATUS);
|
|
if (!error) {
|
|
resp = (struct get_irq_stat_resp *) &cmd->params[0];
|
|
*status = resp->status;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_uni_promisc(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
bool en)
|
|
{
|
|
struct __packed set_uni_promisc_args {
|
|
uint8_t en;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_uni_promisc_args *) &cmd->params[0];
|
|
args->en = en ? 1u : 0u;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_UNI_PROMISC));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_multi_promisc(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, bool en)
|
|
{
|
|
/* TODO: Implementation is the same as for ni_set_uni_promisc(). */
|
|
struct __packed set_multi_promisc_args {
|
|
uint8_t en;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_multi_promisc_args *) &cmd->params[0];
|
|
args->en = en ? 1u : 0u;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_MULTI_PROMISC));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_get_statistics(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t page, uint16_t param, uint64_t *cnt)
|
|
{
|
|
struct __packed get_statistics_args {
|
|
uint8_t page;
|
|
uint16_t param;
|
|
} *args;
|
|
struct __packed get_statistics_resp {
|
|
uint64_t cnt[7];
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || cnt == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct get_statistics_args *) &cmd->params[0];
|
|
args->page = page;
|
|
args->param = param;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_GET_STATISTICS);
|
|
if (!error) {
|
|
resp = (struct get_statistics_resp *) &cmd->params[0];
|
|
for (int i = 0; i < DPAA2_NI_STAT_COUNTERS; i++)
|
|
cnt[i] = resp->cnt[i];
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_ni_set_rx_tc_dist(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint16_t dist_size, uint8_t tc, enum dpaa2_ni_dist_mode dist_mode,
|
|
bus_addr_t key_cfg_buf)
|
|
{
|
|
struct __packed set_rx_tc_dist_args {
|
|
uint16_t dist_size;
|
|
uint8_t tc;
|
|
uint8_t ma_dm; /* miss action + dist. mode */
|
|
uint32_t _reserved1;
|
|
uint64_t _reserved2[5];
|
|
uint64_t key_cfg_iova;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_rx_tc_dist_args *) &cmd->params[0];
|
|
args->dist_size = dist_size;
|
|
args->tc = tc;
|
|
args->ma_dm = ((uint8_t) dist_mode) & 0x0Fu;
|
|
args->key_cfg_iova = key_cfg_buf;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_NI_SET_RX_TC_DIST));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_open(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t dpio_id, uint16_t *token)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
struct dpaa2_cmd_header *hdr;
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || token == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = dpio_id;
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_OPEN);
|
|
if (!error) {
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
*token = hdr->token;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_close(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_CLOSE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_disable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_DISABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_reset(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_RESET));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_get_attributes(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_io_attr *attr)
|
|
{
|
|
struct __packed dpaa2_io_attr {
|
|
uint32_t id;
|
|
uint16_t swp_id;
|
|
uint8_t priors_num;
|
|
uint8_t chan_mode;
|
|
uint64_t swp_ce_paddr;
|
|
uint64_t swp_ci_paddr;
|
|
uint32_t swp_version;
|
|
uint32_t _reserved1;
|
|
uint32_t swp_clk;
|
|
uint32_t _reserved2[5];
|
|
} *pattr;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || attr == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_GET_ATTR);
|
|
if (!error) {
|
|
pattr = (struct dpaa2_io_attr *) &cmd->params[0];
|
|
|
|
attr->swp_ce_paddr = pattr->swp_ce_paddr;
|
|
attr->swp_ci_paddr = pattr->swp_ci_paddr;
|
|
attr->swp_version = pattr->swp_version;
|
|
attr->swp_clk = pattr->swp_clk;
|
|
attr->id = pattr->id;
|
|
attr->swp_id = pattr->swp_id;
|
|
attr->priors_num = pattr->priors_num;
|
|
attr->chan_mode = (enum dpaa2_io_chan_mode)
|
|
pattr->chan_mode;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_set_irq_mask(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint32_t mask)
|
|
{
|
|
/* TODO: Extract similar *_set_irq_mask() into one function. */
|
|
struct __packed set_irq_mask_args {
|
|
uint32_t mask;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_irq_mask_args *) &cmd->params[0];
|
|
args->mask = mask;
|
|
args->irq_idx = irq_idx;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_SET_IRQ_MASK));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_get_irq_status(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint32_t *status)
|
|
{
|
|
/* TODO: Extract similar *_get_irq_status() into one function. */
|
|
struct __packed get_irq_stat_args {
|
|
uint32_t status;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct __packed get_irq_stat_resp {
|
|
uint32_t status;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || status == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct get_irq_stat_args *) &cmd->params[0];
|
|
args->status = *status;
|
|
args->irq_idx = irq_idx;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_GET_IRQ_STATUS);
|
|
if (!error) {
|
|
resp = (struct get_irq_stat_resp *) &cmd->params[0];
|
|
*status = resp->status;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_set_irq_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, bool en)
|
|
{
|
|
/* TODO: Extract similar *_set_irq_enable() into one function. */
|
|
struct __packed set_irq_enable_args {
|
|
uint32_t en;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_irq_enable_args *) &cmd->params[0];
|
|
args->en = en ? 1u : 0u;
|
|
args->irq_idx = irq_idx;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_SET_IRQ_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_io_add_static_dq_chan(device_t dev, device_t child,
|
|
struct dpaa2_cmd *cmd, uint32_t dpcon_id, uint8_t *chan_idx)
|
|
{
|
|
struct __packed add_static_dq_chan_args {
|
|
uint32_t dpcon_id;
|
|
} *args;
|
|
struct __packed add_static_dq_chan_resp {
|
|
uint8_t chan_idx;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || chan_idx == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct add_static_dq_chan_args *) &cmd->params[0];
|
|
args->dpcon_id = dpcon_id;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_IO_ADD_STATIC_DQ_CHAN);
|
|
if (!error) {
|
|
resp = (struct add_static_dq_chan_resp *) &cmd->params[0];
|
|
*chan_idx = resp->chan_idx;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_bp_open(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t dpbp_id, uint16_t *token)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
struct dpaa2_cmd_header *hdr;
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || token == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = dpbp_id;
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_BP_OPEN);
|
|
if (!error) {
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
*token = hdr->token;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_bp_close(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_BP_CLOSE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_bp_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_BP_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_bp_disable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_BP_DISABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_bp_reset(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_BP_RESET));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_bp_get_attributes(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_bp_attr *attr)
|
|
{
|
|
struct __packed dpaa2_bp_attr {
|
|
uint16_t _reserved1;
|
|
uint16_t bpid;
|
|
uint32_t id;
|
|
} *pattr;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || attr == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_BP_GET_ATTR);
|
|
if (!error) {
|
|
pattr = (struct dpaa2_bp_attr *) &cmd->params[0];
|
|
attr->id = pattr->id;
|
|
attr->bpid = pattr->bpid;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_open(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t dpmac_id, uint16_t *token)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
struct dpaa2_cmd_header *hdr;
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || token == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = dpmac_id;
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_OPEN);
|
|
if (!error) {
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
*token = hdr->token;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_close(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_CLOSE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_reset(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_RESET));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_mdio_read(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t phy, uint16_t reg, uint16_t *val)
|
|
{
|
|
struct __packed mdio_read_args {
|
|
uint8_t clause; /* set to 0 by default */
|
|
uint8_t phy;
|
|
uint16_t reg;
|
|
uint32_t _reserved1;
|
|
uint64_t _reserved2[6];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || val == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct mdio_read_args *) &cmd->params[0];
|
|
args->phy = phy;
|
|
args->reg = reg;
|
|
args->clause = 0;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_MDIO_READ);
|
|
if (!error)
|
|
*val = cmd->params[0] & 0xFFFF;
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_mdio_write(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t phy, uint16_t reg, uint16_t val)
|
|
{
|
|
struct __packed mdio_write_args {
|
|
uint8_t clause; /* set to 0 by default */
|
|
uint8_t phy;
|
|
uint16_t reg;
|
|
uint16_t val;
|
|
uint16_t _reserved1;
|
|
uint64_t _reserved2[6];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct mdio_write_args *) &cmd->params[0];
|
|
args->phy = phy;
|
|
args->reg = reg;
|
|
args->val = val;
|
|
args->clause = 0;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_MDIO_WRITE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_get_addr(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t *mac)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || mac == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_GET_ADDR);
|
|
if (!error) {
|
|
mac[0] = (cmd->params[0] >> 56) & 0xFFU;
|
|
mac[1] = (cmd->params[0] >> 48) & 0xFFU;
|
|
mac[2] = (cmd->params[0] >> 40) & 0xFFU;
|
|
mac[3] = (cmd->params[0] >> 32) & 0xFFU;
|
|
mac[4] = (cmd->params[0] >> 24) & 0xFFU;
|
|
mac[5] = (cmd->params[0] >> 16) & 0xFFU;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_get_attributes(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_mac_attr *attr)
|
|
{
|
|
struct __packed mac_attr_resp {
|
|
uint8_t eth_if;
|
|
uint8_t link_type;
|
|
uint16_t id;
|
|
uint32_t max_rate;
|
|
|
|
uint8_t fec_mode;
|
|
uint8_t ifg_mode;
|
|
uint8_t ifg_len;
|
|
uint8_t _reserved1;
|
|
uint32_t _reserved2;
|
|
|
|
uint8_t sgn_post_pre;
|
|
uint8_t serdes_cfg_mode;
|
|
uint8_t eq_amp_red;
|
|
uint8_t eq_post1q;
|
|
uint8_t eq_preq;
|
|
uint8_t eq_type;
|
|
uint16_t _reserved3;
|
|
|
|
uint64_t _reserved[4];
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || attr == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_GET_ATTR);
|
|
if (!error) {
|
|
resp = (struct mac_attr_resp *) &cmd->params[0];
|
|
attr->id = resp->id;
|
|
attr->max_rate = resp->max_rate;
|
|
attr->eth_if = resp->eth_if;
|
|
attr->link_type = resp->link_type;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_set_link_state(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_mac_link_state *state)
|
|
{
|
|
struct __packed mac_set_link_args {
|
|
uint64_t options;
|
|
uint32_t rate;
|
|
uint32_t _reserved1;
|
|
uint32_t flags;
|
|
uint32_t _reserved2;
|
|
uint64_t supported;
|
|
uint64_t advert;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || state == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct mac_set_link_args *) &cmd->params[0];
|
|
args->options = state->options;
|
|
args->rate = state->rate;
|
|
args->supported = state->supported;
|
|
args->advert = state->advert;
|
|
|
|
args->flags |= state->up ? 0x1u : 0u;
|
|
args->flags |= state->state_valid ? 0x2u : 0u;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_SET_LINK_STATE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_set_irq_mask(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint32_t mask)
|
|
{
|
|
/* TODO: Implementation is the same as for ni_set_irq_mask(). */
|
|
struct __packed set_irq_mask_args {
|
|
uint32_t mask;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_irq_mask_args *) &cmd->params[0];
|
|
args->mask = mask;
|
|
args->irq_idx = irq_idx;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_SET_IRQ_MASK));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_set_irq_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, bool en)
|
|
{
|
|
/* TODO: Implementation is the same as for ni_set_irq_enable(). */
|
|
struct __packed set_irq_enable_args {
|
|
uint32_t en;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct set_irq_enable_args *) &cmd->params[0];
|
|
args->en = en ? 1u : 0u;
|
|
args->irq_idx = irq_idx;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_SET_IRQ_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mac_get_irq_status(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, uint32_t *status)
|
|
{
|
|
/* TODO: Implementation is the same as ni_get_irq_status(). */
|
|
struct __packed get_irq_stat_args {
|
|
uint32_t status;
|
|
uint8_t irq_idx;
|
|
} *args;
|
|
struct __packed get_irq_stat_resp {
|
|
uint32_t status;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || status == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
dpaa2_rc_reset_cmd_params(cmd);
|
|
|
|
args = (struct get_irq_stat_args *) &cmd->params[0];
|
|
args->status = *status;
|
|
args->irq_idx = irq_idx;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MAC_GET_IRQ_STATUS);
|
|
if (!error) {
|
|
resp = (struct get_irq_stat_resp *) &cmd->params[0];
|
|
*status = resp->status;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_con_open(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t dpcon_id, uint16_t *token)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
struct dpaa2_cmd_header *hdr;
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || token == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = dpcon_id;
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_CON_OPEN);
|
|
if (!error) {
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
*token = hdr->token;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
|
|
static int
|
|
dpaa2_rc_con_close(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_CON_CLOSE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_con_reset(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_CON_RESET));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_con_enable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_CON_ENABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_con_disable(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_CON_DISABLE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_con_get_attributes(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_con_attr *attr)
|
|
{
|
|
struct __packed con_attr_resp {
|
|
uint32_t id;
|
|
uint16_t chan_id;
|
|
uint8_t prior_num;
|
|
uint8_t _reserved1;
|
|
uint64_t _reserved2[6];
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || attr == NULL)
|
|
return (DPAA2_CMD_STAT_EINVAL);
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_CON_GET_ATTR);
|
|
if (!error) {
|
|
resp = (struct con_attr_resp *) &cmd->params[0];
|
|
attr->id = resp->id;
|
|
attr->chan_id = resp->chan_id;
|
|
attr->prior_num = resp->prior_num;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_con_set_notif(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_con_notif_cfg *cfg)
|
|
{
|
|
struct __packed set_notif_args {
|
|
uint32_t dpio_id;
|
|
uint8_t prior;
|
|
uint8_t _reserved1;
|
|
uint16_t _reserved2;
|
|
uint64_t ctx;
|
|
uint64_t _reserved3[5];
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL || cfg == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct set_notif_args *) &cmd->params[0];
|
|
args->dpio_id = cfg->dpio_id;
|
|
args->prior = cfg->prior;
|
|
args->ctx = cfg->qman_ctx;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_CON_SET_NOTIF));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mcp_create(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t portal_id, uint32_t options, uint32_t *dpmcp_id)
|
|
{
|
|
struct __packed mcp_create_args {
|
|
uint32_t portal_id;
|
|
uint32_t options;
|
|
uint64_t _reserved[6];
|
|
} *args;
|
|
struct __packed mcp_create_resp {
|
|
uint32_t dpmcp_id;
|
|
} *resp;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || dpmcp_id == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct mcp_create_args *) &cmd->params[0];
|
|
args->portal_id = portal_id;
|
|
args->options = options;
|
|
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MCP_CREATE);
|
|
if (!error) {
|
|
resp = (struct mcp_create_resp *) &cmd->params[0];
|
|
*dpmcp_id = resp->dpmcp_id;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mcp_destroy(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t dpmcp_id)
|
|
{
|
|
struct __packed mcp_destroy_args {
|
|
uint32_t dpmcp_id;
|
|
} *args;
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct mcp_destroy_args *) &cmd->params[0];
|
|
args->dpmcp_id = dpmcp_id;
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MCP_DESTROY));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mcp_open(device_t dev, device_t child, struct dpaa2_cmd *cmd,
|
|
uint32_t dpmcp_id, uint16_t *token)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
struct dpaa2_cmd_header *hdr;
|
|
int error;
|
|
|
|
if (portal == NULL || cmd == NULL || token == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
cmd->params[0] = dpmcp_id;
|
|
error = dpaa2_rc_exec_cmd(portal, cmd, CMDID_MCP_OPEN);
|
|
if (!error) {
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
*token = hdr->token;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mcp_close(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MCP_CLOSE));
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_mcp_reset(device_t dev, device_t child, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_mcp *portal = dpaa2_rc_select_portal(dev, child);
|
|
|
|
if (portal == NULL || cmd == NULL)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
return (dpaa2_rc_exec_cmd(portal, cmd, CMDID_MCP_RESET));
|
|
}
|
|
|
|
/**
|
|
* @brief Create and add devices for DPAA2 objects in this resource container.
|
|
*/
|
|
static int
|
|
dpaa2_rc_discover(struct dpaa2_rc_softc *sc)
|
|
{
|
|
device_t rcdev = sc->dev;
|
|
device_t child = sc->dev;
|
|
struct dpaa2_devinfo *rcinfo = device_get_ivars(rcdev);
|
|
struct dpaa2_cmd *cmd = NULL;
|
|
struct dpaa2_rc_attr dprc_attr;
|
|
struct dpaa2_obj obj;
|
|
uint32_t major, minor, rev, obj_count;
|
|
uint16_t rc_token;
|
|
int rc;
|
|
|
|
/* Allocate a command to send to MC hardware. */
|
|
rc = dpaa2_mcp_init_command(&cmd, DPAA2_CMD_DEF);
|
|
if (rc) {
|
|
device_printf(rcdev, "%s: failed to allocate dpaa2_cmd: "
|
|
"error=%d\n", __func__, rc);
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* Print MC firmware version. */
|
|
rc = DPAA2_CMD_MNG_GET_VERSION(rcdev, child, cmd, &major, &minor, &rev);
|
|
if (rc) {
|
|
device_printf(rcdev, "%s: failed to get MC firmware version: "
|
|
"error=%d\n", __func__, rc);
|
|
dpaa2_mcp_free_command(cmd);
|
|
return (ENXIO);
|
|
}
|
|
device_printf(rcdev, "MC firmware version: %u.%u.%u\n", major, minor,
|
|
rev);
|
|
|
|
/* Obtain container ID associated with a given MC portal. */
|
|
rc = DPAA2_CMD_MNG_GET_CONTAINER_ID(rcdev, child, cmd, &sc->cont_id);
|
|
if (rc) {
|
|
device_printf(rcdev, "%s: failed to get container id: "
|
|
"error=%d\n", __func__, rc);
|
|
dpaa2_mcp_free_command(cmd);
|
|
return (ENXIO);
|
|
}
|
|
if (bootverbose)
|
|
device_printf(rcdev, "Resource container ID: %u\n", sc->cont_id);
|
|
|
|
/* Open the resource container. */
|
|
rc = DPAA2_CMD_RC_OPEN(rcdev, child, cmd, sc->cont_id, &rc_token);
|
|
if (rc) {
|
|
device_printf(rcdev, "%s: failed to open container: cont_id=%u, "
|
|
"error=%d\n", __func__, sc->cont_id, rc);
|
|
dpaa2_mcp_free_command(cmd);
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* Obtain a number of objects in this container. */
|
|
rc = DPAA2_CMD_RC_GET_OBJ_COUNT(rcdev, child, cmd, &obj_count);
|
|
if (rc) {
|
|
device_printf(rcdev, "%s: failed to count objects in container: "
|
|
"cont_id=%u, error=%d\n", __func__, sc->cont_id, rc);
|
|
DPAA2_CMD_RC_CLOSE(rcdev, child, cmd);
|
|
dpaa2_mcp_free_command(cmd);
|
|
return (ENXIO);
|
|
}
|
|
if (bootverbose)
|
|
device_printf(rcdev, "Objects in container: %u\n", obj_count);
|
|
|
|
/* Obtain container attributes (including ICID). */
|
|
rc = DPAA2_CMD_RC_GET_ATTRIBUTES(rcdev, child, cmd, &dprc_attr);
|
|
if (rc) {
|
|
device_printf(rcdev, "%s: failed to get attributes of the "
|
|
"container: cont_id=%u, error=%d\n", __func__, sc->cont_id,
|
|
rc);
|
|
DPAA2_CMD_RC_CLOSE(rcdev, child, cmd);
|
|
dpaa2_mcp_free_command(cmd);
|
|
return (ENXIO);
|
|
}
|
|
if (bootverbose)
|
|
device_printf(rcdev, "Isolation context ID: %u\n",
|
|
dprc_attr.icid);
|
|
if (rcinfo) {
|
|
rcinfo->id = dprc_attr.cont_id;
|
|
rcinfo->portal_id = dprc_attr.portal_id;
|
|
rcinfo->icid = dprc_attr.icid;
|
|
}
|
|
|
|
/*
|
|
* Add MC portals before everything else.
|
|
* TODO: Discover DPAA2 objects on-demand.
|
|
*/
|
|
for (uint32_t i = 0; i < obj_count; i++) {
|
|
rc = DPAA2_CMD_RC_GET_OBJ(rcdev, child, cmd, i, &obj);
|
|
if (rc)
|
|
continue; /* Skip silently for now. */
|
|
if (obj.type != DPAA2_DEV_MCP)
|
|
continue;
|
|
|
|
dpaa2_rc_add_managed_child(sc, cmd, &obj);
|
|
}
|
|
/* Probe and attach MC portals. */
|
|
bus_generic_probe(rcdev);
|
|
rc = bus_generic_attach(rcdev);
|
|
if (rc) {
|
|
DPAA2_CMD_RC_CLOSE(rcdev, child, cmd);
|
|
dpaa2_mcp_free_command(cmd);
|
|
return (rc);
|
|
}
|
|
|
|
/* Add managed devices (except DPMCPs) to the resource container. */
|
|
for (uint32_t i = 0; i < obj_count; i++) {
|
|
rc = DPAA2_CMD_RC_GET_OBJ(rcdev, child, cmd, i, &obj);
|
|
if (rc && bootverbose) {
|
|
if (rc == DPAA2_CMD_STAT_UNKNOWN_OBJ) {
|
|
device_printf(rcdev, "%s: skip unsupported "
|
|
"DPAA2 object: idx=%u\n", __func__, i);
|
|
continue;
|
|
} else {
|
|
device_printf(rcdev, "%s: failed to get "
|
|
"information about DPAA2 object: idx=%u, "
|
|
"error=%d\n", __func__, i, rc);
|
|
continue;
|
|
}
|
|
}
|
|
if (obj.type == DPAA2_DEV_MCP)
|
|
continue; /* Already added. */
|
|
|
|
dpaa2_rc_add_managed_child(sc, cmd, &obj);
|
|
}
|
|
/* Probe and attach managed devices properly. */
|
|
bus_generic_probe(rcdev);
|
|
rc = bus_generic_attach(rcdev);
|
|
if (rc) {
|
|
DPAA2_CMD_RC_CLOSE(rcdev, child, cmd);
|
|
dpaa2_mcp_free_command(cmd);
|
|
return (rc);
|
|
}
|
|
|
|
/* Add other devices to the resource container. */
|
|
for (uint32_t i = 0; i < obj_count; i++) {
|
|
rc = DPAA2_CMD_RC_GET_OBJ(rcdev, child, cmd, i, &obj);
|
|
if (rc == DPAA2_CMD_STAT_UNKNOWN_OBJ && bootverbose) {
|
|
device_printf(rcdev, "%s: skip unsupported DPAA2 "
|
|
"object: idx=%u\n", __func__, i);
|
|
continue;
|
|
} else if (rc) {
|
|
device_printf(rcdev, "%s: failed to get object: "
|
|
"idx=%u, error=%d\n", __func__, i, rc);
|
|
continue;
|
|
}
|
|
dpaa2_rc_add_child(sc, cmd, &obj);
|
|
}
|
|
|
|
DPAA2_CMD_RC_CLOSE(rcdev, child, cmd);
|
|
dpaa2_mcp_free_command(cmd);
|
|
|
|
/* Probe and attach the rest of devices. */
|
|
bus_generic_probe(rcdev);
|
|
return (bus_generic_attach(rcdev));
|
|
}
|
|
|
|
/**
|
|
* @brief Add a new DPAA2 device to the resource container bus.
|
|
*/
|
|
static int
|
|
dpaa2_rc_add_child(struct dpaa2_rc_softc *sc, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_obj *obj)
|
|
{
|
|
device_t rcdev, dev;
|
|
struct dpaa2_devinfo *rcinfo;
|
|
struct dpaa2_devinfo *dinfo;
|
|
struct resource_spec *res_spec;
|
|
const char *devclass;
|
|
int dpio_n = 0; /* to limit DPIOs by # of CPUs */
|
|
int dpcon_n = 0; /* to limit DPCONs by # of CPUs */
|
|
int rid, error;
|
|
|
|
rcdev = sc->dev;
|
|
rcinfo = device_get_ivars(rcdev);
|
|
|
|
switch (obj->type) {
|
|
case DPAA2_DEV_NI:
|
|
devclass = "dpaa2_ni";
|
|
res_spec = dpaa2_ni_spec;
|
|
break;
|
|
default:
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* Add a device for the DPAA2 object. */
|
|
dev = device_add_child(rcdev, devclass, -1);
|
|
if (dev == NULL) {
|
|
device_printf(rcdev, "%s: failed to add a device for DPAA2 "
|
|
"object: type=%s, id=%u\n", __func__, dpaa2_ttos(obj->type),
|
|
obj->id);
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* Allocate devinfo for a child. */
|
|
dinfo = malloc(sizeof(struct dpaa2_devinfo), M_DPAA2_RC,
|
|
M_WAITOK | M_ZERO);
|
|
if (!dinfo) {
|
|
device_printf(rcdev, "%s: failed to allocate dpaa2_devinfo "
|
|
"for: type=%s, id=%u\n", __func__, dpaa2_ttos(obj->type),
|
|
obj->id);
|
|
return (ENXIO);
|
|
}
|
|
device_set_ivars(dev, dinfo);
|
|
|
|
dinfo->pdev = rcdev;
|
|
dinfo->dev = dev;
|
|
dinfo->id = obj->id;
|
|
dinfo->dtype = obj->type;
|
|
dinfo->portal = NULL;
|
|
/* Children share their parent container's ICID and portal ID. */
|
|
dinfo->icid = rcinfo->icid;
|
|
dinfo->portal_id = rcinfo->portal_id;
|
|
/* MSI configuration */
|
|
dinfo->msi.msi_msgnum = obj->irq_count;
|
|
dinfo->msi.msi_alloc = 0;
|
|
dinfo->msi.msi_handlers = 0;
|
|
|
|
/* Initialize a resource list for the child. */
|
|
resource_list_init(&dinfo->resources);
|
|
|
|
/* Add DPAA2-specific resources to the resource list. */
|
|
for (; res_spec && res_spec->type != -1; res_spec++) {
|
|
if (res_spec->type < DPAA2_DEV_MC)
|
|
continue; /* Skip non-DPAA2 resource. */
|
|
rid = res_spec->rid;
|
|
|
|
/* Limit DPIOs and DPCONs by number of CPUs. */
|
|
if (res_spec->type == DPAA2_DEV_IO && dpio_n >= mp_ncpus) {
|
|
dpio_n++;
|
|
continue;
|
|
}
|
|
if (res_spec->type == DPAA2_DEV_CON && dpcon_n >= mp_ncpus) {
|
|
dpcon_n++;
|
|
continue;
|
|
}
|
|
|
|
error = dpaa2_rc_add_res(rcdev, dev, res_spec->type, &rid,
|
|
res_spec->flags);
|
|
if (error)
|
|
device_printf(rcdev, "%s: dpaa2_rc_add_res() failed: "
|
|
"error=%d\n", __func__, error);
|
|
|
|
if (res_spec->type == DPAA2_DEV_IO)
|
|
dpio_n++;
|
|
if (res_spec->type == DPAA2_DEV_CON)
|
|
dpcon_n++;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* @brief Add a new managed DPAA2 device to the resource container bus.
|
|
*
|
|
* There are DPAA2 objects (DPIO, DPBP) which have their own drivers and can be
|
|
* allocated as resources or associated with the other DPAA2 objects. This
|
|
* function is supposed to discover such managed objects in the resource
|
|
* container and add them as children to perform a proper initialization.
|
|
*
|
|
* NOTE: It must be called together with bus_generic_probe() and
|
|
* bus_generic_attach() before dpaa2_rc_add_child().
|
|
*/
|
|
static int
|
|
dpaa2_rc_add_managed_child(struct dpaa2_rc_softc *sc, struct dpaa2_cmd *cmd,
|
|
struct dpaa2_obj *obj)
|
|
{
|
|
device_t rcdev, dev, child;
|
|
struct dpaa2_devinfo *rcinfo, *dinfo;
|
|
struct dpaa2_rc_obj_region reg;
|
|
struct resource_spec *res_spec;
|
|
const char *devclass;
|
|
uint64_t start, end, count;
|
|
uint32_t flags = 0;
|
|
int rid, error;
|
|
|
|
rcdev = sc->dev;
|
|
child = sc->dev;
|
|
rcinfo = device_get_ivars(rcdev);
|
|
|
|
switch (obj->type) {
|
|
case DPAA2_DEV_IO:
|
|
devclass = "dpaa2_io";
|
|
res_spec = dpaa2_io_spec;
|
|
flags = DPAA2_MC_DEV_ALLOCATABLE | DPAA2_MC_DEV_SHAREABLE;
|
|
break;
|
|
case DPAA2_DEV_BP:
|
|
devclass = "dpaa2_bp";
|
|
res_spec = dpaa2_bp_spec;
|
|
flags = DPAA2_MC_DEV_ALLOCATABLE;
|
|
break;
|
|
case DPAA2_DEV_CON:
|
|
devclass = "dpaa2_con";
|
|
res_spec = dpaa2_con_spec;
|
|
flags = DPAA2_MC_DEV_ALLOCATABLE;
|
|
break;
|
|
case DPAA2_DEV_MAC:
|
|
devclass = "dpaa2_mac";
|
|
res_spec = dpaa2_mac_spec;
|
|
flags = DPAA2_MC_DEV_ASSOCIATED;
|
|
break;
|
|
case DPAA2_DEV_MCP:
|
|
devclass = "dpaa2_mcp";
|
|
res_spec = NULL;
|
|
flags = DPAA2_MC_DEV_ALLOCATABLE | DPAA2_MC_DEV_SHAREABLE;
|
|
break;
|
|
default:
|
|
/* Only managed devices above are supported. */
|
|
return (EINVAL);
|
|
}
|
|
|
|
/* Add a device for the DPAA2 object. */
|
|
dev = device_add_child(rcdev, devclass, -1);
|
|
if (dev == NULL) {
|
|
device_printf(rcdev, "%s: failed to add a device for DPAA2 "
|
|
"object: type=%s, id=%u\n", __func__, dpaa2_ttos(obj->type),
|
|
obj->id);
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* Allocate devinfo for the child. */
|
|
dinfo = malloc(sizeof(struct dpaa2_devinfo), M_DPAA2_RC,
|
|
M_WAITOK | M_ZERO);
|
|
if (!dinfo) {
|
|
device_printf(rcdev, "%s: failed to allocate dpaa2_devinfo "
|
|
"for: type=%s, id=%u\n", __func__, dpaa2_ttos(obj->type),
|
|
obj->id);
|
|
return (ENXIO);
|
|
}
|
|
device_set_ivars(dev, dinfo);
|
|
|
|
dinfo->pdev = rcdev;
|
|
dinfo->dev = dev;
|
|
dinfo->id = obj->id;
|
|
dinfo->dtype = obj->type;
|
|
dinfo->portal = NULL;
|
|
/* Children share their parent container's ICID and portal ID. */
|
|
dinfo->icid = rcinfo->icid;
|
|
dinfo->portal_id = rcinfo->portal_id;
|
|
/* MSI configuration */
|
|
dinfo->msi.msi_msgnum = obj->irq_count;
|
|
dinfo->msi.msi_alloc = 0;
|
|
dinfo->msi.msi_handlers = 0;
|
|
|
|
/* Initialize a resource list for the child. */
|
|
resource_list_init(&dinfo->resources);
|
|
|
|
/* Add memory regions to the resource list. */
|
|
for (uint8_t i = 0; i < obj->reg_count; i++) {
|
|
error = DPAA2_CMD_RC_GET_OBJ_REGION(rcdev, child, cmd, obj->id,
|
|
i, obj->type, ®);
|
|
if (error) {
|
|
device_printf(rcdev, "%s: failed to obtain memory "
|
|
"region for type=%s, id=%u, reg_idx=%u: error=%d\n",
|
|
__func__, dpaa2_ttos(obj->type), obj->id, i, error);
|
|
continue;
|
|
}
|
|
count = reg.size;
|
|
start = reg.base_paddr + reg.base_offset;
|
|
end = reg.base_paddr + reg.base_offset + reg.size - 1;
|
|
|
|
resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i, start,
|
|
end, count);
|
|
}
|
|
|
|
/* Add DPAA2-specific resources to the resource list. */
|
|
for (; res_spec && res_spec->type != -1; res_spec++) {
|
|
if (res_spec->type < DPAA2_DEV_MC)
|
|
continue; /* Skip non-DPAA2 resource. */
|
|
rid = res_spec->rid;
|
|
|
|
error = dpaa2_rc_add_res(rcdev, dev, res_spec->type, &rid,
|
|
res_spec->flags);
|
|
if (error)
|
|
device_printf(rcdev, "%s: dpaa2_rc_add_res() failed: "
|
|
"error=%d\n", __func__, error);
|
|
}
|
|
|
|
/* Inform MC about a new managed device. */
|
|
error = DPAA2_MC_MANAGE_DEV(rcdev, dev, flags);
|
|
if (error) {
|
|
device_printf(rcdev, "%s: failed to add a managed DPAA2 device: "
|
|
"type=%s, id=%u, error=%d\n", __func__,
|
|
dpaa2_ttos(obj->type), obj->id, error);
|
|
return (ENXIO);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* @brief Configure given IRQ using MC command interface.
|
|
*/
|
|
static int
|
|
dpaa2_rc_configure_irq(device_t rcdev, device_t child, int rid, uint64_t addr,
|
|
uint32_t data)
|
|
{
|
|
struct dpaa2_devinfo *rcinfo;
|
|
struct dpaa2_devinfo *dinfo;
|
|
struct dpaa2_cmd *cmd;
|
|
uint16_t rc_token;
|
|
int rc = EINVAL;
|
|
|
|
if (device_get_parent(child) == rcdev && rid >= 1) {
|
|
rcinfo = device_get_ivars(rcdev);
|
|
dinfo = device_get_ivars(child);
|
|
|
|
/* Allocate a command to send to MC hardware. */
|
|
rc = dpaa2_mcp_init_command(&cmd, DPAA2_CMD_DEF);
|
|
if (rc) {
|
|
device_printf(rcdev, "%s: failed to allocate dpaa2_cmd: "
|
|
"error=%d\n", __func__, rc);
|
|
return (ENODEV);
|
|
}
|
|
|
|
/* Open resource container. */
|
|
rc = DPAA2_CMD_RC_OPEN(rcdev, child, cmd, rcinfo->id, &rc_token);
|
|
if (rc) {
|
|
dpaa2_mcp_free_command(cmd);
|
|
device_printf(rcdev, "%s: failed to open DPRC: "
|
|
"error=%d\n", __func__, rc);
|
|
return (ENODEV);
|
|
}
|
|
/* Set MSI address and value. */
|
|
rc = DPAA2_CMD_RC_SET_OBJ_IRQ(rcdev, child, cmd, rid - 1, addr,
|
|
data, rid, dinfo->id, dinfo->dtype);
|
|
if (rc) {
|
|
dpaa2_mcp_free_command(cmd);
|
|
device_printf(rcdev, "%s: failed to setup IRQ: "
|
|
"rid=%d, addr=%jx, data=%x, error=%d\n", __func__,
|
|
rid, addr, data, rc);
|
|
return (ENODEV);
|
|
}
|
|
/* Close resource container. */
|
|
rc = DPAA2_CMD_RC_CLOSE(rcdev, child, cmd);
|
|
if (rc) {
|
|
dpaa2_mcp_free_command(cmd);
|
|
device_printf(rcdev, "%s: failed to close DPRC: "
|
|
"error=%d\n", __func__, rc);
|
|
return (ENODEV);
|
|
}
|
|
|
|
dpaa2_mcp_free_command(cmd);
|
|
rc = 0;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/**
|
|
* @brief General implementation of the MC command to enable IRQ.
|
|
*/
|
|
static int
|
|
dpaa2_rc_enable_irq(struct dpaa2_mcp *mcp, struct dpaa2_cmd *cmd,
|
|
uint8_t irq_idx, bool enable, uint16_t cmdid)
|
|
{
|
|
struct __packed enable_irq_args {
|
|
uint8_t enable;
|
|
uint8_t _reserved1;
|
|
uint16_t _reserved2;
|
|
uint8_t irq_idx;
|
|
uint8_t _reserved3;
|
|
uint16_t _reserved4;
|
|
uint64_t _reserved5[6];
|
|
} *args;
|
|
|
|
if (!mcp || !cmd)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
args = (struct enable_irq_args *) &cmd->params[0];
|
|
args->irq_idx = irq_idx;
|
|
args->enable = enable == 0u ? 0u : 1u;
|
|
|
|
return (dpaa2_rc_exec_cmd(mcp, cmd, cmdid));
|
|
}
|
|
|
|
/**
|
|
* @brief Sends a command to MC and waits for response.
|
|
*/
|
|
static int
|
|
dpaa2_rc_exec_cmd(struct dpaa2_mcp *mcp, struct dpaa2_cmd *cmd, uint16_t cmdid)
|
|
{
|
|
struct dpaa2_cmd_header *hdr;
|
|
uint16_t flags;
|
|
int error;
|
|
|
|
if (!mcp || !cmd)
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
|
|
/* Prepare a command for the MC hardware. */
|
|
hdr = (struct dpaa2_cmd_header *) &cmd->header;
|
|
hdr->cmdid = cmdid;
|
|
hdr->status = DPAA2_CMD_STAT_READY;
|
|
|
|
DPAA2_MCP_LOCK(mcp, &flags);
|
|
if (flags & DPAA2_PORTAL_DESTROYED) {
|
|
/* Terminate operation if portal is destroyed. */
|
|
DPAA2_MCP_UNLOCK(mcp);
|
|
return (DPAA2_CMD_STAT_INVALID_STATE);
|
|
}
|
|
|
|
/* Send a command to MC and wait for the result. */
|
|
dpaa2_rc_send_cmd(mcp, cmd);
|
|
error = dpaa2_rc_wait_for_cmd(mcp, cmd);
|
|
if (error) {
|
|
DPAA2_MCP_UNLOCK(mcp);
|
|
return (DPAA2_CMD_STAT_ERR);
|
|
}
|
|
if (hdr->status != DPAA2_CMD_STAT_OK) {
|
|
DPAA2_MCP_UNLOCK(mcp);
|
|
return (int)(hdr->status);
|
|
}
|
|
|
|
DPAA2_MCP_UNLOCK(mcp);
|
|
|
|
return (DPAA2_CMD_STAT_OK);
|
|
}
|
|
|
|
/**
|
|
* @brief Writes a command to the MC command portal.
|
|
*/
|
|
static int
|
|
dpaa2_rc_send_cmd(struct dpaa2_mcp *mcp, struct dpaa2_cmd *cmd)
|
|
{
|
|
/* Write command parameters. */
|
|
for (uint32_t i = 1; i <= DPAA2_CMD_PARAMS_N; i++)
|
|
bus_write_8(mcp->map, sizeof(uint64_t) * i, cmd->params[i-1]);
|
|
|
|
bus_barrier(mcp->map, 0, sizeof(struct dpaa2_cmd),
|
|
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
|
|
|
|
/* Write command header to trigger execution. */
|
|
bus_write_8(mcp->map, 0, cmd->header);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* @brief Polls the MC command portal in order to receive a result of the
|
|
* command execution.
|
|
*/
|
|
static int
|
|
dpaa2_rc_wait_for_cmd(struct dpaa2_mcp *mcp, struct dpaa2_cmd *cmd)
|
|
{
|
|
struct dpaa2_cmd_header *hdr;
|
|
uint64_t val;
|
|
uint32_t i;
|
|
|
|
/* Wait for a command execution result from the MC hardware. */
|
|
for (i = 1; i <= CMD_SPIN_ATTEMPTS; i++) {
|
|
val = bus_read_8(mcp->map, 0);
|
|
hdr = (struct dpaa2_cmd_header *) &val;
|
|
if (hdr->status != DPAA2_CMD_STAT_READY) {
|
|
break;
|
|
}
|
|
DELAY(CMD_SPIN_TIMEOUT);
|
|
}
|
|
|
|
if (i > CMD_SPIN_ATTEMPTS) {
|
|
/* Return an error on expired timeout. */
|
|
return (DPAA2_CMD_STAT_TIMEOUT);
|
|
} else {
|
|
/* Read command response. */
|
|
cmd->header = val;
|
|
for (i = 1; i <= DPAA2_CMD_PARAMS_N; i++) {
|
|
cmd->params[i-1] =
|
|
bus_read_8(mcp->map, i * sizeof(uint64_t));
|
|
}
|
|
}
|
|
|
|
return (DPAA2_CMD_STAT_OK);
|
|
}
|
|
|
|
/**
|
|
* @brief Reserve a DPAA2-specific device of the given devtype for the child.
|
|
*/
|
|
static int
|
|
dpaa2_rc_add_res(device_t rcdev, device_t child, enum dpaa2_dev_type devtype,
|
|
int *rid, int flags)
|
|
{
|
|
device_t dpaa2_dev;
|
|
struct dpaa2_devinfo *dinfo = device_get_ivars(child);
|
|
struct resource *res;
|
|
bool shared = false;
|
|
int error;
|
|
|
|
/* Request a free DPAA2 device of the given type from MC. */
|
|
error = DPAA2_MC_GET_FREE_DEV(rcdev, &dpaa2_dev, devtype);
|
|
if (error && !(flags & RF_SHAREABLE)) {
|
|
device_printf(rcdev, "%s: failed to obtain a free %s (rid=%d) "
|
|
"for: %s (id=%u)\n", __func__, dpaa2_ttos(devtype), *rid,
|
|
dpaa2_ttos(dinfo->dtype), dinfo->id);
|
|
return (error);
|
|
}
|
|
|
|
/* Request a shared DPAA2 device of the given type from MC. */
|
|
if (error) {
|
|
error = DPAA2_MC_GET_SHARED_DEV(rcdev, &dpaa2_dev, devtype);
|
|
if (error) {
|
|
device_printf(rcdev, "%s: failed to obtain a shared "
|
|
"%s (rid=%d) for: %s (id=%u)\n", __func__,
|
|
dpaa2_ttos(devtype), *rid, dpaa2_ttos(dinfo->dtype),
|
|
dinfo->id);
|
|
return (error);
|
|
}
|
|
shared = true;
|
|
}
|
|
|
|
/* Add DPAA2 device to the resource list of the child device. */
|
|
resource_list_add(&dinfo->resources, devtype, *rid,
|
|
(rman_res_t) dpaa2_dev, (rman_res_t) dpaa2_dev, 1);
|
|
|
|
/* Reserve a newly added DPAA2 resource. */
|
|
res = resource_list_reserve(&dinfo->resources, rcdev, child, devtype,
|
|
rid, (rman_res_t) dpaa2_dev, (rman_res_t) dpaa2_dev, 1,
|
|
flags & ~RF_ACTIVE);
|
|
if (!res) {
|
|
device_printf(rcdev, "%s: failed to reserve %s (rid=%d) for: %s "
|
|
"(id=%u)\n", __func__, dpaa2_ttos(devtype), *rid,
|
|
dpaa2_ttos(dinfo->dtype), dinfo->id);
|
|
return (EBUSY);
|
|
}
|
|
|
|
/* Reserve a shared DPAA2 device of the given type. */
|
|
if (shared) {
|
|
error = DPAA2_MC_RESERVE_DEV(rcdev, dpaa2_dev, devtype);
|
|
if (error) {
|
|
device_printf(rcdev, "%s: failed to reserve a shared "
|
|
"%s (rid=%d) for: %s (id=%u)\n", __func__,
|
|
dpaa2_ttos(devtype), *rid, dpaa2_ttos(dinfo->dtype),
|
|
dinfo->id);
|
|
return (error);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_print_type(struct resource_list *rl, enum dpaa2_dev_type type)
|
|
{
|
|
struct dpaa2_devinfo *dinfo;
|
|
struct resource_list_entry *rle;
|
|
uint32_t prev_id;
|
|
int printed = 0, series = 0;
|
|
int retval = 0;
|
|
|
|
STAILQ_FOREACH(rle, rl, link) {
|
|
if (rle->type == type) {
|
|
dinfo = device_get_ivars((device_t) rle->start);
|
|
|
|
if (printed == 0) {
|
|
retval += printf(" %s (id=",
|
|
dpaa2_ttos(dinfo->dtype));
|
|
} else {
|
|
if (dinfo->id == prev_id + 1) {
|
|
if (series == 0) {
|
|
series = 1;
|
|
retval += printf("-");
|
|
}
|
|
} else {
|
|
if (series == 1) {
|
|
retval += printf("%u", prev_id);
|
|
series = 0;
|
|
}
|
|
retval += printf(",");
|
|
}
|
|
}
|
|
printed++;
|
|
|
|
if (series == 0)
|
|
retval += printf("%u", dinfo->id);
|
|
prev_id = dinfo->id;
|
|
}
|
|
}
|
|
if (printed) {
|
|
if (series == 1)
|
|
retval += printf("%u", prev_id);
|
|
retval += printf(")");
|
|
}
|
|
|
|
return (retval);
|
|
}
|
|
|
|
static int
|
|
dpaa2_rc_reset_cmd_params(struct dpaa2_cmd *cmd)
|
|
{
|
|
if (cmd != NULL) {
|
|
memset(cmd->params, 0, sizeof(cmd->params[0]) *
|
|
DPAA2_CMD_PARAMS_N);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static struct dpaa2_mcp *
|
|
dpaa2_rc_select_portal(device_t dev, device_t child)
|
|
{
|
|
struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
|
|
struct dpaa2_devinfo *cinfo = device_get_ivars(child);
|
|
|
|
if (cinfo == NULL || dinfo == NULL || dinfo->dtype != DPAA2_DEV_RC)
|
|
return (NULL);
|
|
return (cinfo->portal != NULL ? cinfo->portal : dinfo->portal);
|
|
}
|
|
|
|
static device_method_t dpaa2_rc_methods[] = {
|
|
/* Device interface */
|
|
DEVMETHOD(device_probe, dpaa2_rc_probe),
|
|
DEVMETHOD(device_attach, dpaa2_rc_attach),
|
|
DEVMETHOD(device_detach, dpaa2_rc_detach),
|
|
|
|
/* Bus interface */
|
|
DEVMETHOD(bus_get_resource_list, dpaa2_rc_get_resource_list),
|
|
DEVMETHOD(bus_delete_resource, dpaa2_rc_delete_resource),
|
|
DEVMETHOD(bus_alloc_resource, dpaa2_rc_alloc_resource),
|
|
DEVMETHOD(bus_release_resource, dpaa2_rc_release_resource),
|
|
DEVMETHOD(bus_child_deleted, dpaa2_rc_child_deleted),
|
|
DEVMETHOD(bus_child_detached, dpaa2_rc_child_detached),
|
|
DEVMETHOD(bus_setup_intr, dpaa2_rc_setup_intr),
|
|
DEVMETHOD(bus_teardown_intr, dpaa2_rc_teardown_intr),
|
|
DEVMETHOD(bus_print_child, dpaa2_rc_print_child),
|
|
DEVMETHOD(bus_add_child, device_add_child_ordered),
|
|
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
|
|
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
|
|
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
|
|
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
|
|
DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
|
|
|
|
/* Pseudo-PCI interface */
|
|
DEVMETHOD(pci_alloc_msi, dpaa2_rc_alloc_msi),
|
|
DEVMETHOD(pci_release_msi, dpaa2_rc_release_msi),
|
|
DEVMETHOD(pci_msi_count, dpaa2_rc_msi_count),
|
|
DEVMETHOD(pci_get_id, dpaa2_rc_get_id),
|
|
|
|
/* DPAA2 MC command interface */
|
|
DEVMETHOD(dpaa2_cmd_mng_get_version, dpaa2_rc_mng_get_version),
|
|
DEVMETHOD(dpaa2_cmd_mng_get_soc_version, dpaa2_rc_mng_get_soc_version),
|
|
DEVMETHOD(dpaa2_cmd_mng_get_container_id, dpaa2_rc_mng_get_container_id),
|
|
/* DPRC commands */
|
|
DEVMETHOD(dpaa2_cmd_rc_open, dpaa2_rc_open),
|
|
DEVMETHOD(dpaa2_cmd_rc_close, dpaa2_rc_close),
|
|
DEVMETHOD(dpaa2_cmd_rc_get_obj_count, dpaa2_rc_get_obj_count),
|
|
DEVMETHOD(dpaa2_cmd_rc_get_obj, dpaa2_rc_get_obj),
|
|
DEVMETHOD(dpaa2_cmd_rc_get_obj_descriptor, dpaa2_rc_get_obj_descriptor),
|
|
DEVMETHOD(dpaa2_cmd_rc_get_attributes, dpaa2_rc_get_attributes),
|
|
DEVMETHOD(dpaa2_cmd_rc_get_obj_region, dpaa2_rc_get_obj_region),
|
|
DEVMETHOD(dpaa2_cmd_rc_get_api_version, dpaa2_rc_get_api_version),
|
|
DEVMETHOD(dpaa2_cmd_rc_set_irq_enable, dpaa2_rc_set_irq_enable),
|
|
DEVMETHOD(dpaa2_cmd_rc_set_obj_irq, dpaa2_rc_set_obj_irq),
|
|
DEVMETHOD(dpaa2_cmd_rc_get_conn, dpaa2_rc_get_conn),
|
|
/* DPNI commands */
|
|
DEVMETHOD(dpaa2_cmd_ni_open, dpaa2_rc_ni_open),
|
|
DEVMETHOD(dpaa2_cmd_ni_close, dpaa2_rc_ni_close),
|
|
DEVMETHOD(dpaa2_cmd_ni_enable, dpaa2_rc_ni_enable),
|
|
DEVMETHOD(dpaa2_cmd_ni_disable, dpaa2_rc_ni_disable),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_api_version, dpaa2_rc_ni_get_api_version),
|
|
DEVMETHOD(dpaa2_cmd_ni_reset, dpaa2_rc_ni_reset),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_attributes, dpaa2_rc_ni_get_attributes),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_buf_layout, dpaa2_rc_ni_set_buf_layout),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_tx_data_off, dpaa2_rc_ni_get_tx_data_offset),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_port_mac_addr, dpaa2_rc_ni_get_port_mac_addr),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_prim_mac_addr, dpaa2_rc_ni_set_prim_mac_addr),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_prim_mac_addr, dpaa2_rc_ni_get_prim_mac_addr),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_link_cfg, dpaa2_rc_ni_set_link_cfg),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_link_cfg, dpaa2_rc_ni_get_link_cfg),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_link_state, dpaa2_rc_ni_get_link_state),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_qos_table, dpaa2_rc_ni_set_qos_table),
|
|
DEVMETHOD(dpaa2_cmd_ni_clear_qos_table, dpaa2_rc_ni_clear_qos_table),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_pools, dpaa2_rc_ni_set_pools),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_err_behavior,dpaa2_rc_ni_set_err_behavior),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_queue, dpaa2_rc_ni_get_queue),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_queue, dpaa2_rc_ni_set_queue),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_qdid, dpaa2_rc_ni_get_qdid),
|
|
DEVMETHOD(dpaa2_cmd_ni_add_mac_addr, dpaa2_rc_ni_add_mac_addr),
|
|
DEVMETHOD(dpaa2_cmd_ni_remove_mac_addr, dpaa2_rc_ni_remove_mac_addr),
|
|
DEVMETHOD(dpaa2_cmd_ni_clear_mac_filters, dpaa2_rc_ni_clear_mac_filters),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_mfl, dpaa2_rc_ni_set_mfl),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_offload, dpaa2_rc_ni_set_offload),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_irq_mask, dpaa2_rc_ni_set_irq_mask),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_irq_enable, dpaa2_rc_ni_set_irq_enable),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_irq_status, dpaa2_rc_ni_get_irq_status),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_uni_promisc, dpaa2_rc_ni_set_uni_promisc),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_multi_promisc, dpaa2_rc_ni_set_multi_promisc),
|
|
DEVMETHOD(dpaa2_cmd_ni_get_statistics, dpaa2_rc_ni_get_statistics),
|
|
DEVMETHOD(dpaa2_cmd_ni_set_rx_tc_dist, dpaa2_rc_ni_set_rx_tc_dist),
|
|
/* DPIO commands */
|
|
DEVMETHOD(dpaa2_cmd_io_open, dpaa2_rc_io_open),
|
|
DEVMETHOD(dpaa2_cmd_io_close, dpaa2_rc_io_close),
|
|
DEVMETHOD(dpaa2_cmd_io_enable, dpaa2_rc_io_enable),
|
|
DEVMETHOD(dpaa2_cmd_io_disable, dpaa2_rc_io_disable),
|
|
DEVMETHOD(dpaa2_cmd_io_reset, dpaa2_rc_io_reset),
|
|
DEVMETHOD(dpaa2_cmd_io_get_attributes, dpaa2_rc_io_get_attributes),
|
|
DEVMETHOD(dpaa2_cmd_io_set_irq_mask, dpaa2_rc_io_set_irq_mask),
|
|
DEVMETHOD(dpaa2_cmd_io_get_irq_status, dpaa2_rc_io_get_irq_status),
|
|
DEVMETHOD(dpaa2_cmd_io_set_irq_enable, dpaa2_rc_io_set_irq_enable),
|
|
DEVMETHOD(dpaa2_cmd_io_add_static_dq_chan, dpaa2_rc_io_add_static_dq_chan),
|
|
/* DPBP commands */
|
|
DEVMETHOD(dpaa2_cmd_bp_open, dpaa2_rc_bp_open),
|
|
DEVMETHOD(dpaa2_cmd_bp_close, dpaa2_rc_bp_close),
|
|
DEVMETHOD(dpaa2_cmd_bp_enable, dpaa2_rc_bp_enable),
|
|
DEVMETHOD(dpaa2_cmd_bp_disable, dpaa2_rc_bp_disable),
|
|
DEVMETHOD(dpaa2_cmd_bp_reset, dpaa2_rc_bp_reset),
|
|
DEVMETHOD(dpaa2_cmd_bp_get_attributes, dpaa2_rc_bp_get_attributes),
|
|
/* DPMAC commands */
|
|
DEVMETHOD(dpaa2_cmd_mac_open, dpaa2_rc_mac_open),
|
|
DEVMETHOD(dpaa2_cmd_mac_close, dpaa2_rc_mac_close),
|
|
DEVMETHOD(dpaa2_cmd_mac_reset, dpaa2_rc_mac_reset),
|
|
DEVMETHOD(dpaa2_cmd_mac_mdio_read, dpaa2_rc_mac_mdio_read),
|
|
DEVMETHOD(dpaa2_cmd_mac_mdio_write, dpaa2_rc_mac_mdio_write),
|
|
DEVMETHOD(dpaa2_cmd_mac_get_addr, dpaa2_rc_mac_get_addr),
|
|
DEVMETHOD(dpaa2_cmd_mac_get_attributes, dpaa2_rc_mac_get_attributes),
|
|
DEVMETHOD(dpaa2_cmd_mac_set_link_state, dpaa2_rc_mac_set_link_state),
|
|
DEVMETHOD(dpaa2_cmd_mac_set_irq_mask, dpaa2_rc_mac_set_irq_mask),
|
|
DEVMETHOD(dpaa2_cmd_mac_set_irq_enable, dpaa2_rc_mac_set_irq_enable),
|
|
DEVMETHOD(dpaa2_cmd_mac_get_irq_status, dpaa2_rc_mac_get_irq_status),
|
|
/* DPCON commands */
|
|
DEVMETHOD(dpaa2_cmd_con_open, dpaa2_rc_con_open),
|
|
DEVMETHOD(dpaa2_cmd_con_close, dpaa2_rc_con_close),
|
|
DEVMETHOD(dpaa2_cmd_con_reset, dpaa2_rc_con_reset),
|
|
DEVMETHOD(dpaa2_cmd_con_enable, dpaa2_rc_con_enable),
|
|
DEVMETHOD(dpaa2_cmd_con_disable, dpaa2_rc_con_disable),
|
|
DEVMETHOD(dpaa2_cmd_con_get_attributes, dpaa2_rc_con_get_attributes),
|
|
DEVMETHOD(dpaa2_cmd_con_set_notif, dpaa2_rc_con_set_notif),
|
|
/* DPMCP commands */
|
|
DEVMETHOD(dpaa2_cmd_mcp_create, dpaa2_rc_mcp_create),
|
|
DEVMETHOD(dpaa2_cmd_mcp_destroy, dpaa2_rc_mcp_destroy),
|
|
DEVMETHOD(dpaa2_cmd_mcp_open, dpaa2_rc_mcp_open),
|
|
DEVMETHOD(dpaa2_cmd_mcp_close, dpaa2_rc_mcp_close),
|
|
DEVMETHOD(dpaa2_cmd_mcp_reset, dpaa2_rc_mcp_reset),
|
|
|
|
DEVMETHOD_END
|
|
};
|
|
|
|
static driver_t dpaa2_rc_driver = {
|
|
"dpaa2_rc",
|
|
dpaa2_rc_methods,
|
|
sizeof(struct dpaa2_rc_softc),
|
|
};
|
|
|
|
/* For root container */
|
|
DRIVER_MODULE(dpaa2_rc, dpaa2_mc, dpaa2_rc_driver, 0, 0);
|
|
/* For child containers */
|
|
DRIVER_MODULE(dpaa2_rc, dpaa2_rc, dpaa2_rc_driver, 0, 0);
|