[coreboot-gerrit] Patch set updated for coreboot: 1af09ac arm: libpayload: Add cache coherent DMA memory definition and management

Isaac Christensen (isaac.christensen@se-eng.com) gerrit at coreboot.org
Tue Aug 12 01:43:27 CEST 2014


Isaac Christensen (isaac.christensen at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6622

-gerrit

commit 1af09ace17c215578c0652243fc1a2b23b1f2d6e
Author: Julius Werner <jwerner at chromium.org>
Date:   Tue Aug 27 15:48:32 2013 -0700

    arm: libpayload: Add cache coherent DMA memory definition and management
    
    This patch adds a mechanism to set aside a region of cache-coherent
    (i.e. usually uncached) virtual memory, which can be used to communicate
    with DMA devices without automatic cache snooping (common on ARM)
    without the need of explicit flush/invalidation instructions in the
    driver code.
    
    This works by setting aside said region in the (board-specific) page
    table setup, as exemplary done in this patch for the Snow and Pit
    boards. It uses a new mechanism for adding board-specific Coreboot table
    entries to describe this region in an entry with the LB_DMA tag.
    
    Libpayload's memory allocator is enhanced to be able to operate on
    distinct types/regions of memory. It provides dma_malloc() and
    dma_memalign() functions for use in drivers, which by default just
    operate on the same heap as their traditional counterparts. However, if
    the Coreboot table parsing code finds a CB_DMA section, further requests
    through the dma_xxx() functions will return memory from the region
    described therein instead.
    
    Change-Id: Ia9c249249e936bbc3eb76e7b4822af2230ffb186
    Signed-off-by: Julius Werner <jwerner at chromium.org>
    Reviewed-on: https://chromium-review.googlesource.com/167155
    (cherry picked from commit d142ccdcd902a9d6ab4d495fbe6cbe85c61a5f01)
    Signed-off-by: Isaac Christensen <isaac.christensen at se-eng.com>
---
 payloads/libpayload/arch/armv7/coreboot.c     |   9 ++
 payloads/libpayload/include/coreboot_tables.h |   1 +
 payloads/libpayload/include/stdlib.h          |   3 +
 payloads/libpayload/libc/malloc.c             | 126 +++++++++++++++++---------
 src/include/boot/coreboot_tables.h            |   6 ++
 src/lib/coreboot_table.c                      |   7 +-
 src/mainboard/google/pit/mainboard.c          |  16 ++++
 src/mainboard/google/snow/mainboard.c         |  16 ++++
 8 files changed, 142 insertions(+), 42 deletions(-)

diff --git a/payloads/libpayload/arch/armv7/coreboot.c b/payloads/libpayload/arch/armv7/coreboot.c
index d1f0345..e16c354 100644
--- a/payloads/libpayload/arch/armv7/coreboot.c
+++ b/payloads/libpayload/arch/armv7/coreboot.c
@@ -108,6 +108,12 @@ static void cb_parse_vdat(unsigned char *ptr, struct sysinfo_t *info)
 }
 #endif
 
