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