/ src / commonlib / storage / bouncebuf.c
bouncebuf.c
 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  
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  
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  
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  }