git: 8e994533806d - main - dpaa2: Extract frame-specific routines to dpaa2_frame.[h,c]

From: Dmitry Salychev <dsl_at_FreeBSD.org>
Date: Wed, 08 Apr 2026 19:48:53 UTC
The branch main has been updated by dsl:

URL: https://cgit.FreeBSD.org/src/commit/?id=8e994533806d8aa0ae4582a52d811ede2b19bb26

commit 8e994533806d8aa0ae4582a52d811ede2b19bb26
Author:     Dmitry Salychev <dsl@FreeBSD.org>
AuthorDate: 2026-01-25 16:53:57 +0000
Commit:     Dmitry Salychev <dsl@FreeBSD.org>
CommitDate: 2026-04-08 19:48:11 +0000

    dpaa2: Extract frame-specific routines to dpaa2_frame.[h,c]
    
    As soon as we need information from the hardware frame annotation to
    make sure that checksums of the ingress frames were verified by the
    DPAA2 HW, I've decided to make a preparation and extracted all of the
    frame related routines into the separate dpaa2_frame.[h,c] along with
    some clean up and improvements, e.g. no more dpaa2_fa, but dpaa2_swa
    and dpaa2_hwa structures to describe software and hardware frame
    annotations respectively, dpaa2_fa_get_swa/dpaa2_fa_get_hwa to obtain
    those annotations from the frame descriptor. The next step is to
    implement dpaa2_fa_get_hwa.
    
    PR:             292006
    Approved by:    tuexen
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D56315
---
 sys/conf/files.arm64        |   1 +
 sys/dev/dpaa2/dpaa2_buf.c   |   9 +-
 sys/dev/dpaa2/dpaa2_buf.h   |   2 +
 sys/dev/dpaa2/dpaa2_frame.c | 165 ++++++++++++++++++++++++++++++++++
 sys/dev/dpaa2/dpaa2_frame.h | 174 ++++++++++++++++++++++++++++++++++++
 sys/dev/dpaa2/dpaa2_ni.c    | 210 ++++++++++++++------------------------------
 sys/dev/dpaa2/dpaa2_ni.h    |   3 +-
 sys/dev/dpaa2/dpaa2_swp.h   |  51 +----------
 sys/dev/dpaa2/dpaa2_types.h |   5 ++
 sys/modules/dpaa2/Makefile  |   1 +
 10 files changed, 420 insertions(+), 201 deletions(-)

diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 2a607748db8d..59a65a8251ca 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -262,6 +262,7 @@ dev/dpaa2/dpaa2_channel.c			optional soc_nxp_ls dpaa2
 dev/dpaa2/dpaa2_cmd_if.m			optional soc_nxp_ls dpaa2
 dev/dpaa2/dpaa2_con.c				optional soc_nxp_ls dpaa2
 dev/dpaa2/dpaa2_console.c			optional soc_nxp_ls dpaa2 fdt
+dev/dpaa2/dpaa2_frame.c				optional soc_nxp_ls dpaa2
 dev/dpaa2/dpaa2_io.c				optional soc_nxp_ls dpaa2
 dev/dpaa2/dpaa2_mac.c				optional soc_nxp_ls dpaa2
 dev/dpaa2/dpaa2_mc.c				optional soc_nxp_ls dpaa2
diff --git a/sys/dev/dpaa2/dpaa2_buf.c b/sys/dev/dpaa2/dpaa2_buf.c
index 8505b074fe4f..228e4448210d 100644
--- a/sys/dev/dpaa2/dpaa2_buf.c
+++ b/sys/dev/dpaa2/dpaa2_buf.c
@@ -42,6 +42,7 @@
 #include "dpaa2_swp.h"
 #include "dpaa2_swp_if.h"
 #include "dpaa2_ni.h"
+#include "dpaa2_frame.h"
 
 MALLOC_DEFINE(M_DPAA2_RXB, "dpaa2_rxb", "DPAA2 DMA-mapped buffer (Rx)");
 
