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