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