/*-
 * 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;
	struct dpaa2_rc_attr dprc_attr;
	struct dpaa2_obj obj;
	uint32_t major, minor, rev, obj_count;
	uint16_t rc_token;
	int rc;

	DPAA2_CMD_INIT(&cmd);

	/* 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);
		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);
		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);
		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);
		(void)DPAA2_CMD_RC_CLOSE(rcdev, child, &cmd);
		return (ENXIO);
	}
	if (bootverbose) {
		device_printf(rcdev, "Objects in container: %u\n", obj_count);
	}

	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);
		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);
		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);
		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);

	/* 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;

	DPAA2_CMD_INIT(&cmd);

	if (device_get_parent(child) == rcdev && rid >= 1) {
		rcinfo = device_get_ivars(rcdev);
		dinfo = device_get_ivars(child);

		rc = DPAA2_CMD_RC_OPEN(rcdev, child, &cmd, rcinfo->id,
		    &rc_token);
		if (rc) {
			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) {
			device_printf(rcdev, "%s: failed to setup IRQ: "
			    "rid=%d, addr=%jx, data=%x, error=%d\n", __func__,
			    rid, addr, data, rc);
			return (ENODEV);
		}
		rc = DPAA2_CMD_RC_CLOSE(rcdev, child, &cmd);
		if (rc) {
			device_printf(rcdev, "%s: failed to close DPRC: "
			    "error=%d\n", __func__, rc);
			return (ENODEV);
		}
		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);