1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
11 * 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 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/rman.h>
39 #include <sys/lock.h>
40 #include <sys/malloc.h>
41 #include <sys/mutex.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
44
45 #include <net/if.h>
46 #include <net/if_var.h>
47 #include <net/if_media.h>
48 #include <net/ethernet.h>
49
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52
53 #include <dev/fdt/fdt_common.h>
54 #include <dev/ofw/ofw_bus.h>
55 #include <dev/ofw/ofw_bus_subr.h>
56
57 #include <dev/qcom_ess_edma/qcom_ess_edma_var.h>
58 #include <dev/qcom_ess_edma/qcom_ess_edma_reg.h>
59 #include <dev/qcom_ess_edma/qcom_ess_edma_hw.h>
60 #include <dev/qcom_ess_edma/qcom_ess_edma_desc.h>
61 #include <dev/qcom_ess_edma/qcom_ess_edma_debug.h>
62
63 static void
qcom_ess_edma_desc_map_addr(void * arg,bus_dma_segment_t * segs,int nsegs,int error)64 qcom_ess_edma_desc_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs,
65 int error)
66 {
67 if (error != 0)
68 return;
69 KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs));
70 *(bus_addr_t *)arg = segs[0].ds_addr;
71 }
72
73 /*
74 * Initialise the given descriptor ring.
75 */
76 int
qcom_ess_edma_desc_ring_setup(struct qcom_ess_edma_softc * sc,struct qcom_ess_edma_desc_ring * ring,char * label,int count,int sw_desc_size,int hw_desc_size,int num_segments,int buffer_align)77 qcom_ess_edma_desc_ring_setup(struct qcom_ess_edma_softc *sc,
78 struct qcom_ess_edma_desc_ring *ring,
79 char *label,
80 int count,
81 int sw_desc_size,
82 int hw_desc_size,
83 int num_segments,
84 int buffer_align)
85 {
86 int error;
87 int hw_ring_size;
88
89 ring->label = strdup(label, M_TEMP);
90 if (ring->label == NULL) {
91 device_printf(sc->sc_dev,
92 "ERROR: failed to strdup label\n");
93 error = ENOMEM;
94 goto error;
95 }
96
97 mtx_init(&ring->mtx, ring->label, NULL, MTX_DEF);
98
99 hw_ring_size = count * hw_desc_size;
100
101 /*
102 * Round the hardware ring size up to a cacheline
103 * so we don't end up with partial cacheline sizes
104 * causing bounce buffers to be used.
105 */
106 hw_ring_size = ((hw_ring_size + PAGE_SIZE) / PAGE_SIZE) * PAGE_SIZE;
107
108 /*
109 * For now set it to 4 byte alignment, no max size.
110 */
111 ring->ring_align = EDMA_DESC_RING_ALIGN;
112 error = bus_dma_tag_create(
113 sc->sc_dma_tag, /* parent */
114 EDMA_DESC_RING_ALIGN, 0, /* alignment, boundary */
115 BUS_SPACE_MAXADDR, /* lowaddr */
116 BUS_SPACE_MAXADDR, /* highaddr */
117 NULL, NULL, /* filter, filterarg */
118 hw_ring_size, /* maxsize */
119 1, /* nsegments */
120 hw_ring_size, /* maxsegsize */
121 0, /* flags */
122 NULL, NULL, /* lockfunc, lockarg */
123 &ring->hw_ring_dma_tag);
124 if (error != 0) {
125 device_printf(sc->sc_dev,
126 "ERROR: failed to create descriptor DMA tag (%d)\n",
127 error);
128 goto error;
129 }
130
131 /*
132 * Buffer ring - used passed in value
133 */
134 ring->buffer_align = buffer_align;
135 error = bus_dma_tag_create(
136 sc->sc_dma_tag, /* parent */
137 buffer_align, 0, /* alignment, boundary */
138 BUS_SPACE_MAXADDR, /* lowaddr */
139 BUS_SPACE_MAXADDR, /* highaddr */
140 NULL, NULL, /* filter, filterarg */
141 EDMA_DESC_MAX_BUFFER_SIZE * num_segments, /* maxsize */
142 num_segments, /* nsegments */
143 EDMA_DESC_MAX_BUFFER_SIZE, /* maxsegsize */
144 0, /* flags */
145 NULL, NULL, /* lockfunc, lockarg */
146 &ring->buffer_dma_tag);
147 if (error != 0) {
148 device_printf(sc->sc_dev,
149 "ERROR: failed to create buffer DMA tag (%d)\n",
150 error);
151 goto error;
152 }
153
154 /*
155 * Allocate software descriptors
156 */
157 ring->sw_desc = mallocarray(count, sw_desc_size, M_TEMP,
158 M_NOWAIT | M_ZERO);
159 if (ring->sw_desc == NULL) {
160 device_printf(sc->sc_dev,
161 "ERROR: failed to allocate sw_desc\n");
162 goto error;
163 }
164
165 /*
166 * Allocate hardware descriptors, initialise map, get
167 * physical address.
168 */
169 error = bus_dmamem_alloc(ring->hw_ring_dma_tag,
170 (void **)&ring->hw_desc,
171 BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
172 &ring->hw_desc_map);
173 if (error != 0) {
174 device_printf(sc->sc_dev,
175 "failed to allocate DMA'able memory for hw_desc ring\n");
176 goto error;
177 }
178 ring->hw_desc_paddr = 0;
179 error = bus_dmamap_load(ring->hw_ring_dma_tag, ring->hw_desc_map,
180 ring->hw_desc, hw_ring_size, qcom_ess_edma_desc_map_addr,
181 &ring->hw_desc_paddr, BUS_DMA_NOWAIT);
182 bus_dmamap_sync(ring->hw_ring_dma_tag, ring->hw_desc_map,
183 BUS_DMASYNC_PREWRITE);
184 QCOM_ESS_EDMA_DPRINTF(sc, QCOM_ESS_EDMA_DBG_DESCRIPTOR_SETUP,
185 "%s: PADDR=0x%08lx\n", __func__, ring->hw_desc_paddr);
186
187 /*
188 * All done, initialise state.
189 */
190 ring->hw_entry_size = hw_desc_size;
191 ring->sw_entry_size = sw_desc_size;
192 ring->ring_count = count;
193
194 return (0);
195 error:
196 mtx_destroy(&ring->mtx);
197 if (ring->label != NULL)
198 free(ring->label, M_TEMP);
199 if (ring->hw_desc != NULL) {
200 bus_dmamap_sync(ring->hw_ring_dma_tag, ring->hw_desc_map,
201 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
202 bus_dmamap_unload(ring->hw_ring_dma_tag, ring->hw_desc_map);
203 bus_dmamem_free(ring->hw_ring_dma_tag, ring->hw_desc,
204 ring->hw_desc_map);
205 ring->hw_desc = NULL;
206 }
207 if (ring->sw_desc != NULL) {
208 free(ring->sw_desc, M_TEMP);
209 ring->sw_desc = NULL;
210 }
211 if (ring->hw_ring_dma_tag != NULL) {
212 bus_dma_tag_destroy(ring->hw_ring_dma_tag);
213 ring->hw_ring_dma_tag = NULL;
214 }
215 if (ring->buffer_dma_tag != NULL) {
216 bus_dma_tag_destroy(ring->buffer_dma_tag);
217 ring->buffer_dma_tag = NULL;
218 }
219
220 return (error);
221 }
222
223 /*
224 * Free/clean the given descriptor ring.
225 *
226 * The ring itself right now is static; so we don't free it.
227 * We just free the resources it has.
228 */
229 int
qcom_ess_edma_desc_ring_free(struct qcom_ess_edma_softc * sc,struct qcom_ess_edma_desc_ring * ring)230 qcom_ess_edma_desc_ring_free(struct qcom_ess_edma_softc *sc,
231 struct qcom_ess_edma_desc_ring *ring)
232 {
233
234 mtx_destroy(&ring->mtx);
235 if (ring->label != NULL)
236 free(ring->label, M_TEMP);
237
238 if (ring->hw_desc != NULL) {
239 bus_dmamap_sync(ring->hw_ring_dma_tag, ring->hw_desc_map,
240 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
241 bus_dmamap_unload(ring->hw_ring_dma_tag, ring->hw_desc_map);
242 bus_dmamem_free(ring->hw_ring_dma_tag, ring->hw_desc,
243 ring->hw_desc_map);
244 ring->hw_desc = NULL;
245 }
246
247 if (ring->sw_desc != NULL) {
248 free(ring->sw_desc, M_TEMP);
249 ring->sw_desc = NULL;
250 }
251
252 if (ring->hw_ring_dma_tag != NULL) {
253 bus_dma_tag_destroy(ring->hw_ring_dma_tag);
254 ring->hw_ring_dma_tag = NULL;
255 }
256 if (ring->buffer_dma_tag != NULL) {
257 bus_dma_tag_destroy(ring->buffer_dma_tag);
258 ring->buffer_dma_tag = NULL;
259 }
260
261 return (0);
262 }
263
264 /*
265 * Fetch the given software descriptor pointer by index.
266 *
267 * Returns NULL if the index is out of bounds.
268 */
269 void *
qcom_ess_edma_desc_ring_get_sw_desc(struct qcom_ess_edma_softc * sc,struct qcom_ess_edma_desc_ring * ring,uint16_t index)270 qcom_ess_edma_desc_ring_get_sw_desc(struct qcom_ess_edma_softc *sc,
271 struct qcom_ess_edma_desc_ring *ring, uint16_t index)
272 {
273 char *p;
274
275 if (index >= ring->ring_count)
276 return (NULL);
277
278 p = (char *) ring->sw_desc;
279
280 return (void *) (p + (ring->sw_entry_size * index));
281 }
282
283 /*
284 * Fetch the given hardware descriptor pointer by index.
285 *
286 * Returns NULL if the index is out of bounds.
287 */
288 void *
qcom_ess_edma_desc_ring_get_hw_desc(struct qcom_ess_edma_softc * sc,struct qcom_ess_edma_desc_ring * ring,uint16_t index)289 qcom_ess_edma_desc_ring_get_hw_desc(struct qcom_ess_edma_softc *sc,
290 struct qcom_ess_edma_desc_ring *ring, uint16_t index)
291 {
292 char *p;
293
294 if (index >= ring->ring_count)
295 return (NULL);
296
297 p = (char *) ring->hw_desc;
298
299 return (void *) (p + (ring->hw_entry_size * index));
300 }
301
302 /*
303 * Flush the hardware ring after a write, before the hardware
304 * gets to it.
305 */
306 int
qcom_ess_edma_desc_ring_flush_preupdate(struct qcom_ess_edma_softc * sc,struct qcom_ess_edma_desc_ring * ring)307 qcom_ess_edma_desc_ring_flush_preupdate(struct qcom_ess_edma_softc *sc,
308 struct qcom_ess_edma_desc_ring *ring)
309 {
310
311 bus_dmamap_sync(ring->hw_ring_dma_tag, ring->hw_desc_map,
312 BUS_DMASYNC_PREWRITE);
313
314 return (0);
315 }
316
317
318 /*
319 * Flush the hardware ring after the hardware writes into it,
320 * before a read.
321 */
322 int
qcom_ess_edma_desc_ring_flush_postupdate(struct qcom_ess_edma_softc * sc,struct qcom_ess_edma_desc_ring * ring)323 qcom_ess_edma_desc_ring_flush_postupdate(struct qcom_ess_edma_softc *sc,
324 struct qcom_ess_edma_desc_ring *ring)
325 {
326
327 bus_dmamap_sync(ring->hw_ring_dma_tag, ring->hw_desc_map,
328 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
329
330 return (0);
331 }
332
333 /*
334 * Get how many descriptor slots are available.
335 */
336 int
qcom_ess_edma_desc_ring_get_num_available(struct qcom_ess_edma_softc * sc,struct qcom_ess_edma_desc_ring * ring)337 qcom_ess_edma_desc_ring_get_num_available(struct qcom_ess_edma_softc *sc,
338 struct qcom_ess_edma_desc_ring *ring)
339 {
340 uint16_t sw_next_to_fill;
341 uint16_t sw_next_to_clean;
342 uint16_t count = 0;
343
344 sw_next_to_clean = ring->next_to_clean;
345 sw_next_to_fill = ring->next_to_fill;
346
347 if (sw_next_to_clean <= sw_next_to_fill)
348 count = ring->ring_count;
349
350 return (count + sw_next_to_clean - sw_next_to_fill - 1);
351 }
352