summary refs log tree commit diff
path: root/arch/unicore32/mm
diff options
context:
space:
mode:
authorGuanXuetao <gxt@mprc.pku.edu.cn>2011-01-15 18:18:29 +0800
committerGuanXuetao <gxt@mprc.pku.edu.cn>2011-03-17 09:19:09 +0800
commit10c9c10c31514564b09c153432a42ffaea3ce831 (patch)
tree04a60b9a1e48eaa2d9346e265a1c2fe2db5ec670 /arch/unicore32/mm
parent56372b0b2f533c9a25bd40a0577405f6ddb7cff2 (diff)
downloadlinux-10c9c10c31514564b09c153432a42ffaea3ce831.tar.gz
unicore32 core architecture: mm related: consistent device DMA handling
This patch implements consistent device DMA handling of memory management.
DMA device operations are also here.

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/unicore32/mm')
-rw-r--r--arch/unicore32/mm/cache-ucv2.S212
-rw-r--r--arch/unicore32/mm/dma-swiotlb.c34
-rw-r--r--arch/unicore32/mm/flush.c98
-rw-r--r--arch/unicore32/mm/tlb-ucv2.S89
4 files changed, 433 insertions, 0 deletions
diff --git a/arch/unicore32/mm/cache-ucv2.S b/arch/unicore32/mm/cache-ucv2.S
new file mode 100644
index 000000000000..ecaa1727f906
--- /dev/null
+++ b/arch/unicore32/mm/cache-ucv2.S
@@ -0,0 +1,212 @@
+/*
+ * linux/arch/unicore32/mm/cache-ucv2.S
+ *
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2010 GUAN Xue-tao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  This is the "shell" of the UniCore-v2 processor support.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/page.h>
+
+#include "proc-macros.S"
+
+/*
+ *	__cpuc_flush_icache_all()
+ *	__cpuc_flush_kern_all()
+ *	__cpuc_flush_user_all()
+ *
+ *	Flush the entire cache.
+ */
+ENTRY(__cpuc_flush_icache_all)
+	/*FALLTHROUGH*/
+ENTRY(__cpuc_flush_kern_all)
+	/*FALLTHROUGH*/
+ENTRY(__cpuc_flush_user_all)
+	mov	r0, #0
+	movc	p0.c5, r0, #14			@ Dcache flush all
+	nop8
+
+	mov	r0, #0
+	movc	p0.c5, r0, #20			@ Icache invalidate all
+	nop8
+
+	mov	pc, lr
+
+/*
+ *	__cpuc_flush_user_range(start, end, flags)
+ *
+ *	Flush a range of TLB entries in the specified address space.
+ *
+ *	- start - start address (may not be aligned)
+ *	- end   - end address (exclusive, may not be aligned)
+ *	- flags	- vm_area_struct flags describing address space
+ */
+ENTRY(__cpuc_flush_user_range)
+	cxor.a	r2, #0
+	beq	__cpuc_dma_flush_range
+
+#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
+	andn	r0, r0, #CACHE_LINESIZE - 1	@ Safety check
+	sub	r1, r1, r0
+	csub.a	r1, #MAX_AREA_SIZE
+	bsg	2f
+
+	andn	r1, r1, #CACHE_LINESIZE - 1
+	add	r1, r1, #CACHE_LINESIZE
+
+101:	dcacheline_flush	r0, r11, r12
+
+	add	r0, r0, #CACHE_LINESIZE
+	sub.a	r1, r1, #CACHE_LINESIZE
+	bns	101b
+	b	3f
+#endif
+2:	mov	ip, #0
+	movc	p0.c5, ip, #14			@ Dcache flush all
+	nop8
+
+3:	mov	ip, #0
+	movc	p0.c5, ip, #20			@ Icache invalidate all
+	nop8
+
+	mov	pc, lr
+
+/*
+ *	__cpuc_coherent_kern_range(start,end)
+ *	__cpuc_coherent_user_range(start,end)
+ *
+ *	Ensure that the I and D caches are coherent within specified
+ *	region.  This is typically used when code has been written to
+ *	a memory region, and will be executed.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+ENTRY(__cpuc_coherent_kern_range)
+	/* FALLTHROUGH */
+ENTRY(__cpuc_coherent_user_range)
+#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
+	andn	r0, r0, #CACHE_LINESIZE - 1	@ Safety check
+	sub	r1, r1, r0
+	csub.a	r1, #MAX_AREA_SIZE
+	bsg	2f
+
+	andn	r1, r1, #CACHE_LINESIZE - 1
+	add	r1, r1, #CACHE_LINESIZE
+
+	@ r0 va2pa r10
+	mov	r9, #PAGE_SZ
+	sub	r9, r9, #1			@ PAGE_MASK
+101:	va2pa	r0, r10, r11, r12, r13, 2f	@ r10 is PA
+	b	103f
+102:	cand.a	r0, r9
+	beq	101b
+
+103:	movc	p0.c5, r10, #11			@ Dcache clean line of R10
+	nop8
+
+	add	r0, r0, #CACHE_LINESIZE
+	add	r10, r10, #CACHE_LINESIZE
+	sub.a	r1, r1, #CACHE_LINESIZE
+	bns	102b
+	b	3f
+#endif
+2:	mov	ip, #0
+	movc	p0.c5, ip, #10			@ Dcache clean all
+	nop8
+
+3:	mov	ip, #0
+	movc	p0.c5, ip, #20			@ Icache invalidate all
+	nop8
+
+	mov	pc, lr
+
+/*
+ *	__cpuc_flush_kern_dcache_area(void *addr, size_t size)
+ *
+ *	- addr	- kernel address
+ *	- size	- region size
+ */
+ENTRY(__cpuc_flush_kern_dcache_area)
+	mov	ip, #0
+	movc	p0.c5, ip, #14			@ Dcache flush all
+	nop8
+	mov	pc, lr
+
+/*
+ *	__cpuc_dma_clean_range(start,end)
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+ENTRY(__cpuc_dma_clean_range)
+#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
+	andn	r0, r0, #CACHE_LINESIZE - 1
+	sub	r1, r1, r0
+	andn	r1, r1, #CACHE_LINESIZE - 1
+	add	r1, r1, #CACHE_LINESIZE
+
+	csub.a	r1, #MAX_AREA_SIZE
+	bsg	2f
+
+	@ r0 va2pa r10
+	mov	r9, #PAGE_SZ
+	sub	r9, r9, #1			@ PAGE_MASK
+101:	va2pa	r0, r10, r11, r12, r13, 2f	@ r10 is PA
+	b	1f
+102:	cand.a	r0, r9
+	beq	101b
+
+1:	movc	p0.c5, r10, #11			@ Dcache clean line of R10
+	nop8
+	add	r0, r0, #CACHE_LINESIZE
+	add	r10, r10, #CACHE_LINESIZE
+	sub.a	r1, r1, #CACHE_LINESIZE
+	bns	102b
+	mov	pc, lr
+#endif
+2:	mov	ip, #0
+	movc	p0.c5, ip, #10			@ Dcache clean all
+	nop8
+
+	mov	pc, lr
+
+/*
+ *	__cpuc_dma_inv_range(start,end)
+ *	__cpuc_dma_flush_range(start,end)
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+__cpuc_dma_inv_range:
+	/* FALLTHROUGH */
+ENTRY(__cpuc_dma_flush_range)
+#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
+	andn	r0, r0, #CACHE_LINESIZE - 1
+	sub	r1, r1, r0
+	andn	r1, r1, #CACHE_LINESIZE - 1
+	add	r1, r1, #CACHE_LINESIZE
+
+	csub.a	r1, #MAX_AREA_SIZE
+	bsg	2f
+
+	@ r0 va2pa r10
+101:	dcacheline_flush	r0, r11, r12
+
+	add	r0, r0, #CACHE_LINESIZE
+	sub.a	r1, r1, #CACHE_LINESIZE
+	bns	101b
+	mov	pc, lr
+#endif
+2:	mov	ip, #0
+	movc	p0.c5, ip, #14			@ Dcache flush all
+	nop8
+
+	mov	pc, lr
+
diff --git a/arch/unicore32/mm/dma-swiotlb.c b/arch/unicore32/mm/dma-swiotlb.c
new file mode 100644
index 000000000000..bfa9fbb2bbb1
--- /dev/null
+++ b/arch/unicore32/mm/dma-swiotlb.c
@@ -0,0 +1,34 @@
+/*
+ * Contains routines needed to support swiotlb for UniCore32.
+ *
+ * Copyright (C) 2010 Guan Xuetao
+ *
+ * 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.
+ */
+#include <linux/pci.h>
+#include <linux/cache.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/swiotlb.h>
+#include <linux/bootmem.h>
+
+#include <asm/dma.h>
+
+struct dma_map_ops swiotlb_dma_map_ops = {
+	.alloc_coherent = swiotlb_alloc_coherent,
+	.free_coherent = swiotlb_free_coherent,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.dma_supported = swiotlb_dma_supported,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device,
+	.mapping_error = swiotlb_dma_mapping_error,
+};
+EXPORT_SYMBOL(swiotlb_dma_map_ops);
diff --git a/arch/unicore32/mm/flush.c b/arch/unicore32/mm/flush.c
new file mode 100644
index 000000000000..93478cc8b26d
--- /dev/null
+++ b/arch/unicore32/mm/flush.c
@@ -0,0 +1,98 @@
+/*
+ * linux/arch/unicore32/mm/flush.c
+ *
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2010 GUAN Xue-tao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/cacheflush.h>
+#include <asm/system.h>
+#include <asm/tlbflush.h>
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+}
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+		unsigned long end)
+{
+	if (vma->vm_flags & VM_EXEC)
+		__flush_icache_all();
+}
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr,
+		unsigned long pfn)
+{
+}
+
+static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
+			 unsigned long uaddr, void *kaddr, unsigned long len)
+{
+	/* VIPT non-aliasing D-cache */
+	if (vma->vm_flags & VM_EXEC) {
+		unsigned long addr = (unsigned long)kaddr;
+
+		__cpuc_coherent_kern_range(addr, addr + len);
+	}
+}
+
+/*
+ * Copy user data from/to a page which is mapped into a different
+ * processes address space.  Really, we want to allow our "user
+ * space" model to handle this.
+ *
+ * Note that this code needs to run on the current CPU.
+ */
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+		       unsigned long uaddr, void *dst, const void *src,
+		       unsigned long len)
+{
+	memcpy(dst, src, len);
+	flush_ptrace_access(vma, page, uaddr, dst, len);
+}
+
+void __flush_dcache_page(struct address_space *mapping, struct page *page)
+{
+	/*
+	 * Writeback any data associated with the kernel mapping of this
+	 * page.  This ensures that data in the physical page is mutually
+	 * coherent with the kernels mapping.
+	 */
+	__cpuc_flush_kern_dcache_area(page_address(page), PAGE_SIZE);
+}
+
+/*
+ * Ensure cache coherency between kernel mapping and userspace mapping
+ * of this page.
+ */
+void flush_dcache_page(struct page *page)
+{
+	struct address_space *mapping;
+
+	/*
+	 * The zero page is never written to, so never has any dirty
+	 * cache lines, and therefore never needs to be flushed.
+	 */
+	if (page == ZERO_PAGE(0))
+		return;
+
+	mapping = page_mapping(page);
+
+	if (mapping && !mapping_mapped(mapping))
+		clear_bit(PG_dcache_clean, &page->flags);
+	else {
+		__flush_dcache_page(mapping, page);
+		if (mapping)
+			__flush_icache_all();
+		set_bit(PG_dcache_clean, &page->flags);
+	}
+}
+EXPORT_SYMBOL(flush_dcache_page);
diff --git a/arch/unicore32/mm/tlb-ucv2.S b/arch/unicore32/mm/tlb-ucv2.S
new file mode 100644
index 000000000000..061d455f9a15
--- /dev/null
+++ b/arch/unicore32/mm/tlb-ucv2.S
@@ -0,0 +1,89 @@
+/*
+ * linux/arch/unicore32/mm/tlb-ucv2.S
+ *
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2010 GUAN Xue-tao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+#include "proc-macros.S"
+
+/*
+ *	__cpu_flush_user_tlb_range(start, end, vma)
+ *
+ *	Invalidate a range of TLB entries in the specified address space.
+ *
+ *	- start - start address (may not be aligned)
+ *	- end   - end address (exclusive, may not be aligned)
+ *	- vma   - vma_struct describing address range
+ */
+ENTRY(__cpu_flush_user_tlb_range)
+#ifndef	CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE
+	mov	r0, r0 >> #PAGE_SHIFT		@ align address
+	mov	r0, r0 << #PAGE_SHIFT
+	vma_vm_flags r2, r2			@ get vma->vm_flags
+1:
+	movc	p0.c6, r0, #3
+	nop8
+
+	cand.a	r2, #VM_EXEC			@ Executable area ?
+	beq	2f
+
+	movc	p0.c6, r0, #5
+	nop8
+2:
+	add	r0, r0, #PAGE_SZ
+	csub.a	r0, r1
+	beb	1b
+#else
+	movc	p0.c6, r0, #2
+	nop8
+
+	cand.a	r2, #VM_EXEC			@ Executable area ?
+	beq	2f
+
+	movc	p0.c6, r0, #4
+	nop8
+2:
+#endif
+	mov	pc, lr
+
+/*
+ *	__cpu_flush_kern_tlb_range(start,end)
+ *
+ *	Invalidate a range of kernel TLB entries
+ *
+ *	- start - start address (may not be aligned)
+ *	- end   - end address (exclusive, may not be aligned)
+ */
+ENTRY(__cpu_flush_kern_tlb_range)
+#ifndef	CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE
+	mov	r0, r0 >> #PAGE_SHIFT		@ align address
+	mov	r0, r0 << #PAGE_SHIFT
+1:
+	movc	p0.c6, r0, #3
+	nop8
+
+	movc	p0.c6, r0, #5
+	nop8
+
+	add	r0, r0, #PAGE_SZ
+	csub.a	r0, r1
+	beb	1b
+#else
+	movc	p0.c6, r0, #2
+	nop8
+
+	movc	p0.c6, r0, #4
+	nop8
+#endif
+	mov	pc, lr
+