@@ -129,7 +130,7 @@ dpaa2_buf_seed_rxb(device_t dev, struct dpaa2_buf *buf, int size,
     struct mtx *dma_mtx)
 {
 	struct dpaa2_ni_softc *sc = device_get_softc(dev);
-	struct dpaa2_fa *fa;
+	struct dpaa2_swa *swa;
 	bool map_created = false;
 	bool mbuf_alloc = false;
 	int error;
@@ -179,9 +180,9 @@ dpaa2_buf_seed_rxb(device_t dev, struct dpaa2_buf *buf, int size,
 	buf->vaddr = buf->m->m_data;
 
 	/* Populate frame annotation for future use */
-	fa = (struct dpaa2_fa *)buf->vaddr;
-	fa->magic = DPAA2_MAGIC;
-	fa->buf = buf;
+	swa = (struct dpaa2_swa *)buf->vaddr;
+	swa->magic = DPAA2_MAGIC;
+	swa->buf = buf;
 
 	bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_PREREAD);
 
diff --git a/sys/dev/dpaa2/dpaa2_buf.h b/sys/dev/dpaa2/dpaa2_buf.h
index 853a4fa78d3a..16ea7e1905ac 100644
--- a/sys/dev/dpaa2/dpaa2_buf.h
+++ b/sys/dev/dpaa2/dpaa2_buf.h
@@ -33,6 +33,8 @@
 #include <sys/malloc.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
 
 #include <machine/bus.h>
 
diff --git a/sys/dev/dpaa2/dpaa2_frame.c b/sys/dev/dpaa2/dpaa2_frame.c
new file mode 100644
index 000000000000..4a155f7cb32f
--- /dev/null
+++ b/sys/dev/dpaa2/dpaa2_frame.c
@@ -0,0 +1,165 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright © 2026 Dmitry Salychev
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/errno.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/vmparam.h>
+
+#include "dpaa2_types.h"
+#include "dpaa2_frame.h"
+#include "dpaa2_buf.h"
+#include "dpaa2_swp.h"
+
+/**
+ * @brief Build a DPAA2 frame descriptor.
+ */
+int
+dpaa2_fd_build(device_t dev, const uint16_t tx_data_off, struct dpaa2_buf *buf,
+    bus_dma_segment_t *segs, const int nsegs, struct dpaa2_fd *fd)
+{
+	struct dpaa2_buf *sgt = buf->sgt;
+	struct dpaa2_sg_entry *sge;
+	struct dpaa2_swa *swa;
+	int i, error;
+
+	if (buf == NULL || segs == NULL || nsegs == 0 || fd == NULL)
+		return (EINVAL);
+
+	KASSERT(nsegs <= DPAA2_TX_SEGLIMIT, ("%s: too many segments", __func__));
+	KASSERT(buf->opt != NULL, ("%s: no Tx ring?", __func__));
+	KASSERT(sgt != NULL, ("%s: no S/G table?", __func__));
+	KASSERT(sgt->vaddr != NULL, ("%s: no S/G vaddr?", __func__));
+
+	memset(fd, 0, sizeof(*fd));
+
+	/* Populate and map S/G table */
+	if (__predict_true(nsegs <= DPAA2_TX_SEGLIMIT)) {
+		sge = (struct dpaa2_sg_entry *)sgt->vaddr + tx_data_off;
+		for (i = 0; i < nsegs; i++) {
+			sge[i].addr = (uint64_t)segs[i].ds_addr;
+			sge[i].len = (uint32_t)segs[i].ds_len;
+			sge[i].offset_fmt = 0u;
+		}
+		sge[i-1].offset_fmt |= 0x8000u; /* set final entry flag */
+
+		KASSERT(sgt->paddr == 0, ("%s: paddr(%#jx) != 0", __func__,
+		    sgt->paddr));
+
+		error = bus_dmamap_load(sgt->dmat, sgt->dmap, sgt->vaddr,
+		    DPAA2_TX_SGT_SZ, dpaa2_dmamap_oneseg_cb, &sgt->paddr,
+		    BUS_DMA_NOWAIT);
+		if (__predict_false(error != 0)) {
+			device_printf(dev, "%s: bus_dmamap_load() failed: "
+			    "error=%d\n", __func__, error);
+			return (error);
+		}
+
+		buf->paddr = sgt->paddr;
+		buf->vaddr = sgt->vaddr;
+	} else {
+		return (EINVAL);
+	}
+
+	swa = (struct dpaa2_swa *)sgt->vaddr;
+	swa->magic = DPAA2_MAGIC;
+	swa->buf = buf;
+
+	fd->addr = buf->paddr;
+	fd->data_length = (uint32_t)buf->m->m_pkthdr.len;
+	fd->bpid_ivp_bmt = 0;
+	fd->offset_fmt_sl = 0x2000u | tx_data_off;
+	fd->ctrl = (0x4u & DPAA2_FD_PTAC_MASK) << DPAA2_FD_PTAC_SHIFT;
+
+	return (0);
+}
+
+int
+dpaa2_fd_err(struct dpaa2_fd *fd)
+{
+	return ((fd->ctrl >> DPAA2_FD_ERR_SHIFT) & DPAA2_FD_ERR_MASK);
+}
+
+uint32_t
+dpaa2_fd_data_len(struct dpaa2_fd *fd)
+{
+	if (dpaa2_fd_short_len(fd)) {
+		return (fd->data_length & DPAA2_FD_LEN_MASK);
+	}
+	return (fd->data_length);
+}
+
+int
+dpaa2_fd_format(struct dpaa2_fd *fd)
+{
+	return ((enum dpaa2_fd_format)((fd->offset_fmt_sl >>
+	    DPAA2_FD_FMT_SHIFT) & DPAA2_FD_FMT_MASK));
+}
+
+bool
+dpaa2_fd_short_len(struct dpaa2_fd *fd)
+{
+	return (((fd->offset_fmt_sl >> DPAA2_FD_SL_SHIFT)
+	    & DPAA2_FD_SL_MASK) == 1);
+}
+
+int
+dpaa2_fd_offset(struct dpaa2_fd *fd)
+{
+	return (fd->offset_fmt_sl & DPAA2_FD_OFFSET_MASK);
+}
+
+int
+dpaa2_fa_get_swa(struct dpaa2_fd *fd, struct dpaa2_swa **swa)
+{
+	int rc;
+
+	if (fd == NULL || swa == NULL)
+		return (EINVAL);
+
+	if (((fd->ctrl >> DPAA2_FD_PTAC_SHIFT) & DPAA2_FD_PTAC_MASK) >= 0x4u) {
+		*swa = (struct dpaa2_swa *)PHYS_TO_DMAP((bus_addr_t)fd->addr);
+		rc = 0;
+	} else {
+		*swa = NULL;
+		rc = ENOENT;
+	}
+
+	return (rc);
+}
+
+int
+dpaa2_fa_get_hwa(struct dpaa2_fd *fd, struct dpaa2_hwa **hwa)
+{
+	/* TODO: To be implemented next. */
+	return (ENOENT);
+}
diff --git a/sys/dev/dpaa2/dpaa2_frame.h b/sys/dev/dpaa2/dpaa2_frame.h
new file mode 100644
index 000000000000..0b2a5a7d8e74
--- /dev/null
+++ b/sys/dev/dpaa2/dpaa2_frame.h
@@ -0,0 +1,174 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright © 2026 Dmitry Salychev
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DPAA2_FRAME_H
+#define _DPAA2_FRAME_H
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/kassert.h>
+
+#include "dpaa2_types.h"
+#include "dpaa2_buf.h"
+
+/*
+ * Helper routines for the DPAA2 frames (e.g. descriptors, software/hardware
+ * annotations, etc.).
+ */
+
+/*
+ * DPAA2 frame descriptor size, field offsets and masks.
+ *
+ * See 3.1.1 Frame descriptor format,
+ *     4.2.1.2.2 Structure of Frame Descriptors (FDs),
+ * LX2160A DPAA2 Low-Level Hardware Reference Manual, Rev. 0, 06/2020
+ */
+#define DPAA2_FD_SIZE		32u
+#define DPAA2_FD_FMT_MASK	(0x3u)
+#define DPAA2_FD_FMT_SHIFT	(12)
+#define DPAA2_FD_ERR_MASK	(0xFFu)
+#define DPAA2_FD_ERR_SHIFT	(0)
+#define DPAA2_FD_SL_MASK	(0x1u)
+#define DPAA2_FD_SL_SHIFT	(14)
+#define DPAA2_FD_LEN_MASK	(0x3FFFFu)
+#define DPAA2_FD_OFFSET_MASK	(0x0FFFu)
+#define DPAA2_FD_PTAC_MASK	(0x7u)
+#define DPAA2_FD_PTAC_SHIFT	(21)
+
+/*
+ * DPAA2 frame annotation sizes
+ *
+ * NOTE: Accelerator-specific (HWA) annotation length is described in the 64-byte
+ *       units by the FD[ASAL] bits and can be as big as 960 bytes. Current
+ *       values describe what is actually supported by the DPAA2 drivers.
+ *
+ * See 3.1.1 Frame descriptor format,
+ * LX2160A DPAA2 Low-Level Hardware Reference Manual, Rev. 0
+ */
+#define DPAA2_FA_SIZE			192u	/* DPAA2 frame annotation */
+#define DPAA2_FA_SWA_SIZE		64u	/* SW frame annotation */
+#define DPAA2_FA_HWA_SIZE		128u	/* HW frame annotation */
+#define DPAA2_FA_WRIOP_SIZE		128u	/* WRIOP HW annotation */
+
+/**
+ * @brief DPAA2 frame descriptor.
+ *
+ * addr:		Memory address of the start of the buffer holding the
+ *			frame data or the buffer containing the scatter/gather
+ *			list.
+ * data_length:		Length of the frame data (in bytes).
+ * bpid_ivp_bmt:	Buffer pool ID (14 bit + BMT bit + IVP bit)
+ * offset_fmt_sl:	Frame data offset, frame format and short-length fields.
+ * frame_ctx:		Frame context. This field allows the sender of a frame
+ *			to communicate some out-of-band information to the
+ *			receiver of the frame.
+ * ctrl:		Control bits (ERR, CBMT, ASAL, PTAC, DROPP, SC, DD).
+ * flow_ctx:		Frame flow context. Associates the frame with a flow
+ *			structure. QMan may use the FLC field for 3 purposes:
+ *			stashing control, order definition point identification,
+ *			and enqueue replication control.
+ *
+ * See 3.1.1 Frame descriptor format,
+ *     4.2.1.2.2 Structure of Frame Descriptors (FDs),
+ * LX2160A DPAA2 Low-Level Hardware Reference Manual, Rev. 0, 06/2020
+ */
+struct dpaa2_fd {
+	uint64_t	addr;
+	uint32_t	data_length;
+	uint16_t	bpid_ivp_bmt;
+	uint16_t	offset_fmt_sl;
+	uint32_t	frame_ctx;
+	uint32_t	ctrl;
+	uint64_t	flow_ctx;
+} __packed;
+CTASSERT(sizeof(struct dpaa2_fd) == DPAA2_FD_SIZE);
+
+/**
+ * @brief WRIOP hardware frame annotation.
+ *
+ * See 7.34.2 WRIOP hardware frame annotation (FA),
+ * LX2160A DPAA2 Low-Level Hardware Reference Manual, Rev. 0, 06/2020
+ */
+struct dpaa2_hwa_wriop {
+	union {
+		struct {
+			uint64_t fas;
+			uint64_t timestamp;
+			/* XXX-DSL: more to add here... */
+		} __packed;
+		uint8_t raw[128];
+	};
+} __packed;
+CTASSERT(sizeof(struct dpaa2_hwa_wriop) == DPAA2_FA_WRIOP_SIZE);
+
+/**
+ * @brief DPAA2 hardware frame annotation (accelerator-specific annotation).
+ *
+ * See 3.4.1.2 Accelerator-specific annotation,
+ * LX2160A DPAA2 Low-Level Hardware Reference Manual, Rev. 0, 06/2020 
+ */
+struct dpaa2_hwa {
+	union {
+		struct dpaa2_hwa_wriop wriop;
+	};
+} __packed;
+CTASSERT(sizeof(struct dpaa2_hwa) == DPAA2_FA_HWA_SIZE);
+
+/**
+ * @brief DPAA2 software frame annotation (pass-through annotation).
+ *
+ * See 3.4.1.1 Pass-through annotation,
+ * LX2160A DPAA2 Low-Level Hardware Reference Manual, Rev. 0, 06/2020
+ */
+struct dpaa2_swa {
+	union {
+		struct {
+			uint32_t	  magic;
+			struct dpaa2_buf *buf;
+		};
+		struct {
+			uint8_t pta1[32];
+			uint8_t pta2[32];
+		};
+		uint8_t raw[64];
+	};
+} __packed;
+CTASSERT(sizeof(struct dpaa2_swa) == DPAA2_FA_SWA_SIZE);
+
+int  dpaa2_fd_build(device_t, const uint16_t, struct dpaa2_buf *,
+    bus_dma_segment_t *, const int, struct dpaa2_fd *);
+
+int  dpaa2_fd_err(struct dpaa2_fd *);
+uint32_t dpaa2_fd_data_len(struct dpaa2_fd *);
+int  dpaa2_fd_format(struct dpaa2_fd *);
+bool dpaa2_fd_short_len(struct dpaa2_fd *);
+int  dpaa2_fd_offset(struct dpaa2_fd *);
+
+int  dpaa2_fa_get_swa(struct dpaa2_fd *, struct dpaa2_swa **);
+int  dpaa2_fa_get_hwa(struct dpaa2_fd *, struct dpaa2_hwa **);
+
+#endif /* _DPAA2_FRAME_H */
diff --git a/sys/dev/dpaa2/dpaa2_ni.c b/sys/dev/dpaa2/dpaa2_ni.c
index 49e72c8ee14f..5017b5113109 100644
--- a/sys/dev/dpaa2/dpaa2_ni.c
+++ b/sys/dev/dpaa2/dpaa2_ni.c
@@ -96,6 +96,7 @@
 #include "dpaa2_ni.h"
 #include "dpaa2_channel.h"
 #include "dpaa2_buf.h"
+#include "dpaa2_frame.h"
 
 #define BIT(x)			(1ul << (x))
 #define WRIOP_VERSION(x, y, z)	((x) << 10 | (y) << 5 | (z) << 0)
@@ -156,10 +157,6 @@ MALLOC_DEFINE(M_DPAA2_TXB, "dpaa2_txb", "DPAA2 DMA-mapped buffer (Tx)");
 #define DPAA2_RX_BUFRING_SZ	(4096u)
 #define DPAA2_RXE_BUFRING_SZ	(1024u)
 #define DPAA2_TXC_BUFRING_SZ	(4096u)
-#define DPAA2_TX_SEGLIMIT	(16u) /* arbitrary number */
-#define DPAA2_TX_SEG_SZ		(PAGE_SIZE)
-#define DPAA2_TX_SEGS_MAXSZ	(DPAA2_TX_SEGLIMIT * DPAA2_TX_SEG_SZ)
-#define DPAA2_TX_SGT_SZ		(PAGE_SIZE) /* bytes */
 
 /* Size of a buffer to keep a QoS table key configuration. */
 #define ETH_QOS_KCFG_BUF_SIZE	(PAGE_SIZE)
@@ -186,15 +183,6 @@ MALLOC_DEFINE(M_DPAA2_TXB, "dpaa2_txb", "DPAA2 DMA-mapped buffer (Tx)");
 #define DPAA2_NI_TXBUF_IDX_MASK	(0xFFu)
 #define DPAA2_NI_TXBUF_IDX_SHIFT (49)
 
-#define DPAA2_NI_FD_FMT_MASK	(0x3u)
-#define DPAA2_NI_FD_FMT_SHIFT	(12)
-#define DPAA2_NI_FD_ERR_MASK	(0xFFu)
-#define DPAA2_NI_FD_ERR_SHIFT	(0)
-#define DPAA2_NI_FD_SL_MASK	(0x1u)
-#define DPAA2_NI_FD_SL_SHIFT	(14)
-#define DPAA2_NI_FD_LEN_MASK	(0x3FFFFu)
-#define DPAA2_NI_FD_OFFSET_MASK (0x0FFFu)
-
 /* Enables TCAM for Flow Steering and QoS look-ups. */
 #define DPNI_OPT_HAS_KEY_MASKING 0x10
 
@@ -424,15 +412,6 @@ static int dpaa2_ni_set_mac_addr(device_t);
 static int dpaa2_ni_set_hash(device_t, uint64_t);
 static int dpaa2_ni_set_dist_key(device_t, enum dpaa2_ni_dist_mode, uint64_t);
 
-/* Frame descriptor routines */
-static int dpaa2_ni_build_fd(struct dpaa2_ni_softc *, struct dpaa2_ni_tx_ring *,
-    struct dpaa2_buf *, bus_dma_segment_t *, int, struct dpaa2_fd *);
-static int dpaa2_ni_fd_err(struct dpaa2_fd *);
-static uint32_t dpaa2_ni_fd_data_len(struct dpaa2_fd *);
-static int dpaa2_ni_fd_format(struct dpaa2_fd *);
-static bool dpaa2_ni_fd_short_len(struct dpaa2_fd *);
-static int dpaa2_ni_fd_offset(struct dpaa2_fd *);
-
 /* Various subroutines */
 static int dpaa2_ni_cmp_api_version(struct dpaa2_ni_softc *, uint16_t, uint16_t);
 static int dpaa2_ni_prepare_key_cfg(struct dpkg_profile_cfg *, uint8_t *);
@@ -2995,14 +2974,15 @@ dpaa2_ni_tx(struct dpaa2_ni_softc *sc, struct dpaa2_channel *ch,
 		}
 	}
 
