aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/dpaa
diff options
context:
space:
mode:
authorJustin Hibbits <jhibbits@FreeBSD.org>2016-02-29 03:38:00 +0000
committerJustin Hibbits <jhibbits@FreeBSD.org>2016-02-29 03:38:00 +0000
commit0aeed3e99367bed5755068d9218cd8041644ff2b (patch)
tree5b00ae419405b400d27fe05a3ed4868b17bbcb84 /sys/dev/dpaa
parentb25855675953dace218f705aea63cc7437590bf8 (diff)
downloadsrc-0aeed3e99367bed5755068d9218cd8041644ff2b.tar.gz
src-0aeed3e99367bed5755068d9218cd8041644ff2b.zip
Notes
Diffstat (limited to 'sys/dev/dpaa')
-rw-r--r--sys/dev/dpaa/bman.c370
-rw-r--r--sys/dev/dpaa/bman.h204
-rw-r--r--sys/dev/dpaa/bman_fdt.c225
-rw-r--r--sys/dev/dpaa/bman_portals.c180
-rw-r--r--sys/dev/dpaa/dpaa.c184
-rw-r--r--sys/dev/dpaa/fman.c357
-rw-r--r--sys/dev/dpaa/fman.h67
-rw-r--r--sys/dev/dpaa/fman_fdt.c104
-rw-r--r--sys/dev/dpaa/if_dtsec.c879
-rw-r--r--sys/dev/dpaa/if_dtsec.h154
-rw-r--r--sys/dev/dpaa/if_dtsec_fdt.c215
-rw-r--r--sys/dev/dpaa/if_dtsec_im.c262
-rw-r--r--sys/dev/dpaa/if_dtsec_im.h41
-rw-r--r--sys/dev/dpaa/if_dtsec_rm.c654
-rw-r--r--sys/dev/dpaa/if_dtsec_rm.h53
-rw-r--r--sys/dev/dpaa/portals.h64
-rw-r--r--sys/dev/dpaa/portals_common.c166
-rw-r--r--sys/dev/dpaa/qman.c555
-rw-r--r--sys/dev/dpaa/qman.h246
-rw-r--r--sys/dev/dpaa/qman_fdt.c221
-rw-r--r--sys/dev/dpaa/qman_portals.c191
21 files changed, 5392 insertions, 0 deletions
diff --git a/sys/dev/dpaa/bman.c b/sys/dev/dpaa/bman.c
new file mode 100644
index 000000000000..02499c4902f4
--- /dev/null
+++ b/sys/dev/dpaa/bman.c
@@ -0,0 +1,370 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/rman.h>
+#include <sys/sched.h>
+
+#include <machine/tlb.h>
+
+#include "bman.h"
+
+devclass_t bman_devclass;
+
+static struct bman_softc *bman_sc;
+
+extern t_Handle bman_portal_setup(struct bman_softc *bsc);
+
+static void
+bman_exception(t_Handle h_App, e_BmExceptions exception)
+{
+ struct bman_softc *sc;
+ const char *message;
+
+ sc = h_App;
+
+ switch (exception) {
+ case e_BM_EX_INVALID_COMMAND:
+ message = "Invalid Command Verb";
+ break;
+ case e_BM_EX_FBPR_THRESHOLD:
+ message = "FBPR pool exhaused. Consider increasing "
+ "BMAN_MAX_BUFFERS";
+ break;
+ case e_BM_EX_SINGLE_ECC:
+ message = "Single bit ECC error";
+ break;
+ case e_BM_EX_MULTI_ECC:
+ message = "Multi bit ECC error";
+ break;
+ default:
+ message = "Unknown error";
+ }
+
+ device_printf(sc->sc_dev, "BMAN Exception: %s.\n", message);
+}
+
+int
+bman_attach(device_t dev)
+{
+ struct bman_softc *sc;
+ t_BmRevisionInfo rev;
+ t_Error error;
+ t_BmParam bp;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+ bman_sc = sc;
+
+ /* Check if MallocSmart allocator is ready */
+ if (XX_MallocSmartInit() != E_OK)
+ return (ENXIO);
+
+ /* Allocate resources */
+ sc->sc_rrid = 0;
+ sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY,
+ &sc->sc_rrid, 0, ~0, BMAN_CCSR_SIZE, RF_ACTIVE);
+ if (sc->sc_rres == NULL)
+ return (ENXIO);
+
+ sc->sc_irid = 0;
+ sc->sc_ires = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ,
+ &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE);
+ if (sc->sc_ires == NULL)
+ goto err;
+
+ /* Initialize BMAN */
+ memset(&bp, 0, sizeof(bp));
+ bp.guestId = NCSW_MASTER_ID;
+ bp.baseAddress = rman_get_bushandle(sc->sc_rres);
+ bp.totalNumOfBuffers = BMAN_MAX_BUFFERS;
+ bp.f_Exception = bman_exception;
+ bp.h_App = sc;
+ bp.errIrq = (int)sc->sc_ires;
+ bp.partBpidBase = 0;
+ bp.partNumOfPools = BM_MAX_NUM_OF_POOLS;
+ printf("base address: %llx\n", (uint64_t)bp.baseAddress);
+
+ sc->sc_bh = BM_Config(&bp);
+ if (sc->sc_bh == NULL)
+ goto err;
+
+ /* Warn if there is less than 5% free FPBR's in pool */
+ error = BM_ConfigFbprThreshold(sc->sc_bh, (BMAN_MAX_BUFFERS / 8) / 20);
+ if (error != E_OK)
+ goto err;
+
+ error = BM_Init(sc->sc_bh);
+ if (error != E_OK)
+ goto err;
+
+ error = BM_GetRevision(sc->sc_bh, &rev);
+ if (error != E_OK)
+ goto err;
+
+ device_printf(dev, "Hardware version: %d.%d.\n",
+ rev.majorRev, rev.minorRev);
+
+ return (0);
+
+err:
+ bman_detach(dev);
+ return (ENXIO);
+}
+
+int
+bman_detach(device_t dev)
+{
+ struct bman_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_bh != NULL)
+ BM_Free(sc->sc_bh);
+
+ if (sc->sc_ires != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_irid, sc->sc_ires);
+
+ if (sc->sc_rres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->sc_rrid, sc->sc_rres);
+
+ return (0);
+}
+
+int
+bman_suspend(device_t dev)
+{
+
+ return (0);
+}
+
+int
+bman_resume(device_t dev)
+{
+
+ return (0);
+}
+
+int
+bman_shutdown(device_t dev)
+{
+
+ return (0);
+}
+
+/*
+ * BMAN API
+ */
+
+t_Handle
+bman_pool_create(uint8_t *bpid, uint16_t bufferSize, uint16_t maxBuffers,
+ uint16_t minBuffers, uint16_t allocBuffers, t_GetBufFunction *f_GetBuf,
+ t_PutBufFunction *f_PutBuf, uint32_t dep_sw_entry, uint32_t dep_sw_exit,
+ uint32_t dep_hw_entry, uint32_t dep_hw_exit,
+ t_BmDepletionCallback *f_Depletion, t_Handle h_BufferPool,
+ t_PhysToVirt *f_PhysToVirt, t_VirtToPhys *f_VirtToPhys)
+{
+ uint32_t thresholds[MAX_DEPLETION_THRESHOLDS];
+ struct bman_softc *sc;
+ t_Handle pool, portal;
+ t_BmPoolParam bpp;
+ int error;
+
+ sc = bman_sc;
+ pool = NULL;
+
+ sched_pin();
+
+ portal = bman_portal_setup(sc);
+ if (portal == NULL)
+ goto err;
+
+ memset(&bpp, 0, sizeof(bpp));
+ bpp.h_Bm = sc->sc_bh;
+ bpp.h_BmPortal = portal;
+ bpp.h_App = h_BufferPool;
+ bpp.numOfBuffers = allocBuffers;
+
+ bpp.bufferPoolInfo.h_BufferPool = h_BufferPool;
+ bpp.bufferPoolInfo.f_GetBuf = f_GetBuf;
+ bpp.bufferPoolInfo.f_PutBuf = f_PutBuf;
+ bpp.bufferPoolInfo.f_PhysToVirt = f_PhysToVirt;
+ bpp.bufferPoolInfo.f_VirtToPhys = f_VirtToPhys;
+ bpp.bufferPoolInfo.bufferSize = bufferSize;
+
+ pool = BM_POOL_Config(&bpp);
+ if (pool == NULL)
+ goto err;
+
+ /*
+ * Buffer context must be disabled on FreeBSD
+ * as it could cause memory corruption.
+ */
+ BM_POOL_ConfigBuffContextMode(pool, 0);
+
+ if (minBuffers != 0 || maxBuffers != 0) {
+ error = BM_POOL_ConfigStockpile(pool, maxBuffers, minBuffers);
+ if (error != E_OK)
+ goto err;
+ }
+
+ if (f_Depletion != NULL) {
+ thresholds[BM_POOL_DEP_THRESH_SW_ENTRY] = dep_sw_entry;
+ thresholds[BM_POOL_DEP_THRESH_SW_EXIT] = dep_sw_exit;
+ thresholds[BM_POOL_DEP_THRESH_HW_ENTRY] = dep_hw_entry;
+ thresholds[BM_POOL_DEP_THRESH_HW_EXIT] = dep_hw_exit;
+ error = BM_POOL_ConfigDepletion(pool, f_Depletion, thresholds);
+ if (error != E_OK)
+ goto err;
+ }
+
+ error = BM_POOL_Init(pool);
+ if (error != E_OK)
+ goto err;
+
+ *bpid = BM_POOL_GetId(pool);
+ sc->sc_bpool_cpu[*bpid] = PCPU_GET(cpuid);
+
+ sched_unpin();
+
+ return (pool);
+
+err:
+ if (pool != NULL)
+ BM_POOL_Free(pool);
+
+ sched_unpin();
+
+ return (NULL);
+}
+
+int
+bman_pool_destroy(t_Handle pool)
+{
+ struct bman_softc *sc;
+
+ sc = bman_sc;
+ thread_lock(curthread);
+ sched_bind(curthread, sc->sc_bpool_cpu[BM_POOL_GetId(pool)]);
+ thread_unlock(curthread);
+
+ BM_POOL_Free(pool);
+
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+
+ return (0);
+}
+
+int
+bman_pool_fill(t_Handle pool, uint16_t nbufs)
+{
+ struct bman_softc *sc;
+ t_Handle portal;
+ int error;
+
+ sc = bman_sc;
+ sched_pin();
+
+ portal = bman_portal_setup(sc);
+ if (portal == NULL) {
+ sched_unpin();
+ return (EIO);
+ }
+
+ error = BM_POOL_FillBufs(pool, portal, nbufs);
+
+ sched_unpin();
+
+ return ((error == E_OK) ? 0 : EIO);
+}
+
+void *
+bman_get_buffer(t_Handle pool)
+{
+ struct bman_softc *sc;
+ t_Handle portal;
+ void *buffer;
+
+ sc = bman_sc;
+ sched_pin();
+
+ portal = bman_portal_setup(sc);
+ if (portal == NULL) {
+ sched_unpin();
+ return (NULL);
+ }
+
+ buffer = BM_POOL_GetBuf(pool, portal);
+
+ sched_unpin();
+
+ return (buffer);
+}
+
+int
+bman_put_buffer(t_Handle pool, void *buffer)
+{
+ struct bman_softc *sc;
+ t_Handle portal;
+ int error;
+
+ sc = bman_sc;
+ sched_pin();
+
+ portal = bman_portal_setup(sc);
+ if (portal == NULL) {
+ sched_unpin();
+ return (EIO);
+ }
+
+ error = BM_POOL_PutBuf(pool, portal, buffer);
+
+ sched_unpin();
+
+ return ((error == E_OK) ? 0 : EIO);
+}
+
+uint32_t
+bman_count(t_Handle pool)
+{
+
+ return (BM_POOL_GetCounter(pool, e_BM_POOL_COUNTERS_CONTENT));
+}
diff --git a/sys/dev/dpaa/bman.h b/sys/dev/dpaa/bman.h
new file mode 100644
index 000000000000..449b8172281c
--- /dev/null
+++ b/sys/dev/dpaa/bman.h
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BMAN_H
+#define _BMAN_H
+
+#include <machine/vmparam.h>
+
+#include <contrib/ncsw/inc/Peripherals/bm_ext.h>
+
+/*
+ * BMAN Configuration
+ */
+
+/* Maximum number of buffers in all BMAN pools */
+#define BMAN_MAX_BUFFERS 4096
+
+/*
+ * Portal definitions
+ */
+#define BMAN_CE_PA(base) (base)
+#define BMAN_CI_PA(base) ((base) + 0x100000)
+
+#define BMAN_PORTAL_CE_PA(base, n) \
+ (BMAN_CE_PA(base) + ((n) * BMAN_PORTAL_CE_SIZE))
+#define BMAN_PORTAL_CI_PA(base, n) \
+ (BMAN_CI_PA(base) + ((n) * BMAN_PORTAL_CI_SIZE))
+
+#define BMAN_CCSR_SIZE 0x1000
+
+struct bman_softc {
+ device_t sc_dev; /* device handle */
+ int sc_rrid; /* register rid */
+ struct resource *sc_rres; /* register resource */
+ int sc_irid; /* interrupt rid */
+ struct resource *sc_ires; /* interrupt resource */
+
+ bool sc_regs_mapped[MAXCPU]; /* register mapping status */
+
+ t_Handle sc_bh; /* BMAN handle */
+ t_Handle sc_bph[MAXCPU]; /* BMAN portal handles */
+ vm_paddr_t sc_bp_pa; /* BMAN portals PA */
+ unsigned int sc_bpool_cpu[BM_MAX_NUM_OF_POOLS];
+};
+
+/*
+ * External API
+ */
+
+/*
+ * @brief Function to create BMAN pool.
+ *
+ * @param bpid The pointer to variable where Buffer Pool ID will be
+ * stored.
+ *
+ * @param bufferSize The size of buffers in newly created pool.
+ *
+ * @param maxBuffers The maximum number of buffers in software stockpile.
+ * Set to 0 if software stockpile should not be created.
+ *
+ * @param minBuffers The minimum number of buffers in software stockpile.
+ * Set to 0 if software stockpile should not be created.
+ *
+ * @param allocBuffers The number of buffers to preallocate during pool
+ * creation.
+ *
+ * @param f_GetBuf The buffer allocating function. Called only by
+ * bman_pool_create() and bman_pool_fill().
+ *
+ * @param f_PutBuf The buffer freeing function. Called only by
+ * bman_pool_destroy().
+ *
+ * @param dep_sw_entry The software portal depletion entry threshold.
+ * Set to 0 if depletion should not be signaled on
+ * software portal.
+ *
+ * @param dep_sw_exit The software portal depletion exit threshold.
+ * Set to 0 if depletion should not be signaled on
+ * software portal.
+ *
+ * @param dep_hw_entry The hardware portal depletion entry threshold.
+ * Set to 0 if depletion should not be signaled on
+ * hardware portal.
+ *
+ * @param dep_hw_exit The hardware portal depletion exit threshold.
+ * Set to 0 if depletion should not be signaled on
+ * hardware portal.
+ *
+ * @param f_Depletion The software portal depletion notification function.
+ * Set to NULL if depletion notification is not used.
+ *
+ * @param h_BufferPool The user provided buffer pool context passed to
+ * f_GetBuf, f_PutBuf and f_Depletion functions.
+ *
+ * @param f_PhysToVirt The PA to VA translation function. Set to NULL if
+ * default one should be used.
+ *
+ * @param f_VirtToPhys The VA to PA translation function. Set to NULL if
+ * default one should be used.
+ *
+ * @returns Handle to newly created BMAN pool or NULL on error.
+ *
+ * @cautions If pool uses software stockpile, all accesses to given
+ * pool must be protected by lock. Even if only hardware
+ * portal depletion notification is used, the caller must
+ * provide valid @p f_Depletion function.
+ */
+t_Handle bman_pool_create(uint8_t *bpid, uint16_t bufferSize,
+ uint16_t maxBuffers, uint16_t minBuffers, uint16_t allocBuffers,
+ t_GetBufFunction *f_GetBuf, t_PutBufFunction *f_PutBuf,
+ uint32_t dep_sw_entry, uint32_t dep_sw_exit, uint32_t dep_hw_entry,
+ uint32_t dep_hw_exit, t_BmDepletionCallback *f_Depletion,
+ t_Handle h_BufferPool, t_PhysToVirt *f_PhysToVirt,
+ t_VirtToPhys *f_VirtToPhys);
+
+/*
+ * @brief Fill pool with buffers.
+ *
+ * The bman_pool_fill() function fills the BMAN pool with buffers. The buffers
+ * are allocated through f_GetBuf function (see bman_pool_create() description).
+ *
+ * @param pool The BMAN pool handle.
+ * @param nbufs The number of buffers to allocate. To maximize
+ * performance this value should be multiple of 8.
+ *
+ * @returns Zero on success or error code on failure.
+ */
+int bman_pool_fill(t_Handle pool, uint16_t nbufs);
+
+/*
+ * @brief Destroy pool.
+ *
+ * The bman_pool_destroy() function destroys the BMAN pool. Buffers for pool
+ * are free through f_PutBuf function (see bman_pool_create() description).
+ *
+ * @param pool The BMAN pool handle.
+ *
+ * @returns Zero on success or error code on failure.
+ */
+int bman_pool_destroy(t_Handle pool);
+
+/*
+ * @brief Get a buffer from BMAN pool.
+ *
+ * @param pool The BMAN pool handle.
+ *
+ * @returns Pointer to the buffer or NULL if pool is empty.
+ */
+void *bman_get_buffer(t_Handle pool);
+
+/*
+ * @brief Put a buffer to BMAN pool.
+ *
+ * @param pool The BMAN pool handle.
+ * @param buffer The pointer to buffer.
+ *
+ * @returns Zero on success or error code on failure.
+ */
+int bman_put_buffer(t_Handle pool, void *buffer);
+
+/*
+ * @brief Count free buffers in given pool.
+ *
+ * @param pool The BMAN pool handle.
+ *
+ * @returns Number of free buffers in pool.
+ */
+uint32_t bman_count(t_Handle pool);
+
+/*
+ * Bus i/f
+ */
+int bman_attach(device_t dev);
+int bman_detach(device_t dev);
+int bman_suspend(device_t dev);
+int bman_resume(device_t dev);
+int bman_shutdown(device_t dev);
+
+#endif /* BMAN_H */
diff --git a/sys/dev/dpaa/bman_fdt.c b/sys/dev/dpaa/bman_fdt.c
new file mode 100644
index 000000000000..63f58adb4918
--- /dev/null
+++ b/sys/dev/dpaa/bman_fdt.c
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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 "opt_platform.h"
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_subr.h>
+
+#include "bman.h"
+#include "portals.h"
+
+#define FBMAN_DEVSTR "Freescale Buffer Manager"
+
+static int bman_fdt_probe(device_t);
+
+static device_method_t bman_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bman_fdt_probe),
+ DEVMETHOD(device_attach, bman_attach),
+ DEVMETHOD(device_detach, bman_detach),
+
+ DEVMETHOD(device_suspend, bman_suspend),
+ DEVMETHOD(device_resume, bman_resume),
+ DEVMETHOD(device_shutdown, bman_shutdown),
+
+ { 0, 0 }
+};
+
+static driver_t bman_driver = {
+ "bman",
+ bman_methods,
+ sizeof(struct bman_softc),
+};
+
+static devclass_t bman_devclass;
+DRIVER_MODULE(bman, simplebus, bman_driver, bman_devclass, 0, 0);
+
+static int
+bman_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "fsl,bman"))
+ return (ENXIO);
+
+ device_set_desc(dev, FBMAN_DEVSTR);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+/*
+ * BMAN Portals
+ */
+#define BMAN_PORT_DEVSTR "Freescale Buffer Manager - Portals"
+
+static device_probe_t bman_portals_fdt_probe;
+static device_attach_t bman_portals_fdt_attach;
+
+static device_method_t bm_portals_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bman_portals_fdt_probe),
+ DEVMETHOD(device_attach, bman_portals_fdt_attach),
+ DEVMETHOD(device_detach, bman_portals_detach),
+
+ { 0, 0 }
+};
+
+static driver_t bm_portals_driver = {
+ "bman-portals",
+ bm_portals_methods,
+ sizeof(struct dpaa_portals_softc),
+};
+
+static devclass_t bm_portals_devclass;
+DRIVER_MODULE(bman_portals, ofwbus, bm_portals_driver, bm_portals_devclass, 0, 0);
+
+static void
+get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep)
+{
+
+ *addrp = 2;
+ *sizep = 1;
+ OF_getencprop(node, "#address-cells", addrp, sizeof(*addrp));
+ OF_getencprop(node, "#size-cells", sizep, sizeof(*sizep));
+}
+
+static int
+bman_portals_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "bman-portals"))
+ return (ENXIO);
+
+ device_set_desc(dev, BMAN_PORT_DEVSTR);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+bman_portals_fdt_attach(device_t dev)
+{
+ struct dpaa_portals_softc *sc;
+ struct resource_list_entry *rle;
+ phandle_t node, child, cpu_node;
+ vm_paddr_t portal_pa;
+ vm_size_t portal_size;
+ uint32_t addr, size;
+ ihandle_t cpu;
+ int cpu_num, cpus, intr_rid;
+ struct dpaa_portals_devinfo di;
+ struct ofw_bus_devinfo ofw_di;
+
+ cpus = 0;
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ node = ofw_bus_get_node(dev);
+ get_addr_props(node, &addr, &size);
+
+ /* Find portals tied to CPUs */
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ if (!fdt_is_compatible(child, "fsl,bman-portal")) {
+ continue;
+ }
+ /* Checkout related cpu */
+ if (OF_getprop(child, "cpu-handle", (void *)&cpu,
+ sizeof(cpu)) <= 0) {
+ continue;
+ }
+ /* Acquire cpu number */
+ cpu_node = OF_instance_to_package(cpu);
+ if (OF_getencprop(cpu_node, "reg", &cpu_num, sizeof(cpu_num)) <= 0) {
+ device_printf(dev, "Could not retrieve CPU number.\n");
+ return (ENXIO);
+ }
+
+ cpus++;
+
+ if (cpus > MAXCPU)
+ break;
+
+ if (ofw_bus_gen_setup_devinfo(&ofw_di, child) != 0) {
+ device_printf(dev, "could not set up devinfo\n");
+ continue;
+ }
+
+ resource_list_init(&di.di_res);
+ if (ofw_bus_reg_to_rl(dev, child, addr, size, &di.di_res)) {
+ device_printf(dev, "%s: could not process 'reg' "
+ "property\n", ofw_di.obd_name);
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+ continue;
+ }
+ if (ofw_bus_intr_to_rl(dev, child, &di.di_res, &intr_rid)) {
+ device_printf(dev, "%s: could not process "
+ "'interrupts' property\n", ofw_di.obd_name);
+ resource_list_free(&di.di_res);
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+ continue;
+ }
+ di.di_intr_rid = intr_rid;
+
+ ofw_reg_to_paddr(child, 0, &portal_pa, &portal_size, NULL);
+ rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 0);
+
+ if (sc->sc_dp_pa == 0)
+ sc->sc_dp_pa = portal_pa - rle->start;
+
+ portal_size = rle->end + 1;
+ rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 1);
+ device_printf(dev, "portal size 1: %jx\n", (uintmax_t)portal_size);
+ device_printf(dev, "portal size 2: %jx\n", (uintmax_t)rle->end + 1);
+ portal_size = ulmax(rle->end + 1, portal_size);
+ sc->sc_dp_size = ulmax(sc->sc_dp_size, portal_size);
+ device_printf(dev, "winner: %jx\n", (uintmax_t)sc->sc_dp_size);
+
+ if (dpaa_portal_alloc_res(dev, &di, cpu_num))
+ goto err;
+ }
+ device_printf(dev, "portal start: %jx, size: %jx\n", (uintmax_t)sc->sc_dp_pa, (uintmax_t)sc->sc_dp_size);
+
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+
+ return (bman_portals_attach(dev));
+err:
+ resource_list_free(&di.di_res);
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+ bman_portals_detach(dev);
+ return (ENXIO);
+}
diff --git a/sys/dev/dpaa/bman_portals.c b/sys/dev/dpaa/bman_portals.c
new file mode 100644
index 000000000000..ba9997f5cb74
--- /dev/null
+++ b/sys/dev/dpaa/bman_portals.c
@@ -0,0 +1,180 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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 "opt_platform.h"
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/sched.h>
+
+#include <machine/bus.h>
+#include <machine/tlb.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <powerpc/mpc85xx/mpc85xx.h>
+
+#include "bman.h"
+#include "portals.h"
+
+t_Handle bman_portal_setup(struct bman_softc *);
+
+struct dpaa_portals_softc *bp_sc;
+
+int
+bman_portals_attach(device_t dev)
+{
+ struct dpaa_portals_softc *sc;
+
+ sc = bp_sc = device_get_softc(dev);
+
+ /* Map bman portal to physical address space */
+ if (law_enable(OCP85XX_TGTIF_BMAN, sc->sc_dp_pa, sc->sc_dp_size)) {
+ bman_portals_detach(dev);
+ return (ENXIO);
+ }
+ /* Set portal properties for XX_VirtToPhys() */
+ XX_PortalSetInfo(dev);
+
+ return (bus_generic_attach(dev));
+}
+
+int
+bman_portals_detach(device_t dev)
+{
+ struct dpaa_portals_softc *sc;
+ int i;
+
+ bp_sc = NULL;
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < ARRAY_SIZE(sc->sc_dp); i++) {
+ if (sc->sc_dp[i].dp_ph != NULL) {
+ thread_lock(curthread);
+ sched_bind(curthread, i);
+ thread_unlock(curthread);
+
+ BM_PORTAL_Free(sc->sc_dp[i].dp_ph);
+
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+ }
+
+ if (sc->sc_dp[i].dp_ires != NULL) {
+ XX_DeallocIntr((int)sc->sc_dp[i].dp_ires);
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires);
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(sc->sc_rres); i++) {
+ if (sc->sc_rres[i] != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->sc_rrid[i],
+ sc->sc_rres[i]);
+ }
+
+ return (0);
+}
+
+t_Handle
+bman_portal_setup(struct bman_softc *bsc)
+{
+ struct dpaa_portals_softc *sc;
+ t_BmPortalParam bpp;
+ t_Handle portal;
+ unsigned int cpu, p;
+
+ /* Return NULL if we're not ready or while detach */
+ if (bp_sc == NULL)
+ return (NULL);
+
+ sc = bp_sc;
+
+ sched_pin();
+ portal = NULL;
+ cpu = PCPU_GET(cpuid);
+
+ /* Check if portal is ready */
+ while (atomic_cmpset_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph,
+ 0, -1) == 0) {
+ p = atomic_load_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph);
+
+ /* Return if portal is already initialized */
+ if (p != 0 && p != -1) {
+ sched_unpin();
+ return ((t_Handle)p);
+ }
+
+ /* Not inititialized and "owned" by another thread */
+ thread_lock(curthread);
+ mi_switch(SW_VOL, NULL);
+ thread_unlock(curthread);
+ }
+
+ /* Map portal registers */
+ dpaa_portal_map_registers(sc);
+
+ /* Configure and initialize portal */
+ bpp.ceBaseAddress = rman_get_bushandle(sc->sc_rres[0]);
+ bpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]);
+ bpp.h_Bm = bsc->sc_bh;
+ bpp.swPortalId = cpu;
+ bpp.irq = (int)sc->sc_dp[cpu].dp_ires;
+
+ portal = BM_PORTAL_Config(&bpp);
+ if (portal == NULL)
+ goto err;
+
+ if (BM_PORTAL_Init(portal) != E_OK)
+ goto err;
+
+ atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph,
+ (uint32_t)portal);
+
+ sched_unpin();
+
+ return (portal);
+
+err:
+ if (portal != NULL)
+ BM_PORTAL_Free(portal);
+
+ atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, 0);
+ sched_unpin();
+
+ return (NULL);
+}
diff --git a/sys/dev/dpaa/dpaa.c b/sys/dev/dpaa/dpaa.c
new file mode 100644
index 000000000000..95c04b4d5960
--- /dev/null
+++ b/sys/dev/dpaa/dpaa.c
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ktr.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include "opt_platform.h"
+
+static MALLOC_DEFINE(M_DPAA, "dpaa", "dpaa devices information");
+
+static int dpaa_probe(device_t dev);
+static int dpaa_attach(device_t dev);
+
+static const struct ofw_bus_devinfo *dpaa_get_devinfo(device_t bus,
+ device_t child);
+
+struct dpaa_softc {
+
+};
+
+struct dpaa_devinfo {
+ struct ofw_bus_devinfo di_ofw;
+};
+
+static device_method_t dpaa_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, dpaa_probe),
+ DEVMETHOD(device_attach, dpaa_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* OFW bus interface */
+ DEVMETHOD(ofw_bus_get_devinfo, dpaa_get_devinfo),
+ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
+ DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
+ DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
+ DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
+ DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
+
+ {0, 0}
+};
+
+static driver_t dpaa_driver = {
+ "dpaa",
+ dpaa_methods,
+ sizeof(struct dpaa_softc),
+};
+
+static devclass_t dpaa_devclass;
+DRIVER_MODULE_ORDERED(dpaa, ofwbus, dpaa_driver, dpaa_devclass, 0, 0,
+ SI_ORDER_ANY);
+
+static int
+dpaa_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "fsl,dpaa"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Freescale Data Path Acceleration Architecture");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+dpaa_attach(device_t dev)
+{
+ device_t dev_child;
+ phandle_t dt_node, dt_child, enet_node;
+ struct dpaa_devinfo *di;
+ pcell_t cell_index;
+
+ cell_index = 0;
+ /*
+ * Walk dpaa and add direct subordinates as our children.
+ */
+ dt_node = ofw_bus_get_node(dev);
+ dt_child = OF_child(dt_node);
+
+ for (; dt_child != 0; dt_child = OF_peer(dt_child)) {
+
+ /* Check and process 'status' property. */
+ if (!(fdt_is_enabled(dt_child)))
+ continue;
+
+ di = (struct dpaa_devinfo *)malloc(sizeof(*di), M_DPAA,
+ M_WAITOK | M_ZERO);
+
+ if (ofw_bus_gen_setup_devinfo(&di->di_ofw, dt_child) != 0) {
+ free(di, M_DPAA);
+ device_printf(dev, "could not set up devinfo\n");
+ continue;
+ }
+
+ /*
+ * dTSEC number from SoC is equal to number get from
+ * dts file.
+ */
+ if (OF_getprop(dt_child, "fsl,fman-mac",
+ (void *)&enet_node, sizeof(enet_node)) == -1) {
+ device_printf(dev, "Could not get fsl,fman-mac "
+ "from dts\n");
+ continue;
+ }
+
+ if ((enet_node = OF_instance_to_package(enet_node)) == -1) {
+ device_printf(dev, "Could not get enet node\n");
+ continue;
+ }
+
+ if (OF_getprop(enet_node, "cell-index",
+ (void *)&cell_index, sizeof(cell_index)) == -1) {
+ device_printf(dev, "Could not get cell-index from enet "
+ "node\n");
+ continue;
+ }
+
+ /* Add newbus device for this FDT node */
+ dev_child = device_add_child(dev, "dtsec", (int)cell_index);
+ if (dev_child == NULL) {
+ device_printf(dev, "could not add child: %s\n",
+ di->di_ofw.obd_name);
+ ofw_bus_gen_destroy_devinfo(&di->di_ofw);
+ free(di, M_DPAA);
+ continue;
+ }
+
+#ifdef DEBUG
+ device_printf(dev, "added child: %s\n\n", di->di_ofw.obd_name);
+#endif
+
+ device_set_ivars(dev_child, di);
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static const struct ofw_bus_devinfo *
+dpaa_get_devinfo(device_t bus, device_t child)
+{
+ struct dpaa_devinfo *di;
+
+ di = device_get_ivars(child);
+ return (&di->di_ofw);
+}
diff --git a/sys/dev/dpaa/fman.c b/sys/dev/dpaa/fman.c
new file mode 100644
index 000000000000..3e44db89580c
--- /dev/null
+++ b/sys/dev/dpaa/fman.c
@@ -0,0 +1,357 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "opt_platform.h"
+
+#include <contrib/ncsw/inc/Peripherals/fm_ext.h>
+#include <contrib/ncsw/inc/Peripherals/fm_muram_ext.h>
+#include <contrib/ncsw/inc/ncsw_ext.h>
+#include <contrib/ncsw/integrations/fman_ucode.h>
+
+#include "fman.h"
+
+
+/**
+ * @group FMan private defines.
+ * @{
+ */
+enum fman_irq_enum {
+ FMAN_IRQ_NUM = 0,
+ FMAN_ERR_IRQ_NUM = 1
+};
+
+enum fman_mu_ram_map {
+ FMAN_MURAM_OFF = 0x0,
+ FMAN_MURAM_SIZE = 0x28000
+};
+
+struct fman_config {
+ device_t fman_device;
+ uintptr_t mem_base_addr;
+ int irq_num;
+ int err_irq_num;
+ uint8_t fm_id;
+ t_FmExceptionsCallback *exception_callback;
+ t_FmBusErrorCallback *bus_error_callback;
+};
+
+/**
+ * @group FMan private methods/members.
+ * @{
+ */
+/**
+ * Frame Manager firmware.
+ * We use the same firmware for both P3041 and P2041 devices.
+ */
+const uint32_t fman_firmware[] = FMAN_UC_IMG;
+const uint32_t fman_firmware_size = sizeof(fman_firmware);
+static struct fman_softc *fm_sc = NULL;
+
+static t_Handle
+fman_init(struct fman_softc *sc, struct fman_config *cfg)
+{
+ t_FmParams fm_params;
+ t_Handle muram_handle, fm_handle;
+ t_Error error;
+ t_FmRevisionInfo revision_info;
+ uint16_t clock;
+ uint32_t tmp, mod;
+
+ /* MURAM configuration */
+ muram_handle = FM_MURAM_ConfigAndInit(cfg->mem_base_addr +
+ FMAN_MURAM_OFF, FMAN_MURAM_SIZE);
+ if (muram_handle == NULL) {
+ device_printf(cfg->fman_device, "couldn't init FM MURAM module"
+ "\n");
+ return (NULL);
+ }
+ sc->muram_handle = muram_handle;
+
+ /* Fill in FM configuration */
+ fm_params.fmId = cfg->fm_id;
+ /* XXX we support only one partition thus each fman has master id */
+ fm_params.guestId = NCSW_MASTER_ID;
+
+ fm_params.baseAddr = cfg->mem_base_addr;
+ fm_params.h_FmMuram = muram_handle;
+
+ /* Get FMan clock in Hz */
+ if ((tmp = fman_get_clock(sc)) == 0)
+ return (NULL);
+
+ /* Convert FMan clock to MHz */
+ clock = (uint16_t)(tmp / 1000000);
+ mod = tmp % 1000000;
+
+ if (mod >= 500000)
+ ++clock;
+
+ fm_params.fmClkFreq = clock;
+ fm_params.f_Exception = cfg->exception_callback;
+ fm_params.f_BusError = cfg->bus_error_callback;
+ fm_params.h_App = cfg->fman_device;
+ fm_params.irq = cfg->irq_num;
+ fm_params.errIrq = cfg->err_irq_num;
+
+ fm_params.firmware.size = fman_firmware_size;
+ fm_params.firmware.p_Code = (uint32_t*)fman_firmware;
+
+ fm_handle = FM_Config(&fm_params);
+ if (fm_handle == NULL) {
+ device_printf(cfg->fman_device, "couldn't configure FM "
+ "module\n");
+ goto err;
+ }
+
+ FM_ConfigResetOnInit(fm_handle, TRUE);
+
+ error = FM_Init(fm_handle);
+ if (error != E_OK) {
+ device_printf(cfg->fman_device, "couldn't init FM module\n");
+ goto err2;
+ }
+
+ error = FM_GetRevision(fm_handle, &revision_info);
+ if (error != E_OK) {
+ device_printf(cfg->fman_device, "couldn't get FM revision\n");
+ goto err2;
+ }
+
+ device_printf(cfg->fman_device, "Hardware version: %d.%d.\n",
+ revision_info.majorRev, revision_info.minorRev);
+
+ return (fm_handle);
+
+err2:
+ FM_Free(fm_handle);
+err:
+ FM_MURAM_Free(muram_handle);
+ return (NULL);
+}
+
+static void
+fman_exception_callback(t_Handle app_handle, e_FmExceptions exception)
+{
+ struct fman_softc *sc;
+
+ sc = app_handle;
+ device_printf(sc->dev, "FMan exception occurred.\n");
+}
+
+static void
+fman_error_callback(t_Handle app_handle, e_FmPortType port_type,
+ uint8_t port_id, uint64_t addr, uint8_t tnum, uint16_t liodn)
+{
+ struct fman_softc *sc;
+
+ sc = app_handle;
+ device_printf(sc->dev, "FMan error occurred.\n");
+}
+/** @} */
+
+
+/**
+ * @group FMan driver interface.
+ * @{
+ */
+
+int
+fman_get_handle(t_Handle *fmh)
+{
+
+ if (fm_sc == NULL)
+ return (ENOMEM);
+
+ *fmh = fm_sc->fm_handle;
+
+ return (0);
+}
+
+int
+fman_get_muram_handle(t_Handle *muramh)
+{
+
+ if (fm_sc == NULL)
+ return (ENOMEM);
+
+ *muramh = fm_sc->muram_handle;
+
+ return (0);
+}
+
+int
+fman_get_bushandle(vm_offset_t *fm_base)
+{
+
+ if (fm_sc == NULL)
+ return (ENOMEM);
+
+ *fm_base = rman_get_bushandle(fm_sc->mem_res);
+
+ return (0);
+}
+
+int
+fman_attach(device_t dev)
+{
+ struct fman_softc *sc;
+ struct fman_config cfg;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ fm_sc = sc;
+
+ /* Check if MallocSmart allocator is ready */
+ if (XX_MallocSmartInit() != E_OK) {
+ device_printf(dev, "could not initialize smart allocator.\n");
+ return (ENXIO);
+ }
+
+ XX_TrackInit();
+
+ sc->mem_rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
+ RF_ACTIVE);
+ if (!sc->mem_res) {
+ device_printf(dev, "could not allocate memory.\n");
+ return (ENXIO);
+ }
+
+ sc->irq_rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
+ RF_ACTIVE);
+ if (!sc->irq_res) {
+ device_printf(dev, "could not allocate interrupt.\n");
+ goto err;
+ }
+
+ /*
+ * XXX: Fix FMan interrupt. This is workaround for the issue with
+ * interrupts directed to multiple CPUs by the interrupts subsystem.
+ * Workaround is to bind the interrupt to only one CPU0.
+ */
+ XX_FmanFixIntr(rman_get_start(sc->irq_res));
+
+ sc->err_irq_rid = 1;
+ sc->err_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ &sc->err_irq_rid, RF_ACTIVE | RF_SHAREABLE);
+ if (!sc->err_irq_res) {
+ device_printf(dev, "could not allocate error interrupt.\n");
+ goto err;
+ }
+
+ /* Set FMan configuration */
+ cfg.fman_device = dev;
+ cfg.fm_id = device_get_unit(dev);
+ cfg.mem_base_addr = rman_get_bushandle(sc->mem_res);
+ cfg.irq_num = (int)sc->irq_res;
+ cfg.err_irq_num = (int)sc->err_irq_res;
+ cfg.exception_callback = fman_exception_callback;
+ cfg.bus_error_callback = fman_error_callback;
+
+ sc->fm_handle = fman_init(sc, &cfg);
+ if (sc->fm_handle == NULL) {
+ device_printf(dev, "could not be configured\n");
+ return (ENXIO);
+ }
+
+ return (bus_generic_attach(dev));
+
+err:
+ fman_detach(dev);
+ return (ENXIO);
+}
+
+int
+fman_detach(device_t dev)
+{
+ struct fman_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->muram_handle) {
+ FM_MURAM_Free(sc->muram_handle);
+ }
+
+ if (sc->fm_handle) {
+ FM_Free(sc->fm_handle);
+ }
+
+ if (sc->mem_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
+ sc->mem_res);
+ }
+
+ if (sc->irq_res) {
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
+ sc->irq_res);
+ }
+
+ if (sc->irq_res) {
+ bus_release_resource(dev, SYS_RES_IRQ, sc->err_irq_rid,
+ sc->err_irq_res);
+ }
+
+ return (0);
+}
+
+int
+fman_suspend(device_t dev)
+{
+
+ return (0);
+}
+
+int
+fman_resume(device_t dev)
+{
+
+ return (0);
+}
+
+int
+fman_shutdown(device_t dev)
+{
+
+ return (0);
+}
+
+/** @} */
diff --git a/sys/dev/dpaa/fman.h b/sys/dev/dpaa/fman.h
new file mode 100644
index 000000000000..5a421e056423
--- /dev/null
+++ b/sys/dev/dpaa/fman.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef FMAN_H_
+#define FMAN_H_
+
+/**
+ * FMan driver instance data.
+ */
+struct fman_softc {
+ device_t dev;
+ struct resource *mem_res;
+ struct resource *irq_res;
+ struct resource *err_irq_res;
+ int mem_rid;
+ int irq_rid;
+ int err_irq_rid;
+
+ t_Handle fm_handle;
+ t_Handle muram_handle;
+};
+
+
+/**
+ * @group QMan bus interface.
+ * @{
+ */
+int fman_attach(device_t dev);
+int fman_detach(device_t dev);
+int fman_suspend(device_t dev);
+int fman_resume(device_t dev);
+int fman_shutdown(device_t dev);
+int fman_read_ivar(device_t dev, device_t child, int index,
+ uintptr_t *result);
+/** @} */
+
+uint32_t fman_get_clock(struct fman_softc *sc);
+int fman_get_handle(t_Handle *fmh);
+int fman_get_muram_handle(t_Handle *muramh);
+int fman_get_bushandle(vm_offset_t *fm_base);
+
+#endif /* FMAN_H_ */
diff --git a/sys/dev/dpaa/fman_fdt.c b/sys/dev/dpaa/fman_fdt.c
new file mode 100644
index 000000000000..89c9eca1cb5b
--- /dev/null
+++ b/sys/dev/dpaa/fman_fdt.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <contrib/ncsw/inc/ncsw_ext.h>
+#include <contrib/ncsw/inc/enet_ext.h>
+
+#include "fman.h"
+
+#define FFMAN_DEVSTR "Freescale Frame Manager"
+
+static int fman_fdt_probe(device_t dev);
+
+static device_method_t fman_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, fman_fdt_probe),
+ DEVMETHOD(device_attach, fman_attach),
+ DEVMETHOD(device_detach, fman_detach),
+
+ DEVMETHOD(device_shutdown, fman_shutdown),
+ DEVMETHOD(device_suspend, fman_suspend),
+ DEVMETHOD(device_resume, fman_resume),
+
+ { 0, 0 }
+};
+
+static driver_t fman_driver = {
+ "fman",
+ fman_methods,
+ sizeof(struct fman_softc),
+};
+
+static devclass_t fman_devclass;
+EARLY_DRIVER_MODULE(fman, simplebus, fman_driver, fman_devclass, 0, 0,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+
+
+static int
+fman_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "fsl,fman"))
+ return (ENXIO);
+
+ device_set_desc(dev, FFMAN_DEVSTR);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+uint32_t
+fman_get_clock(struct fman_softc *sc)
+{
+ device_t dev;
+ phandle_t node;
+ pcell_t fman_clock;
+
+ dev = sc->dev;
+ node = ofw_bus_get_node(dev);
+
+ if ((OF_getprop(node, "clock-frequency", &fman_clock,
+ sizeof(fman_clock)) <= 0) || (fman_clock == 0)) {
+ device_printf(dev, "could not acquire correct frequency "
+ "from DTS\n");
+
+ return (0);
+ }
+
+ return ((uint32_t)fman_clock);
+}
+
diff --git a/sys/dev/dpaa/if_dtsec.c b/sys/dev/dpaa/if_dtsec.c
new file mode 100644
index 000000000000..249d605bb42e
--- /dev/null
+++ b/sys/dev/dpaa/if_dtsec.c
@@ -0,0 +1,879 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include "miibus_if.h"
+
+#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
+#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
+#include <contrib/ncsw/inc/xx_ext.h>
+
+#include "fman.h"
+#include "if_dtsec.h"
+#include "if_dtsec_im.h"
+#include "if_dtsec_rm.h"
+
+
+/**
+ * @group dTSEC private defines.
+ * @{
+ */
+/**
+ * dTSEC FMan MAC exceptions info struct.
+ */
+struct dtsec_fm_mac_ex_str {
+ const int num;
+ const char *str;
+};
+
+/* XXX: Handle to FM_MAC instance of dTSEC0 */
+/* From QorIQ Data Path Acceleration Architecture Reference Manual, Rev 2, page
+ * 3-37, "The MII management hardware is shared by all dTSECs... only through
+ * the MIIM registers of dTSEC1 can external PHY's be accessed and configured."
+ */
+static t_Handle dtsec_mdio_mac_handle;
+/** @} */
+
+
+/**
+ * @group FMan MAC routines.
+ * @{
+ */
+#define DTSEC_MAC_EXCEPTIONS_END (-1)
+
+/**
+ * FMan MAC exceptions.
+ */
+static const struct dtsec_fm_mac_ex_str dtsec_fm_mac_exceptions[] = {
+ { e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO, "MDIO scan event" },
+ { e_FM_MAC_EX_10G_MDIO_CMD_CMPL, "MDIO command completion" },
+ { e_FM_MAC_EX_10G_REM_FAULT, "Remote fault" },
+ { e_FM_MAC_EX_10G_LOC_FAULT, "Local fault" },
+ { e_FM_MAC_EX_10G_1TX_ECC_ER, "Transmit frame ECC error" },
+ { e_FM_MAC_EX_10G_TX_FIFO_UNFL, "Transmit FIFO underflow" },
+ { e_FM_MAC_EX_10G_TX_FIFO_OVFL, "Receive FIFO overflow" },
+ { e_FM_MAC_EX_10G_TX_ER, "Transmit frame error" },
+ { e_FM_MAC_EX_10G_RX_FIFO_OVFL, "Receive FIFO overflow" },
+ { e_FM_MAC_EX_10G_RX_ECC_ER, "Receive frame ECC error" },
+ { e_FM_MAC_EX_10G_RX_JAB_FRM, "Receive jabber frame" },
+ { e_FM_MAC_EX_10G_RX_OVRSZ_FRM, "Receive oversized frame" },
+ { e_FM_MAC_EX_10G_RX_RUNT_FRM, "Receive runt frame" },
+ { e_FM_MAC_EX_10G_RX_FRAG_FRM, "Receive fragment frame" },
+ { e_FM_MAC_EX_10G_RX_LEN_ER, "Receive payload length error" },
+ { e_FM_MAC_EX_10G_RX_CRC_ER, "Receive CRC error" },
+ { e_FM_MAC_EX_10G_RX_ALIGN_ER, "Receive alignment error" },
+ { e_FM_MAC_EX_1G_BAB_RX, "Babbling receive error" },
+ { e_FM_MAC_EX_1G_RX_CTL, "Receive control (pause frame) interrupt" },
+ { e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, "Graceful transmit stop "
+ "complete" },
+ { e_FM_MAC_EX_1G_BAB_TX, "Babbling transmit error" },
+ { e_FM_MAC_EX_1G_TX_CTL, "Transmit control (pause frame) interrupt" },
+ { e_FM_MAC_EX_1G_TX_ERR, "Transmit error" },
+ { e_FM_MAC_EX_1G_LATE_COL, "Late collision" },
+ { e_FM_MAC_EX_1G_COL_RET_LMT, "Collision retry limit" },
+ { e_FM_MAC_EX_1G_TX_FIFO_UNDRN, "Transmit FIFO underrun" },
+ { e_FM_MAC_EX_1G_MAG_PCKT, "Magic Packet detected when dTSEC is in "
+ "Magic Packet detection mode" },
+ { e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET, "MII management read completion" },
+ { e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET, "MII management write completion" },
+ { e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, "Graceful receive stop "
+ "complete" },
+ { e_FM_MAC_EX_1G_TX_DATA_ERR, "Internal data error on transmit" },
+ { e_FM_MAC_EX_1G_RX_DATA_ERR, "Internal data error on receive" },
+ { e_FM_MAC_EX_1G_1588_TS_RX_ERR, "Time-Stamp Receive Error" },
+ { e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, "MIB counter overflow" },
+ { DTSEC_MAC_EXCEPTIONS_END, "" }
+};
+
+static const char *
+dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception)
+{
+ int i;
+
+ for (i = 0; dtsec_fm_mac_exceptions[i].num != exception &&
+ dtsec_fm_mac_exceptions[i].num != DTSEC_MAC_EXCEPTIONS_END; ++i)
+ ;
+
+ if (dtsec_fm_mac_exceptions[i].num == DTSEC_MAC_EXCEPTIONS_END)
+ return ("<Unknown Exception>");
+
+ return (dtsec_fm_mac_exceptions[i].str);
+}
+
+static void
+dtsec_fm_mac_mdio_event_callback(t_Handle h_App,
+ e_FmMacExceptions exception)
+{
+ struct dtsec_softc *sc;
+
+ sc = h_App;
+ device_printf(sc->sc_dev, "MDIO event %i: %s.\n", exception,
+ dtsec_fm_mac_ex_to_str(exception));
+}
+
+static void
+dtsec_fm_mac_exception_callback(t_Handle app, e_FmMacExceptions exception)
+{
+ struct dtsec_softc *sc;
+
+ sc = app;
+ device_printf(sc->sc_dev, "MAC exception %i: %s.\n", exception,
+ dtsec_fm_mac_ex_to_str(exception));
+}
+
+static void
+dtsec_fm_mac_free(struct dtsec_softc *sc)
+{
+ if (sc->sc_mach == NULL)
+ return;
+
+ FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
+ FM_MAC_Free(sc->sc_mach);
+ sc->sc_mach = NULL;
+}
+
+static int
+dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac)
+{
+ t_FmMacParams params;
+ t_Error error;
+
+ memset(&params, 0, sizeof(params));
+ memcpy(&params.addr, mac, sizeof(params.addr));
+
+ params.baseAddr = sc->sc_fm_base + sc->sc_mac_mem_offset;
+ params.enetMode = sc->sc_mac_enet_mode;
+ params.macId = sc->sc_eth_id;
+ params.mdioIrq = sc->sc_mac_mdio_irq;
+ params.f_Event = dtsec_fm_mac_mdio_event_callback;
+ params.f_Exception = dtsec_fm_mac_exception_callback;
+ params.h_App = sc;
+ params.h_Fm = sc->sc_fmh;
+
+ sc->sc_mach = FM_MAC_Config(&params);
+ if (sc->sc_hidden)
+ return (0);
+ if (sc->sc_mach == NULL) {
+ device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n"
+ );
+ return (ENXIO);
+ }
+
+ error = FM_MAC_ConfigResetOnInit(sc->sc_mach, TRUE);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't enable reset on init "
+ "feature.\n");
+ dtsec_fm_mac_free(sc);
+ return (ENXIO);
+ }
+
+ /* Do not inform about pause frames */
+ error = FM_MAC_ConfigException(sc->sc_mach, e_FM_MAC_EX_1G_RX_CTL,
+ FALSE);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't disable pause frames "
+ "exception.\n");
+ dtsec_fm_mac_free(sc);
+ return (ENXIO);
+ }
+
+ error = FM_MAC_Init(sc->sc_mach);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't initialize FM_MAC module."
+ "\n");
+ dtsec_fm_mac_free(sc);
+ return (ENXIO);
+ }
+
+ return (0);
+}
+/** @} */
+
+
+/**
+ * @group FMan PORT routines.
+ * @{
+ */
+static const char *
+dtsec_fm_port_ex_to_str(e_FmPortExceptions exception)
+{
+
+ switch (exception) {
+ case e_FM_PORT_EXCEPTION_IM_BUSY:
+ return ("IM: RX busy");
+ default:
+ return ("<Unknown Exception>");
+ }
+}
+
+void
+dtsec_fm_port_rx_exception_callback(t_Handle app,
+ e_FmPortExceptions exception)
+{
+ struct dtsec_softc *sc;
+
+ sc = app;
+ device_printf(sc->sc_dev, "RX exception: %i: %s.\n", exception,
+ dtsec_fm_port_ex_to_str(exception));
+}
+
+void
+dtsec_fm_port_tx_exception_callback(t_Handle app,
+ e_FmPortExceptions exception)
+{
+ struct dtsec_softc *sc;
+
+ sc = app;
+ device_printf(sc->sc_dev, "TX exception: %i: %s.\n", exception,
+ dtsec_fm_port_ex_to_str(exception));
+}
+
+e_FmPortType
+dtsec_fm_port_rx_type(enum eth_dev_type type)
+{
+ switch (type) {
+ case ETH_DTSEC:
+ return (e_FM_PORT_TYPE_RX);
+ case ETH_10GSEC:
+ return (e_FM_PORT_TYPE_RX_10G);
+ default:
+ return (e_FM_PORT_TYPE_DUMMY);
+ }
+}
+
+e_FmPortType
+dtsec_fm_port_tx_type(enum eth_dev_type type)
+{
+
+ switch (type) {
+ case ETH_DTSEC:
+ return (e_FM_PORT_TYPE_TX);
+ case ETH_10GSEC:
+ return (e_FM_PORT_TYPE_TX_10G);
+ default:
+ return (e_FM_PORT_TYPE_DUMMY);
+ }
+}
+
+static void
+dtsec_fm_port_free_both(struct dtsec_softc *sc)
+{
+ if (sc->sc_rxph) {
+ FM_PORT_Free(sc->sc_rxph);
+ sc->sc_rxph = NULL;
+ }
+
+ if (sc->sc_txph) {
+ FM_PORT_Free(sc->sc_txph);
+ sc->sc_txph = NULL;
+ }
+}
+/** @} */
+
+
+/**
+ * @group IFnet routines.
+ * @{
+ */
+static int
+dtsec_if_enable_locked(struct dtsec_softc *sc)
+{
+ int error;
+
+ DTSEC_LOCK_ASSERT(sc);
+
+ error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
+ if (error != E_OK)
+ return (EIO);
+
+ error = FM_PORT_Enable(sc->sc_rxph);
+ if (error != E_OK)
+ return (EIO);
+
+ error = FM_PORT_Enable(sc->sc_txph);
+ if (error != E_OK)
+ return (EIO);
+
+ sc->sc_ifnet->if_drv_flags |= IFF_DRV_RUNNING;
+
+ /* Refresh link state */
+ dtsec_miibus_statchg(sc->sc_dev);
+
+ return (0);
+}
+
+static int
+dtsec_if_disable_locked(struct dtsec_softc *sc)
+{
+ int error;
+
+ DTSEC_LOCK_ASSERT(sc);
+
+ error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
+ if (error != E_OK)
+ return (EIO);
+
+ error = FM_PORT_Disable(sc->sc_rxph);
+ if (error != E_OK)
+ return (EIO);
+
+ error = FM_PORT_Disable(sc->sc_txph);
+ if (error != E_OK)
+ return (EIO);
+
+ sc->sc_ifnet->if_drv_flags &= ~IFF_DRV_RUNNING;
+
+ return (0);
+}
+
+static int
+dtsec_if_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct dtsec_softc *sc;
+ struct ifreq *ifr;
+ int error;
+
+ sc = ifp->if_softc;
+ ifr = (struct ifreq *)data;
+ error = 0;
+
+ /* Basic functionality to achieve media status reports */
+ switch (command) {
+ case SIOCSIFFLAGS:
+ DTSEC_LOCK(sc);
+
+ if (sc->sc_ifnet->if_flags & IFF_UP)
+ error = dtsec_if_enable_locked(sc);
+ else
+ error = dtsec_if_disable_locked(sc);
+
+ DTSEC_UNLOCK(sc);
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media,
+ command);
+ break;
+
+ default:
+ error = ether_ioctl(ifp, command, data);
+ }
+
+ return (error);
+}
+
+static void
+dtsec_if_tick(void *arg)
+{
+ struct dtsec_softc *sc;
+
+ sc = arg;
+
+ /* TODO */
+ DTSEC_LOCK(sc);
+
+ mii_tick(sc->sc_mii);
+ callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
+
+ DTSEC_UNLOCK(sc);
+}
+
+static void
+dtsec_if_deinit_locked(struct dtsec_softc *sc)
+{
+
+ DTSEC_LOCK_ASSERT(sc);
+
+ DTSEC_UNLOCK(sc);
+ callout_drain(&sc->sc_tick_callout);
+ DTSEC_LOCK(sc);
+}
+
+static void
+dtsec_if_init_locked(struct dtsec_softc *sc)
+{
+ int error;
+
+ DTSEC_LOCK_ASSERT(sc);
+
+ /* Set MAC address */
+ error = FM_MAC_ModifyMacAddr(sc->sc_mach,
+ (t_EnetAddr *)IF_LLADDR(sc->sc_ifnet));
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't set MAC address.\n");
+ goto err;
+ }
+
+ /* Start MII polling */
+ if (sc->sc_mii)
+ callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
+
+ if (sc->sc_ifnet->if_flags & IFF_UP) {
+ error = dtsec_if_enable_locked(sc);
+ if (error != 0)
+ goto err;
+ } else {
+ error = dtsec_if_disable_locked(sc);
+ if (error != 0)
+ goto err;
+ }
+
+ return;
+
+err:
+ dtsec_if_deinit_locked(sc);
+ device_printf(sc->sc_dev, "initialization error.\n");
+ return;
+}
+
+static void
+dtsec_if_init(void *data)
+{
+ struct dtsec_softc *sc;
+
+ sc = data;
+
+ DTSEC_LOCK(sc);
+ dtsec_if_init_locked(sc);
+ DTSEC_UNLOCK(sc);
+}
+
+static void
+dtsec_if_start(struct ifnet *ifp)
+{
+ struct dtsec_softc *sc;
+
+ sc = ifp->if_softc;
+ DTSEC_LOCK(sc);
+ sc->sc_start_locked(sc);
+ DTSEC_UNLOCK(sc);
+}
+
+static void
+dtsec_if_watchdog(struct ifnet *ifp)
+{
+ /* TODO */
+}
+/** @} */
+
+
+/**
+ * @group IFmedia routines.
+ * @{
+ */
+static int
+dtsec_ifmedia_upd(struct ifnet *ifp)
+{
+ struct dtsec_softc *sc = ifp->if_softc;
+
+ DTSEC_LOCK(sc);
+ mii_mediachg(sc->sc_mii);
+ DTSEC_UNLOCK(sc);
+
+ return (0);
+}
+
+static void
+dtsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct dtsec_softc *sc = ifp->if_softc;
+
+ DTSEC_LOCK(sc);
+
+ mii_pollstat(sc->sc_mii);
+
+ ifmr->ifm_active = sc->sc_mii->mii_media_active;
+ ifmr->ifm_status = sc->sc_mii->mii_media_status;
+
+ DTSEC_UNLOCK(sc);
+}
+/** @} */
+
+
+/**
+ * @group dTSEC bus interface.
+ * @{
+ */
+static void
+dtsec_configure_mode(struct dtsec_softc *sc)
+{
+ char tunable[64];
+
+ snprintf(tunable, sizeof(tunable), "%s.independent_mode",
+ device_get_nameunit(sc->sc_dev));
+
+ sc->sc_mode = DTSEC_MODE_REGULAR;
+ TUNABLE_INT_FETCH(tunable, &sc->sc_mode);
+
+ if (sc->sc_mode == DTSEC_MODE_REGULAR) {
+ sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init;
+ sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init;
+ sc->sc_start_locked = dtsec_rm_if_start_locked;
+ } else {
+ sc->sc_port_rx_init = dtsec_im_fm_port_rx_init;
+ sc->sc_port_tx_init = dtsec_im_fm_port_tx_init;
+ sc->sc_start_locked = dtsec_im_if_start_locked;
+ }
+
+ device_printf(sc->sc_dev, "Configured for %s mode.\n",
+ (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent");
+}
+
+int
+dtsec_attach(device_t dev)
+{
+ struct dtsec_softc *sc;
+ int error;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+
+ sc->sc_dev = dev;
+ sc->sc_mac_mdio_irq = NO_IRQ;
+ sc->sc_eth_id = device_get_unit(dev);
+
+
+ /* Check if MallocSmart allocator is ready */
+ if (XX_MallocSmartInit() != E_OK)
+ return (ENXIO);
+
+ XX_TrackInit();
+
+ /* Init locks */
+ mtx_init(&sc->sc_lock, device_get_nameunit(dev),
+ "DTSEC Global Lock", MTX_DEF);
+
+ mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev),
+ "DTSEC MII Lock", MTX_DEF);
+
+ /* Init callouts */
+ callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE);
+
+ /* Read configuraton */
+ if ((error = fman_get_handle(&sc->sc_fmh)) != 0)
+ return (error);
+
+ if ((error = fman_get_muram_handle(&sc->sc_muramh)) != 0)
+ return (error);
+
+ if ((error = fman_get_bushandle(&sc->sc_fm_base)) != 0)
+ return (error);
+
+ /* Configure working mode */
+ dtsec_configure_mode(sc);
+
+ /* If we are working in regular mode configure BMAN and QMAN */
+ if (sc->sc_mode == DTSEC_MODE_REGULAR) {
+ /* Create RX buffer pool */
+ error = dtsec_rm_pool_rx_init(sc);
+ if (error != 0)
+ return (EIO);
+
+ /* Create RX frame queue range */
+ error = dtsec_rm_fqr_rx_init(sc);
+ if (error != 0)
+ return (EIO);
+
+ /* Create frame info pool */
+ error = dtsec_rm_fi_pool_init(sc);
+ if (error != 0)
+ return (EIO);
+
+ /* Create TX frame queue range */
+ error = dtsec_rm_fqr_tx_init(sc);
+ if (error != 0)
+ return (EIO);
+ }
+
+ /* Init FMan MAC module. */
+ error = dtsec_fm_mac_init(sc, sc->sc_mac_addr);
+ if (error != 0) {
+ dtsec_detach(dev);
+ return (ENXIO);
+ }
+
+ /*
+ * XXX: All phys are connected to MDIO interface of the first dTSEC
+ * device (dTSEC0). We have to save handle to the FM_MAC instance of
+ * dTSEC0, which is used later during phy's registers accesses. Another
+ * option would be adding new property to DTS pointing to correct dTSEC
+ * instance, of which FM_MAC handle has to be used for phy's registers
+ * accesses. We did not want to add new properties to DTS, thus this
+ * quite ugly hack.
+ */
+ if (sc->sc_eth_id == 0)
+ dtsec_mdio_mac_handle = sc->sc_mach;
+ if (sc->sc_hidden)
+ return (0);
+
+ /* Init FMan TX port */
+ error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev));
+ if (error != 0) {
+ dtsec_detach(dev);
+ return (ENXIO);
+ }
+
+ /* Init FMan RX port */
+ error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev));
+ if (error != 0) {
+ dtsec_detach(dev);
+ return (ENXIO);
+ }
+
+ /* Create network interface for upper layers */
+ ifp = sc->sc_ifnet = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ device_printf(sc->sc_dev, "if_alloc() failed.\n");
+ dtsec_detach(dev);
+ return (ENOMEM);
+ }
+
+ ifp->if_softc = sc;
+ ifp->if_mtu = ETHERMTU; /* TODO: Configure */
+ ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST;
+ ifp->if_init = dtsec_if_init;
+ ifp->if_start = dtsec_if_start;
+ ifp->if_ioctl = dtsec_if_ioctl;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+ if (sc->sc_phy_addr >= 0)
+ if_initname(ifp, device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev));
+ else
+ if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev));
+
+ /* TODO */
+#if 0
+ IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_TX_NUM_DESC - 1);
+ ifp->if_snd.ifq_drv_maxlen = TSEC_TX_NUM_DESC - 1;
+ IFQ_SET_READY(&ifp->if_snd);
+#endif
+ ifp->if_capabilities = 0; /* TODO: Check */
+ ifp->if_capenable = ifp->if_capabilities;
+
+ /* Attach PHY(s) */
+ error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd,
+ dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr,
+ MII_OFFSET_ANY, 0);
+ if (error) {
+ device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error);
+ dtsec_detach(sc->sc_dev);
+ return (error);
+ }
+ sc->sc_mii = device_get_softc(sc->sc_mii_dev);
+
+ /* Attach to stack */
+ ether_ifattach(ifp, sc->sc_mac_addr);
+
+ return (0);
+}
+
+int
+dtsec_detach(device_t dev)
+{
+ struct dtsec_softc *sc;
+ if_t ifp;
+
+ sc = device_get_softc(dev);
+ ifp = sc->sc_ifnet;
+
+ if (device_is_attached(dev)) {
+ ether_ifdetach(ifp);
+ /* Shutdown interface */
+ DTSEC_LOCK(sc);
+ dtsec_if_deinit_locked(sc);
+ DTSEC_UNLOCK(sc);
+ }
+
+ if (sc->sc_ifnet) {
+ if_free(sc->sc_ifnet);
+ sc->sc_ifnet = NULL;
+ }
+
+ if (sc->sc_mode == DTSEC_MODE_REGULAR) {
+ /* Free RX/TX FQRs */
+ dtsec_rm_fqr_rx_free(sc);
+ dtsec_rm_fqr_tx_free(sc);
+
+ /* Free frame info pool */
+ dtsec_rm_fi_pool_free(sc);
+
+ /* Free RX buffer pool */
+ dtsec_rm_pool_rx_free(sc);
+ }
+
+ dtsec_fm_mac_free(sc);
+ dtsec_fm_port_free_both(sc);
+
+ /* Destroy lock */
+ mtx_destroy(&sc->sc_lock);
+
+ return (0);
+}
+
+int
+dtsec_suspend(device_t dev)
+{
+
+ return (0);
+}
+
+int
+dtsec_resume(device_t dev)
+{
+
+ return (0);
+}
+
+int
+dtsec_shutdown(device_t dev)
+{
+
+ return (0);
+}
+/** @} */
+
+
+/**
+ * @group MII bus interface.
+ * @{
+ */
+int
+dtsec_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct dtsec_softc *sc;
+ uint16_t data;
+ t_Error error;
+
+ sc = device_get_softc(dev);
+
+ if (phy != sc->sc_phy_addr)
+ return (0xFFFF);
+
+ DTSEC_MII_LOCK(sc);
+ error = FM_MAC_MII_ReadPhyReg(dtsec_mdio_mac_handle, phy, reg, &data);
+ DTSEC_MII_UNLOCK(sc);
+ if (error != E_OK) {
+ device_printf(dev, "Error while reading from PHY (NetCommSw "
+ "error: %d)\n", error);
+ return (0xFFFF);
+ }
+
+ return ((int)data);
+}
+
+int
+dtsec_miibus_writereg(device_t dev, int phy, int reg, int value)
+{
+ struct dtsec_softc *sc;
+ t_Error error;
+
+ sc = device_get_softc(dev);
+
+ if (phy != sc->sc_phy_addr)
+ return (EINVAL);
+
+ DTSEC_MII_LOCK(sc);
+ error = FM_MAC_MII_WritePhyReg(dtsec_mdio_mac_handle, phy, reg, value);
+ DTSEC_MII_UNLOCK(sc);
+ if (error != E_OK) {
+ device_printf(dev, "Error while writing to PHY (NetCommSw "
+ "error: %d).\n", error);
+ return (EIO);
+ }
+
+ return (0);
+}
+
+void
+dtsec_miibus_statchg(device_t dev)
+{
+ struct dtsec_softc *sc;
+ e_EnetSpeed speed;
+ bool duplex;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ DTSEC_LOCK_ASSERT(sc);
+
+ duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
+
+ switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) {
+ case IFM_1000_T:
+ case IFM_1000_SX:
+ speed = e_ENET_SPEED_1000;
+ break;
+
+ case IFM_100_TX:
+ speed = e_ENET_SPEED_100;
+ break;
+
+ case IFM_10_T:
+ speed = e_ENET_SPEED_10;
+ break;
+
+ default:
+ speed = e_ENET_SPEED_10;
+ }
+
+ error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex);
+ if (error != E_OK)
+ device_printf(sc->sc_dev, "error while adjusting MAC speed.\n");
+}
+/** @} */
diff --git a/sys/dev/dpaa/if_dtsec.h b/sys/dev/dpaa/if_dtsec.h
new file mode 100644
index 000000000000..2e2e28fe24f9
--- /dev/null
+++ b/sys/dev/dpaa/if_dtsec.h
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_DTSEC_H_
+#define IF_DTSEC_H_
+
+/**
+ * @group dTSEC common API.
+ * @{
+ */
+#define DTSEC_MODE_REGULAR 0
+#define DTSEC_MODE_INDEPENDENT 1
+
+#define DTSEC_LOCK(sc) mtx_lock(&(sc)->sc_lock)
+#define DTSEC_UNLOCK(sc) mtx_unlock(&(sc)->sc_lock)
+#define DTSEC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_lock, MA_OWNED)
+#define DTSEC_MII_LOCK(sc) mtx_lock(&(sc)->sc_mii_lock)
+#define DTSEC_MII_UNLOCK(sc) mtx_unlock(&(sc)->sc_mii_lock)
+
+enum eth_dev_type {
+ ETH_DTSEC = 0x1,
+ ETH_10GSEC = 0x2
+};
+
+struct dtsec_softc {
+ /* XXX MII bus requires that struct ifnet is first!!! */
+ struct ifnet *sc_ifnet;
+
+ device_t sc_dev;
+ struct mtx sc_lock;
+ int sc_mode;
+
+ /* Methods */
+ int (*sc_port_rx_init)
+ (struct dtsec_softc *sc, int unit);
+ int (*sc_port_tx_init)
+ (struct dtsec_softc *sc, int unit);
+ void (*sc_start_locked)
+ (struct dtsec_softc *sc);
+
+ /* dTSEC data */
+ enum eth_dev_type sc_eth_dev_type;
+ uint8_t sc_eth_id;
+ uintptr_t sc_mac_mem_offset;
+ e_EnetMode sc_mac_enet_mode;
+ int sc_mac_mdio_irq;
+ uint8_t sc_mac_addr[6];
+ int sc_port_rx_hw_id;
+ int sc_port_tx_hw_id;
+ uint32_t sc_port_tx_qman_chan;
+ int sc_phy_addr;
+ bool sc_hidden;
+
+ /* Params from fman_bus driver */
+ vm_offset_t sc_fm_base;
+ t_Handle sc_fmh;
+ t_Handle sc_muramh;
+
+ t_Handle sc_mach;
+ t_Handle sc_rxph;
+ t_Handle sc_txph;
+
+ /* MII data */
+ struct mii_data *sc_mii;
+ device_t sc_mii_dev;
+ struct mtx sc_mii_lock;
+
+ struct callout sc_tick_callout;
+
+ /* RX Pool */
+ t_Handle sc_rx_pool;
+ uint8_t sc_rx_bpid;
+ uma_zone_t sc_rx_zone;
+ char sc_rx_zname[64];
+
+ /* RX Frame Queue */
+ t_Handle sc_rx_fqr;
+ uint32_t sc_rx_fqid;
+
+ /* TX Frame Queue */
+ t_Handle sc_tx_fqr;
+ bool sc_tx_fqr_full;
+ t_Handle sc_tx_conf_fqr;
+ uint32_t sc_tx_conf_fqid;
+
+ /* Frame Info Zone */
+ uma_zone_t sc_fi_zone;
+ char sc_fi_zname[64];
+};
+/** @} */
+
+
+/**
+ * @group dTSEC FMan PORT API.
+ * @{
+ */
+enum dtsec_fm_port_params {
+ FM_PORT_LIODN_BASE = 0,
+ FM_PORT_LIODN_OFFSET = 0,
+ FM_PORT_MEM_ID = 0,
+ FM_PORT_MEM_ATTR = MEMORY_ATTR_CACHEABLE,
+ FM_PORT_BUFFER_SIZE = MCLBYTES,
+};
+
+e_FmPortType dtsec_fm_port_rx_type(enum eth_dev_type type);
+void dtsec_fm_port_rx_exception_callback(t_Handle app,
+ e_FmPortExceptions exception);
+void dtsec_fm_port_tx_exception_callback(t_Handle app,
+ e_FmPortExceptions exception);
+e_FmPortType dtsec_fm_port_tx_type(enum eth_dev_type type);
+/** @} */
+
+
+/**
+ * @group dTSEC bus interface.
+ * @{
+ */
+int dtsec_attach(device_t dev);
+int dtsec_detach(device_t dev);
+int dtsec_suspend(device_t dev);
+int dtsec_resume(device_t dev);
+int dtsec_shutdown(device_t dev);
+int dtsec_miibus_readreg(device_t dev, int phy, int reg);
+int dtsec_miibus_writereg(device_t dev, int phy, int reg,
+ int value);
+void dtsec_miibus_statchg(device_t dev);
+/** @} */
+
+#endif /* IF_DTSEC_H_ */
diff --git a/sys/dev/dpaa/if_dtsec_fdt.c b/sys/dev/dpaa/if_dtsec_fdt.c
new file mode 100644
index 000000000000..25b2cfc2a712
--- /dev/null
+++ b/sys/dev/dpaa/if_dtsec_fdt.c
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+
+#include <powerpc/mpc85xx/mpc85xx.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include "miibus_if.h"
+
+#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
+#include <contrib/ncsw/inc/xx_ext.h>
+
+#include "if_dtsec.h"
+
+
+static int dtsec_fdt_probe(device_t dev);
+static int dtsec_fdt_attach(device_t dev);
+
+static device_method_t dtsec_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, dtsec_fdt_probe),
+ DEVMETHOD(device_attach, dtsec_fdt_attach),
+ DEVMETHOD(device_detach, dtsec_detach),
+
+ DEVMETHOD(device_shutdown, dtsec_shutdown),
+ DEVMETHOD(device_suspend, dtsec_suspend),
+ DEVMETHOD(device_resume, dtsec_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, dtsec_miibus_readreg),
+ DEVMETHOD(miibus_writereg, dtsec_miibus_writereg),
+ DEVMETHOD(miibus_statchg, dtsec_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t dtsec_driver = {
+ "dtsec",
+ dtsec_methods,
+ sizeof(struct dtsec_softc),
+};
+
+static devclass_t dtsec_devclass;
+DRIVER_MODULE(dtsec, dpaa, dtsec_driver, dtsec_devclass, 0, 0);
+DRIVER_MODULE(miibus, dtsec, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(dtsec, ether, 1, 1, 1);
+MODULE_DEPEND(dtsec, miibus, 1, 1, 1);
+
+static int
+dtsec_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "fsl,dpa-ethernet"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Freescale Data Path Triple Speed Ethernet "
+ "Controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+dtsec_fdt_attach(device_t dev)
+{
+ struct dtsec_softc *sc;
+ phandle_t node, enet_node, phy_node;
+ phandle_t fman_rxtx_node[2];
+ char phy_type[6];
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+
+ if (OF_getprop(node, "fsl,fman-mac", (void *)&enet_node,
+ sizeof(enet_node)) == -1) {
+ device_printf(dev, "Could not load fsl,fman-mac property "
+ "from DTS\n");
+ return (ENXIO);
+ }
+
+ enet_node = OF_instance_to_package(enet_node);
+
+ if (OF_getprop(enet_node, "local-mac-address",
+ (void *)sc->sc_mac_addr, 6) == -1) {
+ if (device_get_unit(dev) != 0) {
+ device_printf(dev,
+ "Could not load local-mac-addr property "
+ "from DTS\n");
+ return (ENXIO);
+ }
+ sc->sc_hidden = true;
+ }
+
+ /* Get link speed */
+ if (fdt_is_compatible(enet_node, "fsl,fman-1g-mac") != 0)
+ sc->sc_eth_dev_type = ETH_DTSEC;
+ else if (fdt_is_compatible(enet_node, "fsl,fman-10g-mac") != 0)
+ sc->sc_eth_dev_type = ETH_10GSEC;
+ else
+ return(ENXIO);
+
+ /* Get MAC memory offset in SoC */
+ if (OF_getprop(enet_node, "reg", (void *)&sc->sc_mac_mem_offset,
+ sizeof(sc->sc_mac_mem_offset)) <= 0)
+ return (ENXIO);
+
+ /* Get PHY address */
+ if (OF_getprop(enet_node, "phy-handle", (void *)&phy_node,
+ sizeof(phy_node)) <= 0)
+ return (ENXIO);
+
+ phy_node = OF_instance_to_package(phy_node);
+
+ if (OF_getprop(phy_node, "reg", (void *)&sc->sc_phy_addr,
+ sizeof(sc->sc_phy_addr)) <= 0)
+ return (ENXIO);
+
+ /* Get PHY connection type */
+ if (OF_getprop(enet_node, "phy-connection-type", (void *)phy_type,
+ sizeof(phy_type)) <= 0)
+ return (ENXIO);
+
+ if (!strcmp(phy_type, "sgmii"))
+ sc->sc_mac_enet_mode = e_ENET_MODE_SGMII_1000;
+ else if (!strcmp(phy_type, "rgmii"))
+ sc->sc_mac_enet_mode = e_ENET_MODE_RGMII_1000;
+ else if (!strcmp(phy_type, "xgmii"))
+ /* We set 10 Gigabit mode flag however we don't support it */
+ sc->sc_mac_enet_mode = e_ENET_MODE_XGMII_10000;
+ else
+ return (ENXIO);
+
+ /* Get RX/TX port handles */
+ if (OF_getprop(enet_node, "fsl,port-handles", (void *)fman_rxtx_node,
+ sizeof(fman_rxtx_node)) <= 0)
+ return (ENXIO);
+
+ if (fman_rxtx_node[0] == 0)
+ return (ENXIO);
+
+ if (fman_rxtx_node[1] == 0)
+ return (ENXIO);
+
+ fman_rxtx_node[0] = OF_instance_to_package(fman_rxtx_node[0]);
+ fman_rxtx_node[1] = OF_instance_to_package(fman_rxtx_node[1]);
+
+ if (fdt_is_compatible(fman_rxtx_node[0], "fsl,fman-port-1g-rx") == 0)
+ return (ENXIO);
+
+ if (fdt_is_compatible(fman_rxtx_node[1], "fsl,fman-port-1g-tx") == 0)
+ return (ENXIO);
+
+ /* Get RX port HW id */
+ if (OF_getprop(fman_rxtx_node[0], "reg", (void *)&sc->sc_port_rx_hw_id,
+ sizeof(sc->sc_port_rx_hw_id)) <= 0)
+ return (ENXIO);
+
+ /* Get TX port HW id */
+ if (OF_getprop(fman_rxtx_node[1], "reg", (void *)&sc->sc_port_tx_hw_id,
+ sizeof(sc->sc_port_tx_hw_id)) <= 0)
+ return (ENXIO);
+
+ /* Get QMan channel */
+ if (OF_getprop(fman_rxtx_node[1], "fsl,qman-channel-id",
+ (void *)&sc->sc_port_tx_qman_chan,
+ sizeof(sc->sc_port_tx_qman_chan)) <= 0)
+ return (ENXIO);
+
+ return (dtsec_attach(dev));
+}
diff --git a/sys/dev/dpaa/if_dtsec_im.c b/sys/dev/dpaa/if_dtsec_im.c
new file mode 100644
index 000000000000..335f489cc591
--- /dev/null
+++ b/sys/dev/dpaa/if_dtsec_im.c
@@ -0,0 +1,262 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
+#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
+#include <contrib/ncsw/inc/xx_ext.h>
+
+#include "fman.h"
+#include "if_dtsec.h"
+#include "if_dtsec_im.h"
+
+
+/**
+ * @group dTSEC FMan PORT routines.
+ * @{
+ */
+static e_RxStoreResponse
+dtsec_im_fm_port_rx_callback(t_Handle app, uint8_t *data, uint16_t length,
+ uint16_t status, uint8_t position, t_Handle buf_context)
+{
+ struct dtsec_softc *sc;
+ struct mbuf *m;
+
+ /* TODO STATUS / Position checking */
+ sc = app;
+
+ m = m_devget(data, length, 0, sc->sc_ifnet, NULL);
+ if (m)
+ (*sc->sc_ifnet->if_input)(sc->sc_ifnet, m);
+
+ XX_FreeSmart(data);
+
+ return (e_RX_STORE_RESPONSE_CONTINUE);
+}
+
+static void
+dtsec_im_fm_port_tx_conf_callback(t_Handle app, uint8_t *data, uint16_t status,
+ t_Handle buf_context)
+{
+
+ /* TODO: Check status */
+ XX_FreeSmart(data);
+}
+
+static uint8_t *
+dtsec_im_fm_port_rx_get_buf(t_Handle buffer_pool, t_Handle *buf_context_handle)
+{
+ struct dtsec_softc *sc;
+ uint8_t *buffer;
+
+ sc = buffer_pool;
+
+ buffer = XX_MallocSmart(FM_PORT_BUFFER_SIZE, 0, sizeof(void *));
+ if (!buffer)
+ device_printf(sc->sc_dev, "couldn't allocate RX buffer.\n");
+
+ return (buffer);
+}
+
+static t_Error
+dtsec_im_fm_port_rx_put_buf(t_Handle buffer_pool, uint8_t *buffer,
+ t_Handle buf_context)
+{
+
+ XX_FreeSmart(buffer);
+ return (E_OK);
+}
+
+int
+dtsec_im_fm_port_rx_init(struct dtsec_softc *sc, int unit)
+{
+ t_FmPortParams params;
+ t_BufferPoolInfo *pool_params;
+ t_FmPortImRxTxParams *im_params;
+ t_Error error;
+
+ memset(&params, 0, sizeof(params));
+
+ params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id;
+ params.h_Fm = sc->sc_fmh;
+ params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type);
+ params.portId = sc->sc_eth_id;
+ params.independentModeEnable = TRUE;
+ params.liodnBase = FM_PORT_LIODN_BASE;
+ params.f_Exception = dtsec_fm_port_rx_exception_callback;
+ params.h_App = sc;
+
+ im_params = &params.specificParams.imRxTxParams;
+ im_params->h_FmMuram = sc->sc_muramh;
+ im_params->liodnOffset = FM_PORT_LIODN_OFFSET;
+ im_params->dataMemId = FM_PORT_MEM_ID;
+ im_params->dataMemAttributes = FM_PORT_MEM_ATTR;
+ im_params->f_RxStore = dtsec_im_fm_port_rx_callback;
+
+ pool_params = &params.specificParams.imRxTxParams.rxPoolParams;
+ pool_params->h_BufferPool = sc;
+ pool_params->f_GetBuf = dtsec_im_fm_port_rx_get_buf;
+ pool_params->f_PutBuf = dtsec_im_fm_port_rx_put_buf;
+ pool_params->bufferSize = FM_PORT_BUFFER_SIZE;
+
+ sc->sc_rxph = FM_PORT_Config(&params);
+ if (sc->sc_rxph == NULL) {
+ device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n");
+ return (ENXIO);
+ }
+
+ error = FM_PORT_Init(sc->sc_rxph);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
+ FM_PORT_Free(sc->sc_rxph);
+ return (ENXIO);
+ }
+
+ if (bootverbose)
+ device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n",
+ sc->sc_port_rx_hw_id);
+
+ return (0);
+}
+
+int
+dtsec_im_fm_port_tx_init(struct dtsec_softc *sc, int unit)
+{
+ t_FmPortParams params;
+ t_FmPortImRxTxParams *im_params;
+ t_Error error;
+
+ memset(&params, 0, sizeof(params));
+
+ params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id;
+ params.h_Fm = sc->sc_fmh;
+ params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type);
+ params.portId = unit;
+ params.independentModeEnable = TRUE;
+ params.liodnBase = FM_PORT_LIODN_BASE;
+ params.f_Exception = dtsec_fm_port_tx_exception_callback;
+ params.h_App = sc;
+
+ im_params = &params.specificParams.imRxTxParams;
+ im_params->h_FmMuram = sc->sc_muramh;
+ im_params->liodnOffset = FM_PORT_LIODN_OFFSET;
+ im_params->dataMemId = FM_PORT_MEM_ID;
+ im_params->dataMemAttributes = FM_PORT_MEM_ATTR;
+ im_params->f_TxConf = dtsec_im_fm_port_tx_conf_callback;
+
+ sc->sc_txph = FM_PORT_Config(&params);
+ if (sc->sc_txph == NULL) {
+ device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n");
+ return (ENXIO);
+ }
+
+ error = FM_PORT_Init(sc->sc_txph);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
+ FM_PORT_Free(sc->sc_txph);
+ return (ENXIO);
+ }
+
+ if (bootverbose)
+ device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n",
+ sc->sc_port_tx_hw_id);
+
+ return (0);
+}
+/** @} */
+
+
+/**
+ * @group dTSEC IFnet routines.
+ * @{
+ */
+void
+dtsec_im_if_start_locked(struct dtsec_softc *sc)
+{
+ uint8_t *buffer;
+ uint16_t length;
+ struct mbuf *m;
+ int error;
+
+ DTSEC_LOCK_ASSERT(sc);
+ /* TODO: IFF_DRV_OACTIVE */
+
+ if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
+ return;
+
+ if ((sc->sc_ifnet->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
+ return;
+
+ while (!IFQ_DRV_IS_EMPTY(&sc->sc_ifnet->if_snd)) {
+ IFQ_DRV_DEQUEUE(&sc->sc_ifnet->if_snd, m);
+ if (m == NULL)
+ break;
+
+ length = m_length(m, NULL);
+ buffer = XX_MallocSmart(length, 0, sizeof(void *));
+ if (!buffer) {
+ m_freem(m);
+ break;
+ }
+
+ m_copydata(m, 0, length, buffer);
+ m_freem(m);
+
+ error = FM_PORT_ImTx(sc->sc_txph, buffer, length, TRUE, buffer);
+ if (error != E_OK) {
+ /* TODO: Ring full */
+ XX_FreeSmart(buffer);
+ break;
+ }
+ }
+}
+/** @} */
diff --git a/sys/dev/dpaa/if_dtsec_im.h b/sys/dev/dpaa/if_dtsec_im.h
new file mode 100644
index 000000000000..922bea4ac77e
--- /dev/null
+++ b/sys/dev/dpaa/if_dtsec_im.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_DTSEC_IM_H_
+#define IF_DTSEC_IM_H_
+
+/**
+ * @group dTSEC Independent Mode API.
+ * @{
+ */
+int dtsec_im_fm_port_tx_init(struct dtsec_softc *sc, int unit);
+int dtsec_im_fm_port_rx_init(struct dtsec_softc *sc, int unit);
+void dtsec_im_if_start_locked(struct dtsec_softc *sc);
+/** @} */
+
+#endif /* IF_DTSEC_IM_H_ */
diff --git a/sys/dev/dpaa/if_dtsec_rm.c b/sys/dev/dpaa/if_dtsec_rm.c
new file mode 100644
index 000000000000..30ab3265d0bc
--- /dev/null
+++ b/sys/dev/dpaa/if_dtsec_rm.c
@@ -0,0 +1,654 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
+#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
+#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
+#include <contrib/ncsw/inc/xx_ext.h>
+
+#include "fman.h"
+#include "bman.h"
+#include "qman.h"
+#include "if_dtsec.h"
+#include "if_dtsec_rm.h"
+
+
+/**
+ * @group dTSEC RM private defines.
+ * @{
+ */
+#define DTSEC_BPOOLS_USED (1)
+#define DTSEC_MAX_TX_QUEUE_LEN 256
+
+struct dtsec_rm_frame_info {
+ struct mbuf *fi_mbuf;
+ t_DpaaSGTE fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY];
+};
+
+enum dtsec_rm_pool_params {
+ DTSEC_RM_POOL_RX_LOW_MARK = 16,
+ DTSEC_RM_POOL_RX_HIGH_MARK = 64,
+ DTSEC_RM_POOL_RX_MAX_SIZE = 256,
+
+ DTSEC_RM_POOL_FI_LOW_MARK = 16,
+ DTSEC_RM_POOL_FI_HIGH_MARK = 64,
+ DTSEC_RM_POOL_FI_MAX_SIZE = 256,
+};
+
+enum dtsec_rm_fqr_params {
+ DTSEC_RM_FQR_RX_CHANNEL = e_QM_FQ_CHANNEL_POOL1,
+ DTSEC_RM_FQR_RX_WQ = 1,
+ DTSEC_RM_FQR_TX_CONF_CHANNEL = e_QM_FQ_CHANNEL_SWPORTAL0,
+ DTSEC_RM_FQR_TX_WQ = 1,
+ DTSEC_RM_FQR_TX_CONF_WQ = 1
+};
+/** @} */
+
+
+/**
+ * @group dTSEC Frame Info routines.
+ * @{
+ */
+void
+dtsec_rm_fi_pool_free(struct dtsec_softc *sc)
+{
+
+ if (sc->sc_fi_zone != NULL)
+ uma_zdestroy(sc->sc_fi_zone);
+}
+
+int
+dtsec_rm_fi_pool_init(struct dtsec_softc *sc)
+{
+
+ snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info",
+ device_get_nameunit(sc->sc_dev));
+
+ sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname,
+ sizeof(struct dtsec_rm_frame_info), NULL, NULL, NULL, NULL,
+ sizeof(void *), 0);
+ if (sc->sc_fi_zone == NULL)
+ return (EIO);
+
+ return (0);
+}
+
+static struct dtsec_rm_frame_info *
+dtsec_rm_fi_alloc(struct dtsec_softc *sc)
+{
+ struct dtsec_rm_frame_info *fi;
+
+ fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT);
+
+ return (fi);
+}
+
+static void
+dtsec_rm_fi_free(struct dtsec_softc *sc, struct dtsec_rm_frame_info *fi)
+{
+
+ XX_UntrackAddress(fi);
+ uma_zfree(sc->sc_fi_zone, fi);
+}
+/** @} */
+
+
+/**
+ * @group dTSEC FMan PORT routines.
+ * @{
+ */
+int
+dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit)
+{
+ t_FmPortParams params;
+ t_FmPortRxParams *rx_params;
+ t_FmPortExtPools *pool_params;
+ t_Error error;
+
+ memset(&params, 0, sizeof(params));
+
+ params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id;
+ params.h_Fm = sc->sc_fmh;
+ params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type);
+ params.portId = sc->sc_eth_id;
+ params.independentModeEnable = FALSE;
+ params.liodnBase = FM_PORT_LIODN_BASE;
+ params.f_Exception = dtsec_fm_port_rx_exception_callback;
+ params.h_App = sc;
+
+ rx_params = &params.specificParams.rxParams;
+ rx_params->errFqid = sc->sc_rx_fqid;
+ rx_params->dfltFqid = sc->sc_rx_fqid;
+ rx_params->liodnOffset = 0;
+
+ pool_params = &rx_params->extBufPools;
+ pool_params->numOfPoolsUsed = DTSEC_BPOOLS_USED;
+ pool_params->extBufPool->id = sc->sc_rx_bpid;
+ pool_params->extBufPool->size = FM_PORT_BUFFER_SIZE;
+
+ sc->sc_rxph = FM_PORT_Config(&params);
+ if (sc->sc_rxph == NULL) {
+ device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n");
+ return (ENXIO);
+ }
+
+ error = FM_PORT_Init(sc->sc_rxph);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
+ FM_PORT_Free(sc->sc_rxph);
+ return (ENXIO);
+ }
+
+ if (bootverbose)
+ device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n",
+ sc->sc_port_rx_hw_id);
+
+ return (0);
+}
+
+int
+dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit)
+{
+ t_FmPortParams params;
+ t_FmPortNonRxParams *tx_params;
+ t_Error error;
+
+ memset(&params, 0, sizeof(params));
+
+ params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id;
+ params.h_Fm = sc->sc_fmh;
+ params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type);
+ params.portId = sc->sc_eth_id;
+ params.independentModeEnable = FALSE;
+ params.liodnBase = FM_PORT_LIODN_BASE;
+ params.f_Exception = dtsec_fm_port_tx_exception_callback;
+ params.h_App = sc;
+
+ tx_params = &params.specificParams.nonRxParams;
+ tx_params->errFqid = sc->sc_tx_conf_fqid;
+ tx_params->dfltFqid = sc->sc_tx_conf_fqid;
+ tx_params->qmChannel = sc->sc_port_tx_qman_chan;
+#ifdef FM_OP_PARTITION_ERRATA_FMANx8
+ tx_params->opLiodnOffset = 0;
+#endif
+
+ sc->sc_txph = FM_PORT_Config(&params);
+ if (sc->sc_txph == NULL) {
+ device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n");
+ return (ENXIO);
+ }
+
+ error = FM_PORT_Init(sc->sc_txph);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
+ FM_PORT_Free(sc->sc_txph);
+ return (ENXIO);
+ }
+
+ if (bootverbose)
+ device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n",
+ sc->sc_port_tx_hw_id);
+
+ return (0);
+}
+/** @} */
+
+
+/**
+ * @group dTSEC buffer pools routines.
+ * @{
+ */
+static t_Error
+dtsec_rm_pool_rx_put_buffer(t_Handle h_BufferPool, uint8_t *buffer,
+ t_Handle context)
+{
+ struct dtsec_softc *sc;
+
+ sc = h_BufferPool;
+ uma_zfree(sc->sc_rx_zone, buffer);
+
+ return (E_OK);
+}
+
+static uint8_t *
+dtsec_rm_pool_rx_get_buffer(t_Handle h_BufferPool, t_Handle *context)
+{
+ struct dtsec_softc *sc;
+ uint8_t *buffer;
+
+ sc = h_BufferPool;
+ buffer = uma_zalloc(sc->sc_rx_zone, M_NOWAIT);
+
+ return (buffer);
+}
+
+static void
+dtsec_rm_pool_rx_depleted(t_Handle h_App, bool in)
+{
+ struct dtsec_softc *sc;
+ unsigned int count;
+
+ sc = h_App;
+
+ if (!in)
+ return;
+
+ while (1) {
+ count = bman_count(sc->sc_rx_pool);
+ if (count > DTSEC_RM_POOL_RX_HIGH_MARK)
+ return;
+
+ bman_pool_fill(sc->sc_rx_pool, DTSEC_RM_POOL_RX_HIGH_MARK);
+ }
+}
+
+void
+dtsec_rm_pool_rx_free(struct dtsec_softc *sc)
+{
+
+ if (sc->sc_rx_pool != NULL)
+ bman_pool_destroy(sc->sc_rx_pool);
+
+ if (sc->sc_rx_zone != NULL)
+ uma_zdestroy(sc->sc_rx_zone);
+}
+
+int
+dtsec_rm_pool_rx_init(struct dtsec_softc *sc)
+{
+
+ /* FM_PORT_BUFFER_SIZE must be less than PAGE_SIZE */
+ CTASSERT(FM_PORT_BUFFER_SIZE < PAGE_SIZE);
+
+ snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers",
+ device_get_nameunit(sc->sc_dev));
+
+ sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, FM_PORT_BUFFER_SIZE, NULL,
+ NULL, NULL, NULL, FM_PORT_BUFFER_SIZE, 0);
+ if (sc->sc_rx_zone == NULL)
+ return (EIO);
+
+ sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, FM_PORT_BUFFER_SIZE,
+ 0, 0, DTSEC_RM_POOL_RX_MAX_SIZE, dtsec_rm_pool_rx_get_buffer,
+ dtsec_rm_pool_rx_put_buffer, DTSEC_RM_POOL_RX_LOW_MARK,
+ DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dtsec_rm_pool_rx_depleted, sc, NULL,
+ NULL);
+ if (sc->sc_rx_pool == NULL) {
+ dtsec_rm_pool_rx_free(sc);
+ return (EIO);
+ }
+
+ return (0);
+}
+/** @} */
+
+
+/**
+ * @group dTSEC Frame Queue Range routines.
+ * @{
+ */
+static void
+dtsec_rm_fqr_mext_free(struct mbuf *m, void *buffer, void *arg)
+{
+ struct dtsec_softc *sc;
+
+ sc = arg;
+ if (bman_count(sc->sc_rx_pool) <= DTSEC_RM_POOL_RX_MAX_SIZE)
+ bman_put_buffer(sc->sc_rx_pool, buffer);
+ else
+ dtsec_rm_pool_rx_put_buffer(arg, buffer, NULL);
+}
+
+static e_RxStoreResponse
+dtsec_rm_fqr_rx_callback(t_Handle app, t_Handle fqr, t_Handle portal,
+ uint32_t fqid_off, t_DpaaFD *frame)
+{
+ struct dtsec_softc *sc;
+ struct mbuf *m;
+
+ m = NULL;
+ sc = app;
+
+ KASSERT(DPAA_FD_GET_FORMAT(frame) == e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF,
+ ("%s(): Got unsupported frame format 0x%02X!", __func__,
+ DPAA_FD_GET_FORMAT(frame)));
+
+ KASSERT(DPAA_FD_GET_OFFSET(frame) == 0,
+ ("%s(): Only offset 0 is supported!", __func__));
+
+ if (DPAA_FD_GET_STATUS(frame) != 0) {
+ device_printf(sc->sc_dev, "RX error: 0x%08X\n",
+ DPAA_FD_GET_STATUS(frame));
+ goto err;
+ }
+
+ m = m_gethdr(M_NOWAIT, MT_HEADER);
+ if (m == NULL)
+ goto err;
+
+ MEXTADD(m, DPAA_FD_GET_ADDR(frame), FM_PORT_BUFFER_SIZE,
+ dtsec_rm_fqr_mext_free, DPAA_FD_GET_ADDR(frame), sc, 0,
+ EXT_NET_DRV);
+
+ m->m_pkthdr.rcvif = sc->sc_ifnet;
+ m->m_len = DPAA_FD_GET_LENGTH(frame);
+ m_fixhdr(m);
+
+ (*sc->sc_ifnet->if_input)(sc->sc_ifnet, m);
+
+ return (e_RX_STORE_RESPONSE_CONTINUE);
+
+err:
+ bman_put_buffer(sc->sc_rx_pool, DPAA_FD_GET_ADDR(frame));
+ if (m != NULL)
+ m_freem(m);
+
+ return (e_RX_STORE_RESPONSE_CONTINUE);
+}
+
+static e_RxStoreResponse
+dtsec_rm_fqr_tx_confirm_callback(t_Handle app, t_Handle fqr, t_Handle portal,
+ uint32_t fqid_off, t_DpaaFD *frame)
+{
+ struct dtsec_rm_frame_info *fi;
+ struct dtsec_softc *sc;
+ unsigned int qlen;
+ t_DpaaSGTE *sgt0;
+
+ sc = app;
+
+ if (DPAA_FD_GET_STATUS(frame) != 0)
+ device_printf(sc->sc_dev, "TX error: 0x%08X\n",
+ DPAA_FD_GET_STATUS(frame));
+
+ /*
+ * We are storing struct dtsec_rm_frame_info in first entry
+ * of scatter-gather table.
+ */
+ sgt0 = DPAA_FD_GET_ADDR(frame);
+ fi = DPAA_SGTE_GET_ADDR(sgt0);
+
+ /* Free transmitted frame */
+ m_freem(fi->fi_mbuf);
+ dtsec_rm_fi_free(sc, fi);
+
+ qlen = qman_fqr_get_counter(sc->sc_tx_conf_fqr, 0,
+ e_QM_FQR_COUNTERS_FRAME);
+
+ if (qlen == 0) {
+ DTSEC_LOCK(sc);
+
+ if (sc->sc_tx_fqr_full) {
+ sc->sc_tx_fqr_full = 0;
+ dtsec_rm_if_start_locked(sc);
+ }
+
+ DTSEC_UNLOCK(sc);
+ }
+
+ return (e_RX_STORE_RESPONSE_CONTINUE);
+}
+
+void
+dtsec_rm_fqr_rx_free(struct dtsec_softc *sc)
+{
+
+ if (sc->sc_rx_fqr)
+ qman_fqr_free(sc->sc_rx_fqr);
+}
+
+int
+dtsec_rm_fqr_rx_init(struct dtsec_softc *sc)
+{
+ t_Error error;
+ t_Handle fqr;
+
+ /* Default Frame Queue */
+ fqr = qman_fqr_create(1, DTSEC_RM_FQR_RX_CHANNEL, DTSEC_RM_FQR_RX_WQ,
+ FALSE, 0, FALSE, FALSE, TRUE, FALSE, 0, 0, 0);
+ if (fqr == NULL) {
+ device_printf(sc->sc_dev, "could not create default RX queue"
+ "\n");
+ return (EIO);
+ }
+
+ sc->sc_rx_fqr = fqr;
+ sc->sc_rx_fqid = qman_fqr_get_base_fqid(fqr);
+
+ error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_rx_callback, sc);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "could not register RX callback\n");
+ dtsec_rm_fqr_rx_free(sc);
+ return (EIO);
+ }
+
+ return (0);
+}
+
+void
+dtsec_rm_fqr_tx_free(struct dtsec_softc *sc)
+{
+
+ if (sc->sc_tx_fqr)
+ qman_fqr_free(sc->sc_tx_fqr);
+
+ if (sc->sc_tx_conf_fqr)
+ qman_fqr_free(sc->sc_tx_conf_fqr);
+}
+
+int
+dtsec_rm_fqr_tx_init(struct dtsec_softc *sc)
+{
+ t_Error error;
+ t_Handle fqr;
+
+ /* TX Frame Queue */
+ fqr = qman_fqr_create(1, sc->sc_port_tx_qman_chan,
+ DTSEC_RM_FQR_TX_WQ, FALSE, 0, FALSE, FALSE, TRUE, FALSE, 0, 0, 0);
+ if (fqr == NULL) {
+ device_printf(sc->sc_dev, "could not create default TX queue"
+ "\n");
+ return (EIO);
+ }
+
+ sc->sc_tx_fqr = fqr;
+
+ /* TX Confirmation Frame Queue */
+ fqr = qman_fqr_create(1, DTSEC_RM_FQR_TX_CONF_CHANNEL,
+ DTSEC_RM_FQR_TX_CONF_WQ, FALSE, 0, FALSE, FALSE, TRUE, FALSE, 0, 0,
+ 0);
+ if (fqr == NULL) {
+ device_printf(sc->sc_dev, "could not create TX confirmation "
+ "queue\n");
+ dtsec_rm_fqr_tx_free(sc);
+ return (EIO);
+ }
+
+ sc->sc_tx_conf_fqr = fqr;
+ sc->sc_tx_conf_fqid = qman_fqr_get_base_fqid(fqr);
+
+ error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_tx_confirm_callback, sc);
+ if (error != E_OK) {
+ device_printf(sc->sc_dev, "could not register TX confirmation "
+ "callback\n");
+ dtsec_rm_fqr_tx_free(sc);
+ return (EIO);
+ }
+
+ return (0);
+}
+/** @} */
+
+
+/**
+ * @group dTSEC IFnet routines.
+ * @{
+ */
+void
+dtsec_rm_if_start_locked(struct dtsec_softc *sc)
+{
+ vm_size_t dsize, psize, ssize;
+ struct dtsec_rm_frame_info *fi;
+ unsigned int qlen, i;
+ struct mbuf *m0, *m;
+ vm_offset_t vaddr;
+ vm_paddr_t paddr;
+ t_DpaaFD fd;
+
+ DTSEC_LOCK_ASSERT(sc);
+ /* TODO: IFF_DRV_OACTIVE */
+
+ if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
+ return;
+
+ if ((sc->sc_ifnet->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
+ return;
+
+ while (!IFQ_DRV_IS_EMPTY(&sc->sc_ifnet->if_snd)) {
+ /* Check length of the TX queue */
+ qlen = qman_fqr_get_counter(sc->sc_tx_fqr, 0,
+ e_QM_FQR_COUNTERS_FRAME);
+
+ if (qlen >= DTSEC_MAX_TX_QUEUE_LEN) {
+ sc->sc_tx_fqr_full = 1;
+ return;
+ }
+
+ fi = dtsec_rm_fi_alloc(sc);
+ if (fi == NULL)
+ return;
+
+ IFQ_DRV_DEQUEUE(&sc->sc_ifnet->if_snd, m0);
+ if (m0 == NULL) {
+ dtsec_rm_fi_free(sc, fi);
+ return;
+ }
+
+ i = 0;
+ m = m0;
+ psize = 0;
+ dsize = 0;
+ fi->fi_mbuf = m0;
+ while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
+ if (m->m_len == 0)
+ continue;
+
+ /*
+ * First entry in scatter-gather table is used to keep
+ * pointer to frame info structure.
+ */
+ DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i], (void *)fi);
+ DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], 0);
+
+ DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
+ DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
+ DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
+ DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
+ i++;
+
+ dsize = m->m_len;
+ vaddr = (vm_offset_t)m->m_data;
+ while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
+ paddr = XX_VirtToPhys((void *)vaddr);
+ ssize = PAGE_SIZE - (paddr & PAGE_MASK);
+ if (m->m_len < ssize)
+ ssize = m->m_len;
+
+ DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i],
+ (void *)vaddr);
+ DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], ssize);
+
+ DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
+ DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
+ DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
+ DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
+
+ dsize -= ssize;
+ vaddr += ssize;
+ psize += ssize;
+ i++;
+ }
+
+ if (dsize > 0)
+ break;
+
+ m = m->m_next;
+ }
+
+ /* Check if SG table was constructed properly */
+ if (m != NULL || dsize != 0) {
+ dtsec_rm_fi_free(sc, fi);
+ m_freem(m0);
+ continue;
+ }
+
+ DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i-1], 1);
+
+ DPAA_FD_SET_ADDR(&fd, fi->fi_sgt);
+ DPAA_FD_SET_LENGTH(&fd, psize);
+ DPAA_FD_SET_FORMAT(&fd, e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF);
+
+ DPAA_FD_SET_DD(&fd, 0);
+ DPAA_FD_SET_PID(&fd, 0);
+ DPAA_FD_SET_BPID(&fd, 0);
+ DPAA_FD_SET_OFFSET(&fd, 0);
+ DPAA_FD_SET_STATUS(&fd, 0);
+
+ DTSEC_UNLOCK(sc);
+ if (qman_fqr_enqueue(sc->sc_tx_fqr, 0, &fd) != E_OK) {
+ dtsec_rm_fi_free(sc, fi);
+ m_freem(m0);
+ }
+ DTSEC_LOCK(sc);
+ }
+}
+/** @} */
diff --git a/sys/dev/dpaa/if_dtsec_rm.h b/sys/dev/dpaa/if_dtsec_rm.h
new file mode 100644
index 000000000000..b79b44facac8
--- /dev/null
+++ b/sys/dev/dpaa/if_dtsec_rm.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IF_DTSEC_RM_H_
+#define IF_DTSEC_RM_H_
+
+/**
+ * @group dTSEC Regular Mode API.
+ * @{
+ */
+int dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit);
+int dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit);
+
+void dtsec_rm_if_start_locked(struct dtsec_softc *sc);
+
+int dtsec_rm_pool_rx_init(struct dtsec_softc *sc);
+void dtsec_rm_pool_rx_free(struct dtsec_softc *sc);
+
+int dtsec_rm_fi_pool_init(struct dtsec_softc *sc);
+void dtsec_rm_fi_pool_free(struct dtsec_softc *sc);
+
+int dtsec_rm_fqr_rx_init(struct dtsec_softc *sc);
+int dtsec_rm_fqr_tx_init(struct dtsec_softc *sc);
+void dtsec_rm_fqr_rx_free(struct dtsec_softc *sc);
+void dtsec_rm_fqr_tx_free(struct dtsec_softc *sc);
+/** @} */
+
+#endif /* IF_DTSEC_RM_H_ */
diff --git a/sys/dev/dpaa/portals.h b/sys/dev/dpaa/portals.h
new file mode 100644
index 000000000000..3f006768f97e
--- /dev/null
+++ b/sys/dev/dpaa/portals.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+typedef struct dpaa_portal {
+ int dp_irid; /* interrupt rid */
+ struct resource *dp_ires; /* interrupt resource */
+
+ bool dp_regs_mapped; /* register mapping status */
+
+ t_Handle dp_ph; /* portal's handle */
+ vm_paddr_t dp_ce_pa; /* portal's CE area PA */
+ vm_paddr_t dp_ci_pa; /* portal's CI area PA */
+ uint32_t dp_ce_size; /* portal's CE area size */
+ uint32_t dp_ci_size; /* portal's CI area size */
+ uint32_t dp_intr_num; /* portal's intr. number */
+} dpaa_portal_t;
+
+struct dpaa_portals_softc {
+ device_t sc_dev; /* device handle */
+ vm_paddr_t sc_dp_pa; /* portal's PA */
+ uint32_t sc_dp_size; /* portal's size */
+ int sc_rrid[2]; /* memory rid */
+ struct resource *sc_rres[2]; /* memory resource */
+ dpaa_portal_t sc_dp[MAXCPU];
+};
+
+struct dpaa_portals_devinfo {
+ struct resource_list di_res;
+ int di_intr_rid;
+};
+
+int bman_portals_attach(device_t);
+int bman_portals_detach(device_t);
+
+int qman_portals_attach(device_t);
+int qman_portals_detach(device_t);
+
+int dpaa_portal_alloc_res(device_t, struct dpaa_portals_devinfo *, int);
+void dpaa_portal_map_registers(struct dpaa_portals_softc *);
diff --git a/sys/dev/dpaa/portals_common.c b/sys/dev/dpaa/portals_common.c
new file mode 100644
index 000000000000..e540077b7555
--- /dev/null
+++ b/sys/dev/dpaa/portals_common.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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 "opt_platform.h"
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/rman.h>
+#include <sys/sched.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/resource.h>
+#include <machine/tlb.h>
+
+#include <contrib/ncsw/inc/error_ext.h>
+#include <contrib/ncsw/inc/xx_ext.h>
+
+#include "portals.h"
+
+
+int
+dpaa_portal_alloc_res(device_t dev, struct dpaa_portals_devinfo *di, int cpu)
+{
+ struct dpaa_portals_softc *sc = device_get_softc(dev);
+ struct resource_list_entry *rle;
+ int err;
+ struct resource_list *res;
+
+ /* Check if MallocSmart allocator is ready */
+ if (XX_MallocSmartInit() != E_OK)
+ return (ENXIO);
+
+ res = &di->di_res;
+
+ /*
+ * Allocate memory.
+ * Reserve only one pair of CE/CI virtual memory regions
+ * for all CPUs, in order to save the space.
+ */
+ if (sc->sc_rres[0] == NULL) {
+ /* Cache enabled area */
+ rle = resource_list_find(res, SYS_RES_MEMORY, 0);
+ sc->sc_rrid[0] = 0;
+ sc->sc_rres[0] = bus_alloc_resource(dev,
+ SYS_RES_MEMORY, &sc->sc_rrid[0], rle->start + sc->sc_dp_pa,
+ rle->end + sc->sc_dp_pa, rle->count, RF_ACTIVE);
+ pmap_change_attr((vm_offset_t)rman_get_bushandle(sc->sc_rres[0]),
+ rle->count, VM_MEMATTR_CACHEABLE);
+ if (sc->sc_rres[0] == NULL) {
+ device_printf(dev, "Could not allocate memory.\n");
+ return (ENXIO);
+ }
+ /* Cache inhibited area */
+ rle = resource_list_find(res, SYS_RES_MEMORY, 1);
+ sc->sc_rrid[1] = 1;
+ sc->sc_rres[1] = bus_alloc_resource(dev,
+ SYS_RES_MEMORY, &sc->sc_rrid[1], rle->start + sc->sc_dp_pa,
+ rle->end + sc->sc_dp_pa, rle->count, RF_ACTIVE);
+ if (sc->sc_rres[1] == NULL) {
+ device_printf(dev, "Could not allocate memory.\n");
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->sc_rrid[0], sc->sc_rres[0]);
+ return (ENXIO);
+ }
+ sc->sc_dp[PCPU_GET(cpuid)].dp_regs_mapped = 1;
+ }
+ /* Acquire portal's CE_PA and CI_PA */
+ rle = resource_list_find(res, SYS_RES_MEMORY, 0);
+ sc->sc_dp[cpu].dp_ce_pa = rle->start + sc->sc_dp_pa;
+ sc->sc_dp[cpu].dp_ce_size = rle->count;
+ rle = resource_list_find(res, SYS_RES_MEMORY, 1);
+ sc->sc_dp[cpu].dp_ci_pa = rle->start + sc->sc_dp_pa;
+ sc->sc_dp[cpu].dp_ci_size = rle->count;
+
+ /* Allocate interrupts */
+ rle = resource_list_find(res, SYS_RES_IRQ, 0);
+ sc->sc_dp[cpu].dp_irid = 0;
+ sc->sc_dp[cpu].dp_ires = bus_alloc_resource(dev,
+ SYS_RES_IRQ, &sc->sc_dp[cpu].dp_irid, rle->start, rle->end,
+ rle->count, RF_ACTIVE);
+ /* Save interrupt number for later use */
+ sc->sc_dp[cpu].dp_intr_num = rle->start;
+
+ if (sc->sc_dp[cpu].dp_ires == NULL) {
+ device_printf(dev, "Could not allocate irq.\n");
+ return (ENXIO);
+ }
+
+ err = XX_PreallocAndBindIntr((int)sc->sc_dp[cpu].dp_ires, cpu);
+
+ if (err != E_OK) {
+ device_printf(dev, "Could not prealloc and bind interrupt\n");
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_dp[cpu].dp_irid, sc->sc_dp[cpu].dp_ires);
+ sc->sc_dp[cpu].dp_ires = NULL;
+ return (ENXIO);
+ }
+
+#if 0
+ err = bus_generic_config_intr(dev, rle->start, di->di_intr_trig,
+ di->di_intr_pol);
+ if (err != 0) {
+ device_printf(dev, "Could not configure interrupt\n");
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_dp[cpu].dp_irid, sc->sc_dp[cpu].dp_ires);
+ sc->sc_dp[cpu].dp_ires = NULL;
+ return (err);
+ }
+#endif
+
+ return (0);
+}
+
+void
+dpaa_portal_map_registers(struct dpaa_portals_softc *sc)
+{
+ unsigned int cpu;
+
+ sched_pin();
+ cpu = PCPU_GET(cpuid);
+ if (sc->sc_dp[cpu].dp_regs_mapped)
+ goto out;
+
+ tlb1_set_entry(rman_get_bushandle(sc->sc_rres[0]),
+ sc->sc_dp[cpu].dp_ce_pa, sc->sc_dp[cpu].dp_ce_size,
+ _TLB_ENTRY_MEM);
+ tlb1_set_entry(rman_get_bushandle(sc->sc_rres[1]),
+ sc->sc_dp[cpu].dp_ci_pa, sc->sc_dp[cpu].dp_ci_size,
+ _TLB_ENTRY_IO);
+
+ sc->sc_dp[cpu].dp_regs_mapped = 1;
+
+out:
+ sched_unpin();
+}
diff --git a/sys/dev/dpaa/qman.c b/sys/dev/dpaa/qman.c
new file mode 100644
index 000000000000..69de8ab11cbd
--- /dev/null
+++ b/sys/dev/dpaa/qman.c
@@ -0,0 +1,555 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/rman.h>
+#include <sys/sched.h>
+#include <sys/smp.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/tlb.h>
+
+#include "qman.h"
+#include "portals.h"
+
+extern struct dpaa_portals_softc *qp_sc;
+static struct qman_softc *qman_sc;
+
+extern t_Handle qman_portal_setup(struct qman_softc *qsc);
+
+static void
+qman_exception(t_Handle app, e_QmExceptions exception)
+{
+ struct qman_softc *sc;
+ const char *message;
+
+ sc = app;
+
+ switch (exception) {
+ case e_QM_EX_CORENET_INITIATOR_DATA:
+ message = "Initiator Data Error";
+ break;
+ case e_QM_EX_CORENET_TARGET_DATA:
+ message = "CoreNet Target Data Error";
+ break;
+ case e_QM_EX_CORENET_INVALID_TARGET_TRANSACTION:
+ message = "Invalid Target Transaction";
+ break;
+ case e_QM_EX_PFDR_THRESHOLD:
+ message = "PFDR Low Watermark Interrupt";
+ break;
+ case e_QM_EX_PFDR_ENQUEUE_BLOCKED:
+ message = "PFDR Enqueues Blocked Interrupt";
+ break;
+ case e_QM_EX_SINGLE_ECC:
+ message = "Single Bit ECC Error Interrupt";
+ break;
+ case e_QM_EX_MULTI_ECC:
+ message = "Multi Bit ECC Error Interrupt";
+ break;
+ case e_QM_EX_INVALID_COMMAND:
+ message = "Invalid Command Verb Interrupt";
+ break;
+ case e_QM_EX_DEQUEUE_DCP:
+ message = "Invalid Dequeue Direct Connect Portal Interrupt";
+ break;
+ case e_QM_EX_DEQUEUE_FQ:
+ message = "Invalid Dequeue FQ Interrupt";
+ break;
+ case e_QM_EX_DEQUEUE_SOURCE:
+ message = "Invalid Dequeue Source Interrupt";
+ break;
+ case e_QM_EX_DEQUEUE_QUEUE:
+ message = "Invalid Dequeue Queue Interrupt";
+ break;
+ case e_QM_EX_ENQUEUE_OVERFLOW:
+ message = "Invalid Enqueue Overflow Interrupt";
+ break;
+ case e_QM_EX_ENQUEUE_STATE:
+ message = "Invalid Enqueue State Interrupt";
+ break;
+ case e_QM_EX_ENQUEUE_CHANNEL:
+ message = "Invalid Enqueue Channel Interrupt";
+ break;
+ case e_QM_EX_ENQUEUE_QUEUE:
+ message = "Invalid Enqueue Queue Interrupt";
+ break;
+ case e_QM_EX_CG_STATE_CHANGE:
+ message = "CG change state notification";
+ break;
+ default:
+ message = "Unknown error";
+ }
+
+ device_printf(sc->sc_dev, "QMan Exception: %s.\n", message);
+}
+
+/**
+ * General received frame callback.
+ * This is called, when user did not register his own callback for a given
+ * frame queue range (fqr).
+ */
+e_RxStoreResponse
+qman_received_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal,
+ uint32_t fqid_offset, t_DpaaFD *frame)
+{
+ struct qman_softc *sc;
+
+ sc = app;
+
+ device_printf(sc->sc_dev, "dummy callback for received frame.\n");
+ return (e_RX_STORE_RESPONSE_CONTINUE);
+}
+
+/**
+ * General rejected frame callback.
+ * This is called, when user did not register his own callback for a given
+ * frame queue range (fqr).
+ */
+e_RxStoreResponse
+qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal,
+ uint32_t fqid_offset, t_DpaaFD *frame,
+ t_QmRejectedFrameInfo *qm_rejected_frame_info)
+{
+ struct qman_softc *sc;
+
+ sc = app;
+
+ device_printf(sc->sc_dev, "dummy callback for rejected frame.\n");
+ return (e_RX_STORE_RESPONSE_CONTINUE);
+}
+
+int
+qman_attach(device_t dev)
+{
+ struct qman_softc *sc;
+ t_QmParam qp;
+ t_Error error;
+ t_QmRevisionInfo rev;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+ qman_sc = sc;
+
+ if (XX_MallocSmartInit() != E_OK) {
+ device_printf(dev, "could not initialize smart allocator.\n");
+ return (ENXIO);
+ }
+
+ sched_pin();
+
+ /* Allocate resources */
+ sc->sc_rrid = 0;
+ sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY,
+ &sc->sc_rrid, 0, ~0, QMAN_CCSR_SIZE, RF_ACTIVE);
+ if (sc->sc_rres == NULL) {
+ device_printf(dev, "could not allocate memory.\n");
+ goto err;
+ }
+
+ sc->sc_irid = 0;
+ sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE);
+ if (sc->sc_ires == NULL) {
+ device_printf(dev, "could not allocate error interrupt.\n");
+ goto err;
+ }
+
+ if (qp_sc == NULL)
+ goto err;
+
+ dpaa_portal_map_registers(qp_sc);
+
+ /* Initialize QMan */
+ qp.guestId = NCSW_MASTER_ID;
+ qp.baseAddress = rman_get_bushandle(sc->sc_rres);
+ qp.swPortalsBaseAddress = rman_get_bushandle(qp_sc->sc_rres[0]);
+ qp.liodn = 0;
+ qp.totalNumOfFqids = QMAN_MAX_FQIDS;
+ qp.fqdMemPartitionId = NCSW_MASTER_ID;
+ qp.pfdrMemPartitionId = NCSW_MASTER_ID;
+ qp.f_Exception = qman_exception;
+ qp.h_App = sc;
+ qp.errIrq = (int)sc->sc_ires;
+ qp.partFqidBase = QMAN_FQID_BASE;
+ qp.partNumOfFqids = QMAN_MAX_FQIDS;
+ qp.partCgsBase = 0;
+ qp.partNumOfCgs = 0;
+
+ sc->sc_qh = QM_Config(&qp);
+ if (sc->sc_qh == NULL) {
+ device_printf(dev, "could not be configured\n");
+ goto err;
+ }
+
+ error = QM_Init(sc->sc_qh);
+ if (error != E_OK) {
+ device_printf(dev, "could not be initialized\n");
+ goto err;
+ }
+
+ error = QM_GetRevision(sc->sc_qh, &rev);
+ if (error != E_OK) {
+ device_printf(dev, "could not get QMan revision\n");
+ goto err;
+ }
+
+ device_printf(dev, "Hardware version: %d.%d.\n",
+ rev.majorRev, rev.minorRev);
+
+ sched_unpin();
+
+ qman_portal_setup(sc);
+
+ return (0);
+
+err:
+ sched_unpin();
+ qman_detach(dev);
+ return (ENXIO);
+}
+
+int
+qman_detach(device_t dev)
+{
+ struct qman_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_qh)
+ QM_Free(sc->sc_qh);
+
+ if (sc->sc_ires != NULL)
+ XX_DeallocIntr((int)sc->sc_ires);
+
+ if (sc->sc_ires != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_irid, sc->sc_ires);
+
+ if (sc->sc_rres != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->sc_rrid, sc->sc_rres);
+
+ return (0);
+}
+
+int
+qman_suspend(device_t dev)
+{
+
+ return (0);
+}
+
+int
+qman_resume(device_t dev)
+{
+
+ return (0);
+}
+
+int
+qman_shutdown(device_t dev)
+{
+
+ return (0);
+}
+
+
+/**
+ * @group QMan API functions implementation.
+ * @{
+ */
+
+t_Handle
+qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq,
+ bool force_fqid, uint32_t fqid_or_align, bool init_parked,
+ bool hold_active, bool prefer_in_cache, bool congst_avoid_ena,
+ t_Handle congst_group, int8_t overhead_accounting_len,
+ uint32_t tail_drop_threshold)
+{
+ struct qman_softc *sc;
+ t_QmFqrParams fqr;
+ unsigned int cpu;
+ t_Handle fqrh, portal;
+
+ sc = qman_sc;
+
+ sched_pin();
+ cpu = PCPU_GET(cpuid);
+
+ /* Ensure we have got QMan port initialized */
+ portal = qman_portal_setup(sc);
+ if (portal == NULL) {
+ device_printf(sc->sc_dev, "could not setup QMan portal\n");
+ goto err;
+ }
+
+ fqr.h_Qm = sc->sc_qh;
+ fqr.h_QmPortal = portal;
+ fqr.initParked = init_parked;
+ fqr.holdActive = hold_active;
+ fqr.preferInCache = prefer_in_cache;
+
+ /* We do not support stashing */
+ fqr.useContextAForStash = FALSE;
+ fqr.p_ContextA = 0;
+ fqr.p_ContextB = 0;
+
+ fqr.channel = channel;
+ fqr.wq = wq;
+ fqr.shadowMode = FALSE;
+ fqr.numOfFqids = fqids_num;
+
+ /* FQID */
+ fqr.useForce = force_fqid;
+ if (force_fqid) {
+ fqr.qs.frcQ.fqid = fqid_or_align;
+ } else {
+ fqr.qs.nonFrcQs.align = fqid_or_align;
+ }
+
+ /* Congestion Avoidance */
+ fqr.congestionAvoidanceEnable = congst_avoid_ena;
+ if (congst_avoid_ena) {
+ fqr.congestionAvoidanceParams.h_QmCg = congst_group;
+ fqr.congestionAvoidanceParams.overheadAccountingLength =
+ overhead_accounting_len;
+ fqr.congestionAvoidanceParams.fqTailDropThreshold =
+ tail_drop_threshold;
+ } else {
+ fqr.congestionAvoidanceParams.h_QmCg = 0;
+ fqr.congestionAvoidanceParams.overheadAccountingLength = 0;
+ fqr.congestionAvoidanceParams.fqTailDropThreshold = 0;
+ }
+
+ fqrh = QM_FQR_Create(&fqr);
+ if (fqrh == NULL) {
+ device_printf(sc->sc_dev, "could not create Frame Queue Range"
+ "\n");
+ goto err;
+ }
+
+ sc->sc_fqr_cpu[QM_FQR_GetFqid(fqrh)] = PCPU_GET(cpuid);
+
+ sched_unpin();
+
+ return (fqrh);
+
+err:
+ sched_unpin();
+
+ return (NULL);
+}
+
+t_Error
+qman_fqr_free(t_Handle fqr)
+{
+ struct qman_softc *sc;
+ t_Error error;
+
+ sc = qman_sc;
+ thread_lock(curthread);
+ sched_bind(curthread, sc->sc_fqr_cpu[QM_FQR_GetFqid(fqr)]);
+ thread_unlock(curthread);
+
+ error = QM_FQR_Free(fqr);
+
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+
+ return (error);
+}
+
+t_Error
+qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback,
+ t_Handle app)
+{
+ struct qman_softc *sc;
+ t_Error error;
+ t_Handle portal;
+
+ sc = qman_sc;
+ sched_pin();
+
+ /* Ensure we have got QMan port initialized */
+ portal = qman_portal_setup(sc);
+ if (portal == NULL) {
+ device_printf(sc->sc_dev, "could not setup QMan portal\n");
+ sched_unpin();
+ return (E_NOT_SUPPORTED);
+ }
+
+ error = QM_FQR_RegisterCB(fqr, callback, app);
+
+ sched_unpin();
+
+ return (error);
+}
+
+t_Error
+qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame)
+{
+ struct qman_softc *sc;
+ t_Error error;
+ t_Handle portal;
+
+ sc = qman_sc;
+ sched_pin();
+
+ /* Ensure we have got QMan port initialized */
+ portal = qman_portal_setup(sc);
+ if (portal == NULL) {
+ device_printf(sc->sc_dev, "could not setup QMan portal\n");
+ sched_unpin();
+ return (E_NOT_SUPPORTED);
+ }
+
+ error = QM_FQR_Enqueue(fqr, portal, fqid_off, frame);
+
+ sched_unpin();
+
+ return (error);
+}
+
+uint32_t
+qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off,
+ e_QmFqrCounters counter)
+{
+ struct qman_softc *sc;
+ uint32_t val;
+ t_Handle portal;
+
+ sc = qman_sc;
+ sched_pin();
+
+ /* Ensure we have got QMan port initialized */
+ portal = qman_portal_setup(sc);
+ if (portal == NULL) {
+ device_printf(sc->sc_dev, "could not setup QMan portal\n");
+ sched_unpin();
+ return (0);
+ }
+
+ val = QM_FQR_GetCounter(fqr, portal, fqid_off, counter);
+
+ sched_unpin();
+
+ return (val);
+}
+
+t_Error
+qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame)
+{
+ struct qman_softc *sc;
+ t_Error error;
+ t_Handle portal;
+
+ sc = qman_sc;
+ sched_pin();
+
+ /* Ensure we have got QMan port initialized */
+ portal = qman_portal_setup(sc);
+ if (portal == NULL) {
+ device_printf(sc->sc_dev, "could not setup QMan portal\n");
+ sched_unpin();
+ return (E_NOT_SUPPORTED);
+ }
+
+ error = QM_FQR_PullFrame(fqr, portal, fqid_off, frame);
+
+ sched_unpin();
+
+ return (error);
+}
+
+uint32_t
+qman_fqr_get_base_fqid(t_Handle fqr)
+{
+ struct qman_softc *sc;
+ uint32_t val;
+ t_Handle portal;
+
+ sc = qman_sc;
+ sched_pin();
+
+ /* Ensure we have got QMan port initialized */
+ portal = qman_portal_setup(sc);
+ if (portal == NULL) {
+ device_printf(sc->sc_dev, "could not setup QMan portal\n");
+ sched_unpin();
+ return (0);
+ }
+
+ val = QM_FQR_GetFqid(fqr);
+
+ sched_unpin();
+
+ return (val);
+}
+
+t_Error
+qman_poll(e_QmPortalPollSource source)
+{
+ struct qman_softc *sc;
+ t_Error error;
+ t_Handle portal;
+
+ sc = qman_sc;
+ sched_pin();
+
+ /* Ensure we have got QMan port initialized */
+ portal = qman_portal_setup(sc);
+ if (portal == NULL) {
+ device_printf(sc->sc_dev, "could not setup QMan portal\n");
+ sched_unpin();
+ return (E_NOT_SUPPORTED);
+ }
+
+ error = QM_Poll(sc->sc_qh, source);
+
+ sched_unpin();
+
+ return (error);
+}
+
+/*
+ * TODO: add polling and/or congestion support.
+ */
+
+/** @} */
diff --git a/sys/dev/dpaa/qman.h b/sys/dev/dpaa/qman.h
new file mode 100644
index 000000000000..97331bbedeee
--- /dev/null
+++ b/sys/dev/dpaa/qman.h
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _QMAN_H
+#define _QMAN_H
+
+#include <machine/vmparam.h>
+
+#include <contrib/ncsw/inc/Peripherals/qm_ext.h>
+
+
+/**
+ * @group QMan private defines/declarations
+ * @{
+ */
+/**
+ * Maximum number of frame queues in all QMans.
+ */
+#define QMAN_MAX_FQIDS 16
+
+/**
+ * Pool channel common to all software portals.
+ * @note Value of 0 reflects the e_QM_FQ_CHANNEL_POOL1 from e_QmFQChannel
+ * type used in qman_fqr_create().
+ */
+#define QMAN_COMMON_POOL_CHANNEL 0
+
+#define QMAN_FQID_BASE 1
+
+#define QMAN_CCSR_SIZE 0x1000
+
+/*
+ * Portal defines
+ */
+#define QMAN_CE_PA(base) (base)
+#define QMAN_CI_PA(base) ((base) + 0x100000)
+
+#define QMAN_PORTAL_CE_PA(base, n) \
+ (QMAN_CE_PA(base) + ((n) * QMAN_PORTAL_CE_SIZE))
+#define QMAN_PORTAL_CI_PA(base, n) \
+ (QMAN_CI_PA(base) + ((n) * QMAN_PORTAL_CI_SIZE))
+
+struct qman_softc {
+ device_t sc_dev; /* device handle */
+ int sc_rrid; /* register rid */
+ struct resource *sc_rres; /* register resource */
+ int sc_irid; /* interrupt rid */
+ struct resource *sc_ires; /* interrupt resource */
+
+ bool sc_regs_mapped[MAXCPU];
+
+ t_Handle sc_qh; /* QMAN handle */
+ t_Handle sc_qph[MAXCPU]; /* QMAN portal handles */
+ vm_paddr_t sc_qp_pa; /* QMAN portal PA */
+
+ int sc_fqr_cpu[QMAN_MAX_FQIDS];
+};
+/** @> */
+
+
+/**
+ * @group QMan bus interface
+ * @{
+ */
+int qman_attach(device_t dev);
+int qman_detach(device_t dev);
+int qman_suspend(device_t dev);
+int qman_resume(device_t dev);
+int qman_shutdown(device_t dev);
+/** @> */
+
+
+/**
+ * @group QMan API
+ * @{
+ */
+
+/**
+ * Create Frame Queue Range.
+ *
+ * @param fqids_num Number of frame queues in the range.
+ *
+ * @param channel Dedicated channel serviced by this
+ * Frame Queue Range.
+ *
+ * @param wq Work Queue Number within the channel.
+ *
+ * @param force_fqid If TRUE, fore allocation of specific
+ * FQID. Notice that there can not be two
+ * frame queues with the same ID in the
+ * system.
+ *
+ * @param fqid_or_align FQID if @force_fqid == TRUE, alignment
+ * of FQIDs entries otherwise.
+ *
+ * @param init_parked If TRUE, FQ state is initialized to
+ * "parked" state on creation. Otherwise,
+ * to "scheduled" state.
+ *
+ * @param hold_active If TRUE, the FQ may be held in the
+ * portal in "held active" state in
+ * anticipation of more frames being
+ * dequeued from it after the head frame
+ * is removed from the FQ and the dequeue
+ * response is returned. If FALSE the
+ * "held_active" state of the FQ is not
+ * allowed. This affects only on queues
+ * destined to software portals. Refer to
+ * the 6.3.4.6 of DPAA Reference Manual.
+ *
+ * @param prefer_in_cache If TRUE, prefer this FQR to be in QMan
+ * internal cache memory for all states.
+ *
+ * @param congst_avoid_ena If TRUE, enable congestion avoidance
+ * mechanism.
+ *
+ * @param congst_group A handle to the congestion group. Only
+ * relevant when @congst_avoid_ena == TRUE.
+ *
+ * @param overhead_accounting_len For each frame add this number for CG
+ * calculation (may be negative), if 0 -
+ * disable feature.
+ *
+ * @param tail_drop_threshold If not 0 - enable tail drop on this
+ * FQR.
+ *
+ * @return A handle to newly created FQR object.
+ */
+t_Handle qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq,
+ bool force_fqid, uint32_t fqid_or_align, bool init_parked,
+ bool hold_active, bool prefer_in_cache, bool congst_avoid_ena,
+ t_Handle congst_group, int8_t overhead_accounting_len,
+ uint32_t tail_drop_threshold);
+
+/**
+ * Free Frame Queue Range.
+ *
+ * @param fqr A handle to FQR to be freed.
+ * @return E_OK on success; error code otherwise.
+ */
+t_Error qman_fqr_free(t_Handle fqr);
+
+/**
+ * Register the callback function.
+ * The callback function will be called when a frame comes from this FQR.
+ *
+ * @param fqr A handle to FQR.
+ * @param callback A pointer to the callback function.
+ * @param app A pointer to the user's data.
+ * @return E_OK on success; error code otherwise.
+ */
+t_Error qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback,
+ t_Handle app);
+
+/**
+ * Enqueue a frame on a given FQR.
+ *
+ * @param fqr A handle to FQR.
+ * @param fqid_off FQID offset wihin the FQR.
+ * @param frame A frame to be enqueued to the transmission.
+ * @return E_OK on success; error code otherwise.
+ */
+t_Error qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame);
+
+/**
+ * Get one of the FQR counter's value.
+ *
+ * @param fqr A handle to FQR.
+ * @param fqid_off FQID offset within the FQR.
+ * @param counter The requested counter.
+ * @return Counter's current value.
+ */
+uint32_t qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off,
+ e_QmFqrCounters counter);
+
+/**
+ * Pull frame from FQR.
+ *
+ * @param fqr A handle to FQR.
+ * @param fqid_off FQID offset within the FQR.
+ * @param frame The received frame.
+ * @return E_OK on success; error code otherwise.
+ */
+t_Error qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame);
+
+/**
+ * Get base FQID of the FQR.
+ * @param fqr A handle to FQR.
+ * @return Base FQID of the FQR.
+ */
+uint32_t qman_fqr_get_base_fqid(t_Handle fqr);
+
+/**
+ * Poll frames from QMan.
+ * This polls frames from the current software portal.
+ *
+ * @param source Type of frames to be polled.
+ * @return E_OK on success; error otherwise.
+ */
+t_Error qman_poll(e_QmPortalPollSource source);
+
+/**
+ * General received frame callback.
+ * This is called, when user did not register his own callback for a given
+ * frame queue range (fqr).
+ */
+e_RxStoreResponse qman_received_frame_callback(t_Handle app, t_Handle qm_fqr,
+ t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame);
+
+/**
+ * General rejected frame callback.
+ * This is called, when user did not register his own callback for a given
+ * frame queue range (fqr).
+ */
+e_RxStoreResponse qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr,
+ t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame,
+ t_QmRejectedFrameInfo *qm_rejected_frame_info);
+
+/** @} */
+
+#endif /* QMAN_H */
diff --git a/sys/dev/dpaa/qman_fdt.c b/sys/dev/dpaa/qman_fdt.c
new file mode 100644
index 000000000000..4df8c05b84e0
--- /dev/null
+++ b/sys/dev/dpaa/qman_fdt.c
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 2011-2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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 "opt_platform.h"
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_subr.h>
+
+#include "qman.h"
+#include "portals.h"
+
+#define FBMAN_DEVSTR "Freescale Queue Manager"
+
+static int qman_fdt_probe(device_t);
+
+static device_method_t qman_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, qman_fdt_probe),
+ DEVMETHOD(device_attach, qman_attach),
+ DEVMETHOD(device_detach, qman_detach),
+
+ DEVMETHOD(device_suspend, qman_suspend),
+ DEVMETHOD(device_resume, qman_resume),
+ DEVMETHOD(device_shutdown, qman_shutdown),
+
+ { 0, 0 }
+};
+
+static driver_t qman_driver = {
+ "qman",
+ qman_methods,
+ sizeof(struct qman_softc),
+};
+
+static devclass_t qman_devclass;
+DRIVER_MODULE(qman, simplebus, qman_driver, qman_devclass, 0, 0);
+
+static int
+qman_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "fsl,qman"))
+ return (ENXIO);
+
+ device_set_desc(dev, FBMAN_DEVSTR);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+/*
+ * BMAN Portals
+ */
+#define BMAN_PORT_DEVSTR "Freescale Queue Manager - Portals"
+
+static device_probe_t qman_portals_fdt_probe;
+static device_attach_t qman_portals_fdt_attach;
+
+static device_method_t bm_portals_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, qman_portals_fdt_probe),
+ DEVMETHOD(device_attach, qman_portals_fdt_attach),
+ DEVMETHOD(device_detach, qman_portals_detach),
+
+ { 0, 0 }
+};
+
+static driver_t bm_portals_driver = {
+ "qman-portals",
+ bm_portals_methods,
+ sizeof(struct dpaa_portals_softc),
+};
+
+static devclass_t bm_portals_devclass;
+DRIVER_MODULE(qman_portals, ofwbus, bm_portals_driver, bm_portals_devclass, 0, 0);
+
+static void
+get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep)
+{
+
+ *addrp = 2;
+ *sizep = 1;
+ OF_getencprop(node, "#address-cells", addrp, sizeof(*addrp));
+ OF_getencprop(node, "#size-cells", sizep, sizeof(*sizep));
+}
+
+static int
+qman_portals_fdt_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "qman-portals"))
+ return (ENXIO);
+
+ device_set_desc(dev, BMAN_PORT_DEVSTR);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+qman_portals_fdt_attach(device_t dev)
+{
+ struct dpaa_portals_softc *sc;
+ struct resource_list_entry *rle;
+ phandle_t node, child, cpu_node;
+ vm_paddr_t portal_pa;
+ vm_size_t portal_size;
+ uint32_t addr, size;
+ ihandle_t cpu;
+ int cpu_num, cpus, intr_rid;
+ struct dpaa_portals_devinfo di;
+ struct ofw_bus_devinfo ofw_di;
+
+ cpus = 0;
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ node = ofw_bus_get_node(dev);
+ get_addr_props(node, &addr, &size);
+
+ /* Find portals tied to CPUs */
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ if (!fdt_is_compatible(child, "fsl,qman-portal")) {
+ continue;
+ }
+ /* Checkout related cpu */
+ if (OF_getprop(child, "cpu-handle", (void *)&cpu,
+ sizeof(cpu)) <= 0) {
+ continue;
+ }
+ /* Acquire cpu number */
+ cpu_node = OF_instance_to_package(cpu);
+ if (OF_getencprop(cpu_node, "reg", &cpu_num, sizeof(cpu_num)) <= 0) {
+ device_printf(dev, "Could not retrieve CPU number.\n");
+ return (ENXIO);
+ }
+
+ cpus++;
+
+ if (cpus > MAXCPU)
+ break;
+
+ if (ofw_bus_gen_setup_devinfo(&ofw_di, child) != 0) {
+ device_printf(dev, "could not set up devinfo\n");
+ continue;
+ }
+
+ resource_list_init(&di.di_res);
+ if (ofw_bus_reg_to_rl(dev, child, addr, size, &di.di_res)) {
+ device_printf(dev, "%s: could not process 'reg' "
+ "property\n", ofw_di.obd_name);
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+ continue;
+ }
+ if (ofw_bus_intr_to_rl(dev, child, &di.di_res, &intr_rid)) {
+ device_printf(dev, "%s: could not process "
+ "'interrupts' property\n", ofw_di.obd_name);
+ resource_list_free(&di.di_res);
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+ continue;
+ }
+ di.di_intr_rid = intr_rid;
+
+ ofw_reg_to_paddr(child, 0, &portal_pa, &portal_size, NULL);
+ rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 0);
+
+ if (sc->sc_dp_pa == 0)
+ sc->sc_dp_pa = portal_pa - rle->start;
+
+ portal_size = rle->end + 1;
+ rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 1);
+ portal_size = ulmax(rle->end + 1, portal_size);
+ sc->sc_dp_size = ulmax(sc->sc_dp_size, portal_size);
+
+ if (dpaa_portal_alloc_res(dev, &di, cpu_num))
+ goto err;
+ }
+
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+
+ return (qman_portals_attach(dev));
+err:
+ resource_list_free(&di.di_res);
+ ofw_bus_gen_destroy_devinfo(&ofw_di);
+ qman_portals_detach(dev);
+ return (ENXIO);
+}
diff --git a/sys/dev/dpaa/qman_portals.c b/sys/dev/dpaa/qman_portals.c
new file mode 100644
index 000000000000..8f39307aeb96
--- /dev/null
+++ b/sys/dev/dpaa/qman_portals.c
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 2012 Semihalf.
+ * All rights reserved.
+ *
+ * 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 "opt_platform.h"
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/sched.h>
+
+#include <machine/bus.h>
+#include <machine/tlb.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <powerpc/mpc85xx/mpc85xx.h>
+
+#include "qman.h"
+#include "portals.h"
+
+extern e_RxStoreResponse qman_received_frame_callback(t_Handle, t_Handle,
+ t_Handle, uint32_t, t_DpaaFD *);
+extern e_RxStoreResponse qman_rejected_frame_callback(t_Handle, t_Handle,
+ t_Handle, uint32_t, t_DpaaFD *, t_QmRejectedFrameInfo *);
+
+t_Handle qman_portal_setup(struct qman_softc *);
+
+struct dpaa_portals_softc *qp_sc;
+
+int
+qman_portals_attach(device_t dev)
+{
+ struct dpaa_portals_softc *sc;
+
+ sc = qp_sc = device_get_softc(dev);
+
+ /* Map bman portal to physical address space */
+ if (law_enable(OCP85XX_TGTIF_QMAN, sc->sc_dp_pa, sc->sc_dp_size)) {
+ qman_portals_detach(dev);
+ return (ENXIO);
+ }
+ /* Set portal properties for XX_VirtToPhys() */
+ XX_PortalSetInfo(dev);
+
+ return (bus_generic_attach(dev));
+}
+
+int
+qman_portals_detach(device_t dev)
+{
+ struct dpaa_portals_softc *sc;
+ int i;
+
+ qp_sc = NULL;
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < ARRAY_SIZE(sc->sc_dp); i++) {
+ if (sc->sc_dp[i].dp_ph != NULL) {
+ thread_lock(curthread);
+ sched_bind(curthread, i);
+ thread_unlock(curthread);
+
+ QM_PORTAL_Free(sc->sc_dp[i].dp_ph);
+
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+ }
+
+ if (sc->sc_dp[i].dp_ires != NULL) {
+ XX_DeallocIntr((int)sc->sc_dp[i].dp_ires);
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires);
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(sc->sc_rres); i++) {
+ if (sc->sc_rres[i] != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->sc_rrid[i],
+ sc->sc_rres[i]);
+ }
+
+ return (0);
+}
+
+t_Handle
+qman_portal_setup(struct qman_softc *qsc)
+{
+ struct dpaa_portals_softc *sc;
+ t_QmPortalParam qpp;
+ unsigned int cpu, p;
+ t_Handle portal;
+
+ /* Return NULL if we're not ready or while detach */
+ if (qp_sc == NULL)
+ return (NULL);
+
+ sc = qp_sc;
+
+ sched_pin();
+ portal = NULL;
+ cpu = PCPU_GET(cpuid);
+
+ /* Check if portal is ready */
+ while (atomic_cmpset_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph,
+ 0, -1) == 0) {
+ p = atomic_load_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph);
+
+ /* Return if portal is already initialized */
+ if (p != 0 && p != -1) {
+ sched_unpin();
+ return ((t_Handle)p);
+ }
+
+ /* Not inititialized and "owned" by another thread */
+ thread_lock(curthread);
+ mi_switch(SW_VOL, NULL);
+ thread_unlock(curthread);
+ }
+
+ /* Map portal registers */
+ dpaa_portal_map_registers(sc);
+
+ /* Configure and initialize portal */
+ qpp.ceBaseAddress = rman_get_bushandle(sc->sc_rres[0]);
+ qpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]);
+ qpp.h_Qm = qsc->sc_qh;
+ qpp.swPortalId = cpu;
+ qpp.irq = (int)sc->sc_dp[cpu].dp_ires;
+ qpp.fdLiodnOffset = 0;
+ qpp.f_DfltFrame = qman_received_frame_callback;
+ qpp.f_RejectedFrame = qman_rejected_frame_callback;
+ qpp.h_App = qsc;
+
+ portal = QM_PORTAL_Config(&qpp);
+ if (portal == NULL)
+ goto err;
+
+ if (QM_PORTAL_Init(portal) != E_OK)
+ goto err;
+
+ if (QM_PORTAL_AddPoolChannel(portal, QMAN_COMMON_POOL_CHANNEL) != E_OK)
+ goto err;
+
+ atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph,
+ (uint32_t)portal);
+ sched_unpin();
+
+ return (portal);
+
+err:
+ if (portal != NULL)
+ QM_PORTAL_Free(portal);
+
+ atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, 0);
+ sched_unpin();
+
+ return (NULL);
+}