patch-2.3.45 linux/arch/arm/mm/consistent.c

Next file: linux/arch/arm/mm/proc-arm6,7.S
Previous file: linux/arch/arm/mm/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.44/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c
@@ -0,0 +1,102 @@
+/*
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+/* Pure 2^n version of get_order */
+extern __inline__ int __get_order(unsigned long size)
+{
+	int order;
+
+	size = (size-1) >> (PAGE_SHIFT-1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
+}
+
+/*
+ * This allocates one page of cache-coherent memory space and returns
+ * both the virtual and a "dma" address to that space.  It is not clear
+ * whether this could be called from an interrupt context or not.  For
+ * now, we expressly forbid it, especially as some of the stuff we do
+ * here is not interrupt context safe.
+ */
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
+{
+	int order;
+	unsigned long page;
+	struct vm_struct *area;
+	void *ret;
+
+	if (in_interrupt())
+		BUG();
+
+	order = __get_order(size);
+
+	page = __get_free_pages(gfp, order);
+	if (!page)
+		goto no_page;
+
+	memset((void *)page, 0, PAGE_SIZE << order);
+	clean_cache_area(page, PAGE_SIZE << order);
+
+	*dma_handle = virt_to_bus((void *)page);
+
+	area = get_vm_area(size, VM_IOREMAP); /* maybe new type? */
+	if (!area)
+		goto no_area;
+
+	ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0);
+	if (ret)
+		return ret;
+
+no_area:
+	free_pages(page, order);
+no_page:
+	BUG();
+	return NULL;
+}
+
+/*
+ * free a page as defined by the above mapping.  We expressly forbid
+ * calling this from interrupt context.
+ */
+void consistent_free(void *vaddr)
+{
+	if (in_interrupt())
+		BUG();
+
+	__iounmap(vaddr);
+}
+
+/*
+ * make an area consistent.
+ */
+void consistent_sync(void *vaddr, size_t size, int rw)
+{
+	switch (rw) {
+	case 0:
+		BUG();
+	case 1:	/* invalidate only */
+		dma_cache_inv(vaddr, size);
+		break;
+	case 2:	/* writeback only */
+		dma_cache_wback(vaddr, size);
+		break;
+	case 3:	/* writeback and invalidate */
+		dma_cache_wback_inv(vaddr, size);
+		break;
+	}
+}

FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen (who was at: [email protected])