opnsense-src/sys/dev/dpaa2/dpaa2_rc.c
Dmitry Salychev ba7319e909
Add initial DPAA2 support
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
2022-10-14 22:49:09 +02:00

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, &reg);
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);