xref: /aosp_15_r20/external/coreboot/src/commonlib/storage/bouncebuf.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Generic bounce buffer implementation
4  */
5 
6 #include <arch/cache.h>
7 #include "bouncebuf.h"
8 #include "storage.h"
9 #include <string.h>
10 #include <commonlib/bsd/stdlib.h>
11 
addr_aligned(struct bounce_buffer * state)12 static int addr_aligned(struct bounce_buffer *state)
13 {
14 	const uint32_t align_mask = ARCH_DMA_MINALIGN - 1;
15 
16 	// Check if start is aligned
17 	if ((uintptr_t)state->user_buffer & align_mask) {
18 		sdhc_debug("Unaligned buffer address %p\n", state->user_buffer);
19 		return 0;
20 	}
21 
22 	// Check if length is aligned
23 	if (state->len != state->len_aligned) {
24 		sdhc_debug("Unaligned buffer length %zd\n", state->len);
25 		return 0;
26 	}
27 
28 	// Aligned
29 	return 1;
30 }
31 
bounce_buffer_start(struct bounce_buffer * state,void * data,size_t len,unsigned int flags)32 int bounce_buffer_start(struct bounce_buffer *state, void *data,
33 			size_t len, unsigned int flags)
34 {
35 	state->user_buffer = data;
36 	state->bounce_buffer = data;
37 	state->len = len;
38 	state->len_aligned = ROUND(len, ARCH_DMA_MINALIGN);
39 	state->flags = flags;
40 
41 	if (!addr_aligned(state)) {
42 		state->bounce_buffer = memalign(ARCH_DMA_MINALIGN,
43 						state->len_aligned);
44 		if (!state->bounce_buffer)
45 			return -1;
46 
47 		if (state->flags & GEN_BB_READ)
48 			memcpy(state->bounce_buffer, state->user_buffer,
49 				state->len);
50 	}
51 
52 	/*
53 	 * Flush data to RAM so DMA reads can pick it up,
54 	 * and any CPU writebacks don't race with DMA writes
55 	 */
56 	dcache_clean_invalidate_by_mva(state->bounce_buffer,
57 				       state->len_aligned);
58 	return 0;
59 }
60 
bounce_buffer_stop(struct bounce_buffer * state)61 int bounce_buffer_stop(struct bounce_buffer *state)
62 {
63 	if (state->flags & GEN_BB_WRITE) {
64 		// Invalidate cache so that CPU can see any newly DMA'd data
65 		dcache_invalidate_by_mva(state->bounce_buffer,
66 					 state->len_aligned);
67 	}
68 
69 	if (state->bounce_buffer == state->user_buffer)
70 		return 0;
71 
72 	if (state->flags & GEN_BB_WRITE)
73 		memcpy(state->user_buffer, state->bounce_buffer, state->len);
74 
75 	free(state->bounce_buffer);
76 
77 	return 0;
78 }
79