1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * Copyright (c) 2013 Hans Petter Selasky. All rights reserved. 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 5f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 6f9f848faSopenharmony_ci * are met: 7f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 8f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 9f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 10f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 11f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 12f9f848faSopenharmony_ci * 13f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23f9f848faSopenharmony_ci * SUCH DAMAGE. 24f9f848faSopenharmony_ci */ 25f9f848faSopenharmony_ci 26f9f848faSopenharmony_ci#include <los_memory.h> 27f9f848faSopenharmony_ci#include "los_vm_iomap.h" 28f9f848faSopenharmony_ci#include "los_vm_map.h" 29f9f848faSopenharmony_ci#include <user_copy.h> 30f9f848faSopenharmony_ci 31f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 32f9f848faSopenharmony_ci 33f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA 34f9f848faSopenharmony_cistatic void usb_pc_common_mem_cb(struct usb_page_cache *pc, 35f9f848faSopenharmony_ci void *vaddr, uint32_t length); 36f9f848faSopenharmony_ci#endif 37f9f848faSopenharmony_ci 38f9f848faSopenharmony_civoid 39f9f848faSopenharmony_ciusb_dma_cache_invalid(void *addr, unsigned int size) 40f9f848faSopenharmony_ci{ 41f9f848faSopenharmony_ci UINTPTR start = (UINTPTR)addr & ~(USB_CACHE_ALIGN_SIZE - 1); 42f9f848faSopenharmony_ci UINTPTR end = (UINTPTR)addr + size; 43f9f848faSopenharmony_ci 44f9f848faSopenharmony_ci end = ALIGN(end, USB_CACHE_ALIGN_SIZE); 45f9f848faSopenharmony_ci DCacheInvRange(start, end); 46f9f848faSopenharmony_ci} 47f9f848faSopenharmony_ci 48f9f848faSopenharmony_civoid 49f9f848faSopenharmony_ciusb_dma_cache_flush(void *addr, unsigned int size) 50f9f848faSopenharmony_ci{ 51f9f848faSopenharmony_ci UINTPTR start = (UINTPTR)addr & ~(USB_CACHE_ALIGN_SIZE - 1); 52f9f848faSopenharmony_ci UINTPTR end = (UINTPTR)addr + size; 53f9f848faSopenharmony_ci 54f9f848faSopenharmony_ci end = ALIGN(end, USB_CACHE_ALIGN_SIZE); 55f9f848faSopenharmony_ci DCacheFlushRange(start, end); 56f9f848faSopenharmony_ci} 57f9f848faSopenharmony_ci 58f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 59f9f848faSopenharmony_ci * usbd_get_page - lookup DMA-able memory for the given offset 60f9f848faSopenharmony_ci * 61f9f848faSopenharmony_ci * NOTE: Only call this function when the "page_cache" structure has 62f9f848faSopenharmony_ci * been properly initialized ! 63f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 64f9f848faSopenharmony_civoid 65f9f848faSopenharmony_ciusbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset, 66f9f848faSopenharmony_ci struct usb_page_search *res) 67f9f848faSopenharmony_ci{ 68f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA 69f9f848faSopenharmony_ci struct usb_page *page; 70f9f848faSopenharmony_ci if (pc->page_start) { 71f9f848faSopenharmony_ci /* Case 1 - something has been loaded into DMA */ 72f9f848faSopenharmony_ci 73f9f848faSopenharmony_ci if (pc->buffer) { 74f9f848faSopenharmony_ci 75f9f848faSopenharmony_ci /* Case 1a - Kernel Virtual Address */ 76f9f848faSopenharmony_ci 77f9f848faSopenharmony_ci res->buffer = USB_ADD_BYTES(pc->buffer, offset); 78f9f848faSopenharmony_ci } 79f9f848faSopenharmony_ci offset += pc->page_offset_buf; 80f9f848faSopenharmony_ci 81f9f848faSopenharmony_ci /* compute destination page */ 82f9f848faSopenharmony_ci 83f9f848faSopenharmony_ci page = pc->page_start; 84f9f848faSopenharmony_ci 85f9f848faSopenharmony_ci if (pc->ismultiseg) { 86f9f848faSopenharmony_ci 87f9f848faSopenharmony_ci page += (offset / USB_PAGE_SIZE); 88f9f848faSopenharmony_ci 89f9f848faSopenharmony_ci offset %= USB_PAGE_SIZE; 90f9f848faSopenharmony_ci 91f9f848faSopenharmony_ci res->length = USB_PAGE_SIZE - offset; 92f9f848faSopenharmony_ci res->physaddr = page->physaddr + offset; 93f9f848faSopenharmony_ci } else { 94f9f848faSopenharmony_ci res->length = (usb_size_t)-1; 95f9f848faSopenharmony_ci res->physaddr = page->physaddr + offset; 96f9f848faSopenharmony_ci } 97f9f848faSopenharmony_ci if (!pc->buffer) { 98f9f848faSopenharmony_ci 99f9f848faSopenharmony_ci /* Case 1b - Non Kernel Virtual Address */ 100f9f848faSopenharmony_ci 101f9f848faSopenharmony_ci res->buffer = USB_ADD_BYTES(page->buffer, offset); 102f9f848faSopenharmony_ci } 103f9f848faSopenharmony_ci return; 104f9f848faSopenharmony_ci } 105f9f848faSopenharmony_ci#endif 106f9f848faSopenharmony_ci /* Case 2 - Plain PIO */ 107f9f848faSopenharmony_ci 108f9f848faSopenharmony_ci res->buffer = USB_ADD_BYTES(pc->buffer, offset); 109f9f848faSopenharmony_ci res->length = (usb_size_t)-1; 110f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA 111f9f848faSopenharmony_ci res->physaddr = 0; 112f9f848faSopenharmony_ci#endif 113f9f848faSopenharmony_ci} 114f9f848faSopenharmony_ci 115f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 116f9f848faSopenharmony_ci * usbd_copy_in - copy directly to DMA-able memory 117f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 118f9f848faSopenharmony_civoid 119f9f848faSopenharmony_ciusbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset, 120f9f848faSopenharmony_ci const void *ptr, usb_frlength_t len) 121f9f848faSopenharmony_ci{ 122f9f848faSopenharmony_ci struct usb_page_search buf_res; 123f9f848faSopenharmony_ci int ret; 124f9f848faSopenharmony_ci 125f9f848faSopenharmony_ci while (len != 0) { 126f9f848faSopenharmony_ci 127f9f848faSopenharmony_ci usbd_get_page(cache, offset, &buf_res); 128f9f848faSopenharmony_ci 129f9f848faSopenharmony_ci if (buf_res.length > len) { 130f9f848faSopenharmony_ci buf_res.length = len; 131f9f848faSopenharmony_ci } 132f9f848faSopenharmony_ci ret = memcpy_s(buf_res.buffer, buf_res.length, ptr, buf_res.length); 133f9f848faSopenharmony_ci if (ret != EOK) { 134f9f848faSopenharmony_ci return; 135f9f848faSopenharmony_ci } 136f9f848faSopenharmony_ci 137f9f848faSopenharmony_ci offset += buf_res.length; 138f9f848faSopenharmony_ci len -= buf_res.length; 139f9f848faSopenharmony_ci ptr = USB_ADD_BYTES(ptr, buf_res.length); 140f9f848faSopenharmony_ci } 141f9f848faSopenharmony_ci} 142f9f848faSopenharmony_ci 143f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 144f9f848faSopenharmony_ci * usbd_copy_out - copy directly from DMA-able memory 145f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 146f9f848faSopenharmony_civoid 147f9f848faSopenharmony_ciusbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, 148f9f848faSopenharmony_ci void *ptr, usb_frlength_t len) 149f9f848faSopenharmony_ci{ 150f9f848faSopenharmony_ci struct usb_page_search res; 151f9f848faSopenharmony_ci 152f9f848faSopenharmony_ci while (len != 0) { 153f9f848faSopenharmony_ci 154f9f848faSopenharmony_ci usbd_get_page(cache, offset, &res); 155f9f848faSopenharmony_ci 156f9f848faSopenharmony_ci if (res.length > len) { 157f9f848faSopenharmony_ci res.length = len; 158f9f848faSopenharmony_ci } 159f9f848faSopenharmony_ci (void)memcpy_s(ptr, len, res.buffer, res.length); 160f9f848faSopenharmony_ci 161f9f848faSopenharmony_ci offset += res.length; 162f9f848faSopenharmony_ci len -= res.length; 163f9f848faSopenharmony_ci ptr = USB_ADD_BYTES(ptr, res.length); 164f9f848faSopenharmony_ci } 165f9f848faSopenharmony_ci} 166f9f848faSopenharmony_ci 167f9f848faSopenharmony_ciint 168f9f848faSopenharmony_cicopyin(const void *uaddr, void *kaddr, size_t len) 169f9f848faSopenharmony_ci{ 170f9f848faSopenharmony_ci size_t ret = LOS_ArchCopyFromUser(kaddr, uaddr, len); 171f9f848faSopenharmony_ci return ret ? EFAULT : 0; 172f9f848faSopenharmony_ci} 173f9f848faSopenharmony_ci 174f9f848faSopenharmony_ciint 175f9f848faSopenharmony_cicopyout(const void *kaddr, void *uaddr, size_t len) 176f9f848faSopenharmony_ci{ 177f9f848faSopenharmony_ci size_t ret = LOS_ArchCopyToUser(uaddr, kaddr, len); 178f9f848faSopenharmony_ci return ret ? EFAULT : 0; 179f9f848faSopenharmony_ci} 180f9f848faSopenharmony_ci 181f9f848faSopenharmony_ci/* In user mode, the src buffer is from user */ 182f9f848faSopenharmony_ciint 183f9f848faSopenharmony_ciusbd_copy_from_user(void *dest, uint32_t dest_len, const void *src, uint32_t src_len) 184f9f848faSopenharmony_ci{ 185f9f848faSopenharmony_ci int ret; 186f9f848faSopenharmony_ci 187f9f848faSopenharmony_ci if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)src, src_len)) { 188f9f848faSopenharmony_ci ret = memcpy_s(dest, dest_len, src, src_len); 189f9f848faSopenharmony_ci } else { 190f9f848faSopenharmony_ci ret = ((dest_len >= src_len) ? LOS_ArchCopyFromUser(dest, src, src_len) : ERANGE_AND_RESET); 191f9f848faSopenharmony_ci } 192f9f848faSopenharmony_ci 193f9f848faSopenharmony_ci return ret ? EFAULT : 0; 194f9f848faSopenharmony_ci} 195f9f848faSopenharmony_ci 196f9f848faSopenharmony_ci/* In user mode, the dest buffer is from user */ 197f9f848faSopenharmony_ciint 198f9f848faSopenharmony_ciusbd_copy_to_user(void *dest, uint32_t dest_len, const void *src, uint32_t src_len) 199f9f848faSopenharmony_ci{ 200f9f848faSopenharmony_ci int ret; 201f9f848faSopenharmony_ci 202f9f848faSopenharmony_ci if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)dest, dest_len)) { 203f9f848faSopenharmony_ci ret = memcpy_s(dest, dest_len, src, src_len); 204f9f848faSopenharmony_ci } else { 205f9f848faSopenharmony_ci ret = ((dest_len >= src_len) ? LOS_ArchCopyToUser(dest, src, src_len) : ERANGE_AND_RESET); 206f9f848faSopenharmony_ci } 207f9f848faSopenharmony_ci 208f9f848faSopenharmony_ci return ret ? EFAULT : 0; 209f9f848faSopenharmony_ci} 210f9f848faSopenharmony_ci 211f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 212f9f848faSopenharmony_ci * usbd_frame_zero - zero DMA-able memory 213f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 214f9f848faSopenharmony_civoid 215f9f848faSopenharmony_ciusbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset, 216f9f848faSopenharmony_ci usb_frlength_t len) 217f9f848faSopenharmony_ci{ 218f9f848faSopenharmony_ci struct usb_page_search res; 219f9f848faSopenharmony_ci 220f9f848faSopenharmony_ci while (len != 0) { 221f9f848faSopenharmony_ci 222f9f848faSopenharmony_ci usbd_get_page(cache, offset, &res); 223f9f848faSopenharmony_ci 224f9f848faSopenharmony_ci if (res.length > len) { 225f9f848faSopenharmony_ci res.length = len; 226f9f848faSopenharmony_ci } 227f9f848faSopenharmony_ci (void)memset_s(res.buffer, res.length, 0, res.length); 228f9f848faSopenharmony_ci 229f9f848faSopenharmony_ci offset += res.length; 230f9f848faSopenharmony_ci len -= res.length; 231f9f848faSopenharmony_ci } 232f9f848faSopenharmony_ci} 233f9f848faSopenharmony_ci 234f9f848faSopenharmony_ci#if USB_HAVE_BUSDMA 235f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 236f9f848faSopenharmony_ci * usb_pc_common_mem_cb - BUS-DMA callback function 237f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 238f9f848faSopenharmony_cistatic void 239f9f848faSopenharmony_ciusb_pc_common_mem_cb(struct usb_page_cache *pc, void *dma_handle, uint32_t length) 240f9f848faSopenharmony_ci{ 241f9f848faSopenharmony_ci struct usb_page *pg; 242f9f848faSopenharmony_ci usb_size_t rem; 243f9f848faSopenharmony_ci bus_size_t off; 244f9f848faSopenharmony_ci bus_addr_t phys = (bus_addr_t)(UINTPTR)dma_handle; 245f9f848faSopenharmony_ci 246f9f848faSopenharmony_ci pg = pc->page_start; 247f9f848faSopenharmony_ci pg->physaddr = phys & ~(USB_PAGE_SIZE - 1); 248f9f848faSopenharmony_ci rem = phys & (USB_PAGE_SIZE - 1); 249f9f848faSopenharmony_ci pc->page_offset_buf = rem; 250f9f848faSopenharmony_ci pc->page_offset_end += rem; 251f9f848faSopenharmony_ci length += rem; 252f9f848faSopenharmony_ci 253f9f848faSopenharmony_ci for (off = USB_PAGE_SIZE; off < length; off += USB_PAGE_SIZE) { 254f9f848faSopenharmony_ci pg++; 255f9f848faSopenharmony_ci pg->physaddr = (phys + off) & ~(USB_PAGE_SIZE - 1); 256f9f848faSopenharmony_ci } 257f9f848faSopenharmony_ci} 258f9f848faSopenharmony_ci 259f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 260f9f848faSopenharmony_ci * usb_pc_alloc_mem - allocate DMA'able memory 261f9f848faSopenharmony_ci * 262f9f848faSopenharmony_ci * Returns: 263f9f848faSopenharmony_ci * 0: Success 264f9f848faSopenharmony_ci * Else: Failure 265f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 266f9f848faSopenharmony_ciuint8_t 267f9f848faSopenharmony_ciusb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg, 268f9f848faSopenharmony_ci usb_size_t size, usb_size_t align) 269f9f848faSopenharmony_ci{ 270f9f848faSopenharmony_ci void *ptr; 271f9f848faSopenharmony_ci DMA_ADDR_T dma_handle; 272f9f848faSopenharmony_ci 273f9f848faSopenharmony_ci /* allocate zeroed memory */ 274f9f848faSopenharmony_ci if (align < USB_CACHE_ALIGN_SIZE) { 275f9f848faSopenharmony_ci ptr = LOS_DmaMemAlloc(&dma_handle, size, USB_CACHE_ALIGN_SIZE, DMA_NOCACHE); 276f9f848faSopenharmony_ci } else { 277f9f848faSopenharmony_ci ptr = LOS_DmaMemAlloc(&dma_handle, size, align, DMA_NOCACHE); 278f9f848faSopenharmony_ci } 279f9f848faSopenharmony_ci if (ptr == NULL) 280f9f848faSopenharmony_ci goto error; 281f9f848faSopenharmony_ci 282f9f848faSopenharmony_ci (void)memset_s(ptr, size, 0, size); 283f9f848faSopenharmony_ci /* setup page cache */ 284f9f848faSopenharmony_ci pc->buffer = (uint8_t *)ptr; 285f9f848faSopenharmony_ci pc->page_start = pg; 286f9f848faSopenharmony_ci pc->page_offset_buf = 0; 287f9f848faSopenharmony_ci pc->page_offset_end = size; 288f9f848faSopenharmony_ci pc->map = NULL; 289f9f848faSopenharmony_ci pc->tag = (bus_dma_tag_t)ptr; 290f9f848faSopenharmony_ci pc->ismultiseg = (align == 1); 291f9f848faSopenharmony_ci 292f9f848faSopenharmony_ci /* compute physical address */ 293f9f848faSopenharmony_ci usb_pc_common_mem_cb(pc, (void *)(UINTPTR)dma_handle, size); 294f9f848faSopenharmony_ci 295f9f848faSopenharmony_ci usb_pc_cpu_flush(pc); 296f9f848faSopenharmony_ci return (0); 297f9f848faSopenharmony_ci 298f9f848faSopenharmony_cierror: 299f9f848faSopenharmony_ci /* reset most of the page cache */ 300f9f848faSopenharmony_ci pc->buffer = NULL; 301f9f848faSopenharmony_ci pc->page_start = NULL; 302f9f848faSopenharmony_ci pc->page_offset_buf = 0; 303f9f848faSopenharmony_ci pc->page_offset_end = 0; 304f9f848faSopenharmony_ci pc->map = NULL; 305f9f848faSopenharmony_ci pc->tag = NULL; 306f9f848faSopenharmony_ci return (1); 307f9f848faSopenharmony_ci} 308f9f848faSopenharmony_ci 309f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 310f9f848faSopenharmony_ci * usb_pc_free_mem - free DMA memory 311f9f848faSopenharmony_ci * 312f9f848faSopenharmony_ci * This function is NULL safe. 313f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 314f9f848faSopenharmony_civoid 315f9f848faSopenharmony_ciusb_pc_free_mem(struct usb_page_cache *pc) 316f9f848faSopenharmony_ci{ 317f9f848faSopenharmony_ci if ((pc != NULL) && (pc->buffer != NULL)) { 318f9f848faSopenharmony_ci LOS_DmaMemFree(pc->tag); 319f9f848faSopenharmony_ci pc->buffer = NULL; 320f9f848faSopenharmony_ci } 321f9f848faSopenharmony_ci} 322f9f848faSopenharmony_ci 323f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 324f9f848faSopenharmony_ci * usb_pc_load_mem - load virtual memory into DMA 325f9f848faSopenharmony_ci * 326f9f848faSopenharmony_ci * Return values: 327f9f848faSopenharmony_ci * 0: Success 328f9f848faSopenharmony_ci * Else: Error 329f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 330f9f848faSopenharmony_ciuint8_t 331f9f848faSopenharmony_ciusb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t data_sync) 332f9f848faSopenharmony_ci{ 333f9f848faSopenharmony_ci /* setup page cache */ 334f9f848faSopenharmony_ci pc->page_offset_buf = 0; 335f9f848faSopenharmony_ci pc->page_offset_end = size; 336f9f848faSopenharmony_ci pc->ismultiseg = 1; 337f9f848faSopenharmony_ci 338f9f848faSopenharmony_ci mtx_assert(pc->tag_parent->mtx, MA_OWNED); 339f9f848faSopenharmony_ci 340f9f848faSopenharmony_ci if (size > 0) { 341f9f848faSopenharmony_ci /* compute physical address */ 342f9f848faSopenharmony_ci#if defined (LOSCFG_DRIVERS_HDF_USB_DDK_HOST) || defined (LOSCFG_DRIVERS_HDF_USB_DDK_DEVICE) 343f9f848faSopenharmony_ci usb_pc_common_mem_cb(pc, (void *)VMM_TO_UNCACHED_ADDR((unsigned long)pc->buffer), size); 344f9f848faSopenharmony_ci#else 345f9f848faSopenharmony_ci usb_pc_common_mem_cb(pc, (void *)(UINTPTR)LOS_DmaVaddrToPaddr(pc->buffer), size); 346f9f848faSopenharmony_ci#endif 347f9f848faSopenharmony_ci } 348f9f848faSopenharmony_ci if (data_sync == 0) { 349f9f848faSopenharmony_ci /* 350f9f848faSopenharmony_ci * Call callback so that refcount is decremented 351f9f848faSopenharmony_ci * properly: 352f9f848faSopenharmony_ci */ 353f9f848faSopenharmony_ci pc->tag_parent->dma_error = 0; 354f9f848faSopenharmony_ci (pc->tag_parent->func) (pc->tag_parent); 355f9f848faSopenharmony_ci } 356f9f848faSopenharmony_ci return (0); 357f9f848faSopenharmony_ci} 358f9f848faSopenharmony_ci 359f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 360f9f848faSopenharmony_ci * usb_pc_cpu_invalidate - invalidate CPU cache 361f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 362f9f848faSopenharmony_civoid 363f9f848faSopenharmony_ciusb_pc_cpu_invalidate(struct usb_page_cache *pc) 364f9f848faSopenharmony_ci{ 365f9f848faSopenharmony_ci if (pc->page_offset_end == pc->page_offset_buf) { 366f9f848faSopenharmony_ci /* nothing has been loaded into this page cache! */ 367f9f848faSopenharmony_ci return; 368f9f848faSopenharmony_ci } 369f9f848faSopenharmony_ci usb_dma_cache_invalid(pc->buffer, pc->page_offset_end - pc->page_offset_buf); 370f9f848faSopenharmony_ci} 371f9f848faSopenharmony_ci 372f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 373f9f848faSopenharmony_ci * usb_pc_cpu_flush - flush CPU cache 374f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 375f9f848faSopenharmony_civoid 376f9f848faSopenharmony_ciusb_pc_cpu_flush(struct usb_page_cache *pc) 377f9f848faSopenharmony_ci{ 378f9f848faSopenharmony_ci if (pc->page_offset_end == pc->page_offset_buf) { 379f9f848faSopenharmony_ci /* nothing has been loaded into this page cache! */ 380f9f848faSopenharmony_ci return; 381f9f848faSopenharmony_ci } 382f9f848faSopenharmony_ci usb_dma_cache_flush(pc->buffer, pc->page_offset_end - pc->page_offset_buf); 383f9f848faSopenharmony_ci} 384f9f848faSopenharmony_ci 385f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 386f9f848faSopenharmony_ci * usb_pc_dmamap_create - create a DMA map 387f9f848faSopenharmony_ci * 388f9f848faSopenharmony_ci * Returns: 389f9f848faSopenharmony_ci * 0: Success 390f9f848faSopenharmony_ci * Else: Failure 391f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 392f9f848faSopenharmony_ciuint8_t 393f9f848faSopenharmony_ciusb_pc_dmamap_create(struct usb_page_cache *pc, usb_size_t size) 394f9f848faSopenharmony_ci{ 395f9f848faSopenharmony_ci return (0); /* NOP, success */ 396f9f848faSopenharmony_ci} 397f9f848faSopenharmony_ci 398f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 399f9f848faSopenharmony_ci * usb_pc_dmamap_destroy 400f9f848faSopenharmony_ci * 401f9f848faSopenharmony_ci * This function is NULL safe. 402f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 403f9f848faSopenharmony_civoid 404f9f848faSopenharmony_ciusb_pc_dmamap_destroy(struct usb_page_cache *pc) 405f9f848faSopenharmony_ci{ 406f9f848faSopenharmony_ci /* NOP */ 407f9f848faSopenharmony_ci} 408f9f848faSopenharmony_ci 409f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 410f9f848faSopenharmony_ci * usb_dma_tag_setup - initialise USB DMA tags 411f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 412f9f848faSopenharmony_civoid 413f9f848faSopenharmony_ciusb_dma_tag_setup(struct usb_dma_parent_tag *udpt, 414f9f848faSopenharmony_ci struct usb_dma_tag *udt, bus_dma_tag_t dmat, 415f9f848faSopenharmony_ci struct mtx *mtx, usb_dma_callback_t *func, 416f9f848faSopenharmony_ci uint8_t ndmabits, uint8_t nudt) 417f9f848faSopenharmony_ci{ 418f9f848faSopenharmony_ci (void)memset_s(udpt, sizeof(*udpt), 0, sizeof(*udpt)); 419f9f848faSopenharmony_ci 420f9f848faSopenharmony_ci /* sanity checking */ 421f9f848faSopenharmony_ci if ((nudt == 0) || 422f9f848faSopenharmony_ci (ndmabits == 0) || 423f9f848faSopenharmony_ci (mtx == NULL)) { 424f9f848faSopenharmony_ci /* something is corrupt */ 425f9f848faSopenharmony_ci return; 426f9f848faSopenharmony_ci } 427f9f848faSopenharmony_ci /* initialise condition variable */ 428f9f848faSopenharmony_ci cv_init(udpt->cv, "USB DMA CV"); 429f9f848faSopenharmony_ci 430f9f848faSopenharmony_ci /* store some information */ 431f9f848faSopenharmony_ci udpt->mtx = mtx; 432f9f848faSopenharmony_ci udpt->func = func; 433f9f848faSopenharmony_ci udpt->tag = dmat; 434f9f848faSopenharmony_ci udpt->utag_first = udt; 435f9f848faSopenharmony_ci udpt->utag_max = nudt; 436f9f848faSopenharmony_ci udpt->dma_bits = ndmabits; 437f9f848faSopenharmony_ci 438f9f848faSopenharmony_ci while (nudt--) { 439f9f848faSopenharmony_ci (void)memset_s(udt, sizeof(*udt), 0, sizeof(*udt)); 440f9f848faSopenharmony_ci udt->tag_parent = udpt; 441f9f848faSopenharmony_ci udt++; 442f9f848faSopenharmony_ci } 443f9f848faSopenharmony_ci} 444f9f848faSopenharmony_ci 445f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 446f9f848faSopenharmony_ci * usb_bus_tag_unsetup - factored out code 447f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 448f9f848faSopenharmony_civoid 449f9f848faSopenharmony_ciusb_dma_tag_unsetup(struct usb_dma_parent_tag *udpt) 450f9f848faSopenharmony_ci{ 451f9f848faSopenharmony_ci struct usb_dma_tag *udt; 452f9f848faSopenharmony_ci uint8_t nudt; 453f9f848faSopenharmony_ci 454f9f848faSopenharmony_ci udt = udpt->utag_first; 455f9f848faSopenharmony_ci nudt = udpt->utag_max; 456f9f848faSopenharmony_ci 457f9f848faSopenharmony_ci while (nudt--) { 458f9f848faSopenharmony_ci udt->align = 0; 459f9f848faSopenharmony_ci udt++; 460f9f848faSopenharmony_ci } 461f9f848faSopenharmony_ci 462f9f848faSopenharmony_ci if (udpt->utag_max) { 463f9f848faSopenharmony_ci /* destroy the condition variable */ 464f9f848faSopenharmony_ci cv_destroy(udpt->cv); 465f9f848faSopenharmony_ci } 466f9f848faSopenharmony_ci} 467f9f848faSopenharmony_ci 468f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 469f9f848faSopenharmony_ci * usb_bdma_work_loop 470f9f848faSopenharmony_ci * 471f9f848faSopenharmony_ci * This function handles loading of virtual buffers into DMA and is 472f9f848faSopenharmony_ci * only called when "dma_refcount" is zero. 473f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 474f9f848faSopenharmony_civoid 475f9f848faSopenharmony_ciusb_bdma_work_loop(struct usb_xfer_queue *pq) 476f9f848faSopenharmony_ci{ 477f9f848faSopenharmony_ci struct usb_xfer_root *info; 478f9f848faSopenharmony_ci struct usb_xfer *xfer; 479f9f848faSopenharmony_ci usb_frcount_t nframes; 480f9f848faSopenharmony_ci 481f9f848faSopenharmony_ci xfer = pq->curr; 482f9f848faSopenharmony_ci info = xfer->xroot; 483f9f848faSopenharmony_ci 484f9f848faSopenharmony_ci mtx_assert(info->xfer_mtx, MA_OWNED); 485f9f848faSopenharmony_ci 486f9f848faSopenharmony_ci if (xfer->error) { 487f9f848faSopenharmony_ci /* some error happened */ 488f9f848faSopenharmony_ci USB_BUS_LOCK(info->bus); 489f9f848faSopenharmony_ci usbd_transfer_done(xfer, USB_ERR_NORMAL_COMPLETION); 490f9f848faSopenharmony_ci USB_BUS_UNLOCK(info->bus); 491f9f848faSopenharmony_ci return; 492f9f848faSopenharmony_ci } 493f9f848faSopenharmony_ci if (!xfer->flags_int.bdma_setup) { 494f9f848faSopenharmony_ci struct usb_page *pg; 495f9f848faSopenharmony_ci usb_frlength_t frlength_0; 496f9f848faSopenharmony_ci uint8_t isread; 497f9f848faSopenharmony_ci 498f9f848faSopenharmony_ci xfer->flags_int.bdma_setup = 1; 499f9f848faSopenharmony_ci 500f9f848faSopenharmony_ci /* reset BUS-DMA load state */ 501f9f848faSopenharmony_ci 502f9f848faSopenharmony_ci info->dma_error = 0; 503f9f848faSopenharmony_ci 504f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 505f9f848faSopenharmony_ci /* only one frame buffer */ 506f9f848faSopenharmony_ci nframes = 1; 507f9f848faSopenharmony_ci frlength_0 = xfer->sumlen; 508f9f848faSopenharmony_ci } else { 509f9f848faSopenharmony_ci /* can be multiple frame buffers */ 510f9f848faSopenharmony_ci nframes = xfer->nframes; 511f9f848faSopenharmony_ci frlength_0 = xfer->frlengths[0]; 512f9f848faSopenharmony_ci } 513f9f848faSopenharmony_ci 514f9f848faSopenharmony_ci /* 515f9f848faSopenharmony_ci * Set DMA direction first. This is needed to 516f9f848faSopenharmony_ci * select the correct cache invalidate and cache 517f9f848faSopenharmony_ci * flush operations. 518f9f848faSopenharmony_ci */ 519f9f848faSopenharmony_ci isread = USB_GET_DATA_ISREAD(xfer); 520f9f848faSopenharmony_ci pg = xfer->dma_page_ptr; 521f9f848faSopenharmony_ci 522f9f848faSopenharmony_ci if (xfer->flags_int.control_xfr && 523f9f848faSopenharmony_ci xfer->flags_int.control_hdr) { 524f9f848faSopenharmony_ci /* special case */ 525f9f848faSopenharmony_ci if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 526f9f848faSopenharmony_ci /* The device controller writes to memory */ 527f9f848faSopenharmony_ci xfer->frbuffers[0].isread = 1; 528f9f848faSopenharmony_ci } else { 529f9f848faSopenharmony_ci /* The host controller reads from memory */ 530f9f848faSopenharmony_ci xfer->frbuffers[0].isread = 0; 531f9f848faSopenharmony_ci } 532f9f848faSopenharmony_ci } else { 533f9f848faSopenharmony_ci /* default case */ 534f9f848faSopenharmony_ci xfer->frbuffers[0].isread = isread; 535f9f848faSopenharmony_ci } 536f9f848faSopenharmony_ci 537f9f848faSopenharmony_ci /* 538f9f848faSopenharmony_ci * Setup the "page_start" pointer which points to an array of 539f9f848faSopenharmony_ci * USB pages where information about the physical address of a 540f9f848faSopenharmony_ci * page will be stored. Also initialise the "isread" field of 541f9f848faSopenharmony_ci * the USB page caches. 542f9f848faSopenharmony_ci */ 543f9f848faSopenharmony_ci xfer->frbuffers[0].page_start = pg; 544f9f848faSopenharmony_ci 545f9f848faSopenharmony_ci info->dma_nframes = nframes; 546f9f848faSopenharmony_ci info->dma_currframe = 0; 547f9f848faSopenharmony_ci info->dma_frlength_0 = frlength_0; 548f9f848faSopenharmony_ci 549f9f848faSopenharmony_ci pg += (frlength_0 / USB_PAGE_SIZE); 550f9f848faSopenharmony_ci pg += 2; 551f9f848faSopenharmony_ci 552f9f848faSopenharmony_ci while (--nframes > 0) { 553f9f848faSopenharmony_ci xfer->frbuffers[nframes].isread = isread; 554f9f848faSopenharmony_ci xfer->frbuffers[nframes].page_start = pg; 555f9f848faSopenharmony_ci 556f9f848faSopenharmony_ci pg += (xfer->frlengths[nframes] / USB_PAGE_SIZE); 557f9f848faSopenharmony_ci pg += 2; 558f9f848faSopenharmony_ci } 559f9f848faSopenharmony_ci 560f9f848faSopenharmony_ci } 561f9f848faSopenharmony_ci if (info->dma_error) { 562f9f848faSopenharmony_ci USB_BUS_LOCK(info->bus); 563f9f848faSopenharmony_ci usbd_transfer_done(xfer, USB_ERR_DMA_LOAD_FAILED); 564f9f848faSopenharmony_ci USB_BUS_UNLOCK(info->bus); 565f9f848faSopenharmony_ci return; 566f9f848faSopenharmony_ci } 567f9f848faSopenharmony_ci if (info->dma_currframe != info->dma_nframes) { 568f9f848faSopenharmony_ci 569f9f848faSopenharmony_ci if (info->dma_currframe == 0) { 570f9f848faSopenharmony_ci /* special case */ 571f9f848faSopenharmony_ci (void)usb_pc_load_mem(xfer->frbuffers, 572f9f848faSopenharmony_ci info->dma_frlength_0, 0); 573f9f848faSopenharmony_ci } else { 574f9f848faSopenharmony_ci /* default case */ 575f9f848faSopenharmony_ci nframes = info->dma_currframe; 576f9f848faSopenharmony_ci (void)usb_pc_load_mem(xfer->frbuffers + nframes, 577f9f848faSopenharmony_ci xfer->frlengths[nframes], 0); 578f9f848faSopenharmony_ci } 579f9f848faSopenharmony_ci 580f9f848faSopenharmony_ci /* advance frame index */ 581f9f848faSopenharmony_ci info->dma_currframe++; 582f9f848faSopenharmony_ci 583f9f848faSopenharmony_ci return; 584f9f848faSopenharmony_ci } 585f9f848faSopenharmony_ci /* go ahead */ 586f9f848faSopenharmony_ci usb_bdma_pre_sync(xfer); 587f9f848faSopenharmony_ci 588f9f848faSopenharmony_ci /* start loading next USB transfer, if any */ 589f9f848faSopenharmony_ci usb_command_wrapper(pq, NULL); 590f9f848faSopenharmony_ci 591f9f848faSopenharmony_ci /* finally start the hardware */ 592f9f848faSopenharmony_ci usbd_pipe_enter(xfer); 593f9f848faSopenharmony_ci} 594f9f848faSopenharmony_ci 595f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 596f9f848faSopenharmony_ci * usb_bdma_done_event 597f9f848faSopenharmony_ci * 598f9f848faSopenharmony_ci * This function is called when the BUS-DMA has loaded virtual memory 599f9f848faSopenharmony_ci * into DMA, if any. 600f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 601f9f848faSopenharmony_civoid 602f9f848faSopenharmony_ciusb_bdma_done_event(struct usb_dma_parent_tag *udpt) 603f9f848faSopenharmony_ci{ 604f9f848faSopenharmony_ci struct usb_xfer_root *info; 605f9f848faSopenharmony_ci 606f9f848faSopenharmony_ci info = USB_DMATAG_TO_XROOT(udpt); 607f9f848faSopenharmony_ci 608f9f848faSopenharmony_ci mtx_assert(info->xfer_mtx, MA_OWNED); 609f9f848faSopenharmony_ci 610f9f848faSopenharmony_ci /* copy error */ 611f9f848faSopenharmony_ci info->dma_error = udpt->dma_error; 612f9f848faSopenharmony_ci 613f9f848faSopenharmony_ci /* enter workloop again */ 614f9f848faSopenharmony_ci usb_command_wrapper(&info->dma_q, 615f9f848faSopenharmony_ci info->dma_q.curr); 616f9f848faSopenharmony_ci} 617f9f848faSopenharmony_ci 618f9f848faSopenharmony_cistatic usb_frcount_t 619f9f848faSopenharmony_ciusb_bdma_frame_num(struct usb_xfer *xfer) 620f9f848faSopenharmony_ci{ 621f9f848faSopenharmony_ci if (xfer->flags_int.isochronous_xfr) { 622f9f848faSopenharmony_ci /* only one frame buffer */ 623f9f848faSopenharmony_ci return (1); 624f9f848faSopenharmony_ci } else { 625f9f848faSopenharmony_ci /* can be multiple frame buffers */ 626f9f848faSopenharmony_ci return (xfer->nframes); 627f9f848faSopenharmony_ci } 628f9f848faSopenharmony_ci} 629f9f848faSopenharmony_ci 630f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 631f9f848faSopenharmony_ci * usb_bdma_pre_sync 632f9f848faSopenharmony_ci * 633f9f848faSopenharmony_ci * This function handles DMA synchronisation that must be done before 634f9f848faSopenharmony_ci * an USB transfer is started. 635f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 636f9f848faSopenharmony_civoid 637f9f848faSopenharmony_ciusb_bdma_pre_sync(struct usb_xfer *xfer) 638f9f848faSopenharmony_ci{ 639f9f848faSopenharmony_ci struct usb_page_cache *pc; 640f9f848faSopenharmony_ci usb_frcount_t nframes; 641f9f848faSopenharmony_ci 642f9f848faSopenharmony_ci nframes = usb_bdma_frame_num(xfer); 643f9f848faSopenharmony_ci pc = xfer->frbuffers; 644f9f848faSopenharmony_ci 645f9f848faSopenharmony_ci while (nframes--) { 646f9f848faSopenharmony_ci 647f9f848faSopenharmony_ci if (pc->isread) { 648f9f848faSopenharmony_ci usb_pc_cpu_invalidate(pc); 649f9f848faSopenharmony_ci } else { 650f9f848faSopenharmony_ci usb_pc_cpu_flush(pc); 651f9f848faSopenharmony_ci } 652f9f848faSopenharmony_ci pc++; 653f9f848faSopenharmony_ci } 654f9f848faSopenharmony_ci} 655f9f848faSopenharmony_ci 656f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 657f9f848faSopenharmony_ci * usb_bdma_post_sync 658f9f848faSopenharmony_ci * 659f9f848faSopenharmony_ci * This function handles DMA synchronisation that must be done after 660f9f848faSopenharmony_ci * an USB transfer is complete. 661f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 662f9f848faSopenharmony_civoid 663f9f848faSopenharmony_ciusb_bdma_post_sync(struct usb_xfer *xfer) 664f9f848faSopenharmony_ci{ 665f9f848faSopenharmony_ci struct usb_page_cache *pc; 666f9f848faSopenharmony_ci usb_frcount_t nframes; 667f9f848faSopenharmony_ci 668f9f848faSopenharmony_ci nframes = usb_bdma_frame_num(xfer); 669f9f848faSopenharmony_ci pc = xfer->frbuffers; 670f9f848faSopenharmony_ci 671f9f848faSopenharmony_ci while (nframes--) { 672f9f848faSopenharmony_ci if (pc->isread) { 673f9f848faSopenharmony_ci usb_pc_cpu_invalidate(pc); 674f9f848faSopenharmony_ci } 675f9f848faSopenharmony_ci pc++; 676f9f848faSopenharmony_ci } 677f9f848faSopenharmony_ci} 678f9f848faSopenharmony_ci#endif 679