1 /* $FreeBSD: stable/9/sys/dev/usb/usb_busdma.c 291251 2015-11-24 12:19:20Z hselasky $ */
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
usbd_get_page(struct usb_page_cache * pc,usb_frlength_t offset,struct usb_page_search * res)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
usb_pc_buffer_is_aligned(struct usb_page_cache * pc,usb_frlength_t offset,usb_frlength_t len,usb_frlength_t mask)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
usbd_copy_in(struct usb_page_cache * cache,usb_frlength_t offset,const void * ptr,usb_frlength_t len)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
usbd_copy_in_user(struct usb_page_cache * cache,usb_frlength_t offset,const void * ptr,usb_frlength_t len)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
usbd_m_copy_in_cb(void * arg,void * src,uint32_t count)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
usbd_m_copy_in(struct usb_page_cache * cache,usb_frlength_t dst_offset,struct mbuf * m,usb_size_t src_offset,usb_frlength_t src_len)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
usb_uiomove(struct usb_page_cache * pc,struct uio * uio,usb_frlength_t pc_offset,usb_frlength_t len)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
usbd_copy_out(struct usb_page_cache * cache,usb_frlength_t offset,void * ptr,usb_frlength_t len)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
usbd_copy_out_user(struct usb_page_cache * cache,usb_frlength_t offset,void * ptr,usb_frlength_t len)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
usbd_frame_zero(struct usb_page_cache * cache,usb_frlength_t offset,usb_frlength_t len)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
usb_dma_lock_cb(void * arg,bus_dma_lock_op_t op)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
usb_dma_tag_create(struct usb_dma_tag * udt,usb_size_t size,usb_size_t align)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
usb_dma_tag_destroy(struct usb_dma_tag * udt)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
usb_pc_alloc_mem_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)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
usb_pc_load_mem_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)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
usb_pc_common_mem_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error,uint8_t isload)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
usb_pc_alloc_mem(struct usb_page_cache * pc,struct usb_page * pg,usb_size_t size,usb_size_t align)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
usb_pc_free_mem(struct usb_page_cache * pc)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
usb_pc_load_mem(struct usb_page_cache * pc,usb_size_t size,uint8_t sync)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
usb_pc_cpu_invalidate(struct usb_page_cache * pc)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
usb_pc_cpu_flush(struct usb_page_cache * pc)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
usb_pc_dmamap_create(struct usb_page_cache * pc,usb_size_t size)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
usb_pc_dmamap_destroy(struct usb_page_cache * pc)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 *
usb_dma_tag_find(struct usb_dma_parent_tag * udpt,usb_size_t size,usb_size_t align)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
usb_dma_tag_setup(struct usb_dma_parent_tag * udpt,struct usb_dma_tag * udt,bus_dma_tag_t dmat,struct mtx * mtx,usb_dma_callback_t * func,uint8_t ndmabits,uint8_t nudt)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
usb_dma_tag_unsetup(struct usb_dma_parent_tag * udpt)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
usb_bdma_work_loop(struct usb_xfer_queue * pq)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
usb_bdma_done_event(struct usb_dma_parent_tag * udpt)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
usb_bdma_pre_sync(struct usb_xfer * xfer)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
usb_bdma_post_sync(struct usb_xfer * xfer)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
1109