xref: /freebsd/sys/dev/dpaa2/dpaa2_frame.c (revision 4a6d7fc1a00b69925b3edc39acef0391487a8e3e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2026 Dmitry Salychev
5  * Copyright (c) 2026 Bjoern A. Zeeb
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 
31 #include <sys/param.h>
32 #include <sys/errno.h>
33 #include <sys/endian.h>
34 
35 #include <vm/vm.h>
36 #include <vm/pmap.h>
37 
38 #include <machine/vmparam.h>
39 
40 #include "dpaa2_types.h"
41 #include "dpaa2_frame.h"
42 #include "dpaa2_buf.h"
43 #include "dpaa2_swp.h"
44 
45 /**
46  * @brief Build a DPAA2 frame descriptor.
47  */
48 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)49 dpaa2_fd_build(device_t dev, const uint16_t tx_data_off, struct dpaa2_buf *buf,
50     bus_dma_segment_t *segs, const int nsegs, struct dpaa2_fd *fd)
51 {
52 	struct dpaa2_buf *sgt = buf->sgt;
53 	struct dpaa2_sg_entry *sge;
54 	struct dpaa2_swa *swa;
55 	int i, error;
56 
57 	if (buf == NULL || segs == NULL || nsegs == 0 || fd == NULL)
58 		return (EINVAL);
59 
60 	KASSERT(nsegs <= DPAA2_TX_SEGLIMIT, ("%s: too many segments", __func__));
61 	KASSERT(buf->opt != NULL, ("%s: no Tx ring?", __func__));
62 	KASSERT(sgt != NULL, ("%s: no S/G table?", __func__));
63 	KASSERT(sgt->vaddr != NULL, ("%s: no S/G vaddr?", __func__));
64 
65 	memset(fd, 0, sizeof(*fd));
66 
67 	/* Populate and map S/G table */
68 	if (__predict_true(nsegs <= DPAA2_TX_SEGLIMIT)) {
69 		sge = (struct dpaa2_sg_entry *)sgt->vaddr + tx_data_off;
70 		for (i = 0; i < nsegs; i++) {
71 			sge[i].addr = (uint64_t)segs[i].ds_addr;
72 			sge[i].len = (uint32_t)segs[i].ds_len;
73 			sge[i].offset_fmt = 0u;
74 		}
75 		sge[i-1].offset_fmt |= 0x8000u; /* set final entry flag */
76 
77 		KASSERT(sgt->paddr == 0, ("%s: paddr(%#jx) != 0", __func__,
78 		    sgt->paddr));
79 
80 		error = bus_dmamap_load(sgt->dmat, sgt->dmap, sgt->vaddr,
81 		    DPAA2_TX_SGT_SZ, dpaa2_dmamap_oneseg_cb, &sgt->paddr,
82 		    BUS_DMA_NOWAIT);
83 		if (__predict_false(error != 0)) {
84 			device_printf(dev, "%s: bus_dmamap_load() failed: "
85 			    "error=%d\n", __func__, error);
86 			return (error);
87 		}
88 
89 		buf->paddr = sgt->paddr;
90 		buf->vaddr = sgt->vaddr;
91 	} else {
92 		return (EINVAL);
93 	}
94 
95 	swa = (struct dpaa2_swa *)sgt->vaddr;
96 	swa->magic = DPAA2_MAGIC;
97 	swa->buf = buf;
98 
99 	fd->addr = buf->paddr;
100 	fd->data_length = (uint32_t)buf->m->m_pkthdr.len;
101 	fd->bpid_ivp_bmt = 0;
102 	fd->offset_fmt_sl = 0x2000u | tx_data_off;
103 	fd->ctrl = (0x4u & DPAA2_FD_PTAC_MASK) << DPAA2_FD_PTAC_SHIFT;
104 
105 	return (0);
106 }
107 
108 int
dpaa2_fd_err(struct dpaa2_fd * fd)109 dpaa2_fd_err(struct dpaa2_fd *fd)
110 {
111 	return ((fd->ctrl >> DPAA2_FD_ERR_SHIFT) & DPAA2_FD_ERR_MASK);
112 }
113 
114 uint32_t
dpaa2_fd_data_len(struct dpaa2_fd * fd)115 dpaa2_fd_data_len(struct dpaa2_fd *fd)
116 {
117 	if (dpaa2_fd_short_len(fd)) {
118 		return (fd->data_length & DPAA2_FD_LEN_MASK);
119 	}
120 	return (fd->data_length);
121 }
122 
123 int
dpaa2_fd_format(struct dpaa2_fd * fd)124 dpaa2_fd_format(struct dpaa2_fd *fd)
125 {
126 	return ((enum dpaa2_fd_format)((fd->offset_fmt_sl >>
127 	    DPAA2_FD_FMT_SHIFT) & DPAA2_FD_FMT_MASK));
128 }
129 
130 bool
dpaa2_fd_short_len(struct dpaa2_fd * fd)131 dpaa2_fd_short_len(struct dpaa2_fd *fd)
132 {
133 	return (((fd->offset_fmt_sl >> DPAA2_FD_SL_SHIFT)
134 	    & DPAA2_FD_SL_MASK) == 1);
135 }
136 
137 int
dpaa2_fd_offset(struct dpaa2_fd * fd)138 dpaa2_fd_offset(struct dpaa2_fd *fd)
139 {
140 	return (fd->offset_fmt_sl & DPAA2_FD_OFFSET_MASK);
141 }
142 
143 uint32_t
dpaa2_fd_get_frc(struct dpaa2_fd * fd)144 dpaa2_fd_get_frc(struct dpaa2_fd *fd)
145 {
146 	/* TODO: Convert endiannes in the other functions as well. */
147 	return (le32toh(fd->frame_ctx));
148 }
149 
150 #ifdef _not_yet_
151 void
dpaa2_fd_set_frc(struct dpaa2_fd * fd,uint32_t frc)152 dpaa2_fd_set_frc(struct dpaa2_fd *fd, uint32_t frc)
153 {
154 	/* TODO: Convert endiannes in the other functions as well. */
155 	fd->frame_ctx = htole32(frc);
156 }
157 #endif
158 
159 int
dpaa2_fa_get_swa(struct dpaa2_fd * fd,struct dpaa2_swa ** swa)160 dpaa2_fa_get_swa(struct dpaa2_fd *fd, struct dpaa2_swa **swa)
161 {
162 	if (__predict_false(fd == NULL || swa == NULL))
163 		return (EINVAL);
164 
165 	if (((fd->ctrl >> DPAA2_FD_PTAC_SHIFT) & DPAA2_FD_PTAC_PTA_MASK) == 0u) {
166 		*swa = NULL;
167 		return (ENOENT);
168 	}
169 
170 	*swa = (struct dpaa2_swa *)PHYS_TO_DMAP((bus_addr_t)fd->addr);
171 
172 	return (0);
173 }
174 
175 int
dpaa2_fa_get_hwa(struct dpaa2_fd * fd,struct dpaa2_hwa ** hwa)176 dpaa2_fa_get_hwa(struct dpaa2_fd *fd, struct dpaa2_hwa **hwa)
177 {
178 	uint8_t *buf;
179 	uint32_t hwo; /* HW annotation offset */
180 
181 	if (__predict_false(fd == NULL || hwa == NULL))
182 		return (EINVAL);
183 
184 	/*
185 	 * As soon as the ASAL is in the 64-byte units, we don't need to
186 	 * calculate the exact length, but make sure that it isn't 0.
187 	 */
188 	if (((fd->ctrl >> DPAA2_FD_ASAL_SHIFT) & DPAA2_FD_ASAL_MASK) == 0u) {
189 		*hwa = NULL;
190 		return (ENOENT);
191 	}
192 
193 	buf = (uint8_t *)PHYS_TO_DMAP((bus_addr_t)fd->addr);
194 	hwo = ((fd->ctrl >> DPAA2_FD_PTAC_SHIFT) & DPAA2_FD_PTAC_PTA_MASK) > 0u
195 	    ? DPAA2_FA_SWA_SIZE : 0u;
196 	*hwa = (struct dpaa2_hwa *)(buf + hwo);
197 
198 	return (0);
199 }
200 
201 int
dpaa2_fa_get_fas(struct dpaa2_fd * fd,struct dpaa2_hwa_fas * fas)202 dpaa2_fa_get_fas(struct dpaa2_fd *fd, struct dpaa2_hwa_fas *fas)
203 {
204 	struct dpaa2_hwa *hwa;
205 	struct dpaa2_hwa_fas *fasp;
206 	int rc;
207 
208 	if (__predict_false(fd == NULL || fas == NULL))
209 		return (EINVAL);
210 
211 	rc = dpaa2_fa_get_hwa(fd, &hwa);
212 	if (__predict_false(rc != 0))
213 		return (rc);
214 
215 	fasp = (struct dpaa2_hwa_fas *)&hwa->fas;
216 	*fas = *fasp;
217 
218 	return (rc);
219 }
220 
221 #ifdef _not_yet_
222 int
dpaa2_fa_set_fas(struct dpaa2_fd * fd,struct dpaa2_hwa_fas * fas)223 dpaa2_fa_set_fas(struct dpaa2_fd *fd, struct dpaa2_hwa_fas *fas)
224 {
225 	struct dpaa2_hwa *hwa;
226 	uint64_t *valp;
227 	int rc;
228 
229 	if (__predict_false(fd == NULL || fas == NULL))
230 		return (EINVAL);
231 
232 	rc = dpaa2_fa_get_hwa(fd, &hwa);
233 	if (__predict_false(rc != 0))
234 		return (rc);
235 
236 	valp = (uint64_t *)fas;
237 	hwa->fas = *valp;
238 
239 	return (rc);
240 }
241 #endif
242