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