-	error = dpaa2_ni_build_fd(sc, tx, buf, segs, nsegs, &fd);
+	error = dpaa2_fd_build(dev, sc->tx_data_off, buf, segs, nsegs, &fd);
 	if (__predict_false(error != 0)) {
 		device_printf(dev, "%s: failed to build frame descriptor: "
 		    "error=%d\n", __func__, error);
 		fq->chan->tx_dropped++;
 		if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
 		goto err_unload;
-	}
+	} else
+		sc->tx_sg_frames++; /* for sysctl(9) */
 
 	bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_PREWRITE);
 	bus_dmamap_sync(sgt->dmat, sgt->dmap, BUS_DMASYNC_PREWRITE);
@@ -3130,14 +3110,14 @@ dpaa2_ni_consume_frames(struct dpaa2_channel *chan, struct dpaa2_ni_fq **src,
  * @brief Receive frames.
  */
 static int
-dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, struct dpaa2_fd *fd,
-    struct dpaa2_ni_rx_ctx *ctx)
+dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq,
+    struct dpaa2_fd *fd, struct dpaa2_ni_rx_ctx *ctx)
 {
-	bus_addr_t paddr = (bus_addr_t)fd->addr;
-	struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr);
-	struct dpaa2_buf *buf = fa->buf;
-	struct dpaa2_channel *bch = (struct dpaa2_channel *)buf->opt;
-	struct dpaa2_ni_softc *sc = device_get_softc(bch->ni_dev);
+	bus_addr_t paddr;
+	struct dpaa2_swa *swa;
+	struct dpaa2_buf *buf;
+	struct dpaa2_channel *bch;
+	struct dpaa2_ni_softc *sc;
 	struct dpaa2_bp_softc *bpsc;
 	struct mbuf *m;
 	device_t bpdev;
