]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - sys/dev/usb/usb_busdma.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / sys / dev / usb / usb_busdma.c
1 /* $FreeBSD$ */
2 /*-
3  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4  *
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.
13  *
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.
25  */
26
27 #include <sys/stdint.h>
28 #include <sys/stddef.h>
29 #include <sys/param.h>
30 #include <sys/queue.h>
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/bus.h>
35 #include <sys/module.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/condvar.h>
39 #include <sys/sysctl.h>
40 #include <sys/sx.h>
41 #include <sys/unistd.h>
42 #include <sys/callout.h>
43 #include <sys/malloc.h>
44 #include <sys/priv.h>
45
46 #include <dev/usb/usb.h>
47 #include <dev/usb/usbdi.h>
48 #include <dev/usb/usbdi_util.h>
49
50 #define USB_DEBUG_VAR usb_debug
51
52 #include <dev/usb/usb_core.h>
53 #include <dev/usb/usb_busdma.h>
54 #include <dev/usb/usb_process.h>
55 #include <dev/usb/usb_transfer.h>
56 #include <dev/usb/usb_device.h>
57 #include <dev/usb/usb_util.h>
58 #include <dev/usb/usb_debug.h>
59
60 #include <dev/usb/usb_controller.h>
61 #include <dev/usb/usb_bus.h>
62
63 #if USB_HAVE_BUSDMA
64 static void     usb_dma_tag_create(struct usb_dma_tag *, usb_size_t, usb_size_t);
65 static void     usb_dma_tag_destroy(struct usb_dma_tag *);
66 static void     usb_dma_lock_cb(void *, bus_dma_lock_op_t);
67 static void     usb_pc_alloc_mem_cb(void *, bus_dma_segment_t *, int, int);
68 static void     usb_pc_load_mem_cb(void *, bus_dma_segment_t *, int, int);
69 static void     usb_pc_common_mem_cb(void *, bus_dma_segment_t *, int, int,
70                     uint8_t);
71 #endif
72
73 /*------------------------------------------------------------------------*
74  *  usbd_get_page - lookup DMA-able memory for the given offset
75  *
76  * NOTE: Only call this function when the "page_cache" structure has
77  * been properly initialized !
78  *------------------------------------------------------------------------*/
79 void
80 usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset,
81     struct usb_page_search *res)
82 {
83 #if USB_HAVE_BUSDMA
84         struct usb_page *page;
85
86         if (pc->page_start) {
87
88                 /* Case 1 - something has been loaded into DMA */
89
90                 if (pc->buffer) {
91
92                         /* Case 1a - Kernel Virtual Address */
93
94                         res->buffer = USB_ADD_BYTES(pc->buffer, offset);
95                 }
96                 offset += pc->page_offset_buf;
97
98                 /* compute destination page */
99
100                 page = pc->page_start;
101
102                 if (pc->ismultiseg) {
103
104                         page += (offset / USB_PAGE_SIZE);
105
106                         offset %= USB_PAGE_SIZE;
107
108                         res->length = USB_PAGE_SIZE - offset;
109                         res->physaddr = page->physaddr + offset;
110                 } else {
111                         res->length = (usb_size_t)-1;
112                         res->physaddr = page->physaddr + offset;
113                 }
114                 if (!pc->buffer) {
115
116                         /* Case 1b - Non Kernel Virtual Address */
117
118                         res->buffer = USB_ADD_BYTES(page->buffer, offset);
119                 }
120                 return;
121         }
122 #endif
123         /* Case 2 - Plain PIO */
124
125         res->buffer = USB_ADD_BYTES(pc->buffer, offset);
126         res->length = (usb_size_t)-1;
127 #if USB_HAVE_BUSDMA
128         res->physaddr = 0;
129 #endif
130 }
131
132 /*------------------------------------------------------------------------*
133  *  usbd_copy_in - copy directly to DMA-able memory
134  *------------------------------------------------------------------------*/
135 void
136 usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset,
137     const void *ptr, usb_frlength_t len)
138 {
139         struct usb_page_search buf_res;
140
141         while (len != 0) {
142
143                 usbd_get_page(cache, offset, &buf_res);
144
145                 if (buf_res.length > len) {
146                         buf_res.length = len;
147                 }
148                 memcpy(buf_res.buffer, ptr, buf_res.length);
149
150                 offset += buf_res.length;
151                 len -= buf_res.length;
152                 ptr = USB_ADD_BYTES(ptr, buf_res.length);
153         }
154 }
155
156 /*------------------------------------------------------------------------*
157  *  usbd_copy_in_user - copy directly to DMA-able memory from userland
158  *
159  * Return values:
160  *    0: Success
161  * Else: Failure
162  *------------------------------------------------------------------------*/
163 #if USB_HAVE_USER_IO
164 int
165 usbd_copy_in_user(struct usb_page_cache *cache, usb_frlength_t offset,
166     const void *ptr, usb_frlength_t len)
167 {
168         struct usb_page_search buf_res;
169         int error;
170
171         while (len != 0) {
172
173                 usbd_get_page(cache, offset, &buf_res);
174
175                 if (buf_res.length > len) {
176                         buf_res.length = len;
177                 }
178                 error = copyin(ptr, buf_res.buffer, buf_res.length);
179                 if (error)
180                         return (error);
181
182                 offset += buf_res.length;
183                 len -= buf_res.length;
184                 ptr = USB_ADD_BYTES(ptr, buf_res.length);
185         }
186         return (0);                     /* success */
187 }
188 #endif
189
190 /*------------------------------------------------------------------------*
191  *  usbd_m_copy_in - copy a mbuf chain directly into DMA-able memory
192  *------------------------------------------------------------------------*/
193 #if USB_HAVE_MBUF
194 struct usb_m_copy_in_arg {
195         struct usb_page_cache *cache;
196         usb_frlength_t dst_offset;
197 };
198
199 static int
200 usbd_m_copy_in_cb(void *arg, void *src, uint32_t count)
201 {
202         register struct usb_m_copy_in_arg *ua = arg;
203
204         usbd_copy_in(ua->cache, ua->dst_offset, src, count);
205         ua->dst_offset += count;
206         return (0);
207 }
208
209 void
210 usbd_m_copy_in(struct usb_page_cache *cache, usb_frlength_t dst_offset,
211     struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len)
212 {
213         struct usb_m_copy_in_arg arg = {cache, dst_offset};
214         (void) m_apply(m, src_offset, src_len, &usbd_m_copy_in_cb, &arg);
215 }
216 #endif
217
218 /*------------------------------------------------------------------------*
219  *  usb_uiomove - factored out code
220  *------------------------------------------------------------------------*/
221 #if USB_HAVE_USER_IO
222 int
223 usb_uiomove(struct usb_page_cache *pc, struct uio *uio,
224     usb_frlength_t pc_offset, usb_frlength_t len)
225 {
226         struct usb_page_search res;
227         int error = 0;
228
229         while (len != 0) {
230
231                 usbd_get_page(pc, pc_offset, &res);
232
233                 if (res.length > len) {
234                         res.length = len;
235                 }
236                 /*
237                  * "uiomove()" can sleep so one needs to make a wrapper,
238                  * exiting the mutex and checking things
239                  */
240                 error = uiomove(res.buffer, res.length, uio);
241
242                 if (error) {
243                         break;
244                 }
245                 pc_offset += res.length;
246                 len -= res.length;
247         }
248         return (error);
249 }
250 #endif
251
252 /*------------------------------------------------------------------------*
253  *  usbd_copy_out - copy directly from DMA-able memory
254  *------------------------------------------------------------------------*/
255 void
256 usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset,
257     void *ptr, usb_frlength_t len)
258 {
259         struct usb_page_search res;
260
261         while (len != 0) {
262
263                 usbd_get_page(cache, offset, &res);
264
265                 if (res.length > len) {
266                         res.length = len;
267                 }
268                 memcpy(ptr, res.buffer, res.length);
269
270                 offset += res.length;
271                 len -= res.length;
272                 ptr = USB_ADD_BYTES(ptr, res.length);
273         }
274 }
275
276 /*------------------------------------------------------------------------*
277  *  usbd_copy_out_user - copy directly from DMA-able memory to userland
278  *
279  * Return values:
280  *    0: Success
281  * Else: Failure
282  *------------------------------------------------------------------------*/
283 #if USB_HAVE_USER_IO
284 int
285 usbd_copy_out_user(struct usb_page_cache *cache, usb_frlength_t offset,
286     void *ptr, usb_frlength_t len)
287 {
288         struct usb_page_search res;
289         int error;
290
291         while (len != 0) {
292
293                 usbd_get_page(cache, offset, &res);
294
295                 if (res.length > len) {
296                         res.length = len;
297                 }
298                 error = copyout(res.buffer, ptr, res.length);
299                 if (error)
300                         return (error);
301
302                 offset += res.length;
303                 len -= res.length;
304                 ptr = USB_ADD_BYTES(ptr, res.length);
305         }
306         return (0);                     /* success */
307 }
308 #endif
309
310 /*------------------------------------------------------------------------*
311  *  usbd_frame_zero - zero DMA-able memory
312  *------------------------------------------------------------------------*/
313 void
314 usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
315     usb_frlength_t len)
316 {
317         struct usb_page_search res;
318
319         while (len != 0) {
320
321                 usbd_get_page(cache, offset, &res);
322
323                 if (res.length > len) {
324                         res.length = len;
325                 }
326                 memset(res.buffer, 0, res.length);
327
328                 offset += res.length;
329                 len -= res.length;
330         }
331 }
332
333 #if USB_HAVE_BUSDMA
334
335 /*------------------------------------------------------------------------*
336  *      usb_dma_lock_cb - dummy callback
337  *------------------------------------------------------------------------*/
338 static void
339 usb_dma_lock_cb(void *arg, bus_dma_lock_op_t op)
340 {
341         /* we use "mtx_owned()" instead of this function */
342 }
343
344 /*------------------------------------------------------------------------*
345  *      usb_dma_tag_create - allocate a DMA tag
346  *
347  * NOTE: If the "align" parameter has a value of 1 the DMA-tag will
348  * allow multi-segment mappings. Else all mappings are single-segment.
349  *------------------------------------------------------------------------*/
350 static void
351 usb_dma_tag_create(struct usb_dma_tag *udt,
352     usb_size_t size, usb_size_t align)
353 {
354         bus_dma_tag_t tag;
355
356         if (bus_dma_tag_create
357             ( /* parent    */ udt->tag_parent->tag,
358              /* alignment */ align,
359              /* boundary  */ 0,
360              /* lowaddr   */ (2ULL << (udt->tag_parent->dma_bits - 1)) - 1,
361              /* highaddr  */ BUS_SPACE_MAXADDR,
362              /* filter    */ NULL,
363              /* filterarg */ NULL,
364              /* maxsize   */ size,
365              /* nsegments */ (align == 1 && size > 1) ?
366             (2 + (size / USB_PAGE_SIZE)) : 1,
367              /* maxsegsz  */ (align == 1 && size > USB_PAGE_SIZE) ?
368             USB_PAGE_SIZE : size,
369              /* flags     */ BUS_DMA_KEEP_PG_OFFSET,
370              /* lockfn    */ &usb_dma_lock_cb,
371              /* lockarg   */ NULL,
372             &tag)) {
373                 tag = NULL;
374         }
375         udt->tag = tag;
376 }
377
378 /*------------------------------------------------------------------------*
379  *      usb_dma_tag_free - free a DMA tag
380  *------------------------------------------------------------------------*/
381 static void
382 usb_dma_tag_destroy(struct usb_dma_tag *udt)
383 {
384         bus_dma_tag_destroy(udt->tag);
385 }
386
387 /*------------------------------------------------------------------------*
388  *      usb_pc_alloc_mem_cb - BUS-DMA callback function
389  *------------------------------------------------------------------------*/
390 static void
391 usb_pc_alloc_mem_cb(void *arg, bus_dma_segment_t *segs,
392     int nseg, int error)
393 {
394         usb_pc_common_mem_cb(arg, segs, nseg, error, 0);
395 }
396
397 /*------------------------------------------------------------------------*
398  *      usb_pc_load_mem_cb - BUS-DMA callback function
399  *------------------------------------------------------------------------*/
400 static void
401 usb_pc_load_mem_cb(void *arg, bus_dma_segment_t *segs,
402     int nseg, int error)
403 {
404         usb_pc_common_mem_cb(arg, segs, nseg, error, 1);
405 }
406
407 /*------------------------------------------------------------------------*
408  *      usb_pc_common_mem_cb - BUS-DMA callback function
409  *------------------------------------------------------------------------*/
410 static void
411 usb_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs,
412     int nseg, int error, uint8_t isload)
413 {
414         struct usb_dma_parent_tag *uptag;
415         struct usb_page_cache *pc;
416         struct usb_page *pg;
417         usb_size_t rem;
418         bus_size_t off;
419         uint8_t owned;
420
421         pc = arg;
422         uptag = pc->tag_parent;
423
424         /*
425          * XXX There is sometimes recursive locking here.
426          * XXX We should try to find a better solution.
427          * XXX Until further the "owned" variable does
428          * XXX the trick.
429          */
430
431         if (error) {
432                 goto done;
433         }
434
435         off = 0;
436         pg = pc->page_start;
437         pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
438         rem = segs->ds_addr & (USB_PAGE_SIZE - 1);
439         pc->page_offset_buf = rem;
440         pc->page_offset_end += rem;
441 #ifdef USB_DEBUG
442         if (rem != (USB_P2U(pc->buffer) & (USB_PAGE_SIZE - 1))) {
443                 /*
444                  * This check verifies that the physical address is correct:
445                  */
446                 DPRINTFN(0, "Page offset was not preserved\n");
447                 error = 1;
448                 goto done;
449         }
450 #endif
451         while (pc->ismultiseg) {
452                 off += USB_PAGE_SIZE;
453                 if (off >= (segs->ds_len + rem)) {
454                         /* page crossing */
455                         nseg--;
456                         segs++;
457                         off = 0;
458                         rem = 0;
459                         if (nseg == 0)
460                                 break;
461                 }
462                 pg++;
463                 pg->physaddr = (segs->ds_addr + off) & ~(USB_PAGE_SIZE - 1);
464         }
465
466 done:
467         owned = mtx_owned(uptag->mtx);
468         if (!owned)
469                 mtx_lock(uptag->mtx);
470
471         uptag->dma_error = (error ? 1 : 0);
472         if (isload) {
473                 (uptag->func) (uptag);
474         } else {
475                 cv_broadcast(uptag->cv);
476         }
477         if (!owned)
478                 mtx_unlock(uptag->mtx);
479 }
480
481 /*------------------------------------------------------------------------*
482  *      usb_pc_alloc_mem - allocate DMA'able memory
483  *
484  * Returns:
485  *    0: Success
486  * Else: Failure
487  *------------------------------------------------------------------------*/
488 uint8_t
489 usb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg,
490     usb_size_t size, usb_size_t align)
491 {
492         struct usb_dma_parent_tag *uptag;
493         struct usb_dma_tag *utag;
494         bus_dmamap_t map;
495         void *ptr;
496         int err;
497
498         uptag = pc->tag_parent;
499
500         if (align != 1) {
501                 /*
502                  * The alignment must be greater or equal to the
503                  * "size" else the object can be split between two
504                  * memory pages and we get a problem!
505                  */
506                 while (align < size) {
507                         align *= 2;
508                         if (align == 0) {
509                                 goto error;
510                         }
511                 }
512 #if 1
513                 /*
514                  * XXX BUS-DMA workaround - FIXME later:
515                  *
516                  * We assume that that the aligment at this point of
517                  * the code is greater than or equal to the size and
518                  * less than two times the size, so that if we double
519                  * the size, the size will be greater than the
520                  * alignment.
521                  *
522                  * The bus-dma system has a check for "alignment"
523                  * being less than "size". If that check fails we end
524                  * up using contigmalloc which is page based even for
525                  * small allocations. Try to avoid that to save
526                  * memory, hence we sometimes to a large number of
527                  * small allocations!
528                  */
529                 if (size <= (USB_PAGE_SIZE / 2)) {
530                         size *= 2;
531                 }
532 #endif
533         }
534         /* get the correct DMA tag */
535         utag = usb_dma_tag_find(uptag, size, align);
536         if (utag == NULL) {
537                 goto error;
538         }
539         /* allocate memory */
540         if (bus_dmamem_alloc(
541             utag->tag, &ptr, (BUS_DMA_WAITOK | BUS_DMA_COHERENT), &map)) {
542                 goto error;
543         }
544         /* setup page cache */
545         pc->buffer = ptr;
546         pc->page_start = pg;
547         pc->page_offset_buf = 0;
548         pc->page_offset_end = size;
549         pc->map = map;
550         pc->tag = utag->tag;
551         pc->ismultiseg = (align == 1);
552
553         mtx_lock(uptag->mtx);
554
555         /* load memory into DMA */
556         err = bus_dmamap_load(
557             utag->tag, map, ptr, size, &usb_pc_alloc_mem_cb,
558             pc, (BUS_DMA_WAITOK | BUS_DMA_COHERENT));
559
560         if (err == EINPROGRESS) {
561                 cv_wait(uptag->cv, uptag->mtx);
562                 err = 0;
563         }
564         mtx_unlock(uptag->mtx);
565
566         if (err || uptag->dma_error) {
567                 bus_dmamem_free(utag->tag, ptr, map);
568                 goto error;
569         }
570         memset(ptr, 0, size);
571
572         usb_pc_cpu_flush(pc);
573
574         return (0);
575
576 error:
577         /* reset most of the page cache */
578         pc->buffer = NULL;
579         pc->page_start = NULL;
580         pc->page_offset_buf = 0;
581         pc->page_offset_end = 0;
582         pc->map = NULL;
583         pc->tag = NULL;
584         return (1);
585 }
586
587 /*------------------------------------------------------------------------*
588  *      usb_pc_free_mem - free DMA memory
589  *
590  * This function is NULL safe.
591  *------------------------------------------------------------------------*/
592 void
593 usb_pc_free_mem(struct usb_page_cache *pc)
594 {
595         if (pc && pc->buffer) {
596
597                 bus_dmamap_unload(pc->tag, pc->map);
598
599                 bus_dmamem_free(pc->tag, pc->buffer, pc->map);
600
601                 pc->buffer = NULL;
602         }
603 }
604
605 /*------------------------------------------------------------------------*
606  *      usb_pc_load_mem - load virtual memory into DMA
607  *
608  * Return values:
609  * 0: Success
610  * Else: Error
611  *------------------------------------------------------------------------*/
612 uint8_t
613 usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync)
614 {
615         /* setup page cache */
616         pc->page_offset_buf = 0;
617         pc->page_offset_end = size;
618         pc->ismultiseg = 1;
619
620         mtx_assert(pc->tag_parent->mtx, MA_OWNED);
621
622         if (size > 0) {
623                 if (sync) {
624                         struct usb_dma_parent_tag *uptag;
625                         int err;
626
627                         uptag = pc->tag_parent;
628
629                         /*
630                          * We have to unload the previous loaded DMA
631                          * pages before trying to load a new one!
632                          */
633                         bus_dmamap_unload(pc->tag, pc->map);
634
635                         /*
636                          * Try to load memory into DMA.
637                          */
638                         err = bus_dmamap_load(
639                             pc->tag, pc->map, pc->buffer, size,
640                             &usb_pc_alloc_mem_cb, pc, BUS_DMA_WAITOK);
641                         if (err == EINPROGRESS) {
642                                 cv_wait(uptag->cv, uptag->mtx);
643                                 err = 0;
644                         }
645                         if (err || uptag->dma_error) {
646                                 return (1);
647                         }
648                 } else {
649
650                         /*
651                          * We have to unload the previous loaded DMA
652                          * pages before trying to load a new one!
653                          */
654                         bus_dmamap_unload(pc->tag, pc->map);
655
656                         /*
657                          * Try to load memory into DMA. The callback
658                          * will be called in all cases:
659                          */
660                         if (bus_dmamap_load(
661                             pc->tag, pc->map, pc->buffer, size,
662                             &usb_pc_load_mem_cb, pc, BUS_DMA_WAITOK)) {
663                         }
664                 }
665         } else {
666                 if (!sync) {
667                         /*
668                          * Call callback so that refcount is decremented
669                          * properly:
670                          */
671                         pc->tag_parent->dma_error = 0;
672                         (pc->tag_parent->func) (pc->tag_parent);
673                 }
674         }
675         return (0);
676 }
677
678 /*------------------------------------------------------------------------*
679  *      usb_pc_cpu_invalidate - invalidate CPU cache
680  *------------------------------------------------------------------------*/
681 void
682 usb_pc_cpu_invalidate(struct usb_page_cache *pc)
683 {
684         if (pc->page_offset_end == pc->page_offset_buf) {
685                 /* nothing has been loaded into this page cache! */
686                 return;
687         }
688
689         /*
690          * TODO: We currently do XXX_POSTREAD and XXX_PREREAD at the
691          * same time, but in the future we should try to isolate the
692          * different cases to optimise the code. --HPS
693          */
694         bus_dmamap_sync(pc->tag, pc->map, BUS_DMASYNC_POSTREAD);
695         bus_dmamap_sync(pc->tag, pc->map, BUS_DMASYNC_PREREAD);
696 }
697
698 /*------------------------------------------------------------------------*
699  *      usb_pc_cpu_flush - flush CPU cache
700  *------------------------------------------------------------------------*/
701 void
702 usb_pc_cpu_flush(struct usb_page_cache *pc)
703 {
704         if (pc->page_offset_end == pc->page_offset_buf) {
705                 /* nothing has been loaded into this page cache! */
706                 return;
707         }
708         bus_dmamap_sync(pc->tag, pc->map, BUS_DMASYNC_PREWRITE);
709 }
710
711 /*------------------------------------------------------------------------*
712  *      usb_pc_dmamap_create - create a DMA map
713  *
714  * Returns:
715  *    0: Success
716  * Else: Failure
717  *------------------------------------------------------------------------*/
718 uint8_t
719 usb_pc_dmamap_create(struct usb_page_cache *pc, usb_size_t size)
720 {
721         struct usb_xfer_root *info;
722         struct usb_dma_tag *utag;
723
724         /* get info */
725         info = USB_DMATAG_TO_XROOT(pc->tag_parent);
726
727         /* sanity check */
728         if (info == NULL) {
729                 goto error;
730         }
731         utag = usb_dma_tag_find(pc->tag_parent, size, 1);
732         if (utag == NULL) {
733                 goto error;
734         }
735         /* create DMA map */
736         if (bus_dmamap_create(utag->tag, 0, &pc->map)) {
737                 goto error;
738         }
739         pc->tag = utag->tag;
740         return 0;                       /* success */
741
742 error:
743         pc->map = NULL;
744         pc->tag = NULL;
745         return 1;                       /* failure */
746 }
747
748 /*------------------------------------------------------------------------*
749  *      usb_pc_dmamap_destroy
750  *
751  * This function is NULL safe.
752  *------------------------------------------------------------------------*/
753 void
754 usb_pc_dmamap_destroy(struct usb_page_cache *pc)
755 {
756         if (pc && pc->tag) {
757                 bus_dmamap_destroy(pc->tag, pc->map);
758                 pc->tag = NULL;
759                 pc->map = NULL;
760         }
761 }
762
763 /*------------------------------------------------------------------------*
764  *      usb_dma_tag_find - factored out code
765  *------------------------------------------------------------------------*/
766 struct usb_dma_tag *
767 usb_dma_tag_find(struct usb_dma_parent_tag *udpt,
768     usb_size_t size, usb_size_t align)
769 {
770         struct usb_dma_tag *udt;
771         uint8_t nudt;
772
773         USB_ASSERT(align > 0, ("Invalid parameter align = 0\n"));
774         USB_ASSERT(size > 0, ("Invalid parameter size = 0\n"));
775
776         udt = udpt->utag_first;
777         nudt = udpt->utag_max;
778
779         while (nudt--) {
780
781                 if (udt->align == 0) {
782                         usb_dma_tag_create(udt, size, align);
783                         if (udt->tag == NULL) {
784                                 return (NULL);
785                         }
786                         udt->align = align;
787                         udt->size = size;
788                         return (udt);
789                 }
790                 if ((udt->align == align) && (udt->size == size)) {
791                         return (udt);
792                 }
793                 udt++;
794         }
795         return (NULL);
796 }
797
798 /*------------------------------------------------------------------------*
799  *      usb_dma_tag_setup - initialise USB DMA tags
800  *------------------------------------------------------------------------*/
801 void
802 usb_dma_tag_setup(struct usb_dma_parent_tag *udpt,
803     struct usb_dma_tag *udt, bus_dma_tag_t dmat,
804     struct mtx *mtx, usb_dma_callback_t *func,
805     uint8_t ndmabits, uint8_t nudt)
806 {
807         memset(udpt, 0, sizeof(*udpt));
808
809         /* sanity checking */
810         if ((nudt == 0) ||
811             (ndmabits == 0) ||
812             (mtx == NULL)) {
813                 /* something is corrupt */
814                 return;
815         }
816         /* initialise condition variable */
817         cv_init(udpt->cv, "USB DMA CV");
818
819         /* store some information */
820         udpt->mtx = mtx;
821         udpt->func = func;
822         udpt->tag = dmat;
823         udpt->utag_first = udt;
824         udpt->utag_max = nudt;
825         udpt->dma_bits = ndmabits;
826
827         while (nudt--) {
828                 memset(udt, 0, sizeof(*udt));
829                 udt->tag_parent = udpt;
830                 udt++;
831         }
832 }
833
834 /*------------------------------------------------------------------------*
835  *      usb_bus_tag_unsetup - factored out code
836  *------------------------------------------------------------------------*/
837 void
838 usb_dma_tag_unsetup(struct usb_dma_parent_tag *udpt)
839 {
840         struct usb_dma_tag *udt;
841         uint8_t nudt;
842
843         udt = udpt->utag_first;
844         nudt = udpt->utag_max;
845
846         while (nudt--) {
847
848                 if (udt->align) {
849                         /* destroy the USB DMA tag */
850                         usb_dma_tag_destroy(udt);
851                         udt->align = 0;
852                 }
853                 udt++;
854         }
855
856         if (udpt->utag_max) {
857                 /* destroy the condition variable */
858                 cv_destroy(udpt->cv);
859         }
860 }
861
862 /*------------------------------------------------------------------------*
863  *      usb_bdma_work_loop
864  *
865  * This function handles loading of virtual buffers into DMA and is
866  * only called when "dma_refcount" is zero.
867  *------------------------------------------------------------------------*/
868 void
869 usb_bdma_work_loop(struct usb_xfer_queue *pq)
870 {
871         struct usb_xfer_root *info;
872         struct usb_xfer *xfer;
873         usb_frcount_t nframes;
874
875         xfer = pq->curr;
876         info = xfer->xroot;
877
878         mtx_assert(info->xfer_mtx, MA_OWNED);
879
880         if (xfer->error) {
881                 /* some error happened */
882                 USB_BUS_LOCK(info->bus);
883                 usbd_transfer_done(xfer, 0);
884                 USB_BUS_UNLOCK(info->bus);
885                 return;
886         }
887         if (!xfer->flags_int.bdma_setup) {
888                 struct usb_page *pg;
889                 usb_frlength_t frlength_0;
890                 uint8_t isread;
891
892                 xfer->flags_int.bdma_setup = 1;
893
894                 /* reset BUS-DMA load state */
895
896                 info->dma_error = 0;
897
898                 if (xfer->flags_int.isochronous_xfr) {
899                         /* only one frame buffer */
900                         nframes = 1;
901                         frlength_0 = xfer->sumlen;
902                 } else {
903                         /* can be multiple frame buffers */
904                         nframes = xfer->nframes;
905                         frlength_0 = xfer->frlengths[0];
906                 }
907
908                 /*
909                  * Set DMA direction first. This is needed to
910                  * select the correct cache invalidate and cache
911                  * flush operations.
912                  */
913                 isread = USB_GET_DATA_ISREAD(xfer);
914                 pg = xfer->dma_page_ptr;
915
916                 if (xfer->flags_int.control_xfr &&
917                     xfer->flags_int.control_hdr) {
918                         /* special case */
919                         if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
920                                 /* The device controller writes to memory */
921                                 xfer->frbuffers[0].isread = 1;
922                         } else {
923                                 /* The host controller reads from memory */
924                                 xfer->frbuffers[0].isread = 0;
925                         }
926                 } else {
927                         /* default case */
928                         xfer->frbuffers[0].isread = isread;
929                 }
930
931                 /*
932                  * Setup the "page_start" pointer which points to an array of
933                  * USB pages where information about the physical address of a
934                  * page will be stored. Also initialise the "isread" field of
935                  * the USB page caches.
936                  */
937                 xfer->frbuffers[0].page_start = pg;
938
939                 info->dma_nframes = nframes;
940                 info->dma_currframe = 0;
941                 info->dma_frlength_0 = frlength_0;
942
943                 pg += (frlength_0 / USB_PAGE_SIZE);
944                 pg += 2;
945
946                 while (--nframes > 0) {
947                         xfer->frbuffers[nframes].isread = isread;
948                         xfer->frbuffers[nframes].page_start = pg;
949
950                         pg += (xfer->frlengths[nframes] / USB_PAGE_SIZE);
951                         pg += 2;
952                 }
953
954         }
955         if (info->dma_error) {
956                 USB_BUS_LOCK(info->bus);
957                 usbd_transfer_done(xfer, USB_ERR_DMA_LOAD_FAILED);
958                 USB_BUS_UNLOCK(info->bus);
959                 return;
960         }
961         if (info->dma_currframe != info->dma_nframes) {
962
963                 if (info->dma_currframe == 0) {
964                         /* special case */
965                         usb_pc_load_mem(xfer->frbuffers,
966                             info->dma_frlength_0, 0);
967                 } else {
968                         /* default case */
969                         nframes = info->dma_currframe;
970                         usb_pc_load_mem(xfer->frbuffers + nframes,
971                             xfer->frlengths[nframes], 0);
972                 }
973
974                 /* advance frame index */
975                 info->dma_currframe++;
976
977                 return;
978         }
979         /* go ahead */
980         usb_bdma_pre_sync(xfer);
981
982         /* start loading next USB transfer, if any */
983         usb_command_wrapper(pq, NULL);
984
985         /* finally start the hardware */
986         usbd_pipe_enter(xfer);
987 }
988
989 /*------------------------------------------------------------------------*
990  *      usb_bdma_done_event
991  *
992  * This function is called when the BUS-DMA has loaded virtual memory
993  * into DMA, if any.
994  *------------------------------------------------------------------------*/
995 void
996 usb_bdma_done_event(struct usb_dma_parent_tag *udpt)
997 {
998         struct usb_xfer_root *info;
999
1000         info = USB_DMATAG_TO_XROOT(udpt);
1001
1002         mtx_assert(info->xfer_mtx, MA_OWNED);
1003
1004         /* copy error */
1005         info->dma_error = udpt->dma_error;
1006
1007         /* enter workloop again */
1008         usb_command_wrapper(&info->dma_q,
1009             info->dma_q.curr);
1010 }
1011
1012 /*------------------------------------------------------------------------*
1013  *      usb_bdma_pre_sync
1014  *
1015  * This function handles DMA synchronisation that must be done before
1016  * an USB transfer is started.
1017  *------------------------------------------------------------------------*/
1018 void
1019 usb_bdma_pre_sync(struct usb_xfer *xfer)
1020 {
1021         struct usb_page_cache *pc;
1022         usb_frcount_t nframes;
1023
1024         if (xfer->flags_int.isochronous_xfr) {
1025                 /* only one frame buffer */
1026                 nframes = 1;
1027         } else {
1028                 /* can be multiple frame buffers */
1029                 nframes = xfer->nframes;
1030         }
1031
1032         pc = xfer->frbuffers;
1033
1034         while (nframes--) {
1035
1036                 if (pc->isread) {
1037                         usb_pc_cpu_invalidate(pc);
1038                 } else {
1039                         usb_pc_cpu_flush(pc);
1040                 }
1041                 pc++;
1042         }
1043 }
1044
1045 /*------------------------------------------------------------------------*
1046  *      usb_bdma_post_sync
1047  *
1048  * This function handles DMA synchronisation that must be done after
1049  * an USB transfer is complete.
1050  *------------------------------------------------------------------------*/
1051 void
1052 usb_bdma_post_sync(struct usb_xfer *xfer)
1053 {
1054         struct usb_page_cache *pc;
1055         usb_frcount_t nframes;
1056
1057         if (xfer->flags_int.isochronous_xfr) {
1058                 /* only one frame buffer */
1059                 nframes = 1;
1060         } else {
1061                 /* can be multiple frame buffers */
1062                 nframes = xfer->nframes;
1063         }
1064
1065         pc = xfer->frbuffers;
1066
1067         while (nframes--) {
1068                 if (pc->isread) {
1069                         usb_pc_cpu_invalidate(pc);
1070                 }
1071                 pc++;
1072         }
1073 }
1074
1075 #endif