kernel/mrsas: Fix a double assignment.
[dragonfly.git] / sys / bus / u4b / usb_busdma.c
blob8e75ed5b6fc9446b786d63015053eff6859f0182
1 /* $FreeBSD: head/sys/dev/usb/usb_busdma.c 261505 2014-02-05 08:02:52Z hselasky $ */
2 /*-
3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
27 #include <sys/stdint.h>
28 #include <sys/param.h>
29 #include <sys/queue.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/module.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/mutex2.h>
38 #include <sys/condvar.h>
39 #include <sys/sysctl.h>
40 #include <sys/unistd.h>
41 #include <sys/callout.h>
42 #include <sys/malloc.h>
43 #include <sys/priv.h>
45 #include <bus/u4b/usb.h>
46 #include <bus/u4b/usbdi.h>
47 #include <bus/u4b/usbdi_util.h>
49 #define USB_DEBUG_VAR usb_debug
51 #include <bus/u4b/usb_core.h>
52 #include <bus/u4b/usb_busdma.h>
53 #include <bus/u4b/usb_process.h>
54 #include <bus/u4b/usb_transfer.h>
55 #include <bus/u4b/usb_device.h>
56 #include <bus/u4b/usb_util.h>
57 #include <bus/u4b/usb_debug.h>
59 #include <bus/u4b/usb_controller.h>
60 #include <bus/u4b/usb_bus.h>
62 #if USB_HAVE_BUSDMA
63 static void usb_dma_tag_create(struct usb_dma_tag *, usb_size_t, usb_size_t);
64 static void usb_dma_tag_destroy(struct usb_dma_tag *);
65 #if 0
66 static void usb_dma_lock_cb(void *, bus_dma_lock_op_t);
67 #endif
68 static void usb_pc_alloc_mem_cb(void *, bus_dma_segment_t *, int, int);
69 static void usb_pc_load_mem_cb(void *, bus_dma_segment_t *, int, int);
70 static void usb_pc_common_mem_cb(void *, bus_dma_segment_t *, int, int,
71 uint8_t);
72 #endif
74 /*------------------------------------------------------------------------*
75 * usbd_get_page - lookup DMA-able memory for the given offset
77 * NOTE: Only call this function when the "page_cache" structure has
78 * been properly initialized !
79 *------------------------------------------------------------------------*/
80 void
81 usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset,
82 struct usb_page_search *res)
84 #if USB_HAVE_BUSDMA
85 struct usb_page *page;
87 if (pc->page_start) {
89 /* Case 1 - something has been loaded into DMA */
91 if (pc->buffer) {
93 /* Case 1a - Kernel Virtual Address */
95 res->buffer = USB_ADD_BYTES(pc->buffer, offset);
97 offset += pc->page_offset_buf;
99 /* compute destination page */
101 page = pc->page_start;
103 if (pc->ismultiseg) {
105 page += (offset / USB_PAGE_SIZE);
107 offset %= USB_PAGE_SIZE;
109 res->length = USB_PAGE_SIZE - offset;
110 res->physaddr = page->physaddr + offset;
111 } else {
112 res->length = (usb_size_t)-1;
113 res->physaddr = page->physaddr + offset;
115 if (!pc->buffer) {
117 /* Case 1b - Non Kernel Virtual Address */
119 res->buffer = USB_ADD_BYTES(page->buffer, offset);
121 return;
123 #endif
124 /* Case 2 - Plain PIO */
126 res->buffer = USB_ADD_BYTES(pc->buffer, offset);
127 res->length = (usb_size_t)-1;
128 #if USB_HAVE_BUSDMA
129 res->physaddr = 0;
130 #endif
133 /*------------------------------------------------------------------------*
134 * usbd_copy_in - copy directly to DMA-able memory
135 *------------------------------------------------------------------------*/
136 void
137 usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset,
138 const void *ptr, usb_frlength_t len)
140 struct usb_page_search buf_res;
142 while (len != 0) {
144 usbd_get_page(cache, offset, &buf_res);
146 if (buf_res.length > len) {
147 buf_res.length = len;
149 memcpy(buf_res.buffer, ptr, buf_res.length);
151 offset += buf_res.length;
152 len -= buf_res.length;
153 ptr = USB_ADD_BYTES(ptr, buf_res.length);
157 /*------------------------------------------------------------------------*
158 * usbd_copy_in_user - copy directly to DMA-able memory from userland
160 * Return values:
161 * 0: Success
162 * Else: Failure
163 *------------------------------------------------------------------------*/
164 #if USB_HAVE_USER_IO
166 usbd_copy_in_user(struct usb_page_cache *cache, usb_frlength_t offset,
167 const void *ptr, usb_frlength_t len)
169 struct usb_page_search buf_res;
170 int error;
172 while (len != 0) {
174 usbd_get_page(cache, offset, &buf_res);
176 if (buf_res.length > len) {
177 buf_res.length = len;
179 error = copyin(ptr, buf_res.buffer, buf_res.length);
180 if (error)
181 return (error);
183 offset += buf_res.length;
184 len -= buf_res.length;
185 ptr = USB_ADD_BYTES(ptr, buf_res.length);
187 return (0); /* success */
189 #endif
191 /*------------------------------------------------------------------------*
192 * usbd_m_copy_in - copy a mbuf chain directly into DMA-able memory
193 *------------------------------------------------------------------------*/
194 #if USB_HAVE_MBUF
195 struct usb_m_copy_in_arg {
196 struct usb_page_cache *cache;
197 usb_frlength_t dst_offset;
200 static int
201 usbd_m_copy_in_cb(void *arg, void *src, uint32_t count)
203 register struct usb_m_copy_in_arg *ua = arg;
205 usbd_copy_in(ua->cache, ua->dst_offset, src, count);
206 ua->dst_offset += count;
207 return (0);
210 void
211 usbd_m_copy_in(struct usb_page_cache *cache, usb_frlength_t dst_offset,
212 struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len)
214 struct usb_m_copy_in_arg arg = {cache, dst_offset};
215 (void) m_apply(m, src_offset, src_len, &usbd_m_copy_in_cb, &arg);
217 #endif
219 /*------------------------------------------------------------------------*
220 * usb_uiomove - factored out code
221 *------------------------------------------------------------------------*/
222 #if USB_HAVE_USER_IO
224 usb_uiomove(struct usb_page_cache *pc, struct uio *uio,
225 usb_frlength_t pc_offset, usb_frlength_t len)
227 struct usb_page_search res;
228 int error = 0;
230 while (len != 0) {
232 usbd_get_page(pc, pc_offset, &res);
234 if (res.length > len) {
235 res.length = len;
238 * "uiomove()" can sleep so one needs to make a wrapper,
239 * exiting the mutex and checking things
241 error = uiomove(res.buffer, res.length, uio);
243 if (error) {
244 break;
246 pc_offset += res.length;
247 len -= res.length;
249 return (error);
251 #endif
253 /*------------------------------------------------------------------------*
254 * usbd_copy_out - copy directly from DMA-able memory
255 *------------------------------------------------------------------------*/
256 void
257 usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset,
258 void *ptr, usb_frlength_t len)
260 struct usb_page_search res;
262 while (len != 0) {
264 usbd_get_page(cache, offset, &res);
266 if (res.length > len) {
267 res.length = len;
269 memcpy(ptr, res.buffer, res.length);
271 offset += res.length;
272 len -= res.length;
273 ptr = USB_ADD_BYTES(ptr, res.length);
277 /*------------------------------------------------------------------------*
278 * usbd_copy_out_user - copy directly from DMA-able memory to userland
280 * Return values:
281 * 0: Success
282 * Else: Failure
283 *------------------------------------------------------------------------*/
284 #if USB_HAVE_USER_IO
286 usbd_copy_out_user(struct usb_page_cache *cache, usb_frlength_t offset,
287 void *ptr, usb_frlength_t len)
289 struct usb_page_search res;
290 int error;
292 while (len != 0) {
294 usbd_get_page(cache, offset, &res);
296 if (res.length > len) {
297 res.length = len;
299 error = copyout(res.buffer, ptr, res.length);
300 if (error)
301 return (error);
303 offset += res.length;
304 len -= res.length;
305 ptr = USB_ADD_BYTES(ptr, res.length);
307 return (0); /* success */
309 #endif
311 /*------------------------------------------------------------------------*
312 * usbd_frame_zero - zero DMA-able memory
313 *------------------------------------------------------------------------*/
314 void
315 usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
316 usb_frlength_t len)
318 struct usb_page_search res;
320 while (len != 0) {
322 usbd_get_page(cache, offset, &res);
324 if (res.length > len) {
325 res.length = len;
327 memset(res.buffer, 0, res.length);
329 offset += res.length;
330 len -= res.length;
334 #if USB_HAVE_BUSDMA
336 /*------------------------------------------------------------------------*
337 * usb_dma_lock_cb - dummy callback
338 *------------------------------------------------------------------------*/
339 #if 0
340 static void
341 usb_dma_lock_cb(void *arg, bus_dma_lock_op_t op)
343 /* we use "mtx_owned()" instead of this function */
345 #endif
347 /*------------------------------------------------------------------------*
348 * usb_dma_tag_create - allocate a DMA tag
350 * NOTE: If the "align" parameter has a value of 1 the DMA-tag will
351 * allow multi-segment mappings. Else all mappings are single-segment.
352 *------------------------------------------------------------------------*/
353 static void
354 usb_dma_tag_create(struct usb_dma_tag *udt,
355 usb_size_t size, usb_size_t align)
357 bus_dma_tag_t tag;
359 if (bus_dma_tag_create
360 ( /* parent */ udt->tag_parent->tag,
361 /* alignment */ align,
362 /* boundary */ 0,
363 /* lowaddr */ (2ULL << (udt->tag_parent->dma_bits - 1)) - 1,
364 /* highaddr */ BUS_SPACE_MAXADDR,
365 /* filter */ NULL,
366 /* filterarg */ NULL,
367 /* maxsize */ size,
368 /* nsegments */ (align == 1 && size > 1) ? (2 + (size / USB_PAGE_SIZE)) : 1,
369 /* maxsegsz */ (align == 1 && size > USB_PAGE_SIZE) ? USB_PAGE_SIZE : size,
370 /* flags */ BUS_DMA_KEEP_PG_OFFSET,
371 &tag)) {
372 tag = NULL;
374 udt->tag = tag;
377 /*------------------------------------------------------------------------*
378 * usb_dma_tag_free - free a DMA tag
379 *------------------------------------------------------------------------*/
380 static void
381 usb_dma_tag_destroy(struct usb_dma_tag *udt)
383 bus_dma_tag_destroy(udt->tag);
386 /*------------------------------------------------------------------------*
387 * usb_pc_alloc_mem_cb - BUS-DMA callback function
388 *------------------------------------------------------------------------*/
389 static void
390 usb_pc_alloc_mem_cb(void *arg, bus_dma_segment_t *segs,
391 int nseg, int error)
393 usb_pc_common_mem_cb(arg, segs, nseg, error, 0);
396 /*------------------------------------------------------------------------*
397 * usb_pc_load_mem_cb - BUS-DMA callback function
398 *------------------------------------------------------------------------*/
399 static void
400 usb_pc_load_mem_cb(void *arg, bus_dma_segment_t *segs,
401 int nseg, int error)
403 usb_pc_common_mem_cb(arg, segs, nseg, error, 1);
406 /*------------------------------------------------------------------------*
407 * usb_pc_common_mem_cb - BUS-DMA callback function
408 *------------------------------------------------------------------------*/
409 static void
410 usb_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs,
411 int nseg, int error, uint8_t isload)
413 struct usb_dma_parent_tag *uptag;
414 struct usb_page_cache *pc;
415 struct usb_page *pg;
416 usb_size_t rem;
417 bus_size_t off;
418 uint8_t owned;
420 pc = arg;
421 uptag = pc->tag_parent;
424 * XXX There is sometimes recursive locking here.
425 * XXX We should try to find a better solution.
426 * XXX Until further the "owned" variable does
427 * XXX the trick.
430 if (error) {
431 goto done;
434 off = 0;
435 pg = pc->page_start;
436 pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
437 rem = segs->ds_addr & (USB_PAGE_SIZE - 1);
438 pc->page_offset_buf = rem;
439 pc->page_offset_end += rem;
440 #ifdef USB_DEBUG
441 if (rem != (USB_P2U(pc->buffer) & (USB_PAGE_SIZE - 1))) {
443 * This check verifies that the physical address is correct:
445 DPRINTFN(0, "Page offset was not preserved\n");
446 error = 1;
447 goto done;
449 #endif
450 while (pc->ismultiseg) {
451 off += USB_PAGE_SIZE;
452 if (off >= (segs->ds_len + rem)) {
453 /* page crossing */
454 nseg--;
455 segs++;
456 off = 0;
457 rem = 0;
458 if (nseg == 0)
459 break;
461 pg++;
462 pg->physaddr = (segs->ds_addr + off) & ~(USB_PAGE_SIZE - 1);
465 done:
466 owned = lockowned(uptag->lock);
467 if (!owned)
468 lockmgr(uptag->lock, LK_EXCLUSIVE);
470 uptag->dma_error = (error ? 1 : 0);
471 if (isload) {
472 (uptag->func) (uptag);
473 } else {
474 cv_broadcast(uptag->cv);
476 if (!owned)
477 lockmgr(uptag->lock, LK_RELEASE);
480 /*------------------------------------------------------------------------*
481 * usb_pc_alloc_mem - allocate DMA'able memory
483 * Returns:
484 * 0: Success
485 * Else: Failure
486 *------------------------------------------------------------------------*/
487 uint8_t
488 usb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg,
489 usb_size_t size, usb_size_t align)
491 struct usb_dma_parent_tag *uptag;
492 struct usb_dma_tag *utag;
493 bus_dmamap_t map;
494 void *ptr;
495 int err;
497 uptag = pc->tag_parent;
499 if (align != 1) {
501 * The alignment must be greater or equal to the
502 * "size" else the object can be split between two
503 * memory pages and we get a problem!
505 while (align < size) {
506 align *= 2;
507 if (align == 0) {
508 goto error;
511 #if 1
513 * XXX BUS-DMA workaround - FIXME later:
515 * We assume that that the aligment at this point of
516 * the code is greater than or equal to the size and
517 * less than two times the size, so that if we double
518 * the size, the size will be greater than the
519 * alignment.
521 * The bus-dma system has a check for "alignment"
522 * being less than "size". If that check fails we end
523 * up using contigmalloc which is page based even for
524 * small allocations. Try to avoid that to save
525 * memory, hence we sometimes to a large number of
526 * small allocations!
528 if (size <= (USB_PAGE_SIZE / 2)) {
529 size *= 2;
531 #endif
533 /* get the correct DMA tag */
534 utag = usb_dma_tag_find(uptag, size, align);
535 if (utag == NULL) {
536 goto error;
538 /* allocate memory */
539 if (bus_dmamem_alloc(
540 utag->tag, &ptr, (BUS_DMA_WAITOK | BUS_DMA_COHERENT), &map)) {
541 goto error;
543 /* setup page cache */
544 pc->buffer = ptr;
545 pc->page_start = pg;
546 pc->page_offset_buf = 0;
547 pc->page_offset_end = size;
548 pc->map = map;
549 pc->tag = utag->tag;
550 pc->ismultiseg = (align == 1);
552 lockmgr(uptag->lock, LK_EXCLUSIVE);
554 /* load memory into DMA */
555 err = bus_dmamap_load(
556 utag->tag, map, ptr, size, &usb_pc_alloc_mem_cb,
557 pc, (BUS_DMA_WAITOK | BUS_DMA_COHERENT));
559 if (err == EINPROGRESS) {
560 cv_wait(uptag->cv, uptag->lock);
561 err = 0;
563 lockmgr(uptag->lock, LK_RELEASE);
565 if (err || uptag->dma_error) {
566 bus_dmamem_free(utag->tag, ptr, map);
567 goto error;
569 memset(ptr, 0, size);
571 usb_pc_cpu_flush(pc);
573 return (0);
575 error:
576 /* reset most of the page cache */
577 pc->buffer = NULL;
578 pc->page_start = NULL;
579 pc->page_offset_buf = 0;
580 pc->page_offset_end = 0;
581 pc->map = NULL;
582 pc->tag = NULL;
583 return (1);
586 /*------------------------------------------------------------------------*
587 * usb_pc_free_mem - free DMA memory
589 * This function is NULL safe.
590 *------------------------------------------------------------------------*/
591 void
592 usb_pc_free_mem(struct usb_page_cache *pc)
594 if (pc && pc->buffer) {
596 bus_dmamap_unload(pc->tag, pc->map);
598 bus_dmamem_free(pc->tag, pc->buffer, pc->map);
600 pc->buffer = NULL;
604 /*------------------------------------------------------------------------*
605 * usb_pc_load_mem - load virtual memory into DMA
607 * Return values:
608 * 0: Success
609 * Else: Error
610 *------------------------------------------------------------------------*/
611 uint8_t
612 usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync)
614 /* setup page cache */
615 pc->page_offset_buf = 0;
616 pc->page_offset_end = size;
617 pc->ismultiseg = 1;
619 KKASSERT(lockowned(pc->tag_parent->lock));
621 if (size > 0) {
622 if (sync) {
623 struct usb_dma_parent_tag *uptag;
624 int err;
626 uptag = pc->tag_parent;
629 * We have to unload the previous loaded DMA
630 * pages before trying to load a new one!
632 bus_dmamap_unload(pc->tag, pc->map);
635 * Try to load memory into DMA.
637 err = bus_dmamap_load(
638 pc->tag, pc->map, pc->buffer, size,
639 &usb_pc_alloc_mem_cb, pc, BUS_DMA_WAITOK);
640 if (err == EINPROGRESS) {
641 cv_wait(uptag->cv, uptag->lock);
642 err = 0;
644 if (err || uptag->dma_error) {
645 return (1);
647 } else {
650 * We have to unload the previous loaded DMA
651 * pages before trying to load a new one!
653 bus_dmamap_unload(pc->tag, pc->map);
656 * Try to load memory into DMA. The callback
657 * will be called in all cases:
659 if (bus_dmamap_load(
660 pc->tag, pc->map, pc->buffer, size,
661 &usb_pc_load_mem_cb, pc, BUS_DMA_WAITOK)) {
664 } else {
665 if (!sync) {
667 * Call callback so that refcount is decremented
668 * properly:
670 pc->tag_parent->dma_error = 0;
671 (pc->tag_parent->func) (pc->tag_parent);
674 return (0);
677 /*------------------------------------------------------------------------*
678 * usb_pc_cpu_invalidate - invalidate CPU cache
679 *------------------------------------------------------------------------*/
680 void
681 usb_pc_cpu_invalidate(struct usb_page_cache *pc)
683 if (pc->page_offset_end == pc->page_offset_buf) {
684 /* nothing has been loaded into this page cache! */
685 return;
689 * TODO: We currently do XXX_POSTREAD and XXX_PREREAD at the
690 * same time, but in the future we should try to isolate the
691 * different cases to optimise the code. --HPS
693 bus_dmamap_sync(pc->tag, pc->map, BUS_DMASYNC_POSTREAD);
694 bus_dmamap_sync(pc->tag, pc->map, BUS_DMASYNC_PREREAD);
697 /*------------------------------------------------------------------------*
698 * usb_pc_cpu_flush - flush CPU cache
699 *------------------------------------------------------------------------*/
700 void
701 usb_pc_cpu_flush(struct usb_page_cache *pc)
703 if (pc->page_offset_end == pc->page_offset_buf) {
704 /* nothing has been loaded into this page cache! */
705 return;
707 bus_dmamap_sync(pc->tag, pc->map, BUS_DMASYNC_PREWRITE);
710 /*------------------------------------------------------------------------*
711 * usb_pc_dmamap_create - create a DMA map
713 * Returns:
714 * 0: Success
715 * Else: Failure
716 *------------------------------------------------------------------------*/
717 uint8_t
718 usb_pc_dmamap_create(struct usb_page_cache *pc, usb_size_t size)
720 struct usb_xfer_root *info;
721 struct usb_dma_tag *utag;
723 /* get info */
724 info = USB_DMATAG_TO_XROOT(pc->tag_parent);
726 /* sanity check */
727 if (info == NULL) {
728 goto error;
730 utag = usb_dma_tag_find(pc->tag_parent, size, 1);
731 if (utag == NULL) {
732 goto error;
734 /* create DMA map */
735 if (bus_dmamap_create(utag->tag, 0, &pc->map)) {
736 goto error;
738 pc->tag = utag->tag;
739 return 0; /* success */
741 error:
742 pc->map = NULL;
743 pc->tag = NULL;
744 return 1; /* failure */
747 /*------------------------------------------------------------------------*
748 * usb_pc_dmamap_destroy
750 * This function is NULL safe.
751 *------------------------------------------------------------------------*/
752 void
753 usb_pc_dmamap_destroy(struct usb_page_cache *pc)
755 if (pc && pc->tag) {
756 bus_dmamap_destroy(pc->tag, pc->map);
757 pc->tag = NULL;
758 pc->map = NULL;
762 /*------------------------------------------------------------------------*
763 * usb_dma_tag_find - factored out code
764 *------------------------------------------------------------------------*/
765 struct usb_dma_tag *
766 usb_dma_tag_find(struct usb_dma_parent_tag *udpt,
767 usb_size_t size, usb_size_t align)
769 struct usb_dma_tag *udt;
770 uint8_t nudt;
772 USB_ASSERT(align > 0, ("Invalid parameter align = 0\n"));
773 USB_ASSERT(size > 0, ("Invalid parameter size = 0\n"));
775 udt = udpt->utag_first;
776 nudt = udpt->utag_max;
778 while (nudt--) {
780 if (udt->align == 0) {
781 usb_dma_tag_create(udt, size, align);
782 if (udt->tag == NULL) {
783 return (NULL);
785 udt->align = align;
786 udt->size = size;
787 return (udt);
789 if ((udt->align == align) && (udt->size == size)) {
790 return (udt);
792 udt++;
794 return (NULL);
797 /*------------------------------------------------------------------------*
798 * usb_dma_tag_setup - initialise USB DMA tags
799 *------------------------------------------------------------------------*/
800 void
801 usb_dma_tag_setup(struct usb_dma_parent_tag *udpt,
802 struct usb_dma_tag *udt, bus_dma_tag_t dmat,
803 struct lock *lock, usb_dma_callback_t *func,
804 uint8_t ndmabits, uint8_t nudt)
806 memset(udpt, 0, sizeof(*udpt));
808 /* sanity checking */
809 if ((nudt == 0) ||
810 (ndmabits == 0) ||
811 (lock == NULL)) {
812 /* something is corrupt */
813 return;
815 /* initialise condition variable */
816 cv_init(udpt->cv, "USB DMA CV");
818 /* store some information */
819 udpt->lock = lock;
820 udpt->func = func;
821 udpt->tag = dmat;
822 udpt->utag_first = udt;
823 udpt->utag_max = nudt;
824 udpt->dma_bits = ndmabits;
826 while (nudt--) {
827 memset(udt, 0, sizeof(*udt));
828 udt->tag_parent = udpt;
829 udt++;
833 /*------------------------------------------------------------------------*
834 * usb_bus_tag_unsetup - factored out code
835 *------------------------------------------------------------------------*/
836 void
837 usb_dma_tag_unsetup(struct usb_dma_parent_tag *udpt)
839 struct usb_dma_tag *udt;
840 uint8_t nudt;
842 udt = udpt->utag_first;
843 nudt = udpt->utag_max;
845 while (nudt--) {
847 if (udt->align) {
848 /* destroy the USB DMA tag */
849 usb_dma_tag_destroy(udt);
850 udt->align = 0;
852 udt++;
855 if (udpt->utag_max) {
856 /* destroy the condition variable */
857 cv_destroy(udpt->cv);
861 /*------------------------------------------------------------------------*
862 * usb_bdma_work_loop
864 * This function handles loading of virtual buffers into DMA and is
865 * only called when "dma_refcount" is zero.
866 *------------------------------------------------------------------------*/
867 void
868 usb_bdma_work_loop(struct usb_xfer_queue *pq)
870 struct usb_xfer_root *info;
871 struct usb_xfer *xfer;
872 usb_frcount_t nframes;
874 xfer = pq->curr;
875 info = xfer->xroot;
877 KKASSERT(lockowned(info->xfer_lock));
879 if (xfer->error) {
880 /* some error happened */
881 USB_BUS_LOCK(info->bus);
882 usbd_transfer_done(xfer, 0);
883 USB_BUS_UNLOCK(info->bus);
884 return;
886 if (!xfer->flags_int.bdma_setup) {
887 struct usb_page *pg;
888 usb_frlength_t frlength_0;
889 uint8_t isread;
891 xfer->flags_int.bdma_setup = 1;
893 /* reset BUS-DMA load state */
895 info->dma_error = 0;
897 if (xfer->flags_int.isochronous_xfr) {
898 /* only one frame buffer */
899 nframes = 1;
900 frlength_0 = xfer->sumlen;
901 } else {
902 /* can be multiple frame buffers */
903 nframes = xfer->nframes;
904 frlength_0 = xfer->frlengths[0];
908 * Set DMA direction first. This is needed to
909 * select the correct cache invalidate and cache
910 * flush operations.
912 isread = USB_GET_DATA_ISREAD(xfer);
913 pg = xfer->dma_page_ptr;
915 if (xfer->flags_int.control_xfr &&
916 xfer->flags_int.control_hdr) {
917 /* special case */
918 if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
919 /* The device controller writes to memory */
920 xfer->frbuffers[0].isread = 1;
921 } else {
922 /* The host controller reads from memory */
923 xfer->frbuffers[0].isread = 0;
925 } else {
926 /* default case */
927 xfer->frbuffers[0].isread = isread;
931 * Setup the "page_start" pointer which points to an array of
932 * USB pages where information about the physical address of a
933 * page will be stored. Also initialise the "isread" field of
934 * the USB page caches.
936 xfer->frbuffers[0].page_start = pg;
938 info->dma_nframes = nframes;
939 info->dma_currframe = 0;
940 info->dma_frlength_0 = frlength_0;
942 pg += (frlength_0 / USB_PAGE_SIZE);
943 pg += 2;
945 while (--nframes > 0) {
946 xfer->frbuffers[nframes].isread = isread;
947 xfer->frbuffers[nframes].page_start = pg;
949 pg += (xfer->frlengths[nframes] / USB_PAGE_SIZE);
950 pg += 2;
954 if (info->dma_error) {
955 USB_BUS_LOCK(info->bus);
956 usbd_transfer_done(xfer, USB_ERR_DMA_LOAD_FAILED);
957 USB_BUS_UNLOCK(info->bus);
958 return;
960 if (info->dma_currframe != info->dma_nframes) {
962 if (info->dma_currframe == 0) {
963 /* special case */
964 usb_pc_load_mem(xfer->frbuffers,
965 info->dma_frlength_0, 0);
966 } else {
967 /* default case */
968 nframes = info->dma_currframe;
969 usb_pc_load_mem(xfer->frbuffers + nframes,
970 xfer->frlengths[nframes], 0);
973 /* advance frame index */
974 info->dma_currframe++;
976 return;
978 /* go ahead */
979 usb_bdma_pre_sync(xfer);
981 /* start loading next USB transfer, if any */
982 usb_command_wrapper(pq, NULL);
984 /* finally start the hardware */
985 usbd_pipe_enter(xfer);
988 /*------------------------------------------------------------------------*
989 * usb_bdma_done_event
991 * This function is called when the BUS-DMA has loaded virtual memory
992 * into DMA, if any.
993 *------------------------------------------------------------------------*/
994 void
995 usb_bdma_done_event(struct usb_dma_parent_tag *udpt)
997 struct usb_xfer_root *info;
999 info = USB_DMATAG_TO_XROOT(udpt);
1001 KKASSERT(lockowned(info->xfer_lock));
1003 /* copy error */
1004 info->dma_error = udpt->dma_error;
1006 /* enter workloop again */
1007 usb_command_wrapper(&info->dma_q,
1008 info->dma_q.curr);
1011 /*------------------------------------------------------------------------*
1012 * usb_bdma_pre_sync
1014 * This function handles DMA synchronisation that must be done before
1015 * an USB transfer is started.
1016 *------------------------------------------------------------------------*/
1017 void
1018 usb_bdma_pre_sync(struct usb_xfer *xfer)
1020 struct usb_page_cache *pc;
1021 usb_frcount_t nframes;
1023 if (xfer->flags_int.isochronous_xfr) {
1024 /* only one frame buffer */
1025 nframes = 1;
1026 } else {
1027 /* can be multiple frame buffers */
1028 nframes = xfer->nframes;
1031 pc = xfer->frbuffers;
1033 while (nframes--) {
1035 if (pc->isread) {
1036 usb_pc_cpu_invalidate(pc);
1037 } else {
1038 usb_pc_cpu_flush(pc);
1040 pc++;
1044 /*------------------------------------------------------------------------*
1045 * usb_bdma_post_sync
1047 * This function handles DMA synchronisation that must be done after
1048 * an USB transfer is complete.
1049 *------------------------------------------------------------------------*/
1050 void
1051 usb_bdma_post_sync(struct usb_xfer *xfer)
1053 struct usb_page_cache *pc;
1054 usb_frcount_t nframes;
1056 if (xfer->flags_int.isochronous_xfr) {
1057 /* only one frame buffer */
1058 nframes = 1;
1059 } else {
1060 /* can be multiple frame buffers */
1061 nframes = xfer->nframes;
1064 pc = xfer->frbuffers;
1066 while (nframes--) {
1067 if (pc->isread) {
1068 usb_pc_cpu_invalidate(pc);
1070 pc++;
1074 #endif