1246145Shselasky/* $FreeBSD$ */ 2246145Shselasky/*- 3246145Shselasky * Copyright (c) 2013 Hans Petter Selasky. All rights reserved. 4246145Shselasky * 5246145Shselasky * Redistribution and use in source and binary forms, with or without 6246145Shselasky * modification, are permitted provided that the following conditions 7246145Shselasky * are met: 8246145Shselasky * 1. Redistributions of source code must retain the above copyright 9246145Shselasky * notice, this list of conditions and the following disclaimer. 10246145Shselasky * 2. Redistributions in binary form must reproduce the above copyright 11246145Shselasky * notice, this list of conditions and the following disclaimer in the 12246145Shselasky * documentation and/or other materials provided with the distribution. 13246145Shselasky * 14246145Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15246145Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16246145Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17246145Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18246145Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19246145Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20246145Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21246145Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22246145Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23246145Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24246145Shselasky * SUCH DAMAGE. 25246145Shselasky */ 26246145Shselasky 27246145Shselasky#include <bsd_global.h> 28246145Shselasky 29246145Shselasky#if USB_HAVE_BUSDMA 30246145Shselaskystatic void usb_pc_common_mem_cb(struct usb_page_cache *pc, 31246145Shselasky void *vaddr, uint32_t length); 32246145Shselasky#endif 33246145Shselasky 34246145Shselasky/*------------------------------------------------------------------------* 35246145Shselasky * usbd_get_page - lookup DMA-able memory for the given offset 36246145Shselasky * 37246145Shselasky * NOTE: Only call this function when the "page_cache" structure has 38246145Shselasky * been properly initialized ! 39246145Shselasky *------------------------------------------------------------------------*/ 40246145Shselaskyvoid 41246145Shselaskyusbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset, 42246145Shselasky struct usb_page_search *res) 43246145Shselasky{ 44246145Shselasky#if USB_HAVE_BUSDMA 45246145Shselasky struct usb_page *page; 46246145Shselasky 47246145Shselasky if (pc->page_start) { 48246145Shselasky 49246145Shselasky /* Case 1 - something has been loaded into DMA */ 50246145Shselasky 51246145Shselasky if (pc->buffer) { 52246145Shselasky 53246145Shselasky /* Case 1a - Kernel Virtual Address */ 54246145Shselasky 55246145Shselasky res->buffer = USB_ADD_BYTES(pc->buffer, offset); 56246145Shselasky } 57246145Shselasky offset += pc->page_offset_buf; 58246145Shselasky 59246145Shselasky /* compute destination page */ 60246145Shselasky 61246145Shselasky page = pc->page_start; 62246145Shselasky 63246145Shselasky if (pc->ismultiseg) { 64246145Shselasky 65246145Shselasky page += (offset / USB_PAGE_SIZE); 66246145Shselasky 67246145Shselasky offset %= USB_PAGE_SIZE; 68246145Shselasky 69246145Shselasky res->length = USB_PAGE_SIZE - offset; 70246145Shselasky res->physaddr = page->physaddr + offset; 71246145Shselasky } else { 72246145Shselasky res->length = (usb_size_t)-1; 73246145Shselasky res->physaddr = page->physaddr + offset; 74246145Shselasky } 75246145Shselasky if (!pc->buffer) { 76246145Shselasky 77246145Shselasky /* Case 1b - Non Kernel Virtual Address */ 78246145Shselasky 79246145Shselasky res->buffer = USB_ADD_BYTES(page->buffer, offset); 80246145Shselasky } 81246145Shselasky return; 82246145Shselasky } 83246145Shselasky#endif 84246145Shselasky /* Case 2 - Plain PIO */ 85246145Shselasky 86246145Shselasky res->buffer = USB_ADD_BYTES(pc->buffer, offset); 87246145Shselasky res->length = (usb_size_t)-1; 88246145Shselasky#if USB_HAVE_BUSDMA 89246145Shselasky res->physaddr = 0; 90246145Shselasky#endif 91246145Shselasky} 92246145Shselasky 93246145Shselasky/*------------------------------------------------------------------------* 94246145Shselasky * usbd_copy_in - copy directly to DMA-able memory 95246145Shselasky *------------------------------------------------------------------------*/ 96246145Shselaskyvoid 97246145Shselaskyusbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset, 98246145Shselasky const void *ptr, usb_frlength_t len) 99246145Shselasky{ 100246145Shselasky struct usb_page_search buf_res; 101246145Shselasky 102246145Shselasky while (len != 0) { 103246145Shselasky 104246145Shselasky usbd_get_page(cache, offset, &buf_res); 105246145Shselasky 106246145Shselasky if (buf_res.length > len) { 107246145Shselasky buf_res.length = len; 108246145Shselasky } 109246145Shselasky memcpy(buf_res.buffer, ptr, buf_res.length); 110246145Shselasky 111246145Shselasky offset += buf_res.length; 112246145Shselasky len -= buf_res.length; 113246145Shselasky ptr = USB_ADD_BYTES(ptr, buf_res.length); 114246145Shselasky } 115246145Shselasky} 116246145Shselasky 117246145Shselasky/*------------------------------------------------------------------------* 118246145Shselasky * usbd_copy_out - copy directly from DMA-able memory 119246145Shselasky *------------------------------------------------------------------------*/ 120246145Shselaskyvoid 121246145Shselaskyusbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, 122246145Shselasky void *ptr, usb_frlength_t len) 123246145Shselasky{ 124246145Shselasky struct usb_page_search res; 125246145Shselasky 126246145Shselasky while (len != 0) { 127246145Shselasky 128246145Shselasky usbd_get_page(cache, offset, &res); 129246145Shselasky 130246145Shselasky if (res.length > len) { 131246145Shselasky res.length = len; 132246145Shselasky } 133246145Shselasky memcpy(ptr, res.buffer, res.length); 134246145Shselasky 135246145Shselasky offset += res.length; 136246145Shselasky len -= res.length; 137246145Shselasky ptr = USB_ADD_BYTES(ptr, res.length); 138246145Shselasky } 139246145Shselasky} 140246145Shselasky 141246145Shselasky/*------------------------------------------------------------------------* 142246145Shselasky * usbd_frame_zero - zero DMA-able memory 143246145Shselasky *------------------------------------------------------------------------*/ 144246145Shselaskyvoid 145246145Shselaskyusbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset, 146246145Shselasky usb_frlength_t len) 147246145Shselasky{ 148246145Shselasky struct usb_page_search res; 149246145Shselasky 150246145Shselasky while (len != 0) { 151246145Shselasky 152246145Shselasky usbd_get_page(cache, offset, &res); 153246145Shselasky 154246145Shselasky if (res.length > len) { 155246145Shselasky res.length = len; 156246145Shselasky } 157246145Shselasky memset(res.buffer, 0, res.length); 158246145Shselasky 159246145Shselasky offset += res.length; 160246145Shselasky len -= res.length; 161246145Shselasky } 162246145Shselasky} 163246145Shselasky 164246145Shselasky#if USB_HAVE_BUSDMA 165246145Shselasky 166246145Shselasky/*------------------------------------------------------------------------* 167246145Shselasky * usb_pc_common_mem_cb - BUS-DMA callback function 168246145Shselasky *------------------------------------------------------------------------*/ 169246145Shselaskystatic void 170246145Shselaskyusb_pc_common_mem_cb(struct usb_page_cache *pc, 171246145Shselasky void *vaddr, uint32_t length) 172246145Shselasky{ 173246145Shselasky struct usb_page *pg; 174246145Shselasky usb_size_t rem; 175246145Shselasky bus_size_t off; 176246145Shselasky bus_addr_t phys = (uintptr_t)vaddr; /* XXX */ 177246145Shselasky uint32_t nseg; 178246145Shselasky 179246145Shselasky if (length == 0) 180246145Shselasky nseg = 1; 181246145Shselasky else 182246145Shselasky nseg = ((length + USB_PAGE_SIZE - 1) / USB_PAGE_SIZE); 183246145Shselasky 184246145Shselasky pg = pc->page_start; 185246145Shselasky pg->physaddr = phys & ~(USB_PAGE_SIZE - 1); 186246145Shselasky rem = phys & (USB_PAGE_SIZE - 1); 187246145Shselasky pc->page_offset_buf = rem; 188246145Shselasky pc->page_offset_end += rem; 189246145Shselasky length += rem; 190246145Shselasky 191246145Shselasky for (off = USB_PAGE_SIZE; off < length; off += USB_PAGE_SIZE) { 192246145Shselasky pg++; 193246145Shselasky pg->physaddr = (phys + off) & ~(USB_PAGE_SIZE - 1); 194246145Shselasky } 195246145Shselasky} 196246145Shselasky 197246145Shselasky/*------------------------------------------------------------------------* 198246145Shselasky * usb_pc_alloc_mem - allocate DMA'able memory 199246145Shselasky * 200246145Shselasky * Returns: 201246145Shselasky * 0: Success 202246145Shselasky * Else: Failure 203246145Shselasky *------------------------------------------------------------------------*/ 204246145Shselaskyuint8_t 205246145Shselaskyusb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg, 206246145Shselasky usb_size_t size, usb_size_t align) 207246145Shselasky{ 208246145Shselasky void *ptr; 209246145Shselasky uint32_t rem; 210246145Shselasky 211246145Shselasky /* allocate zeroed memory */ 212246145Shselasky 213246145Shselasky if (align != 1) { 214246145Shselasky ptr = usb_malloc(size + align); 215246145Shselasky if (ptr == NULL) 216246145Shselasky goto error; 217246145Shselasky 218246145Shselasky rem = (-((uintptr_t)ptr)) & (align - 1); 219246145Shselasky } else { 220246145Shselasky ptr = usb_malloc(size); 221246145Shselasky if (ptr == NULL) 222246145Shselasky goto error; 223246145Shselasky rem = 0; 224246145Shselasky } 225246145Shselasky 226246145Shselasky /* setup page cache */ 227246145Shselasky pc->buffer = ((uint8_t *)ptr) + rem; 228246145Shselasky pc->page_start = pg; 229246145Shselasky pc->page_offset_buf = 0; 230246145Shselasky pc->page_offset_end = size; 231246145Shselasky pc->map = NULL; 232246145Shselasky pc->tag = ptr; 233246145Shselasky pc->ismultiseg = (align == 1); 234246145Shselasky 235246145Shselasky /* compute physical address */ 236246145Shselasky usb_pc_common_mem_cb(pc, ptr, size); 237246145Shselasky 238246145Shselasky usb_pc_cpu_flush(pc); 239246145Shselasky return (0); 240246145Shselasky 241246145Shselaskyerror: 242246145Shselasky /* reset most of the page cache */ 243246145Shselasky pc->buffer = NULL; 244246145Shselasky pc->page_start = NULL; 245246145Shselasky pc->page_offset_buf = 0; 246246145Shselasky pc->page_offset_end = 0; 247246145Shselasky pc->map = NULL; 248246145Shselasky pc->tag = NULL; 249246145Shselasky return (1); 250246145Shselasky} 251246145Shselasky 252246145Shselasky/*------------------------------------------------------------------------* 253246145Shselasky * usb_pc_free_mem - free DMA memory 254246145Shselasky * 255246145Shselasky * This function is NULL safe. 256246145Shselasky *------------------------------------------------------------------------*/ 257246145Shselaskyvoid 258246145Shselaskyusb_pc_free_mem(struct usb_page_cache *pc) 259246145Shselasky{ 260246145Shselasky if (pc != NULL && pc->buffer != NULL) { 261246145Shselasky usb_free(pc->tag); 262246145Shselasky pc->buffer = NULL; 263246145Shselasky } 264246145Shselasky} 265246145Shselasky 266246145Shselasky/*------------------------------------------------------------------------* 267246145Shselasky * usb_pc_load_mem - load virtual memory into DMA 268246145Shselasky * 269246145Shselasky * Return values: 270246145Shselasky * 0: Success 271246145Shselasky * Else: Error 272246145Shselasky *------------------------------------------------------------------------*/ 273246145Shselaskyuint8_t 274246145Shselaskyusb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync) 275246145Shselasky{ 276246145Shselasky /* setup page cache */ 277246145Shselasky pc->page_offset_buf = 0; 278246145Shselasky pc->page_offset_end = size; 279246145Shselasky pc->ismultiseg = 1; 280246145Shselasky 281246145Shselasky mtx_assert(pc->tag_parent->mtx, MA_OWNED); 282246145Shselasky 283246145Shselasky if (size > 0) { 284246145Shselasky /* compute physical address */ 285246145Shselasky usb_pc_common_mem_cb(pc, pc->buffer, size); 286246145Shselasky } 287246145Shselasky if (sync == 0) { 288246145Shselasky /* 289246145Shselasky * Call callback so that refcount is decremented 290246145Shselasky * properly: 291246145Shselasky */ 292246145Shselasky pc->tag_parent->dma_error = 0; 293246145Shselasky (pc->tag_parent->func) (pc->tag_parent); 294246145Shselasky } 295246145Shselasky return (0); 296246145Shselasky} 297246145Shselasky 298246145Shselasky/*------------------------------------------------------------------------* 299246145Shselasky * usb_pc_cpu_invalidate - invalidate CPU cache 300246145Shselasky *------------------------------------------------------------------------*/ 301246145Shselaskyvoid 302246145Shselaskyusb_pc_cpu_invalidate(struct usb_page_cache *pc) 303246145Shselasky{ 304246145Shselasky if (pc->page_offset_end == pc->page_offset_buf) { 305246145Shselasky /* nothing has been loaded into this page cache! */ 306246145Shselasky return; 307246145Shselasky } 308246145Shselasky /* NOP */ 309246145Shselasky} 310246145Shselasky 311246145Shselasky/*------------------------------------------------------------------------* 312246145Shselasky * usb_pc_cpu_flush - flush CPU cache 313246145Shselasky *------------------------------------------------------------------------*/ 314246145Shselaskyvoid 315246145Shselaskyusb_pc_cpu_flush(struct usb_page_cache *pc) 316246145Shselasky{ 317246145Shselasky if (pc->page_offset_end == pc->page_offset_buf) { 318246145Shselasky /* nothing has been loaded into this page cache! */ 319246145Shselasky return; 320246145Shselasky } 321246145Shselasky /* NOP */ 322246145Shselasky} 323246145Shselasky 324246145Shselasky/*------------------------------------------------------------------------* 325246145Shselasky * usb_pc_dmamap_create - create a DMA map 326246145Shselasky * 327246145Shselasky * Returns: 328246145Shselasky * 0: Success 329246145Shselasky * Else: Failure 330246145Shselasky *------------------------------------------------------------------------*/ 331246145Shselaskyuint8_t 332246145Shselaskyusb_pc_dmamap_create(struct usb_page_cache *pc, usb_size_t size) 333246145Shselasky{ 334246145Shselasky return (0); /* NOP, success */ 335246145Shselasky} 336246145Shselasky 337246145Shselasky/*------------------------------------------------------------------------* 338246145Shselasky * usb_pc_dmamap_destroy 339246145Shselasky * 340246145Shselasky * This function is NULL safe. 341246145Shselasky *------------------------------------------------------------------------*/ 342246145Shselaskyvoid 343246145Shselaskyusb_pc_dmamap_destroy(struct usb_page_cache *pc) 344246145Shselasky{ 345246145Shselasky /* NOP */ 346246145Shselasky} 347246145Shselasky 348246145Shselasky/*------------------------------------------------------------------------* 349246145Shselasky * usb_dma_tag_setup - initialise USB DMA tags 350246145Shselasky *------------------------------------------------------------------------*/ 351246145Shselaskyvoid 352246145Shselaskyusb_dma_tag_setup(struct usb_dma_parent_tag *udpt, 353246145Shselasky struct usb_dma_tag *udt, bus_dma_tag_t dmat, 354246145Shselasky struct mtx *mtx, usb_dma_callback_t *func, 355246145Shselasky uint8_t ndmabits, uint8_t nudt) 356246145Shselasky{ 357246145Shselasky memset(udpt, 0, sizeof(*udpt)); 358246145Shselasky 359246145Shselasky /* sanity checking */ 360246145Shselasky if ((nudt == 0) || 361246145Shselasky (ndmabits == 0) || 362246145Shselasky (mtx == NULL)) { 363246145Shselasky /* something is corrupt */ 364246145Shselasky return; 365246145Shselasky } 366246145Shselasky /* initialise condition variable */ 367246145Shselasky cv_init(udpt->cv, "USB DMA CV"); 368246145Shselasky 369246145Shselasky /* store some information */ 370246145Shselasky udpt->mtx = mtx; 371246145Shselasky udpt->func = func; 372246145Shselasky udpt->tag = dmat; 373246145Shselasky udpt->utag_first = udt; 374246145Shselasky udpt->utag_max = nudt; 375246145Shselasky udpt->dma_bits = ndmabits; 376246145Shselasky 377246145Shselasky while (nudt--) { 378246145Shselasky memset(udt, 0, sizeof(*udt)); 379246145Shselasky udt->tag_parent = udpt; 380246145Shselasky udt++; 381246145Shselasky } 382246145Shselasky} 383246145Shselasky 384246145Shselasky/*------------------------------------------------------------------------* 385246145Shselasky * usb_bus_tag_unsetup - factored out code 386246145Shselasky *------------------------------------------------------------------------*/ 387246145Shselaskyvoid 388246145Shselaskyusb_dma_tag_unsetup(struct usb_dma_parent_tag *udpt) 389246145Shselasky{ 390246145Shselasky struct usb_dma_tag *udt; 391246145Shselasky uint8_t nudt; 392246145Shselasky 393246145Shselasky udt = udpt->utag_first; 394246145Shselasky nudt = udpt->utag_max; 395246145Shselasky 396246145Shselasky while (nudt--) { 397246145Shselasky udt->align = 0; 398246145Shselasky udt++; 399246145Shselasky } 400246145Shselasky 401246145Shselasky if (udpt->utag_max) { 402246145Shselasky /* destroy the condition variable */ 403246145Shselasky cv_destroy(udpt->cv); 404246145Shselasky } 405246145Shselasky} 406246145Shselasky 407246145Shselasky/*------------------------------------------------------------------------* 408246145Shselasky * usb_bdma_work_loop 409246145Shselasky * 410246145Shselasky * This function handles loading of virtual buffers into DMA and is 411246145Shselasky * only called when "dma_refcount" is zero. 412246145Shselasky *------------------------------------------------------------------------*/ 413246145Shselaskyvoid 414246145Shselaskyusb_bdma_work_loop(struct usb_xfer_queue *pq) 415246145Shselasky{ 416246145Shselasky struct usb_xfer_root *info; 417246145Shselasky struct usb_xfer *xfer; 418246145Shselasky usb_frcount_t nframes; 419246145Shselasky 420246145Shselasky xfer = pq->curr; 421246145Shselasky info = xfer->xroot; 422246145Shselasky 423246145Shselasky mtx_assert(info->xfer_mtx, MA_OWNED); 424246145Shselasky 425246145Shselasky if (xfer->error) { 426246145Shselasky /* some error happened */ 427246145Shselasky USB_BUS_LOCK(info->bus); 428246145Shselasky usbd_transfer_done(xfer, 0); 429246145Shselasky USB_BUS_UNLOCK(info->bus); 430246145Shselasky return; 431246145Shselasky } 432246145Shselasky if (!xfer->flags_int.bdma_setup) { 433246145Shselasky struct usb_page *pg; 434246145Shselasky usb_frlength_t frlength_0; 435246145Shselasky uint8_t isread; 436246145Shselasky 437246145Shselasky xfer->flags_int.bdma_setup = 1; 438246145Shselasky 439246145Shselasky /* reset BUS-DMA load state */ 440246145Shselasky 441246145Shselasky info->dma_error = 0; 442246145Shselasky 443246145Shselasky if (xfer->flags_int.isochronous_xfr) { 444246145Shselasky /* only one frame buffer */ 445246145Shselasky nframes = 1; 446246145Shselasky frlength_0 = xfer->sumlen; 447246145Shselasky } else { 448246145Shselasky /* can be multiple frame buffers */ 449246145Shselasky nframes = xfer->nframes; 450246145Shselasky frlength_0 = xfer->frlengths[0]; 451246145Shselasky } 452246145Shselasky 453246145Shselasky /* 454246145Shselasky * Set DMA direction first. This is needed to 455246145Shselasky * select the correct cache invalidate and cache 456246145Shselasky * flush operations. 457246145Shselasky */ 458246145Shselasky isread = USB_GET_DATA_ISREAD(xfer); 459246145Shselasky pg = xfer->dma_page_ptr; 460246145Shselasky 461246145Shselasky if (xfer->flags_int.control_xfr && 462246145Shselasky xfer->flags_int.control_hdr) { 463246145Shselasky /* special case */ 464246145Shselasky if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 465246145Shselasky /* The device controller writes to memory */ 466246145Shselasky xfer->frbuffers[0].isread = 1; 467246145Shselasky } else { 468246145Shselasky /* The host controller reads from memory */ 469246145Shselasky xfer->frbuffers[0].isread = 0; 470246145Shselasky } 471246145Shselasky } else { 472246145Shselasky /* default case */ 473246145Shselasky xfer->frbuffers[0].isread = isread; 474246145Shselasky } 475246145Shselasky 476246145Shselasky /* 477246145Shselasky * Setup the "page_start" pointer which points to an array of 478246145Shselasky * USB pages where information about the physical address of a 479246145Shselasky * page will be stored. Also initialise the "isread" field of 480246145Shselasky * the USB page caches. 481246145Shselasky */ 482246145Shselasky xfer->frbuffers[0].page_start = pg; 483246145Shselasky 484246145Shselasky info->dma_nframes = nframes; 485246145Shselasky info->dma_currframe = 0; 486246145Shselasky info->dma_frlength_0 = frlength_0; 487246145Shselasky 488246145Shselasky pg += (frlength_0 / USB_PAGE_SIZE); 489246145Shselasky pg += 2; 490246145Shselasky 491246145Shselasky while (--nframes > 0) { 492246145Shselasky xfer->frbuffers[nframes].isread = isread; 493246145Shselasky xfer->frbuffers[nframes].page_start = pg; 494246145Shselasky 495246145Shselasky pg += (xfer->frlengths[nframes] / USB_PAGE_SIZE); 496246145Shselasky pg += 2; 497246145Shselasky } 498246145Shselasky 499246145Shselasky } 500246145Shselasky if (info->dma_error) { 501246145Shselasky USB_BUS_LOCK(info->bus); 502246145Shselasky usbd_transfer_done(xfer, USB_ERR_DMA_LOAD_FAILED); 503246145Shselasky USB_BUS_UNLOCK(info->bus); 504246145Shselasky return; 505246145Shselasky } 506246145Shselasky if (info->dma_currframe != info->dma_nframes) { 507246145Shselasky 508246145Shselasky if (info->dma_currframe == 0) { 509246145Shselasky /* special case */ 510246145Shselasky usb_pc_load_mem(xfer->frbuffers, 511246145Shselasky info->dma_frlength_0, 0); 512246145Shselasky } else { 513246145Shselasky /* default case */ 514246145Shselasky nframes = info->dma_currframe; 515246145Shselasky usb_pc_load_mem(xfer->frbuffers + nframes, 516246145Shselasky xfer->frlengths[nframes], 0); 517246145Shselasky } 518246145Shselasky 519246145Shselasky /* advance frame index */ 520246145Shselasky info->dma_currframe++; 521246145Shselasky 522246145Shselasky return; 523246145Shselasky } 524246145Shselasky /* go ahead */ 525246145Shselasky usb_bdma_pre_sync(xfer); 526246145Shselasky 527246145Shselasky /* start loading next USB transfer, if any */ 528246145Shselasky usb_command_wrapper(pq, NULL); 529246145Shselasky 530246145Shselasky /* finally start the hardware */ 531246145Shselasky usbd_pipe_enter(xfer); 532246145Shselasky} 533246145Shselasky 534246145Shselasky/*------------------------------------------------------------------------* 535246145Shselasky * usb_bdma_done_event 536246145Shselasky * 537246145Shselasky * This function is called when the BUS-DMA has loaded virtual memory 538246145Shselasky * into DMA, if any. 539246145Shselasky *------------------------------------------------------------------------*/ 540246145Shselaskyvoid 541246145Shselaskyusb_bdma_done_event(struct usb_dma_parent_tag *udpt) 542246145Shselasky{ 543246145Shselasky struct usb_xfer_root *info; 544246145Shselasky 545246145Shselasky info = USB_DMATAG_TO_XROOT(udpt); 546246145Shselasky 547246145Shselasky mtx_assert(info->xfer_mtx, MA_OWNED); 548246145Shselasky 549246145Shselasky /* copy error */ 550246145Shselasky info->dma_error = udpt->dma_error; 551246145Shselasky 552246145Shselasky /* enter workloop again */ 553246145Shselasky usb_command_wrapper(&info->dma_q, 554246145Shselasky info->dma_q.curr); 555246145Shselasky} 556246145Shselasky 557246145Shselasky/*------------------------------------------------------------------------* 558246145Shselasky * usb_bdma_pre_sync 559246145Shselasky * 560246145Shselasky * This function handles DMA synchronisation that must be done before 561246145Shselasky * an USB transfer is started. 562246145Shselasky *------------------------------------------------------------------------*/ 563246145Shselaskyvoid 564246145Shselaskyusb_bdma_pre_sync(struct usb_xfer *xfer) 565246145Shselasky{ 566246145Shselasky struct usb_page_cache *pc; 567246145Shselasky usb_frcount_t nframes; 568246145Shselasky 569246145Shselasky if (xfer->flags_int.isochronous_xfr) { 570246145Shselasky /* only one frame buffer */ 571246145Shselasky nframes = 1; 572246145Shselasky } else { 573246145Shselasky /* can be multiple frame buffers */ 574246145Shselasky nframes = xfer->nframes; 575246145Shselasky } 576246145Shselasky 577246145Shselasky pc = xfer->frbuffers; 578246145Shselasky 579246145Shselasky while (nframes--) { 580246145Shselasky 581246145Shselasky if (pc->isread) { 582246145Shselasky usb_pc_cpu_invalidate(pc); 583246145Shselasky } else { 584246145Shselasky usb_pc_cpu_flush(pc); 585246145Shselasky } 586246145Shselasky pc++; 587246145Shselasky } 588246145Shselasky} 589246145Shselasky 590246145Shselasky/*------------------------------------------------------------------------* 591246145Shselasky * usb_bdma_post_sync 592246145Shselasky * 593246145Shselasky * This function handles DMA synchronisation that must be done after 594246145Shselasky * an USB transfer is complete. 595246145Shselasky *------------------------------------------------------------------------*/ 596246145Shselaskyvoid 597246145Shselaskyusb_bdma_post_sync(struct usb_xfer *xfer) 598246145Shselasky{ 599246145Shselasky struct usb_page_cache *pc; 600246145Shselasky usb_frcount_t nframes; 601246145Shselasky 602246145Shselasky if (xfer->flags_int.isochronous_xfr) { 603246145Shselasky /* only one frame buffer */ 604246145Shselasky nframes = 1; 605246145Shselasky } else { 606246145Shselasky /* can be multiple frame buffers */ 607246145Shselasky nframes = xfer->nframes; 608246145Shselasky } 609246145Shselasky 610246145Shselasky pc = xfer->frbuffers; 611246145Shselasky 612246145Shselasky while (nframes--) { 613246145Shselasky if (pc->isread) { 614246145Shselasky usb_pc_cpu_invalidate(pc); 615246145Shselasky } 616246145Shselasky pc++; 617246145Shselasky } 618246145Shselasky} 619246145Shselasky#endif 620