xref: /freebsd/sys/dev/altera/softdma/softdma.c (revision ce6a89e27cd190313be39bb479880aeda4778436)
1 /*-
2  * Copyright (c) 2017-2018 Ruslan Bukin <br@bsdpad.com>
3  * All rights reserved.
4  *
5  * This software was developed by SRI International and the University of
6  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
7  * ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /* This is driver for SoftDMA device built using Altera FIFO component. */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 #include "opt_platform.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/conf.h>
40 #include <sys/bus.h>
41 #include <sys/endian.h>
42 #include <sys/kernel.h>
43 #include <sys/kthread.h>
44 #include <sys/module.h>
45 #include <sys/lock.h>
46 #include <sys/mutex.h>
47 #include <sys/resource.h>
48 #include <sys/rman.h>
49 
50 #include <machine/bus.h>
51 
52 #ifdef FDT
53 #include <dev/fdt/fdt_common.h>
54 #include <dev/ofw/ofw_bus.h>
55 #include <dev/ofw/ofw_bus_subr.h>
56 #endif
57 
58 #include <dev/altera/softdma/a_api.h>
59 
60 #include <dev/xdma/xdma.h>
61 #include "xdma_if.h"
62 
63 #define SOFTDMA_DEBUG
64 #undef SOFTDMA_DEBUG
65 
66 #ifdef SOFTDMA_DEBUG
67 #define dprintf(fmt, ...)  printf(fmt, ##__VA_ARGS__)
68 #else
69 #define dprintf(fmt, ...)
70 #endif
71 
72 #define	AVALON_FIFO_TX_BASIC_OPTS_DEPTH		16
73 #define	SOFTDMA_NCHANNELS			1
74 #define	CONTROL_GEN_SOP				(1 << 0)
75 #define	CONTROL_GEN_EOP				(1 << 1)
76 #define	CONTROL_OWN				(1 << 31)
77 
78 #define	SOFTDMA_RX_EVENTS	\
79 	(A_ONCHIP_FIFO_MEM_CORE_INTR_FULL	| \
80 	 A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW	| \
81 	 A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
82 #define	SOFTDMA_TX_EVENTS	\
83 	(A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY	| \
84  	A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW	| \
85  	A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
86 
87 struct softdma_channel {
88 	struct softdma_softc	*sc;
89 	struct mtx		mtx;
90 	xdma_channel_t		*xchan;
91 	struct proc		*p;
92 	int			used;
93 	int			index;
94 	int			run;
95 	uint32_t		idx_tail;
96 	uint32_t		idx_head;
97 	struct softdma_desc	*descs;
98 
99 	uint32_t		descs_num;
100 	uint32_t		descs_used_count;
101 };
102 
103 struct softdma_desc {
104 	uint64_t		src_addr;
105 	uint64_t		dst_addr;
106 	uint32_t		len;
107 	uint32_t		access_width;
108 	uint32_t		count;
109 	uint16_t		src_incr;
110 	uint16_t		dst_incr;
111 	uint32_t		direction;
112 	struct softdma_desc	*next;
113 	uint32_t		transfered;
114 	uint32_t		status;
115 	uint32_t		reserved;
116 	uint32_t		control;
117 };
118 
119 struct softdma_softc {
120 	device_t		dev;
121 	struct resource		*res[3];
122 	bus_space_tag_t		bst;
123 	bus_space_handle_t	bsh;
124 	bus_space_tag_t		bst_c;
125 	bus_space_handle_t	bsh_c;
126 	void			*ih;
127 	struct softdma_channel	channels[SOFTDMA_NCHANNELS];
128 };
129 
130 static struct resource_spec softdma_spec[] = {
131 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* fifo */
132 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* core */
133 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
134 	{ -1, 0 }
135 };
136 
137 static int softdma_probe(device_t dev);
138 static int softdma_attach(device_t dev);
139 static int softdma_detach(device_t dev);
140 
141 static inline uint32_t
142 softdma_next_desc(struct softdma_channel *chan, uint32_t curidx)
143 {
144 
145 	return ((curidx + 1) % chan->descs_num);
146 }
147 
148 static void
149 softdma_mem_write(struct softdma_softc *sc, uint32_t reg, uint32_t val)
150 {
151 
152 	bus_write_4(sc->res[0], reg, htole32(val));
153 }
154 
155 static uint32_t
156 softdma_mem_read(struct softdma_softc *sc, uint32_t reg)
157 {
158 	uint32_t val;
159 
160 	val = bus_read_4(sc->res[0], reg);
161 
162 	return (le32toh(val));
163 }
164 
165 static void
166 softdma_memc_write(struct softdma_softc *sc, uint32_t reg, uint32_t val)
167 {
168 
169 	bus_write_4(sc->res[1], reg, htole32(val));
170 }
171 
172 static uint32_t
173 softdma_memc_read(struct softdma_softc *sc, uint32_t reg)
174 {
175 	uint32_t val;
176 
177 	val = bus_read_4(sc->res[1], reg);
178 
179 	return (le32toh(val));
180 }
181 
182 static uint32_t
183 softdma_fill_level(struct softdma_softc *sc)
184 {
185 	uint32_t val;
186 
187 	val = softdma_memc_read(sc,
188 	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL);
189 
190 	return (val);
191 }
192 
193 static uint32_t
194 fifo_fill_level_wait(struct softdma_softc *sc)
195 {
196 	uint32_t val;
197 
198 	do
199 		val = softdma_fill_level(sc);
200 	while (val == AVALON_FIFO_TX_BASIC_OPTS_DEPTH);
201 
202 	return (val);
203 }
204 
205 static void
206 softdma_intr(void *arg)
207 {
208 	struct softdma_channel *chan;
209 	struct softdma_softc *sc;
210 	int reg;
211 	int err;
212 
213 	sc = arg;
214 
215 	chan = &sc->channels[0];
216 
217 	reg = softdma_memc_read(sc, A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT);
218 
219 	if (reg & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW |
220 	    A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) {
221 		/* Errors */
222 		err = (((reg & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> \
223 		    A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff);
224 	}
225 
226 	if (reg != 0) {
227 		softdma_memc_write(sc,
228 		    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, reg);
229 		chan->run = 1;
230 		wakeup(chan);
231 	}
232 }
233 
234 static int
235 softdma_probe(device_t dev)
236 {
237 
238 	if (!ofw_bus_status_okay(dev))
239 		return (ENXIO);
240 
241 	if (!ofw_bus_is_compatible(dev, "altr,softdma"))
242 		return (ENXIO);
243 
244 	device_set_desc(dev, "SoftDMA");
245 
246 	return (BUS_PROBE_DEFAULT);
247 }
248 
249 static int
250 softdma_attach(device_t dev)
251 {
252 	struct softdma_softc *sc;
253 	phandle_t xref, node;
254 	int err;
255 
256 	sc = device_get_softc(dev);
257 	sc->dev = dev;
258 
259 	if (bus_alloc_resources(dev, softdma_spec, sc->res)) {
260 		device_printf(dev,
261 		    "could not allocate resources for device\n");
262 		return (ENXIO);
263 	}
264 
265 	/* FIFO memory interface */
266 	sc->bst = rman_get_bustag(sc->res[0]);
267 	sc->bsh = rman_get_bushandle(sc->res[0]);
268 
269 	/* FIFO control memory interface */
270 	sc->bst_c = rman_get_bustag(sc->res[1]);
271 	sc->bsh_c = rman_get_bushandle(sc->res[1]);
272 
273 	/* Setup interrupt handler */
274 	err = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
275 	    NULL, softdma_intr, sc, &sc->ih);
276 	if (err) {
277 		device_printf(dev, "Unable to alloc interrupt resource.\n");
278 		return (ENXIO);
279 	}
280 
281 	node = ofw_bus_get_node(dev);
282 	xref = OF_xref_from_node(node);
283 	OF_device_register_xref(xref, dev);
284 
285 	return (0);
286 }
287 
288 static int
289 softdma_detach(device_t dev)
290 {
291 	struct softdma_softc *sc;
292 
293 	sc = device_get_softc(dev);
294 
295 	return (0);
296 }
297 
298 static int
299 softdma_process_tx(struct softdma_channel *chan, struct softdma_desc *desc)
300 {
301 	struct softdma_softc *sc;
302 	uint64_t addr;
303 	uint64_t buf;
304 	uint32_t word;
305 	uint32_t missing;
306 	uint32_t reg;
307 	int got_bits;
308 	int len;
309 
310 	sc = chan->sc;
311 
312 	fifo_fill_level_wait(sc);
313 
314 	/* Set start of packet. */
315 	if (desc->control & CONTROL_GEN_SOP)
316 		softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
317 		    A_ONCHIP_FIFO_MEM_CORE_SOP);
318 
319 	got_bits = 0;
320 	buf = 0;
321 
322 	addr = desc->src_addr;
323 	len = desc->len;
324 
325 	if (addr & 1) {
326 		buf = (buf << 8) | *(uint8_t *)addr;
327 		got_bits += 8;
328 		addr += 1;
329 		len -= 1;
330 	}
331 
332 	if (len >= 2 && addr & 2) {
333 		buf = (buf << 16) | *(uint16_t *)addr;
334 		got_bits += 16;
335 		addr += 2;
336 		len -= 2;
337 	}
338 
339 	while (len >= 4) {
340 		buf = (buf << 32) | (uint64_t)*(uint32_t *)addr;
341 		addr += 4;
342 		len -= 4;
343 		word = (uint32_t)((buf >> got_bits) & 0xffffffff);
344 
345 		fifo_fill_level_wait(sc);
346 		if (len == 0 && got_bits == 0 &&
347 		    (desc->control & CONTROL_GEN_EOP) != 0)
348 			softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
349 			    A_ONCHIP_FIFO_MEM_CORE_EOP);
350 		bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
351 	}
352 
353 	if (len & 2) {
354 		buf = (buf << 16) | *(uint16_t *)addr;
355 		got_bits += 16;
356 		addr += 2;
357 		len -= 2;
358 	}
359 
360 	if (len & 1) {
361 		buf = (buf << 8) | *(uint8_t *)addr;
362 		got_bits += 8;
363 		addr += 1;
364 		len -= 1;
365 	}
366 
367 	if (got_bits >= 32) {
368 		got_bits -= 32;
369 		word = (uint32_t)((buf >> got_bits) & 0xffffffff);
370 
371 		fifo_fill_level_wait(sc);
372 		if (len == 0 && got_bits == 0 &&
373 		    (desc->control & CONTROL_GEN_EOP) != 0)
374 			softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
375 			    A_ONCHIP_FIFO_MEM_CORE_EOP);
376 		bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
377 	}
378 
379 	if (got_bits) {
380 		missing = 32 - got_bits;
381 		got_bits /= 8;
382 
383 		fifo_fill_level_wait(sc);
384 		reg = A_ONCHIP_FIFO_MEM_CORE_EOP |
385 		    ((4 - got_bits) << A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT);
386 		softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA, reg);
387 		word = (uint32_t)((buf << missing) & 0xffffffff);
388 		bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
389 	}
390 
391 	return (desc->len);
392 }
393 
394 static int
395 softdma_process_rx(struct softdma_channel *chan, struct softdma_desc *desc)
396 {
397 	uint32_t src_offs, dst_offs;
398 	struct softdma_softc *sc;
399 	uint32_t fill_level;
400 	uint32_t empty;
401 	uint32_t meta;
402 	uint32_t data;
403 	int sop_rcvd;
404 	int timeout;
405 	size_t len;
406 	int error;
407 
408 	sc = chan->sc;
409 	empty = 0;
410 	src_offs = dst_offs = 0;
411 	error = 0;
412 
413 	fill_level = softdma_fill_level(sc);
414 	if (fill_level == 0) {
415 		/* Nothing to receive. */
416 		return (0);
417 	}
418 
419 	len = desc->len;
420 
421 	sop_rcvd = 0;
422 	while (fill_level) {
423 		empty = 0;
424 		data = bus_read_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA);
425 		meta = softdma_mem_read(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA);
426 
427 		if (meta & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) {
428 			error = 1;
429 			break;
430 		}
431 
432 		if ((meta & A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) != 0) {
433 			error = 1;
434 			break;
435 		}
436 
437 		if (meta & A_ONCHIP_FIFO_MEM_CORE_SOP) {
438 			sop_rcvd = 1;
439 		}
440 
441 		if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP) {
442 			empty = (meta & A_ONCHIP_FIFO_MEM_CORE_EMPTY_MASK) >>
443 			    A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT;
444 		}
445 
446 		if (sop_rcvd == 0) {
447 			error = 1;
448 			break;
449 		}
450 
451 		if (empty == 0) {
452 			*(uint32_t *)(desc->dst_addr + dst_offs) = data;
453 			dst_offs += 4;
454 		} else if (empty == 1) {
455 			*(uint16_t *)(desc->dst_addr + dst_offs) =
456 			    ((data >> 16) & 0xffff);
457 			dst_offs += 2;
458 
459 			*(uint8_t *)(desc->dst_addr + dst_offs) =
460 			    ((data >> 8) & 0xff);
461 			dst_offs += 1;
462 		} else {
463 			panic("empty %d\n", empty);
464 		}
465 
466 		if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP)
467 			break;
468 
469 		fill_level = softdma_fill_level(sc);
470 		timeout = 100;
471 		while (fill_level == 0 && timeout--)
472 			fill_level = softdma_fill_level(sc);
473 		if (timeout == 0) {
474 			/* No EOP received. Broken packet. */
475 			error = 1;
476 			break;
477 		}
478 	}
479 
480 	if (error) {
481 		return (-1);
482 	}
483 
484 	return (dst_offs);
485 }
486 
487 static uint32_t
488 softdma_process_descriptors(struct softdma_channel *chan,
489     xdma_transfer_status_t *status)
490 {
491 	struct xdma_channel *xchan;
492 	struct softdma_desc *desc;
493 	struct softdma_softc *sc;
494 	xdma_transfer_status_t st;
495 	int ret;
496 
497 	sc = chan->sc;
498 
499 	xchan = chan->xchan;
500 
501 	desc = &chan->descs[chan->idx_tail];
502 
503 	while (desc != NULL) {
504 
505 		if ((desc->control & CONTROL_OWN) == 0) {
506 			break;
507 		}
508 
509 		if (desc->direction == XDMA_MEM_TO_DEV) {
510 			ret = softdma_process_tx(chan, desc);
511 		} else {
512 			ret = softdma_process_rx(chan, desc);
513 			if (ret == 0) {
514 				/* No new data available. */
515 				break;
516 			}
517 		}
518 
519 		/* Descriptor processed. */
520 		desc->control = 0;
521 
522 		if (ret >= 0) {
523 			st.error = 0;
524 			st.transferred = ret;
525 		} else {
526 			st.error = ret;
527 			st.transferred = 0;
528 		}
529 
530 		xchan_seg_done(xchan, &st);
531 		atomic_subtract_int(&chan->descs_used_count, 1);
532 
533 		if (ret >= 0) {
534 			status->transferred += ret;
535 		} else {
536 			status->error = 1;
537 			break;
538 		}
539 
540 		chan->idx_tail = softdma_next_desc(chan, chan->idx_tail);
541 
542 		/* Process next descriptor, if any. */
543 		desc = desc->next;
544 	}
545 
546 	return (0);
547 }
548 
549 static void
550 softdma_worker(void *arg)
551 {
552 	xdma_transfer_status_t status;
553 	struct softdma_channel *chan;
554 	struct softdma_softc *sc;
555 
556 	chan = arg;
557 
558 	sc = chan->sc;
559 
560 	while (1) {
561 		mtx_lock(&chan->mtx);
562 
563 		do {
564 			mtx_sleep(chan, &chan->mtx, 0, "softdma_wait", hz / 2);
565 		} while (chan->run == 0);
566 
567 		status.error = 0;
568 		status.transferred = 0;
569 
570 		softdma_process_descriptors(chan, &status);
571 
572 		/* Finish operation */
573 		chan->run = 0;
574 		xdma_callback(chan->xchan, &status);
575 
576 		mtx_unlock(&chan->mtx);
577 	}
578 
579 }
580 
581 static int
582 softdma_proc_create(struct softdma_channel *chan)
583 {
584 	struct softdma_softc *sc;
585 
586 	sc = chan->sc;
587 
588 	if (chan->p != NULL) {
589 		/* Already created */
590 		return (0);
591 	}
592 
593 	mtx_init(&chan->mtx, "SoftDMA", NULL, MTX_DEF);
594 
595 	if (kproc_create(softdma_worker, (void *)chan, &chan->p, 0, 0,
596 	    "softdma_worker") != 0) {
597 		device_printf(sc->dev,
598 		    "%s: Failed to create worker thread.\n", __func__);
599 		return (-1);
600 	}
601 
602 	return (0);
603 }
604 
605 static int
606 softdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
607 {
608 	struct softdma_channel *chan;
609 	struct softdma_softc *sc;
610 	int i;
611 
612 	sc = device_get_softc(dev);
613 
614 	for (i = 0; i < SOFTDMA_NCHANNELS; i++) {
615 		chan = &sc->channels[i];
616 		if (chan->used == 0) {
617 			chan->xchan = xchan;
618 			xchan->chan = (void *)chan;
619 			xchan->caps |= XCHAN_CAP_NOSEG;
620 			chan->index = i;
621 			chan->idx_head = 0;
622 			chan->idx_tail = 0;
623 			chan->descs_used_count = 0;
624 			chan->descs_num = 1024;
625 			chan->sc = sc;
626 
627 			if (softdma_proc_create(chan) != 0) {
628 				return (-1);
629 			}
630 
631 			chan->used = 1;
632 
633 			return (0);
634 		}
635 	}
636 
637 	return (-1);
638 }
639 
640 static int
641 softdma_channel_free(device_t dev, struct xdma_channel *xchan)
642 {
643 	struct softdma_channel *chan;
644 	struct softdma_softc *sc;
645 
646 	sc = device_get_softc(dev);
647 
648 	chan = (struct softdma_channel *)xchan->chan;
649 
650 	if (chan->descs != NULL) {
651 		free(chan->descs, M_DEVBUF);
652 	}
653 
654 	chan->used = 0;
655 
656 	return (0);
657 }
658 
659 static int
660 softdma_desc_alloc(struct xdma_channel *xchan)
661 {
662 	struct softdma_channel *chan;
663 	uint32_t nsegments;
664 
665 	chan = (struct softdma_channel *)xchan->chan;
666 
667 	nsegments = chan->descs_num;
668 
669 	chan->descs = malloc(nsegments * sizeof(struct softdma_desc),
670 	    M_DEVBUF, (M_WAITOK | M_ZERO));
671 
672 	return (0);
673 }
674 
675 static int
676 softdma_channel_prep_sg(device_t dev, struct xdma_channel *xchan)
677 {
678 	struct softdma_channel *chan;
679 	struct softdma_desc *desc;
680 	struct softdma_softc *sc;
681 	int ret;
682 	int i;
683 
684 	sc = device_get_softc(dev);
685 
686 	chan = (struct softdma_channel *)xchan->chan;
687 
688 	ret = softdma_desc_alloc(xchan);
689 	if (ret != 0) {
690 		device_printf(sc->dev,
691 		    "%s: Can't allocate descriptors.\n", __func__);
692 		return (-1);
693 	}
694 
695 	for (i = 0; i < chan->descs_num; i++) {
696 		desc = &chan->descs[i];
697 
698 		if (i == (chan->descs_num - 1)) {
699 			desc->next = &chan->descs[0];
700 		} else {
701 			desc->next = &chan->descs[i+1];
702 		}
703 	}
704 
705 	return (0);
706 }
707 
708 static int
709 softdma_channel_capacity(device_t dev, xdma_channel_t *xchan,
710     uint32_t *capacity)
711 {
712 	struct softdma_channel *chan;
713 	uint32_t c;
714 
715 	chan = (struct softdma_channel *)xchan->chan;
716 
717 	/* At least one descriptor must be left empty. */
718 	c = (chan->descs_num - chan->descs_used_count - 1);
719 
720 	*capacity = c;
721 
722 	return (0);
723 }
724 
725 static int
726 softdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan,
727     struct xdma_sglist *sg, uint32_t sg_n)
728 {
729 	struct softdma_channel *chan;
730 	struct softdma_desc *desc;
731 	struct softdma_softc *sc;
732 	uint32_t enqueued;
733 	uint32_t saved_dir;
734 	uint32_t tmp;
735 	uint32_t len;
736 	int i;
737 
738 	sc = device_get_softc(dev);
739 
740 	chan = (struct softdma_channel *)xchan->chan;
741 
742 	enqueued = 0;
743 
744 	for (i = 0; i < sg_n; i++) {
745 		len = (uint32_t)sg[i].len;
746 
747 		desc = &chan->descs[chan->idx_head];
748 		desc->src_addr = sg[i].src_addr;
749 		desc->dst_addr = sg[i].dst_addr;
750 		if (sg[i].direction == XDMA_MEM_TO_DEV) {
751 			desc->src_incr = 1;
752 			desc->dst_incr = 0;
753 		} else {
754 			desc->src_incr = 0;
755 			desc->dst_incr = 1;
756 		}
757 		desc->direction = sg[i].direction;
758 		saved_dir = sg[i].direction;
759 		desc->len = len;
760 		desc->transfered = 0;
761 		desc->status = 0;
762 		desc->reserved = 0;
763 		desc->control = 0;
764 
765 		if (sg[i].first == 1)
766 			desc->control |= CONTROL_GEN_SOP;
767 		if (sg[i].last == 1)
768 			desc->control |= CONTROL_GEN_EOP;
769 
770 		tmp = chan->idx_head;
771 		chan->idx_head = softdma_next_desc(chan, chan->idx_head);
772 		atomic_add_int(&chan->descs_used_count, 1);
773 		desc->control |= CONTROL_OWN;
774 		enqueued += 1;
775 	}
776 
777 	if (enqueued == 0)
778 		return (0);
779 
780 	if (saved_dir == XDMA_MEM_TO_DEV) {
781 		chan->run = 1;
782 		wakeup(chan);
783 	} else
784 		softdma_memc_write(sc,
785 		    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,
786 		    SOFTDMA_RX_EVENTS);
787 
788 	return (0);
789 }
790 
791 static int
792 softdma_channel_request(device_t dev, struct xdma_channel *xchan,
793     struct xdma_request *req)
794 {
795 	struct softdma_channel *chan;
796 	struct softdma_desc *desc;
797 	struct softdma_softc *sc;
798 	int ret;
799 
800 	sc = device_get_softc(dev);
801 
802 	chan = (struct softdma_channel *)xchan->chan;
803 
804 	ret = softdma_desc_alloc(xchan);
805 	if (ret != 0) {
806 		device_printf(sc->dev,
807 		    "%s: Can't allocate descriptors.\n", __func__);
808 		return (-1);
809 	}
810 
811 	desc = &chan->descs[0];
812 
813 	desc->src_addr = req->src_addr;
814 	desc->dst_addr = req->dst_addr;
815 	desc->len = req->block_len;
816 	desc->src_incr = 1;
817 	desc->dst_incr = 1;
818 	desc->next = NULL;
819 
820 	return (0);
821 }
822 
823 static int
824 softdma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd)
825 {
826 	struct softdma_channel *chan;
827 	struct softdma_softc *sc;
828 
829 	sc = device_get_softc(dev);
830 
831 	chan = (struct softdma_channel *)xchan->chan;
832 
833 	switch (cmd) {
834 	case XDMA_CMD_BEGIN:
835 	case XDMA_CMD_TERMINATE:
836 	case XDMA_CMD_PAUSE:
837 		/* TODO: implement me */
838 		return (-1);
839 	}
840 
841 	return (0);
842 }
843 
844 #ifdef FDT
845 static int
846 softdma_ofw_md_data(device_t dev, pcell_t *cells,
847     int ncells, void **ptr)
848 {
849 
850 	return (0);
851 }
852 #endif
853 
854 static device_method_t softdma_methods[] = {
855 	/* Device interface */
856 	DEVMETHOD(device_probe,			softdma_probe),
857 	DEVMETHOD(device_attach,		softdma_attach),
858 	DEVMETHOD(device_detach,		softdma_detach),
859 
860 	/* xDMA Interface */
861 	DEVMETHOD(xdma_channel_alloc,		softdma_channel_alloc),
862 	DEVMETHOD(xdma_channel_free,		softdma_channel_free),
863 	DEVMETHOD(xdma_channel_request,		softdma_channel_request),
864 	DEVMETHOD(xdma_channel_control,		softdma_channel_control),
865 
866 	/* xDMA SG Interface */
867 	DEVMETHOD(xdma_channel_prep_sg,		softdma_channel_prep_sg),
868 	DEVMETHOD(xdma_channel_submit_sg,	softdma_channel_submit_sg),
869 	DEVMETHOD(xdma_channel_capacity,	softdma_channel_capacity),
870 
871 #ifdef FDT
872 	DEVMETHOD(xdma_ofw_md_data,		softdma_ofw_md_data),
873 #endif
874 
875 	DEVMETHOD_END
876 };
877 
878 static driver_t softdma_driver = {
879 	"softdma",
880 	softdma_methods,
881 	sizeof(struct softdma_softc),
882 };
883 
884 static devclass_t softdma_devclass;
885 
886 EARLY_DRIVER_MODULE(softdma, simplebus, softdma_driver, softdma_devclass, 0, 0,
887     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
888