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