[U-Boot] [PATCH] ARM: support for cache coherent allocations

Ilya Yanok ilya.yanok at cogentembedded.com
Wed May 30 23:41:53 CEST 2012


This is a draft implementation of cache coherent memory allocator.
This simple implementation just reserves memory area below malloc
space and leave it uncached even if data cache is enabled.
Allocations are even simpler: code just verifies that we have
enough space and increments the offset counter. No deallocations
supported for now. In future versions we could probably use
dlmalloc allocator to get space out of coherent pool.

Signed-off-by: Ilya Yanok <ilya.yanok at cogentembedded.com>
---
 arch/arm/include/asm/dma-mapping.h |    4 ++++
 arch/arm/include/asm/global_data.h |    4 ++++
 arch/arm/lib/Makefile              |    1 +
 arch/arm/lib/board.c               |    8 ++++++++
 arch/arm/lib/cache-cp15.c          |    5 +++++
 arch/arm/lib/dma-coherent.c        |   37 ++++++++++++++++++++++++++++++++++++
 6 files changed, 59 insertions(+)
 create mode 100644 arch/arm/lib/dma-coherent.c

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..a2145fc 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -30,11 +30,15 @@ enum dma_data_direction {
 	DMA_FROM_DEVICE		= 2,
 };
 
+#ifndef CONFIG_DMA_COHERENT
 static void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
 	*handle = (unsigned long)malloc(len);
 	return (void *)*handle;
 }
+#else
+void *dma_alloc_coherent(size_t len, unsigned long *handle);
+#endif
 
 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index c3ff789..4655035 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -76,6 +76,10 @@ typedef	struct	global_data {
 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
 	unsigned long	tlb_addr;
 #endif
+#ifdef CONFIG_DMA_COHERENT
+	unsigned long	coherent_base;	/* Start address of coherent space */
+	unsigned long	coherent_size;	/* Size of coherent space */
+#endif
 	const void	*fdt_blob;	/* Our device tree, NULL if none */
 	void		**jt;		/* jump table */
 	char		env_buf[32];	/* buffer for getenv() before reloc. */
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 39a9550..e91dcd0 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -40,6 +40,7 @@ GLCOBJS	+= div0.o
 COBJS-y	+= board.o
 COBJS-y	+= bootm.o
 COBJS-$(CONFIG_SYS_L2_PL310) += cache-pl310.o
+COBJS-$(CONFIG_DMA_COHERENT) += dma-coherent.o
 COBJS-y	+= interrupts.o
 COBJS-y	+= reset.o
 SOBJS-$(CONFIG_USE_ARCH_MEMSET) += memset.o
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 5270c11..6541a49 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -400,6 +400,14 @@ void board_init_f(ulong bootflag)
 	debug("Reserving %zu Bytes for Global Data at: %08lx\n",
 			sizeof (gd_t), addr_sp);
 
+#ifdef CONFIG_DMA_COHERENT
+	/* reserve space for cache coherent allocations */
+	gd->coherent_size = ALIGN(CONFIG_DMA_COHERENT_SIZE, 1 << 20);
+	addr_sp &= ~((1 << 20) - 1);
+	addr_sp -= gd->coherent_size;
+	gd->coherent_base = addr_sp;
+#endif
+
 	/* setup stackpointer for exeptions */
 	gd->irq_sp = addr_sp;
 #ifdef CONFIG_USE_IRQ
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index e6c3eae..c11e871 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -60,6 +60,11 @@ static inline void dram_bank_mmu_setup(int bank)
 	for (i = bd->bi_dram[bank].start >> 20;
 	     i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
 	     i++) {
+#ifdef CONFIG_DMA_COHERENT
+		if ((i >= gd->coherent_base >> 20) &&
+		    (i < (gd->coherent_base + gd->coherent_size) >> 20))
+			continue;
+#endif
 		page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP;
 	}
 }
diff --git a/arch/arm/lib/dma-coherent.c b/arch/arm/lib/dma-coherent.c
new file mode 100644
index 0000000..30fa893
--- /dev/null
+++ b/arch/arm/lib/dma-coherent.c
@@ -0,0 +1,37 @@
+/*
+ * (C) Copyright 2012
+ * Ilya Yanok, ilya.yanok at gmail.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+size_t offset;
+
+void *dma_alloc_coherent(size_t size, unsigned long *handle)
+{
+	if (size + offset > gd->coherent_size)
+		return NULL;
+
+	*handle = gd->coherent_base + offset;
+	offset += size;
+
+	return (void*)(*handle);
+}
-- 
1.7.9.5



More information about the U-Boot mailing list