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
85struct 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
101struct 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
117struct 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
128static 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
135static int softdma_probe(device_t dev);
136static int softdma_attach(device_t dev);
137static int softdma_detach(device_t dev);
138
139static inline uint32_t
140softdma_next_desc(struct softdma_channel *chan, uint32_t curidx)
141{
142
143	return ((curidx + 1) % chan->descs_num);
144}
145
146static void
147softdma_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
153static uint32_t
154softdma_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
163static void
164softdma_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
170static uint32_t
171softdma_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
180static uint32_t
181softdma_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
191static uint32_t
192fifo_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
203static void
204softdma_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
232static int
233softdma_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
247static int
248softdma_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
286static int
287softdma_detach(device_t dev)
288{
289	struct softdma_softc *sc;
290
291	sc = device_get_softc(dev);
292
293	return (0);
294}
295
296static int
297softdma_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
392static int
393softdma_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
485static uint32_t
486softdma_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
546static void
547softdma_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
578static int
579softdma_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
602static int
603softdma_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
637static int
638softdma_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
656static int
657softdma_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
672static int
673softdma_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
705static int
706softdma_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
722static int
723softdma_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
788static int
789softdma_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
820static int
821softdma_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
842static int
843softdma_ofw_md_data(device_t dev, pcell_t *cells,
844    int ncells, void **ptr)
845{
846
847	return (0);
848}
849#endif
850
851static 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
875static driver_t softdma_driver = {
876	"softdma",
877	softdma_methods,
878	sizeof(struct softdma_softc),
879};
880
881EARLY_DRIVER_MODULE(softdma, simplebus, softdma_driver, 0, 0,
882    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
883