]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
b660df3c MV |
2 | /* |
3 | * Generic bounce buffer implementation | |
4 | * | |
5 | * Copyright (C) 2012 Marek Vasut <[email protected]> | |
b660df3c MV |
6 | */ |
7 | ||
8 | #include <common.h> | |
9 | #include <malloc.h> | |
10 | #include <errno.h> | |
11 | #include <bouncebuf.h> | |
12 | ||
84d35b28 | 13 | static int addr_aligned(struct bounce_buffer *state) |
b660df3c MV |
14 | { |
15 | const ulong align_mask = ARCH_DMA_MINALIGN - 1; | |
16 | ||
17 | /* Check if start is aligned */ | |
84d35b28 SW |
18 | if ((ulong)state->user_buffer & align_mask) { |
19 | debug("Unaligned buffer address %p\n", state->user_buffer); | |
b660df3c MV |
20 | return 0; |
21 | } | |
22 | ||
84d35b28 SW |
23 | /* Check if length is aligned */ |
24 | if (state->len != state->len_aligned) { | |
5d69a5d1 | 25 | debug("Unaligned buffer length %zu\n", state->len); |
b660df3c MV |
26 | return 0; |
27 | } | |
28 | ||
29 | /* Aligned */ | |
30 | return 1; | |
31 | } | |
32 | ||
84d35b28 SW |
33 | int bounce_buffer_start(struct bounce_buffer *state, void *data, |
34 | size_t len, unsigned int flags) | |
b660df3c | 35 | { |
84d35b28 SW |
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); | |
b660df3c MV |
51 | } |
52 | ||
84d35b28 SW |
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); | |
b660df3c MV |
60 | |
61 | return 0; | |
62 | } | |
63 | ||
84d35b28 | 64 | int bounce_buffer_stop(struct bounce_buffer *state) |
b660df3c | 65 | { |
84d35b28 SW |
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 | } | |
b660df3c | 72 | |
84d35b28 | 73 | if (state->bounce_buffer == state->user_buffer) |
b660df3c MV |
74 | return 0; |
75 | ||
84d35b28 SW |
76 | if (state->flags & GEN_BB_WRITE) |
77 | memcpy(state->user_buffer, state->bounce_buffer, state->len); | |
b660df3c | 78 | |
84d35b28 | 79 | free(state->bounce_buffer); |
b660df3c MV |
80 | |
81 | return 0; | |
82 | } |