+static void cb_parse_dma(unsigned char *ptr)
+{
+	struct cb_range *dma = (struct cb_range *)ptr;
+	init_dma_memory(phys_to_virt(dma->range_start), dma->range_size);
+}
+
 static void cb_parse_tstamp(unsigned char *ptr, struct sysinfo_t *info)
 {
 	struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
@@ -262,6 +268,9 @@ static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
 			cb_parse_vbnv(ptr, info);
 			break;
 #endif
+		case CB_TAG_DMA:
+			cb_parse_dma(ptr);
+			break;
 		case CB_TAG_TIMESTAMPS:
 			cb_parse_tstamp(ptr, info);
 			break;
diff --git a/payloads/libpayload/include/coreboot_tables.h b/payloads/libpayload/include/coreboot_tables.h
index 5132d50..e20249d 100644
--- a/payloads/libpayload/include/coreboot_tables.h
+++ b/payloads/libpayload/include/coreboot_tables.h
@@ -187,6 +187,7 @@ struct cb_gpios {
 #define CB_TAG_VDAT		0x0015
 #define CB_TAG_VBNV		0x0019
 #define CB_TAG_VBOOT_HANDOFF	0x0020
+#define CB_TAG_DMA		0x0022
 struct lb_range {
 	uint32_t tag;
 	uint32_t size;
diff --git a/payloads/libpayload/include/stdlib.h b/payloads/libpayload/include/stdlib.h
index 92a13e3..8c8c200 100644
--- a/payloads/libpayload/include/stdlib.h
+++ b/payloads/libpayload/include/stdlib.h
@@ -112,6 +112,9 @@ void *calloc(size_t nmemb, size_t size);
 void *realloc(void *ptr, size_t size);
 void *memalign(size_t align, size_t size);
 #endif
+void init_dma_memory(void *start, u32 size);
+void *dma_malloc(size_t size);
+void *dma_memalign(size_t align, size_t size);
 /** @} */
 
 /**
diff --git a/payloads/libpayload/libc/malloc.c b/payloads/libpayload/libc/malloc.c
index f022f73..618d8b3 100644
--- a/payloads/libpayload/libc/malloc.c
+++ b/payloads/libpayload/libc/malloc.c
@@ -42,10 +42,17 @@
 #define IN_MALLOC_C
 #include <libpayload.h>
 
+struct memory_type {
+	void *start;
+	void *end;
+	struct align_region_t* align_regions;
+};
+
 extern char _heap, _eheap;	/* Defined in the ldscript. */
 
-static void *hstart = (void *)&_heap;
-static void *hend = (void *)&_eheap;
+static struct memory_type default_type = { (void *)&_heap, (void *)&_eheap, NULL };
+static struct memory_type *const heap = &default_type;
+static struct memory_type *dma = &default_type;
 
 typedef u64 hdrtype_t;
 #define HDRSIZE (sizeof(hdrtype_t))
@@ -65,7 +72,7 @@ typedef u64 hdrtype_t;
 #define IS_FREE(_h) (((_h) & (MAGIC | FLAG_FREE)) == (MAGIC | FLAG_FREE))
 #define HAS_MAGIC(_h) (((_h) & MAGIC) == MAGIC)
 
-static int free_aligned(void* addr);
+static int free_aligned(void* addr, struct memory_type *type);
 void print_malloc_map(void);
 
 #ifdef CONFIG_LP_DEBUG_MALLOC
@@ -73,6 +80,23 @@ static int heap_initialized = 0;
 static int minimal_free = 0;
 #endif
 
+void init_dma_memory(void *start, u32 size)
+{
+#ifdef CONFIG_LP_DEBUG_MALLOC
+	if (dma != heap) {
+		printf("WARNING: %s called twice!\n");
+		return;
+	}
+
+	printf("Initializing cache-coherent DMA memory at [%p:%p]\n", start, start + size);
+#endif
+
+	dma = malloc(sizeof(*dma));
+	dma->start = start;
+	dma->end = start + size;
+	dma->align_regions = NULL;
+}
+
 static void setup(hdrtype_t volatile *start, int size)
 {
 	*start = FREE_BLOCK(size);
@@ -83,10 +107,10 @@ static void setup(hdrtype_t volatile *start, int size)
 #endif
 }
 
-static void *alloc(int len)
+static void *alloc(int len, struct memory_type *type)
 {
 	hdrtype_t header;
-	hdrtype_t volatile *ptr = (hdrtype_t volatile *) hstart;
+	hdrtype_t volatile *ptr = (hdrtype_t volatile *)type->start;
 
 	/* Align the size. */
 	len = (len + HDRSIZE - 1) & ~(HDRSIZE - 1);
@@ -137,17 +161,17 @@ static void *alloc(int len)
 
 		ptr = (hdrtype_t volatile *)((int)ptr + HDRSIZE + size);
 
-	} while (ptr < (hdrtype_t *) hend);
+	} while (ptr < (hdrtype_t *) type->end);
 
 	/* Nothing available. */
 	return (void *)NULL;
 }
 
-static void _consolidate(void)
+static void _consolidate(struct memory_type *type)
 {
-	void *ptr = hstart;
+	void *ptr = type->start;
 
-	while (ptr < hend) {
+	while (ptr < type->end) {
 		void *nptr;
 		hdrtype_t hdr = *((hdrtype_t *) ptr);
 		unsigned int size = 0;
@@ -160,7 +184,7 @@ static void _consolidate(void)
 		size = SIZE(hdr);
 		nptr = ptr + HDRSIZE + SIZE(hdr);
 
-		while (nptr < hend) {
+		while (nptr < type->end) {
 			hdrtype_t nhdr = *((hdrtype_t *) nptr);
 
 			if (!(IS_FREE(nhdr)))
@@ -181,15 +205,18 @@ static void _consolidate(void)
 void free(void *ptr)
 {
 	hdrtype_t hdr;
-
-	if (free_aligned(ptr)) return;
-
-	ptr -= HDRSIZE;
+	struct memory_type *type = heap;
 
 	/* Sanity check. */
-	if (ptr < hstart || ptr >= hend)
-		return;
+	if (ptr < type->start || ptr >= type->end) {
+		type = dma;
+		if (ptr < type->start || ptr >= type->end)
+			return;
+	}
 
+	if (free_aligned(ptr, type)) return;
+
+	ptr -= HDRSIZE;
 	hdr = *((hdrtype_t *) ptr);
 
 	/* Not our header (we're probably poisoned). */
@@ -201,18 +228,23 @@ void free(void *ptr)
 		return;
 
 	*((hdrtype_t *) ptr) = FREE_BLOCK(SIZE(hdr));
-	_consolidate();
+	_consolidate(type);
 }
 
 void *malloc(size_t size)
 {
-	return alloc(size);
+	return alloc(size, heap);
+}
+
+void *dma_malloc(size_t size)
+{
+	return alloc(size, dma);
 }
 
 void *calloc(size_t nmemb, size_t size)
 {
 	size_t total = nmemb * size;
-	void *ptr = alloc(total);
+	void *ptr = alloc(total, heap);
 
 	if (ptr)
 		memset(ptr, 0, total);
@@ -224,15 +256,19 @@ void *realloc(void *ptr, size_t size)
 {
 	void *ret, *pptr;
 	unsigned int osize;
+	struct memory_type *type = heap;
 
 	if (ptr == NULL)
-		return alloc(size);
+		return alloc(size, type);
 
 	pptr = ptr - HDRSIZE;
 
 	if (!HAS_MAGIC(*((hdrtype_t *) pptr)))
 		return NULL;
 
+	if (ptr < type->start || ptr >= type->end)
+		type = dma;
+
 	/* Get the original size of the block. */
 	osize = SIZE(*((hdrtype_t *) pptr));
 
@@ -242,7 +278,7 @@ void *realloc(void *ptr, size_t size)
 	 * reallocated the new space.
 	 */
 	free(ptr);
-	ret = alloc(size);
+	ret = alloc(size, type);
 
 	/*
 	 * if ret == NULL, then doh - failure.
@@ -277,14 +313,12 @@ struct align_region_t
 	struct align_region_t *next;
 };
 
-static struct align_region_t* align_regions = 0;
-
-static struct align_region_t *allocate_region(int alignment, int num_elements)
+static struct align_region_t *allocate_region(int alignment, int num_elements, struct memory_type *type)
 {
 	struct align_region_t *new_region;
 #ifdef CONFIG_LP_DEBUG_MALLOC
 	printf("%s(old align_regions=%p, alignment=%u, num_elements=%u)\n",
-			__func__, align_regions, alignment, num_elements);
+			__func__, type->align_regions, alignment, num_elements);
 #endif
 
 	new_region = malloc(sizeof(struct align_region_t));
@@ -292,7 +326,7 @@ static struct align_region_t *allocate_region(int alignment, int num_elements)
 	if (!new_region)
 		return NULL;
 	new_region->alignment = alignment;
-	new_region->start = malloc((num_elements+1) * alignment + num_elements);
+	new_region->start = alloc((num_elements+1) * alignment + num_elements, type);
 	if (!new_region->start) {
 		free(new_region);
 		return NULL;
@@ -300,16 +334,16 @@ static struct align_region_t *allocate_region(int alignment, int num_elements)
 	new_region->start_data = (void*)((u32)(new_region->start + num_elements + alignment - 1) & (~(alignment-1)));
 	new_region->size = num_elements * alignment;
 	new_region->free = num_elements;
-	new_region->next = align_regions;
+	new_region->next = type->align_regions;
 	memset(new_region->start, 0, num_elements);
-	align_regions = new_region;
+	type->align_regions = new_region;
 	return new_region;
 }
 
 
-static int free_aligned(void* addr)
+static int free_aligned(void* addr, struct memory_type *type)
 {
-	struct align_region_t *reg = align_regions;
+	struct align_region_t *reg = type->align_regions;
 	while (reg != 0)
 	{
 		if ((addr >= reg->start_data) && (addr < reg->start_data + reg->size))
@@ -329,16 +363,16 @@ static int free_aligned(void* addr)
 	return 0;
 }
 
-void *memalign(size_t align, size_t size)
+static void *alloc_aligned(size_t align, size_t size, struct memory_type *type)
 {
 	if (size == 0) return 0;
-	if (align_regions == 0) {
-		align_regions = malloc(sizeof(struct align_region_t));
-		if (align_regions == NULL)
+	if (type->align_regions == 0) {
+		type->align_regions = malloc(sizeof(struct align_region_t));
+		if (type->align_regions == NULL)
 			return NULL;
-		memset(align_regions, 0, sizeof(struct align_region_t));
+		memset(type->align_regions, 0, sizeof(struct align_region_t));
 	}
-	struct align_region_t *reg = align_regions;
+	struct align_region_t *reg = type->align_regions;
 look_further:
 	while (reg != 0)
 	{
@@ -357,9 +391,9 @@ look_further:
 		printf("  need to allocate a new memalign region\n");
 #endif
 		/* get align regions */
-		reg = allocate_region(align, (size<1024)?(1024/align):(((size-1)/align)+1));
+		reg = allocate_region(align, (size<1024)?(1024/align):(((size-1)/align)+1), type);
 #ifdef CONFIG_LP_DEBUG_MALLOC
-		printf("  ... returned %p\n", align_regions);
+		printf("  ... returned %p\n", reg);
 #endif
 	}
 	if (reg == 0) {
@@ -393,14 +427,24 @@ look_further:
 	goto look_further; // end condition is once a new region is allocated - it always has enough space
 }
 
+void *memalign(size_t align, size_t size)
+{
+	return alloc_aligned(align, size, heap);
+}
+
+void *dma_memalign(size_t align, size_t size)
+{
+	return alloc_aligned(align, size, dma);
+}
+
 /* This is for debugging purposes. */
 #ifdef CONFIG_LP_DEBUG_MALLOC
 void print_malloc_map(void)
 {
-	void *ptr = hstart;
+	void *ptr = heap->start;
 	int free_memory = 0;
 
-	while (ptr < hend) {
+	while (ptr < heap->end) {
 		hdrtype_t hdr = *((hdrtype_t *) ptr);
 
 		if (!HAS_MAGIC(hdr)) {
@@ -414,7 +458,7 @@ void print_malloc_map(void)
 		/* FIXME: Verify the size of the block. */
 
 		printf("%x: %s (%x bytes)\n",
-		       (unsigned int)(ptr - hstart),
+		       (unsigned int)(ptr - heap->start),
 		       hdr & FLAG_FREE ? "FREE" : "USED", SIZE(hdr));
 
 		if (hdr & FLAG_FREE)
diff --git a/src/include/boot/coreboot_tables.h b/src/include/boot/coreboot_tables.h
index 3c569a1..db3c508 100644
--- a/src/include/boot/coreboot_tables.h
+++ b/src/include/boot/coreboot_tables.h
@@ -218,6 +218,7 @@ struct lb_gpios {
 #define LB_TAG_VDAT		0x0015
 #define LB_TAG_VBNV		0x0019
 #define LB_TAB_VBOOT_HANDOFF	0x0020
+#define LB_TAB_DMA		0x0022
 struct lb_range {
 	uint32_t tag;
 	uint32_t size;
@@ -332,4 +333,9 @@ void uart_fill_lb(void *data);
 void lb_add_serial(struct lb_serial *serial, void *data);
 void lb_add_console(uint16_t consoletype, void *data);
 
+/* Define this in mainboard.c to add board-specific table entries. */
+void lb_board(struct lb_header *header);
+
+struct lb_record *lb_new_record(struct lb_header *header);
+
 #endif /* COREBOOT_TABLES_H */
diff --git a/src/lib/coreboot_table.c b/src/lib/coreboot_table.c
index f0ae6c5..9f9c453 100644
--- a/src/lib/coreboot_table.c
+++ b/src/lib/coreboot_table.c
@@ -77,7 +77,7 @@ static struct lb_record *lb_last_record(struct lb_header *header)
 	return rec;
 }
 
-static struct lb_record *lb_new_record(struct lb_header *header)
+struct lb_record *lb_new_record(struct lb_header *header)
 {
 	struct lb_record *rec;
 	rec = lb_last_record(header);
@@ -298,6 +298,8 @@ static void lb_strings(struct lb_header *header)
 
 }
 
+void __attribute__((weak)) lb_board(struct lb_header *header) { /* NOOP */ }
+
 static struct lb_forward *lb_forward(struct lb_header *header, struct lb_header *next_header)
 {
 	struct lb_record *rec;
@@ -425,6 +427,9 @@ unsigned long write_coreboot_table(
 #endif
 	add_cbmem_pointers(head);
 
+	/* Add board-specific table entries, if any. */
+	lb_board(head);
+
 	/* Remember where my valid memory ranges are */
 	return lb_table_fini(head);
 }
diff --git a/src/mainboard/google/pit/mainboard.c b/src/mainboard/google/pit/mainboard.c
index 77c54a1..467b9d0 100644
--- a/src/mainboard/google/pit/mainboard.c
+++ b/src/mainboard/google/pit/mainboard.c
@@ -45,6 +45,10 @@
 #define DRAM_START	(CONFIG_SYS_SDRAM_BASE >> 20)
 #define DRAM_SIZE	CONFIG_DRAM_SIZE_MB
 
+/* Arbitrary range of DMA memory for depthcharge's drivers */
+#define DMA_START	(0x77300000)
+#define DMA_SIZE	(0x00100000)
+
 static struct edid edid = {
 	.ha = 1366,
 	.va = 768,
@@ -452,6 +456,7 @@ static void mainboard_enable(device_t dev)
 
 	/* set up caching for the DRAM */
 	mmu_config_range(DRAM_START, DRAM_SIZE, DCACHE_WRITEBACK);
+	mmu_config_range(DMA_START >> 20, DMA_SIZE >> 20, DCACHE_OFF);
 	tlb_invalidate_all();
 
 	/* this is going to move, but we must have it now and we're
@@ -472,3 +477,14 @@ struct chip_operations mainboard_ops = {
 	.name	= "Samsung/Google ARM Chromebook",
 	.enable_dev = mainboard_enable,
 };
+
+void lb_board(struct lb_header *header)
+{
+	struct lb_range *dma;
+
+	dma = (struct lb_range *)lb_new_record(header);
+	dma->tag = LB_TAB_DMA;
+	dma->size = sizeof(*dma);
+	dma->range_start = (intptr_t)DMA_START;
+	dma->range_size = DMA_SIZE;
+}
diff --git a/src/mainboard/google/snow/mainboard.c b/src/mainboard/google/snow/mainboard.c
index d209a76..dfaf81d 100644
--- a/src/mainboard/google/snow/mainboard.c
+++ b/src/mainboard/google/snow/mainboard.c
@@ -46,6 +46,10 @@
 #define DRAM_SIZE	CONFIG_DRAM_SIZE_MB
 #define DRAM_END	(DRAM_START + DRAM_SIZE)	/* plus one... */
 
+/* Arbitrary range of DMA memory for depthcharge's drivers */
+#define DMA_START	(0x77300000)
+#define DMA_SIZE	(0x00100000)
+
 static struct edid edid = {
 	.ha = 1366,
 	.va = 768,
@@ -320,6 +324,7 @@ static void mainboard_enable(device_t dev)
 	mmu_init();
 	mmu_config_range(0, DRAM_START, DCACHE_OFF);
 	mmu_config_range(DRAM_START, DRAM_SIZE, DCACHE_WRITEBACK);
+	mmu_config_range(DMA_START >> 20, DMA_SIZE >> 20, DCACHE_OFF);
 	mmu_config_range(DRAM_END, 4096 - DRAM_END, DCACHE_OFF);
 	dcache_invalidate_all();
 	dcache_mmu_enable();
@@ -342,3 +347,14 @@ struct chip_operations mainboard_ops = {
 	.name	= "Samsung/Google ARM Chromebook",
 	.enable_dev = mainboard_enable,
 };
+
+void lb_board(struct lb_header *header)
+{
+	struct lb_range *dma;
+
+	dma = (struct lb_range *)lb_new_record(header);
+	dma->tag = LB_TAB_DMA;
+	dma->size = sizeof(*dma);
+	dma->range_start = (intptr_t)DMA_START;
+	dma->range_size = DMA_SIZE;
+}



More information about the coreboot-gerrit mailing list