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