xref: /freebsd/sys/dev/altera/softdma/softdma.c (revision 38a52bd3)
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 		if ((desc->control & CONTROL_OWN) == 0) {
505 			break;
506 		}
507 
508 		if (desc->direction == XDMA_MEM_TO_DEV) {
509 			ret = softdma_process_tx(chan, desc);
510 		} else {
511 			ret = softdma_process_rx(chan, desc);
512 			if (ret == 0) {
513 				/* No new data available. */
514 				break;
515 			}
516 		}
517 
518 		/* Descriptor processed. */
519 		desc->control = 0;
520 
521 		if (ret >= 0) {
522 			st.error = 0;
523 			st.transferred = ret;
524 		} else {
525 			st.error = ret;
526 			st.transferred = 0;
527 		}
528 
529 		xchan_seg_done(xchan, &st);
530 		atomic_subtract_int(&chan->descs_used_count, 1);
531 
532 		if (ret >= 0) {
533 			status->transferred += ret;
534 		} else {
535 			status->error = 1;
536 			break;
537 		}
538 
539 		chan->idx_tail = softdma_next_desc(chan, chan->idx_tail);
540 
541 		/* Process next descriptor, if any. */
542 		desc = desc->next;
543 	}
544 
545 	return (0);
546 }
547 
548 static void
549 softdma_worker(void *arg)
550 {
551 	xdma_transfer_status_t status;
552 	struct softdma_channel *chan;
553 	struct softdma_softc *sc;
554 
555 	chan = arg;
556 
557 	sc = chan->sc;
558 
559 	while (1) {
560 		mtx_lock(&chan->mtx);
561 
562 		do {
563 			mtx_sleep(chan, &chan->mtx, 0, "softdma_wait", hz / 2);
564 		} while (chan->run == 0);
565 
566 		status.error = 0;
567 		status.transferred = 0;
568 
569 		softdma_process_descriptors(chan, &status);
570 
571 		/* Finish operation */
572 		chan->run = 0;
573 		xdma_callback(chan->xchan, &status);
574 
575 		mtx_unlock(&chan->mtx);
576 	}
577 
578 }
579 
580 static int
581 softdma_proc_create(struct softdma_channel *chan)
582 {
583 	struct softdma_softc *sc;
584 
585 	sc = chan->sc;
586 
587 	if (chan->p != NULL) {
588 		/* Already created */
589 		return (0);
590 	}
591 
592 	mtx_init(&chan->mtx, "SoftDMA", NULL, MTX_DEF);
593 
594 	if (kproc_create(softdma_worker, (void *)chan, &chan->p, 0, 0,
595 	    "softdma_worker") != 0) {
596 		device_printf(sc->dev,
597 		    "%s: Failed to create worker thread.\n", __func__);
598 		return (-1);
599 	}
600 
601 	return (0);
602 }
603 
604 static int
605 softdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
606 {
607 	struct softdma_channel *chan;
608 	struct softdma_softc *sc;
609 	int i;
610 
611 	sc = device_get_softc(dev);
612 
613 	for (i = 0; i < SOFTDMA_NCHANNELS; i++) {
614 		chan = &sc->channels[i];
615 		if (chan->used == 0) {
616 			chan->xchan = xchan;
617 			xchan->chan = (void *)chan;
618 			xchan->caps |= XCHAN_CAP_NOSEG;
619 			chan->index = i;
620 			chan->idx_head = 0;
621 			chan->idx_tail = 0;
622 			chan->descs_used_count = 0;
623 			chan->descs_num = 1024;
624 			chan->sc = sc;
625 
626 			if (softdma_proc_create(chan) != 0) {
627 				return (-1);
628 			}
629 
630 			chan->used = 1;
631 
632 			return (0);
633 		}
634 	}
635 
636 	return (-1);
637 }
638 
639 static int
640 softdma_channel_free(device_t dev, struct xdma_channel *xchan)
641 {
642 	struct softdma_channel *chan;
643 	struct softdma_softc *sc;
644 
645 	sc = device_get_softc(dev);
646 
647 	chan = (struct softdma_channel *)xchan->chan;
648 
649 	if (chan->descs != NULL) {
650 		free(chan->descs, M_DEVBUF);
651 	}
652 
653 	chan->used = 0;
654 
655 	return (0);
656 }
657 
658 static int
659 softdma_desc_alloc(struct xdma_channel *xchan)
660 {
661 	struct softdma_channel *chan;
662 	uint32_t nsegments;
663 
664 	chan = (struct softdma_channel *)xchan->chan;
665 
666 	nsegments = chan->descs_num;
667 
668 	chan->descs = malloc(nsegments * sizeof(struct softdma_desc),
669 	    M_DEVBUF, (M_WAITOK | M_ZERO));
670 
671 	return (0);
672 }
673 
674 static int
675 softdma_channel_prep_sg(device_t dev, struct xdma_channel *xchan)
676 {
677 	struct softdma_channel *chan;
678 	struct softdma_desc *desc;
679 	struct softdma_softc *sc;
680 	int ret;
681 	int i;
682 
683 	sc = device_get_softc(dev);
684 
685 	chan = (struct softdma_channel *)xchan->chan;
686 
687 	ret = softdma_desc_alloc(xchan);
688 	if (ret != 0) {
689 		device_printf(sc->dev,
690 		    "%s: Can't allocate descriptors.\n", __func__);
691 		return (-1);
692 	}
693 
694 	for (i = 0; i < chan->descs_num; i++) {
695 		desc = &chan->descs[i];
696 
697 		if (i == (chan->descs_num - 1)) {
698 			desc->next = &chan->descs[0];
699 		} else {
700 			desc->next = &chan->descs[i+1];
701 		}
702 	}
703 
704 	return (0);
705 }
706 
707 static int
708 softdma_channel_capacity(device_t dev, xdma_channel_t *xchan,
709     uint32_t *capacity)
710 {
711 	struct softdma_channel *chan;
712 	uint32_t c;
713 
714 	chan = (struct softdma_channel *)xchan->chan;
715 
716 	/* At least one descriptor must be left empty. */
717 	c = (chan->descs_num - chan->descs_used_count - 1);
718 
719 	*capacity = c;
720 
721 	return (0);
722 }
723 
724 static int
725 softdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan,
726     struct xdma_sglist *sg, uint32_t sg_n)
727 {
728 	struct softdma_channel *chan;
729 	struct softdma_desc *desc;
730 	struct softdma_softc *sc;
731 	uint32_t enqueued;
732 	uint32_t saved_dir;
733 	uint32_t tmp;
734 	uint32_t len;
735 	int i;
736 
737 	sc = device_get_softc(dev);
738 
739 	chan = (struct softdma_channel *)xchan->chan;
740 
741 	enqueued = 0;
742 
743 	for (i = 0; i < sg_n; i++) {
744 		len = (uint32_t)sg[i].len;
745 
746 		desc = &chan->descs[chan->idx_head];
747 		desc->src_addr = sg[i].src_addr;
748 		desc->dst_addr = sg[i].dst_addr;
749 		if (sg[i].direction == XDMA_MEM_TO_DEV) {
750 			desc->src_incr = 1;
751 			desc->dst_incr = 0;
752 		} else {
753 			desc->src_incr = 0;
754 			desc->dst_incr = 1;
755 		}
756 		desc->direction = sg[i].direction;
757 		saved_dir = sg[i].direction;
758 		desc->len = len;
759 		desc->transfered = 0;
760 		desc->status = 0;
761 		desc->reserved = 0;
762 		desc->control = 0;
763 
764 		if (sg[i].first == 1)
765 			desc->control |= CONTROL_GEN_SOP;
766 		if (sg[i].last == 1)
767 			desc->control |= CONTROL_GEN_EOP;
768 
769 		tmp = chan->idx_head;
770 		chan->idx_head = softdma_next_desc(chan, chan->idx_head);
771 		atomic_add_int(&chan->descs_used_count, 1);
772 		desc->control |= CONTROL_OWN;
773 		enqueued += 1;
774 	}
775 
776 	if (enqueued == 0)
777 		return (0);
778 
779 	if (saved_dir == XDMA_MEM_TO_DEV) {
780 		chan->run = 1;
781 		wakeup(chan);
782 	} else
783 		softdma_memc_write(sc,
784 		    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,
785 		    SOFTDMA_RX_EVENTS);
786 
787 	return (0);
788 }
789 
790 static int
791 softdma_channel_request(device_t dev, struct xdma_channel *xchan,
792     struct xdma_request *req)
793 {
794 	struct softdma_channel *chan;
795 	struct softdma_desc *desc;
796 	struct softdma_softc *sc;
797 	int ret;
798 
799 	sc = device_get_softc(dev);
800 
801 	chan = (struct softdma_channel *)xchan->chan;
802 
803 	ret = softdma_desc_alloc(xchan);
804 	if (ret != 0) {
805 		device_printf(sc->dev,
806 		    "%s: Can't allocate descriptors.\n", __func__);
807 		return (-1);
808 	}
809 
810 	desc = &chan->descs[0];
811 
812 	desc->src_addr = req->src_addr;
813 	desc->dst_addr = req->dst_addr;
814 	desc->len = req->block_len;
815 	desc->src_incr = 1;
816 	desc->dst_incr = 1;
817 	desc->next = NULL;
818 
819 	return (0);
820 }
821 
822 static int
823 softdma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd)
824 {
825 	struct softdma_channel *chan;
826 	struct softdma_softc *sc;
827 
828 	sc = device_get_softc(dev);
829 
830 	chan = (struct softdma_channel *)xchan->chan;
831 
832 	switch (cmd) {
833 	case XDMA_CMD_BEGIN:
834 	case XDMA_CMD_TERMINATE:
835 	case XDMA_CMD_PAUSE:
836 		/* TODO: implement me */
837 		return (-1);
838 	}
839 
840 	return (0);
841 }
842 
843 #ifdef FDT
844 static int
845 softdma_ofw_md_data(device_t dev, pcell_t *cells,
846     int ncells, void **ptr)
847 {
848 
849 	return (0);
850 }
851 #endif
852 
853 static device_method_t softdma_methods[] = {
854 	/* Device interface */
855 	DEVMETHOD(device_probe,			softdma_probe),
856 	DEVMETHOD(device_attach,		softdma_attach),
857 	DEVMETHOD(device_detach,		softdma_detach),
858 
859 	/* xDMA Interface */
860 	DEVMETHOD(xdma_channel_alloc,		softdma_channel_alloc),
861 	DEVMETHOD(xdma_channel_free,		softdma_channel_free),
862 	DEVMETHOD(xdma_channel_request,		softdma_channel_request),
863 	DEVMETHOD(xdma_channel_control,		softdma_channel_control),
864 
865 	/* xDMA SG Interface */
866 	DEVMETHOD(xdma_channel_prep_sg,		softdma_channel_prep_sg),
867 	DEVMETHOD(xdma_channel_submit_sg,	softdma_channel_submit_sg),
868 	DEVMETHOD(xdma_channel_capacity,	softdma_channel_capacity),
869 
870 #ifdef FDT
871 	DEVMETHOD(xdma_ofw_md_data,		softdma_ofw_md_data),
872 #endif
873 
874 	DEVMETHOD_END
875 };
876 
877 static driver_t softdma_driver = {
878 	"softdma",
879 	softdma_methods,
880 	sizeof(struct softdma_softc),
881 };
882 
883 EARLY_DRIVER_MODULE(softdma, simplebus, softdma_driver, 0, 0,
884     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
885