Add string.h to files that use string functions like strdup, strcmp, strcpy, etc. These are implicitly available through the malloc.h header but that will soon change. For bouncebuf, take this opportunity to sort the headers correctly. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com>
97 lines
2.2 KiB
C
97 lines
2.2 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Generic bounce buffer implementation
|
|
*
|
|
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
|
|
*/
|
|
|
|
#include <bouncebuf.h>
|
|
#include <cpu_func.h>
|
|
#include <errno.h>
|
|
#include <log.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <asm/cache.h>
|
|
#include <linux/dma-mapping.h>
|
|
|
|
static int addr_aligned(struct bounce_buffer *state)
|
|
{
|
|
const ulong align_mask = ARCH_DMA_MINALIGN - 1;
|
|
|
|
/* Check if start is aligned */
|
|
if ((ulong)state->user_buffer & align_mask) {
|
|
debug("Unaligned buffer address %p\n", state->user_buffer);
|
|
return 0;
|
|
}
|
|
|
|
/* Check if length is aligned */
|
|
if (state->len != state->len_aligned) {
|
|
debug("Unaligned buffer length %zu\n", state->len);
|
|
return 0;
|
|
}
|
|
|
|
/* Aligned */
|
|
return 1;
|
|
}
|
|
|
|
int bounce_buffer_start_extalign(struct bounce_buffer *state, void *data,
|
|
size_t len, unsigned int flags,
|
|
size_t alignment,
|
|
int (*addr_is_aligned)(struct bounce_buffer *state))
|
|
{
|
|
state->user_buffer = data;
|
|
state->bounce_buffer = data;
|
|
state->len = len;
|
|
state->len_aligned = roundup(len, alignment);
|
|
state->flags = flags;
|
|
|
|
if (!addr_is_aligned(state)) {
|
|
state->bounce_buffer = memalign(alignment,
|
|
state->len_aligned);
|
|
if (!state->bounce_buffer)
|
|
return -ENOMEM;
|
|
|
|
if (state->flags & GEN_BB_READ)
|
|
memcpy(state->bounce_buffer, state->user_buffer,
|
|
state->len);
|
|
}
|
|
|
|
/*
|
|
* Flush data to RAM so DMA reads can pick it up,
|
|
* and any CPU writebacks don't race with DMA writes
|
|
*/
|
|
dma_map_single(state->bounce_buffer,
|
|
state->len_aligned,
|
|
DMA_BIDIRECTIONAL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bounce_buffer_start(struct bounce_buffer *state, void *data,
|
|
size_t len, unsigned int flags)
|
|
{
|
|
return bounce_buffer_start_extalign(state, data, len, flags,
|
|
ARCH_DMA_MINALIGN,
|
|
addr_aligned);
|
|
}
|
|
|
|
int bounce_buffer_stop(struct bounce_buffer *state)
|
|
{
|
|
if (state->flags & GEN_BB_WRITE) {
|
|
/* Invalidate cache so that CPU can see any newly DMA'd data */
|
|
dma_unmap_single((dma_addr_t)(uintptr_t)state->bounce_buffer,
|
|
state->len_aligned,
|
|
DMA_BIDIRECTIONAL);
|
|
}
|
|
|
|
if (state->bounce_buffer == state->user_buffer)
|
|
return 0;
|
|
|
|
if (state->flags & GEN_BB_WRITE)
|
|
memcpy(state->user_buffer, state->bounce_buffer, state->len);
|
|
|
|
free(state->bounce_buffer);
|
|
|
|
return 0;
|
|
}
|