1 /* 2 * Generic bounce buffer implementation 3 * 4 * Copyright (C) 2012 Marek Vasut <marex@denx.de> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <malloc.h> 11 #include <errno.h> 12 #include <bouncebuf.h> 13 14 static int addr_aligned(struct bounce_buffer *state) 15 { 16 const ulong align_mask = ARCH_DMA_MINALIGN - 1; 17 18 /* Check if start is aligned */ 19 if ((ulong)state->user_buffer & align_mask) { 20 debug("Unaligned buffer address %p\n", state->user_buffer); 21 return 0; 22 } 23 24 /* Check if length is aligned */ 25 if (state->len != state->len_aligned) { 26 debug("Unaligned buffer length %d\n", state->len); 27 return 0; 28 } 29 30 /* Aligned */ 31 return 1; 32 } 33 34 int bounce_buffer_start(struct bounce_buffer *state, void *data, 35 size_t len, unsigned int flags) 36 { 37 state->user_buffer = data; 38 state->bounce_buffer = data; 39 state->len = len; 40 state->len_aligned = roundup(len, ARCH_DMA_MINALIGN); 41 state->flags = flags; 42 43 if (!addr_aligned(state)) { 44 state->bounce_buffer = memalign(ARCH_DMA_MINALIGN, 45 state->len_aligned); 46 if (!state->bounce_buffer) 47 return -ENOMEM; 48 49 if (state->flags & GEN_BB_READ) 50 memcpy(state->bounce_buffer, state->user_buffer, 51 state->len); 52 } 53 54 /* 55 * Flush data to RAM so DMA reads can pick it up, 56 * and any CPU writebacks don't race with DMA writes 57 */ 58 flush_dcache_range((unsigned long)state->bounce_buffer, 59 (unsigned long)(state->bounce_buffer) + 60 state->len_aligned); 61 62 return 0; 63 } 64 65 int bounce_buffer_stop(struct bounce_buffer *state) 66 { 67 if (state->flags & GEN_BB_WRITE) { 68 /* Invalidate cache so that CPU can see any newly DMA'd data */ 69 invalidate_dcache_range((unsigned long)state->bounce_buffer, 70 (unsigned long)(state->bounce_buffer) + 71 state->len_aligned); 72 } 73 74 if (state->bounce_buffer == state->user_buffer) 75 return 0; 76 77 if (state->flags & GEN_BB_WRITE) 78 memcpy(state->user_buffer, state->bounce_buffer, state->len); 79 80 free(state->bounce_buffer); 81 82 return 0; 83 } 84