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