@@ -3145,7 +3125,17 @@ dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, struct dpaa2_fd *f
 	void *buf_data;
 	int buf_len, error, released_n = 0;
 
-	KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
+	error = dpaa2_fa_get_swa(fd, &swa);
+	if (__predict_false(error != 0))
+		panic("%s: frame has no software annotation: error=%d",
+		    __func__, error);
+
+	paddr = (bus_addr_t)fd->addr;
+	buf = swa->buf;
+	bch = (struct dpaa2_channel *)buf->opt;
+	sc = device_get_softc(bch->ni_dev);
+
+	KASSERT(swa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
 	/*
 	 * NOTE: Current channel might not be the same as the "buffer" channel
 	 * and it's fine. It must not be NULL though.
@@ -3157,7 +3147,7 @@ dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, struct dpaa2_fd *f
 		    __func__, paddr, buf->paddr);
 	}
 
-	switch (dpaa2_ni_fd_err(fd)) {
+	switch (dpaa2_fd_err(fd)) {
 	case 1: /* Enqueue rejected by QMan */
 		sc->rx_enq_rej_frames++;
 		break;
@@ -3167,7 +3157,7 @@ dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, struct dpaa2_fd *f
 	default:
 		break;
 	}
-	switch (dpaa2_ni_fd_format(fd)) {
+	switch (dpaa2_fd_format(fd)) {
 	case DPAA2_FD_SINGLE:
 		sc->rx_single_buf_frames++;
 		break;
@@ -3183,9 +3173,11 @@ dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, struct dpaa2_fd *f
 
 	bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_POSTREAD);
 	bus_dmamap_unload(buf->dmat, buf->dmap);
+
 	m = buf->m;
-	buf_len = dpaa2_ni_fd_data_len(fd);
-	buf_data = (uint8_t *)buf->vaddr + dpaa2_ni_fd_offset(fd);
+	buf_len = dpaa2_fd_data_len(fd);
+	buf_data = (uint8_t *)buf->vaddr + dpaa2_fd_offset(fd);
+
 	/* Prepare buffer to be re-cycled */
 	buf->m = NULL;
 	buf->paddr = 0;
@@ -3273,16 +3265,26 @@ static int
 dpaa2_ni_rx_err(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq,
     struct dpaa2_fd *fd)
 {
-	bus_addr_t paddr = (bus_addr_t)fd->addr;
-	struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr);
-	struct dpaa2_buf *buf = fa->buf;
-	struct dpaa2_channel *bch = (struct dpaa2_channel *)buf->opt;
-	struct dpaa2_ni_softc *sc = device_get_softc(bch->ni_dev);
+	bus_addr_t paddr;
+	struct dpaa2_swa *swa;
+	struct dpaa2_buf *buf;
+	struct dpaa2_channel *bch;
+	struct dpaa2_ni_softc *sc;
 	device_t bpdev;
 	struct dpaa2_bp_softc *bpsc;
 	int error;
 
-	KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
+	error = dpaa2_fa_get_swa(fd, &swa);
+	if (__predict_false(error != 0))
+		panic("%s: frame has no software annotation: error=%d",
+		    __func__, error);
+
+	paddr = (bus_addr_t)fd->addr;
+	buf = swa->buf;
+	bch = (struct dpaa2_channel *)buf->opt;
+	sc = device_get_softc(bch->ni_dev);
+
+	KASSERT(swa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
 	/*
 	 * NOTE: Current channel might not be the same as the "buffer" channel
 	 * and it's fine. It must not be NULL though.
@@ -3316,14 +3318,26 @@ static int
 dpaa2_ni_tx_conf(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq,
     struct dpaa2_fd *fd)
 {
-	bus_addr_t paddr = (bus_addr_t)fd->addr;
-	struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr);
-	struct dpaa2_buf *buf = fa->buf;
-	struct dpaa2_buf *sgt = buf->sgt;
-	struct dpaa2_ni_tx_ring *tx = (struct dpaa2_ni_tx_ring *)buf->opt;
-	struct dpaa2_channel *bch = tx->fq->chan;
-
-	KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
+	bus_addr_t paddr;
+	struct dpaa2_swa *swa;
+	struct dpaa2_buf *buf;
+	struct dpaa2_buf *sgt;
+	struct dpaa2_ni_tx_ring *tx;
+	struct dpaa2_channel *bch;
+	int error;
+
+	error = dpaa2_fa_get_swa(fd, &swa);
+	if (__predict_false(error != 0))
+		panic("%s: frame has no software annotation: error=%d",
+		    __func__, error);
+
+	paddr = (bus_addr_t)fd->addr;
+	buf = swa->buf;
+	sgt = buf->sgt;
+	tx = (struct dpaa2_ni_tx_ring *)buf->opt;
+	bch = tx->fq->chan;
+
+	KASSERT(swa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__));
 	KASSERT(tx != NULL, ("%s: Tx ring is NULL", __func__));
 	KASSERT(sgt != NULL, ("%s: S/G table is NULL", __func__));
 	/*
@@ -3371,102 +3385,6 @@ dpaa2_ni_cmp_api_version(struct dpaa2_ni_softc *sc, uint16_t major,
 	return sc->api_major - major;
 }
 
-/**
- * @brief Build a DPAA2 frame descriptor.
- */
-static int
-dpaa2_ni_build_fd(struct dpaa2_ni_softc *sc, struct dpaa2_ni_tx_ring *tx,
-    struct dpaa2_buf *buf, bus_dma_segment_t *segs, int nsegs, struct dpaa2_fd *fd)
-{
-	struct dpaa2_buf *sgt = buf->sgt;
-	struct dpaa2_sg_entry *sge;
-	struct dpaa2_fa *fa;
-	int i, error;
-
-	KASSERT(nsegs <= DPAA2_TX_SEGLIMIT, ("%s: too many segments", __func__));
-	KASSERT(buf->opt != NULL, ("%s: no Tx ring?", __func__));
-	KASSERT(sgt != NULL, ("%s: no S/G table?", __func__));
-	KASSERT(sgt->vaddr != NULL, ("%s: no S/G vaddr?", __func__));
-
-	memset(fd, 0, sizeof(*fd));
-
-	/* Populate and map S/G table */
-	if (__predict_true(nsegs <= DPAA2_TX_SEGLIMIT)) {
-		sge = (struct dpaa2_sg_entry *)sgt->vaddr + sc->tx_data_off;
-		for (i = 0; i < nsegs; i++) {
-			sge[i].addr = (uint64_t)segs[i].ds_addr;
-			sge[i].len = (uint32_t)segs[i].ds_len;
-			sge[i].offset_fmt = 0u;
-		}
-		sge[i-1].offset_fmt |= 0x8000u; /* set final entry flag */
-
-		KASSERT(sgt->paddr == 0, ("%s: paddr(%#jx) != 0", __func__,
-		    sgt->paddr));
-
-		error = bus_dmamap_load(sgt->dmat, sgt->dmap, sgt->vaddr,
-		    DPAA2_TX_SGT_SZ, dpaa2_dmamap_oneseg_cb, &sgt->paddr,
-		    BUS_DMA_NOWAIT);
-		if (__predict_false(error != 0)) {
-			device_printf(sc->dev, "%s: bus_dmamap_load() failed: "
-			    "error=%d\n", __func__, error);
-			return (error);
-		}
-
-		buf->paddr = sgt->paddr;
-		buf->vaddr = sgt->vaddr;
-		sc->tx_sg_frames++; /* for sysctl(9) */
-	} else {
-		return (EINVAL);
-	}
-
-	fa = (struct dpaa2_fa *)sgt->vaddr;
-	fa->magic = DPAA2_MAGIC;
-	fa->buf = buf;
-
-	fd->addr = buf->paddr;
-	fd->data_length = (uint32_t)buf->m->m_pkthdr.len;
-	fd->bpid_ivp_bmt = 0;
-	fd->offset_fmt_sl = 0x2000u | sc->tx_data_off;
-	fd->ctrl = 0x00800000u;
-
-	return (0);
-}
-
-static int
-dpaa2_ni_fd_err(struct dpaa2_fd *fd)
-{
-	return ((fd->ctrl >> DPAA2_NI_FD_ERR_SHIFT) & DPAA2_NI_FD_ERR_MASK);
-}
-
-static uint32_t
-dpaa2_ni_fd_data_len(struct dpaa2_fd *fd)
-{
-	if (dpaa2_ni_fd_short_len(fd)) {
-		return (fd->data_length & DPAA2_NI_FD_LEN_MASK);
-	}
-	return (fd->data_length);
-}
-
-static int
-dpaa2_ni_fd_format(struct dpaa2_fd *fd)
-{
-	return ((enum dpaa2_fd_format)((fd->offset_fmt_sl >>
-	    DPAA2_NI_FD_FMT_SHIFT) & DPAA2_NI_FD_FMT_MASK));
-}
-
-static bool
-dpaa2_ni_fd_short_len(struct dpaa2_fd *fd)
-{
-	return (((fd->offset_fmt_sl >> DPAA2_NI_FD_SL_SHIFT)
-	    & DPAA2_NI_FD_SL_MASK) == 1);
-}
-
-static int
-dpaa2_ni_fd_offset(struct dpaa2_fd *fd)
-{
-	return (fd->offset_fmt_sl & DPAA2_NI_FD_OFFSET_MASK);
-}
-
 /**
  * @brief Collect statistics of the network interface.
  */
diff --git a/sys/dev/dpaa2/dpaa2_ni.h b/sys/dev/dpaa2/dpaa2_ni.h
index 6fb0673fac09..fcd37501ebd0 100644
--- a/sys/dev/dpaa2/dpaa2_ni.h
+++ b/sys/dev/dpaa2/dpaa2_ni.h
@@ -490,8 +490,9 @@ struct dpaa2_ni_softc {
 	struct dpaa2_channel	*channels[DPAA2_MAX_CHANNELS];
 	struct dpaa2_ni_fq	 rxe_queue; /* one per DPNI */
 
+	/* sysctl(9) */
 	struct dpaa2_atomic	 buf_num;
-	struct dpaa2_atomic	 buf_free; /* for sysctl(9) only */
+	struct dpaa2_atomic	 buf_free;
 
 	int			 irq_rid[DPAA2_NI_MSI_COUNT];
 	struct resource		*irq_res;
diff --git a/sys/dev/dpaa2/dpaa2_swp.h b/sys/dev/dpaa2/dpaa2_swp.h
index 1b1383b4241f..20980c6b71b7 100644
--- a/sys/dev/dpaa2/dpaa2_swp.h
+++ b/sys/dev/dpaa2/dpaa2_swp.h
@@ -35,6 +35,7 @@
 #include "dpaa2_types.h"
 #include "dpaa2_buf.h"
 #include "dpaa2_bp.h"
+#include "dpaa2_frame.h"
 
 /*
  * DPAA2 QBMan software portal.
@@ -200,10 +201,8 @@
 
 #define DPAA2_EQ_DESC_SIZE		32u	/* Enqueue Command Descriptor */
 #define DPAA2_FDR_DESC_SIZE		32u	/* Descriptor of the FDR */
-#define DPAA2_FD_SIZE			32u	/* Frame Descriptor */
 #define DPAA2_FDR_SIZE			64u	/* Frame Dequeue Response */
 #define DPAA2_SCN_SIZE			16u	/* State Change Notification */
-#define DPAA2_FA_SIZE			64u	/* SW Frame Annotation */
 #define DPAA2_SGE_SIZE			16u	/* S/G table entry */
 #define DPAA2_DQ_SIZE			64u	/* Dequeue Response */
 #define DPAA2_SWP_CMD_SIZE		64u	/* SWP Command */
@@ -284,54 +283,6 @@ struct dpaa2_scn {
 } __packed;
 CTASSERT(sizeof(struct dpaa2_scn) == DPAA2_SCN_SIZE);
 
-/**
- * @brief DPAA2 frame descriptor.
- *
- * addr:		Memory address of the start of the buffer holding the
- *			frame data or the buffer containing the scatter/gather
- *			list.
- * data_length:		Length of the frame data (in bytes).
- * bpid_ivp_bmt:	Buffer pool ID (14 bit + BMT bit + IVP bit)
- * offset_fmt_sl:	Frame data offset, frame format and short-length fields.
- * frame_ctx:		Frame context. This field allows the sender of a frame
- *			to communicate some out-of-band information to the
- *			receiver of the frame.
- * ctrl:		Control bits (ERR, CBMT, ASAL, PTAC, DROPP, SC, DD).
- * flow_ctx:		Frame flow context. Associates the frame with a flow
- *			structure. QMan may use the FLC field for 3 purposes:
- *			stashing control, order definition point identification,
- *			and enqueue replication control.
- */
-struct dpaa2_fd {
-	uint64_t	addr;
-	uint32_t	data_length;
-	uint16_t	bpid_ivp_bmt;
-	uint16_t	offset_fmt_sl;
-	uint32_t	frame_ctx;
-	uint32_t	ctrl;
-	uint64_t	flow_ctx;
-} __packed;
-CTASSERT(sizeof(struct dpaa2_fd) == DPAA2_FD_SIZE);
-
-/**
- * @brief DPAA2 frame annotation.
- */
-struct dpaa2_fa {
-	uint32_t		 magic;
-	struct dpaa2_buf	*buf;
-#ifdef __notyet__
-	union {
-		struct { /* Tx frame annotation */
-			struct dpaa2_ni_tx_ring *tx;
-		};
-		struct { /* Rx frame annotation */
-			uint64_t		 _notused;
-		};
-	};
-#endif
-} __packed;
-CTASSERT(sizeof(struct dpaa2_fa) <= DPAA2_FA_SIZE);
-
 /**
  * @brief DPAA2 scatter/gather entry.
  */
diff --git a/sys/dev/dpaa2/dpaa2_types.h b/sys/dev/dpaa2/dpaa2_types.h
index dbfac9ce0a40..dc1c232c09c2 100644
--- a/sys/dev/dpaa2/dpaa2_types.h
+++ b/sys/dev/dpaa2/dpaa2_types.h
@@ -40,6 +40,11 @@
 #define DPAA2_MAX_CHANNELS	 16 /* CPU cores */
 #define DPAA2_MAX_TCS		 8  /* Traffic classes */
 
+#define DPAA2_TX_SEGLIMIT	(16u) /* for 64 KiB frames */
+#define DPAA2_TX_SEG_SZ		(PAGE_SIZE)
+#define DPAA2_TX_SEGS_MAXSZ	(DPAA2_TX_SEGLIMIT * DPAA2_TX_SEG_SZ)
+#define DPAA2_TX_SGT_SZ		(PAGE_SIZE) /* in bytes */
+
 /**
  * @brief Types of the DPAA2 devices.
  */
diff --git a/sys/modules/dpaa2/Makefile b/sys/modules/dpaa2/Makefile
index 816d6fa5cf4a..388303eed0c7 100644
--- a/sys/modules/dpaa2/Makefile
+++ b/sys/modules/dpaa2/Makefile
@@ -14,6 +14,7 @@ SRCS+=	dpaa2_con.c
 SRCS+=	dpaa2_buf.c
 SRCS+=	dpaa2_channel.c
 SRCS+=	dpaa2_types.c
+SRCS+=	dpaa2_frame.c
 
 SRCS+=	dpaa2_cmd_if.c dpaa2_cmd_if.h
 SRCS+=	dpaa2_swp_if.c dpaa2_swp_if.h