1 /* 2 * Generic bounce buffer implementation 3 * 4 * Copyright (C) 2012 Marek Vasut <marex@denx.de> 5 * 6 * See file CREDITS for list of people who contributed to this 7 * project. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of 12 * the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22 * MA 02111-1307 USA 23 */ 24 25 #include <common.h> 26 #include <malloc.h> 27 #include <errno.h> 28 #include <bouncebuf.h> 29 30 static int addr_aligned(void *data, size_t len) 31 { 32 const ulong align_mask = ARCH_DMA_MINALIGN - 1; 33 34 /* Check if start is aligned */ 35 if ((ulong)data & align_mask) { 36 debug("Unaligned start address %p\n", data); 37 return 0; 38 } 39 40 data += len; 41 42 /* Check if end is aligned */ 43 if ((ulong)data & align_mask) { 44 debug("Unaligned end address %p\n", data); 45 return 0; 46 } 47 48 /* Aligned */ 49 return 1; 50 } 51 52 int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags) 53 { 54 void *tmp; 55 size_t alen; 56 57 if (addr_aligned(*data, len)) { 58 *backup = NULL; 59 return 0; 60 } 61 62 alen = roundup(len, ARCH_DMA_MINALIGN); 63 tmp = memalign(ARCH_DMA_MINALIGN, alen); 64 65 if (!tmp) 66 return -ENOMEM; 67 68 if (flags & GEN_BB_READ) 69 memcpy(tmp, *data, len); 70 71 *backup = *data; 72 *data = tmp; 73 74 return 0; 75 } 76 77 int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags) 78 { 79 void *tmp = *data; 80 81 /* The buffer was already aligned, since "backup" is NULL. */ 82 if (!*backup) 83 return 0; 84 85 if (flags & GEN_BB_WRITE) 86 memcpy(*backup, *data, len); 87 88 *data = *backup; 89 free(tmp); 90 91 return 0; 92 } 93