xref: /freebsd/sys/dev/dpaa2/dpaa2_frame.c (revision 4a6d7fc1a00b69925b3edc39acef0391487a8e3e)
18e994533SDmitry Salychev /*-
28e994533SDmitry Salychev  * SPDX-License-Identifier: BSD-2-Clause
38e994533SDmitry Salychev  *
4*4a6d7fc1SDmitry Salychev  * Copyright (c) 2026 Dmitry Salychev
5*4a6d7fc1SDmitry Salychev  * Copyright (c) 2026 Bjoern A. Zeeb
68e994533SDmitry Salychev  *
78e994533SDmitry Salychev  * Redistribution and use in source and binary forms, with or without
88e994533SDmitry Salychev  * modification, are permitted provided that the following conditions
98e994533SDmitry Salychev  * are met:
108e994533SDmitry Salychev  * 1. Redistributions of source code must retain the above copyright
118e994533SDmitry Salychev  *    notice, this list of conditions and the following disclaimer.
128e994533SDmitry Salychev  * 2. Redistributions in binary form must reproduce the above copyright
138e994533SDmitry Salychev  *    notice, this list of conditions and the following disclaimer in the
148e994533SDmitry Salychev  *    documentation and/or other materials provided with the distribution.
158e994533SDmitry Salychev  *
168e994533SDmitry Salychev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
178e994533SDmitry Salychev  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188e994533SDmitry Salychev  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198e994533SDmitry Salychev  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
208e994533SDmitry Salychev  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218e994533SDmitry Salychev  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228e994533SDmitry Salychev  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238e994533SDmitry Salychev  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248e994533SDmitry Salychev  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258e994533SDmitry Salychev  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268e994533SDmitry Salychev  * SUCH DAMAGE.
278e994533SDmitry Salychev  */
288e994533SDmitry Salychev 
298e994533SDmitry Salychev #include <sys/cdefs.h>
308e994533SDmitry Salychev 
318e994533SDmitry Salychev #include <sys/param.h>
328e994533SDmitry Salychev #include <sys/errno.h>
33*4a6d7fc1SDmitry Salychev #include <sys/endian.h>
348e994533SDmitry Salychev 
358e994533SDmitry Salychev #include <vm/vm.h>
368e994533SDmitry Salychev #include <vm/pmap.h>
378e994533SDmitry Salychev 
388e994533SDmitry Salychev #include <machine/vmparam.h>
398e994533SDmitry Salychev 
408e994533SDmitry Salychev #include "dpaa2_types.h"
418e994533SDmitry Salychev #include "dpaa2_frame.h"
428e994533SDmitry Salychev #include "dpaa2_buf.h"
438e994533SDmitry Salychev #include "dpaa2_swp.h"
448e994533SDmitry Salychev 
458e994533SDmitry Salychev /**
468e994533SDmitry Salychev  * @brief Build a DPAA2 frame descriptor.
478e994533SDmitry Salychev  */
488e994533SDmitry Salychev 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)498e994533SDmitry Salychev dpaa2_fd_build(device_t dev, const uint16_t tx_data_off, struct dpaa2_buf *buf,
508e994533SDmitry Salychev     bus_dma_segment_t *segs, const int nsegs, struct dpaa2_fd *fd)
518e994533SDmitry Salychev {
528e994533SDmitry Salychev 	struct dpaa2_buf *sgt = buf->sgt;
538e994533SDmitry Salychev 	struct dpaa2_sg_entry *sge;
548e994533SDmitry Salychev 	struct dpaa2_swa *swa;
558e994533SDmitry Salychev 	int i, error;
568e994533SDmitry Salychev 
578e994533SDmitry Salychev 	if (buf == NULL || segs == NULL || nsegs == 0 || fd == NULL)
588e994533SDmitry Salychev 		return (EINVAL);
598e994533SDmitry Salychev 
608e994533SDmitry Salychev 	KASSERT(nsegs <= DPAA2_TX_SEGLIMIT, ("%s: too many segments", __func__));
618e994533SDmitry Salychev 	KASSERT(buf->opt != NULL, ("%s: no Tx ring?", __func__));
628e994533SDmitry Salychev 	KASSERT(sgt != NULL, ("%s: no S/G table?", __func__));
638e994533SDmitry Salychev 	KASSERT(sgt->vaddr != NULL, ("%s: no S/G vaddr?", __func__));
648e994533SDmitry Salychev 
658e994533SDmitry Salychev 	memset(fd, 0, sizeof(*fd));
668e994533SDmitry Salychev 
678e994533SDmitry Salychev 	/* Populate and map S/G table */
688e994533SDmitry Salychev 	if (__predict_true(nsegs <= DPAA2_TX_SEGLIMIT)) {
698e994533SDmitry Salychev 		sge = (struct dpaa2_sg_entry *)sgt->vaddr + tx_data_off;
708e994533SDmitry Salychev 		for (i = 0; i < nsegs; i++) {
718e994533SDmitry Salychev 			sge[i].addr = (uint64_t)segs[i].ds_addr;
728e994533SDmitry Salychev 			sge[i].len = (uint32_t)segs[i].ds_len;
738e994533SDmitry Salychev 			sge[i].offset_fmt = 0u;
748e994533SDmitry Salychev 		}
758e994533SDmitry Salychev 		sge[i-1].offset_fmt |= 0x8000u; /* set final entry flag */
768e994533SDmitry Salychev 
778e994533SDmitry Salychev 		KASSERT(sgt->paddr == 0, ("%s: paddr(%#jx) != 0", __func__,
788e994533SDmitry Salychev 		    sgt->paddr));
798e994533SDmitry Salychev 
808e994533SDmitry Salychev 		error = bus_dmamap_load(sgt->dmat, sgt->dmap, sgt->vaddr,
818e994533SDmitry Salychev 		    DPAA2_TX_SGT_SZ, dpaa2_dmamap_oneseg_cb, &sgt->paddr,
828e994533SDmitry Salychev 		    BUS_DMA_NOWAIT);
838e994533SDmitry Salychev 		if (__predict_false(error != 0)) {
848e994533SDmitry Salychev 			device_printf(dev, "%s: bus_dmamap_load() failed: "
858e994533SDmitry Salychev 			    "error=%d\n", __func__, error);
868e994533SDmitry Salychev 			return (error);
878e994533SDmitry Salychev 		}
888e994533SDmitry Salychev 
898e994533SDmitry Salychev 		buf->paddr = sgt->paddr;
908e994533SDmitry Salychev 		buf->vaddr = sgt->vaddr;
918e994533SDmitry Salychev 	} else {
928e994533SDmitry Salychev 		return (EINVAL);
938e994533SDmitry Salychev 	}
948e994533SDmitry Salychev 
958e994533SDmitry Salychev 	swa = (struct dpaa2_swa *)sgt->vaddr;
968e994533SDmitry Salychev 	swa->magic = DPAA2_MAGIC;
978e994533SDmitry Salychev 	swa->buf = buf;
988e994533SDmitry Salychev 
998e994533SDmitry Salychev 	fd->addr = buf->paddr;
1008e994533SDmitry Salychev 	fd->data_length = (uint32_t)buf->m->m_pkthdr.len;
1018e994533SDmitry Salychev 	fd->bpid_ivp_bmt = 0;
1028e994533SDmitry Salychev 	fd->offset_fmt_sl = 0x2000u | tx_data_off;
1038e994533SDmitry Salychev 	fd->ctrl = (0x4u & DPAA2_FD_PTAC_MASK) << DPAA2_FD_PTAC_SHIFT;
1048e994533SDmitry Salychev 
1058e994533SDmitry Salychev 	return (0);
1068e994533SDmitry Salychev }
1078e994533SDmitry Salychev 
1088e994533SDmitry Salychev int
dpaa2_fd_err(struct dpaa2_fd * fd)1098e994533SDmitry Salychev dpaa2_fd_err(struct dpaa2_fd *fd)
1108e994533SDmitry Salychev {
1118e994533SDmitry Salychev 	return ((fd->ctrl >> DPAA2_FD_ERR_SHIFT) & DPAA2_FD_ERR_MASK);
1128e994533SDmitry Salychev }
1138e994533SDmitry Salychev 
1148e994533SDmitry Salychev uint32_t
dpaa2_fd_data_len(struct dpaa2_fd * fd)1158e994533SDmitry Salychev dpaa2_fd_data_len(struct dpaa2_fd *fd)
1168e994533SDmitry Salychev {
1178e994533SDmitry Salychev 	if (dpaa2_fd_short_len(fd)) {
1188e994533SDmitry Salychev 		return (fd->data_length & DPAA2_FD_LEN_MASK);
1198e994533SDmitry Salychev 	}
1208e994533SDmitry Salychev 	return (fd->data_length);
1218e994533SDmitry Salychev }
1228e994533SDmitry Salychev 
1238e994533SDmitry Salychev int
dpaa2_fd_format(struct dpaa2_fd * fd)1248e994533SDmitry Salychev dpaa2_fd_format(struct dpaa2_fd *fd)
1258e994533SDmitry Salychev {
1268e994533SDmitry Salychev 	return ((enum dpaa2_fd_format)((fd->offset_fmt_sl >>
1278e994533SDmitry Salychev 	    DPAA2_FD_FMT_SHIFT) & DPAA2_FD_FMT_MASK));
1288e994533SDmitry Salychev }
1298e994533SDmitry Salychev 
1308e994533SDmitry Salychev bool
dpaa2_fd_short_len(struct dpaa2_fd * fd)1318e994533SDmitry Salychev dpaa2_fd_short_len(struct dpaa2_fd *fd)
1328e994533SDmitry Salychev {
1338e994533SDmitry Salychev 	return (((fd->offset_fmt_sl >> DPAA2_FD_SL_SHIFT)
1348e994533SDmitry Salychev 	    & DPAA2_FD_SL_MASK) == 1);
1358e994533SDmitry Salychev }
1368e994533SDmitry Salychev 
1378e994533SDmitry Salychev int
dpaa2_fd_offset(struct dpaa2_fd * fd)1388e994533SDmitry Salychev dpaa2_fd_offset(struct dpaa2_fd *fd)
1398e994533SDmitry Salychev {
1408e994533SDmitry Salychev 	return (fd->offset_fmt_sl & DPAA2_FD_OFFSET_MASK);
1418e994533SDmitry Salychev }
1428e994533SDmitry Salychev 
143*4a6d7fc1SDmitry Salychev uint32_t
dpaa2_fd_get_frc(struct dpaa2_fd * fd)144*4a6d7fc1SDmitry Salychev dpaa2_fd_get_frc(struct dpaa2_fd *fd)
145*4a6d7fc1SDmitry Salychev {
146*4a6d7fc1SDmitry Salychev 	/* TODO: Convert endiannes in the other functions as well. */
147*4a6d7fc1SDmitry Salychev 	return (le32toh(fd->frame_ctx));
148*4a6d7fc1SDmitry Salychev }
149*4a6d7fc1SDmitry Salychev 
150*4a6d7fc1SDmitry Salychev #ifdef _not_yet_
151*4a6d7fc1SDmitry Salychev void
dpaa2_fd_set_frc(struct dpaa2_fd * fd,uint32_t frc)152*4a6d7fc1SDmitry Salychev dpaa2_fd_set_frc(struct dpaa2_fd *fd, uint32_t frc)
153*4a6d7fc1SDmitry Salychev {
154*4a6d7fc1SDmitry Salychev 	/* TODO: Convert endiannes in the other functions as well. */
155*4a6d7fc1SDmitry Salychev 	fd->frame_ctx = htole32(frc);
156*4a6d7fc1SDmitry Salychev }
157*4a6d7fc1SDmitry Salychev #endif
158*4a6d7fc1SDmitry Salychev 
1598e994533SDmitry Salychev int
dpaa2_fa_get_swa(struct dpaa2_fd * fd,struct dpaa2_swa ** swa)1608e994533SDmitry Salychev dpaa2_fa_get_swa(struct dpaa2_fd *fd, struct dpaa2_swa **swa)
1618e994533SDmitry Salychev {
162*4a6d7fc1SDmitry Salychev 	if (__predict_false(fd == NULL || swa == NULL))
1638e994533SDmitry Salychev 		return (EINVAL);
1648e994533SDmitry Salychev 
165*4a6d7fc1SDmitry Salychev 	if (((fd->ctrl >> DPAA2_FD_PTAC_SHIFT) & DPAA2_FD_PTAC_PTA_MASK) == 0u) {
1668e994533SDmitry Salychev 		*swa = NULL;
167*4a6d7fc1SDmitry Salychev 		return (ENOENT);
1688e994533SDmitry Salychev 	}
1698e994533SDmitry Salychev 
170*4a6d7fc1SDmitry Salychev 	*swa = (struct dpaa2_swa *)PHYS_TO_DMAP((bus_addr_t)fd->addr);
171*4a6d7fc1SDmitry Salychev 
172*4a6d7fc1SDmitry Salychev 	return (0);
1738e994533SDmitry Salychev }
1748e994533SDmitry Salychev 
1758e994533SDmitry Salychev int
dpaa2_fa_get_hwa(struct dpaa2_fd * fd,struct dpaa2_hwa ** hwa)1768e994533SDmitry Salychev dpaa2_fa_get_hwa(struct dpaa2_fd *fd, struct dpaa2_hwa **hwa)
1778e994533SDmitry Salychev {
178*4a6d7fc1SDmitry Salychev 	uint8_t *buf;
179*4a6d7fc1SDmitry Salychev 	uint32_t hwo; /* HW annotation offset */
180*4a6d7fc1SDmitry Salychev 
181*4a6d7fc1SDmitry Salychev 	if (__predict_false(fd == NULL || hwa == NULL))
182*4a6d7fc1SDmitry Salychev 		return (EINVAL);
183*4a6d7fc1SDmitry Salychev 
184*4a6d7fc1SDmitry Salychev 	/*
185*4a6d7fc1SDmitry Salychev 	 * As soon as the ASAL is in the 64-byte units, we don't need to
186*4a6d7fc1SDmitry Salychev 	 * calculate the exact length, but make sure that it isn't 0.
187*4a6d7fc1SDmitry Salychev 	 */
188*4a6d7fc1SDmitry Salychev 	if (((fd->ctrl >> DPAA2_FD_ASAL_SHIFT) & DPAA2_FD_ASAL_MASK) == 0u) {
189*4a6d7fc1SDmitry Salychev 		*hwa = NULL;
1908e994533SDmitry Salychev 		return (ENOENT);
1918e994533SDmitry Salychev 	}
192*4a6d7fc1SDmitry Salychev 
193*4a6d7fc1SDmitry Salychev 	buf = (uint8_t *)PHYS_TO_DMAP((bus_addr_t)fd->addr);
194*4a6d7fc1SDmitry Salychev 	hwo = ((fd->ctrl >> DPAA2_FD_PTAC_SHIFT) & DPAA2_FD_PTAC_PTA_MASK) > 0u
195*4a6d7fc1SDmitry Salychev 	    ? DPAA2_FA_SWA_SIZE : 0u;
196*4a6d7fc1SDmitry Salychev 	*hwa = (struct dpaa2_hwa *)(buf + hwo);
197*4a6d7fc1SDmitry Salychev 
198*4a6d7fc1SDmitry Salychev 	return (0);
199*4a6d7fc1SDmitry Salychev }
200*4a6d7fc1SDmitry Salychev 
201*4a6d7fc1SDmitry Salychev int
dpaa2_fa_get_fas(struct dpaa2_fd * fd,struct dpaa2_hwa_fas * fas)202*4a6d7fc1SDmitry Salychev dpaa2_fa_get_fas(struct dpaa2_fd *fd, struct dpaa2_hwa_fas *fas)
203*4a6d7fc1SDmitry Salychev {
204*4a6d7fc1SDmitry Salychev 	struct dpaa2_hwa *hwa;
205*4a6d7fc1SDmitry Salychev 	struct dpaa2_hwa_fas *fasp;
206*4a6d7fc1SDmitry Salychev 	int rc;
207*4a6d7fc1SDmitry Salychev 
208*4a6d7fc1SDmitry Salychev 	if (__predict_false(fd == NULL || fas == NULL))
209*4a6d7fc1SDmitry Salychev 		return (EINVAL);
210*4a6d7fc1SDmitry Salychev 
211*4a6d7fc1SDmitry Salychev 	rc = dpaa2_fa_get_hwa(fd, &hwa);
212*4a6d7fc1SDmitry Salychev 	if (__predict_false(rc != 0))
213*4a6d7fc1SDmitry Salychev 		return (rc);
214*4a6d7fc1SDmitry Salychev 
215*4a6d7fc1SDmitry Salychev 	fasp = (struct dpaa2_hwa_fas *)&hwa->fas;
216*4a6d7fc1SDmitry Salychev 	*fas = *fasp;
217*4a6d7fc1SDmitry Salychev 
218*4a6d7fc1SDmitry Salychev 	return (rc);
219*4a6d7fc1SDmitry Salychev }
220*4a6d7fc1SDmitry Salychev 
221*4a6d7fc1SDmitry Salychev #ifdef _not_yet_
222*4a6d7fc1SDmitry Salychev int
dpaa2_fa_set_fas(struct dpaa2_fd * fd,struct dpaa2_hwa_fas * fas)223*4a6d7fc1SDmitry Salychev dpaa2_fa_set_fas(struct dpaa2_fd *fd, struct dpaa2_hwa_fas *fas)
224*4a6d7fc1SDmitry Salychev {
225*4a6d7fc1SDmitry Salychev 	struct dpaa2_hwa *hwa;
226*4a6d7fc1SDmitry Salychev 	uint64_t *valp;
227*4a6d7fc1SDmitry Salychev 	int rc;
228*4a6d7fc1SDmitry Salychev 
229*4a6d7fc1SDmitry Salychev 	if (__predict_false(fd == NULL || fas == NULL))
230*4a6d7fc1SDmitry Salychev 		return (EINVAL);
231*4a6d7fc1SDmitry Salychev 
232*4a6d7fc1SDmitry Salychev 	rc = dpaa2_fa_get_hwa(fd, &hwa);
233*4a6d7fc1SDmitry Salychev 	if (__predict_false(rc != 0))
234*4a6d7fc1SDmitry Salychev 		return (rc);
235*4a6d7fc1SDmitry Salychev 
236*4a6d7fc1SDmitry Salychev 	valp = (uint64_t *)fas;
237*4a6d7fc1SDmitry Salychev 	hwa->fas = *valp;
238*4a6d7fc1SDmitry Salychev 
239*4a6d7fc1SDmitry Salychev 	return (rc);
240*4a6d7fc1SDmitry Salychev }
241*4a6d7fc1SDmitry Salychev #endif
242