diff options
author | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-01-15 05:18:29 -0500 |
---|---|---|
committer | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-03-16 21:19:09 -0400 |
commit | 10c9c10c31514564b09c153432a42ffaea3ce831 (patch) | |
tree | 04a60b9a1e48eaa2d9346e265a1c2fe2db5ec670 /arch | |
parent | 56372b0b2f533c9a25bd40a0577405f6ddb7cff2 (diff) |
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')
-rw-r--r-- | arch/unicore32/include/asm/cacheflush.h | 211 | ||||
-rw-r--r-- | arch/unicore32/include/asm/dma-mapping.h | 124 | ||||
-rw-r--r-- | arch/unicore32/include/asm/dma.h | 23 | ||||
-rw-r--r-- | arch/unicore32/include/asm/tlbflush.h | 195 | ||||
-rw-r--r-- | arch/unicore32/include/mach/dma.h | 41 | ||||
-rw-r--r-- | arch/unicore32/kernel/dma.c | 180 | ||||
-rw-r--r-- | arch/unicore32/mm/cache-ucv2.S | 212 | ||||
-rw-r--r-- | arch/unicore32/mm/dma-swiotlb.c | 34 | ||||
-rw-r--r-- | arch/unicore32/mm/flush.c | 98 | ||||
-rw-r--r-- | arch/unicore32/mm/tlb-ucv2.S | 89 |
10 files changed, 1207 insertions, 0 deletions
diff --git a/arch/unicore32/include/asm/cacheflush.h b/arch/unicore32/include/asm/cacheflush.h new file mode 100644 index 00000000000..c0301e6c8b8 --- /dev/null +++ b/arch/unicore32/include/asm/cacheflush.h | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/cacheflush.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_CACHEFLUSH_H__ | ||
13 | #define __UNICORE_CACHEFLUSH_H__ | ||
14 | |||
15 | #include <linux/mm.h> | ||
16 | |||
17 | #include <asm/shmparam.h> | ||
18 | |||
19 | #define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) | ||
20 | |||
21 | /* | ||
22 | * This flag is used to indicate that the page pointed to by a pte is clean | ||
23 | * and does not require cleaning before returning it to the user. | ||
24 | */ | ||
25 | #define PG_dcache_clean PG_arch_1 | ||
26 | |||
27 | /* | ||
28 | * MM Cache Management | ||
29 | * =================== | ||
30 | * | ||
31 | * The arch/unicore32/mm/cache.S files implement these methods. | ||
32 | * | ||
33 | * Start addresses are inclusive and end addresses are exclusive; | ||
34 | * start addresses should be rounded down, end addresses up. | ||
35 | * | ||
36 | * See Documentation/cachetlb.txt for more information. | ||
37 | * Please note that the implementation of these, and the required | ||
38 | * effects are cache-type (VIVT/VIPT/PIPT) specific. | ||
39 | * | ||
40 | * flush_icache_all() | ||
41 | * | ||
42 | * Unconditionally clean and invalidate the entire icache. | ||
43 | * Currently only needed for cache-v6.S and cache-v7.S, see | ||
44 | * __flush_icache_all for the generic implementation. | ||
45 | * | ||
46 | * flush_kern_all() | ||
47 | * | ||
48 | * Unconditionally clean and invalidate the entire cache. | ||
49 | * | ||
50 | * flush_user_all() | ||
51 | * | ||
52 | * Clean and invalidate all user space cache entries | ||
53 | * before a change of page tables. | ||
54 | * | ||
55 | * flush_user_range(start, end, flags) | ||
56 | * | ||
57 | * Clean and invalidate a range of cache entries in the | ||
58 | * specified address space before a change of page tables. | ||
59 | * - start - user start address (inclusive, page aligned) | ||
60 | * - end - user end address (exclusive, page aligned) | ||
61 | * - flags - vma->vm_flags field | ||
62 | * | ||
63 | * coherent_kern_range(start, end) | ||
64 | * | ||
65 | * Ensure coherency between the Icache and the Dcache in the | ||
66 | * region described by start, end. If you have non-snooping | ||
67 | * Harvard caches, you need to implement this function. | ||
68 | * - start - virtual start address | ||
69 | * - end - virtual end address | ||
70 | * | ||
71 | * coherent_user_range(start, end) | ||
72 | * | ||
73 | * Ensure coherency between the Icache and the Dcache in the | ||
74 | * region described by start, end. If you have non-snooping | ||
75 | * Harvard caches, you need to implement this function. | ||
76 | * - start - virtual start address | ||
77 | * - end - virtual end address | ||
78 | * | ||
79 | * flush_kern_dcache_area(kaddr, size) | ||
80 | * | ||
81 | * Ensure that the data held in page is written back. | ||
82 | * - kaddr - page address | ||
83 | * - size - region size | ||
84 | * | ||
85 | * DMA Cache Coherency | ||
86 | * =================== | ||
87 | * | ||
88 | * dma_flush_range(start, end) | ||
89 | * | ||
90 | * Clean and invalidate the specified virtual address range. | ||
91 | * - start - virtual start address | ||
92 | * - end - virtual end address | ||
93 | */ | ||
94 | |||
95 | extern void __cpuc_flush_icache_all(void); | ||
96 | extern void __cpuc_flush_kern_all(void); | ||
97 | extern void __cpuc_flush_user_all(void); | ||
98 | extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int); | ||
99 | extern void __cpuc_coherent_kern_range(unsigned long, unsigned long); | ||
100 | extern void __cpuc_coherent_user_range(unsigned long, unsigned long); | ||
101 | extern void __cpuc_flush_dcache_area(void *, size_t); | ||
102 | extern void __cpuc_flush_kern_dcache_area(void *addr, size_t size); | ||
103 | |||
104 | /* | ||
105 | * These are private to the dma-mapping API. Do not use directly. | ||
106 | * Their sole purpose is to ensure that data held in the cache | ||
107 | * is visible to DMA, or data written by DMA to system memory is | ||
108 | * visible to the CPU. | ||
109 | */ | ||
110 | extern void __cpuc_dma_clean_range(unsigned long, unsigned long); | ||
111 | extern void __cpuc_dma_flush_range(unsigned long, unsigned long); | ||
112 | |||
113 | /* | ||
114 | * Copy user data from/to a page which is mapped into a different | ||
115 | * processes address space. Really, we want to allow our "user | ||
116 | * space" model to handle this. | ||
117 | */ | ||
118 | extern void copy_to_user_page(struct vm_area_struct *, struct page *, | ||
119 | unsigned long, void *, const void *, unsigned long); | ||
120 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | ||
121 | do { \ | ||
122 | memcpy(dst, src, len); \ | ||
123 | } while (0) | ||
124 | |||
125 | /* | ||
126 | * Convert calls to our calling convention. | ||
127 | */ | ||
128 | /* Invalidate I-cache */ | ||
129 | static inline void __flush_icache_all(void) | ||
130 | { | ||
131 | asm("movc p0.c5, %0, #20;\n" | ||
132 | "nop; nop; nop; nop; nop; nop; nop; nop\n" | ||
133 | : | ||
134 | : "r" (0)); | ||
135 | } | ||
136 | |||
137 | #define flush_cache_all() __cpuc_flush_kern_all() | ||
138 | |||
139 | extern void flush_cache_mm(struct mm_struct *mm); | ||
140 | extern void flush_cache_range(struct vm_area_struct *vma, | ||
141 | unsigned long start, unsigned long end); | ||
142 | extern void flush_cache_page(struct vm_area_struct *vma, | ||
143 | unsigned long user_addr, unsigned long pfn); | ||
144 | |||
145 | #define flush_cache_dup_mm(mm) flush_cache_mm(mm) | ||
146 | |||
147 | /* | ||
148 | * flush_cache_user_range is used when we want to ensure that the | ||
149 | * Harvard caches are synchronised for the user space address range. | ||
150 | * This is used for the UniCore private sys_cacheflush system call. | ||
151 | */ | ||
152 | #define flush_cache_user_range(vma, start, end) \ | ||
153 | __cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end)) | ||
154 | |||
155 | /* | ||
156 | * Perform necessary cache operations to ensure that data previously | ||
157 | * stored within this range of addresses can be executed by the CPU. | ||
158 | */ | ||
159 | #define flush_icache_range(s, e) __cpuc_coherent_kern_range(s, e) | ||
160 | |||
161 | /* | ||
162 | * Perform necessary cache operations to ensure that the TLB will | ||
163 | * see data written in the specified area. | ||
164 | */ | ||
165 | #define clean_dcache_area(start, size) cpu_dcache_clean_area(start, size) | ||
166 | |||
167 | /* | ||
168 | * flush_dcache_page is used when the kernel has written to the page | ||
169 | * cache page at virtual address page->virtual. | ||
170 | * | ||
171 | * If this page isn't mapped (ie, page_mapping == NULL), or it might | ||
172 | * have userspace mappings, then we _must_ always clean + invalidate | ||
173 | * the dcache entries associated with the kernel mapping. | ||
174 | * | ||
175 | * Otherwise we can defer the operation, and clean the cache when we are | ||
176 | * about to change to user space. This is the same method as used on SPARC64. | ||
177 | * See update_mmu_cache for the user space part. | ||
178 | */ | ||
179 | #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 | ||
180 | extern void flush_dcache_page(struct page *); | ||
181 | |||
182 | #define flush_dcache_mmap_lock(mapping) \ | ||
183 | spin_lock_irq(&(mapping)->tree_lock) | ||
184 | #define flush_dcache_mmap_unlock(mapping) \ | ||
185 | spin_unlock_irq(&(mapping)->tree_lock) | ||
186 | |||
187 | #define flush_icache_user_range(vma, page, addr, len) \ | ||
188 | flush_dcache_page(page) | ||
189 | |||
190 | /* | ||
191 | * We don't appear to need to do anything here. In fact, if we did, we'd | ||
192 | * duplicate cache flushing elsewhere performed by flush_dcache_page(). | ||
193 | */ | ||
194 | #define flush_icache_page(vma, page) do { } while (0) | ||
195 | |||
196 | /* | ||
197 | * flush_cache_vmap() is used when creating mappings (eg, via vmap, | ||
198 | * vmalloc, ioremap etc) in kernel space for pages. On non-VIPT | ||
199 | * caches, since the direct-mappings of these pages may contain cached | ||
200 | * data, we need to do a full cache flush to ensure that writebacks | ||
201 | * don't corrupt data placed into these pages via the new mappings. | ||
202 | */ | ||
203 | static inline void flush_cache_vmap(unsigned long start, unsigned long end) | ||
204 | { | ||
205 | } | ||
206 | |||
207 | static inline void flush_cache_vunmap(unsigned long start, unsigned long end) | ||
208 | { | ||
209 | } | ||
210 | |||
211 | #endif | ||
diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h new file mode 100644 index 00000000000..9258e592f41 --- /dev/null +++ b/arch/unicore32/include/asm/dma-mapping.h | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/dma-mapping.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_DMA_MAPPING_H__ | ||
13 | #define __UNICORE_DMA_MAPPING_H__ | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | |||
17 | #include <linux/mm_types.h> | ||
18 | #include <linux/scatterlist.h> | ||
19 | #include <linux/swiotlb.h> | ||
20 | |||
21 | #include <asm-generic/dma-coherent.h> | ||
22 | |||
23 | #include <asm/memory.h> | ||
24 | #include <asm/cacheflush.h> | ||
25 | |||
26 | extern struct dma_map_ops swiotlb_dma_map_ops; | ||
27 | |||
28 | static inline struct dma_map_ops *get_dma_ops(struct device *dev) | ||
29 | { | ||
30 | return &swiotlb_dma_map_ops; | ||
31 | } | ||
32 | |||
33 | static inline int dma_supported(struct device *dev, u64 mask) | ||
34 | { | ||
35 | struct dma_map_ops *dma_ops = get_dma_ops(dev); | ||
36 | |||
37 | if (unlikely(dma_ops == NULL)) | ||
38 | return 0; | ||
39 | |||
40 | return dma_ops->dma_supported(dev, mask); | ||
41 | } | ||
42 | |||
43 | static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) | ||
44 | { | ||
45 | struct dma_map_ops *dma_ops = get_dma_ops(dev); | ||
46 | |||
47 | if (dma_ops->mapping_error) | ||
48 | return dma_ops->mapping_error(dev, dma_addr); | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | #include <asm-generic/dma-mapping-common.h> | ||
54 | |||
55 | static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) | ||
56 | { | ||
57 | if (dev && dev->dma_mask) | ||
58 | return addr + size - 1 <= *dev->dma_mask; | ||
59 | |||
60 | return 1; | ||
61 | } | ||
62 | |||
63 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | ||
64 | { | ||
65 | return paddr; | ||
66 | } | ||
67 | |||
68 | static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) | ||
69 | { | ||
70 | return daddr; | ||
71 | } | ||
72 | |||
73 | static inline void dma_mark_clean(void *addr, size_t size) {} | ||
74 | |||
75 | static inline int dma_set_mask(struct device *dev, u64 dma_mask) | ||
76 | { | ||
77 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | ||
78 | return -EIO; | ||
79 | |||
80 | *dev->dma_mask = dma_mask; | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static inline void *dma_alloc_coherent(struct device *dev, size_t size, | ||
86 | dma_addr_t *dma_handle, gfp_t flag) | ||
87 | { | ||
88 | struct dma_map_ops *dma_ops = get_dma_ops(dev); | ||
89 | |||
90 | return dma_ops->alloc_coherent(dev, size, dma_handle, flag); | ||
91 | } | ||
92 | |||
93 | static inline void dma_free_coherent(struct device *dev, size_t size, | ||
94 | void *cpu_addr, dma_addr_t dma_handle) | ||
95 | { | ||
96 | struct dma_map_ops *dma_ops = get_dma_ops(dev); | ||
97 | |||
98 | dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); | ||
99 | } | ||
100 | |||
101 | #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) | ||
102 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) | ||
103 | |||
104 | static inline void dma_cache_sync(struct device *dev, void *vaddr, | ||
105 | size_t size, enum dma_data_direction direction) | ||
106 | { | ||
107 | unsigned long start = (unsigned long)vaddr; | ||
108 | unsigned long end = start + size; | ||
109 | |||
110 | switch (direction) { | ||
111 | case DMA_NONE: | ||
112 | BUG(); | ||
113 | case DMA_FROM_DEVICE: | ||
114 | case DMA_BIDIRECTIONAL: /* writeback and invalidate */ | ||
115 | __cpuc_dma_flush_range(start, end); | ||
116 | break; | ||
117 | case DMA_TO_DEVICE: /* writeback only */ | ||
118 | __cpuc_dma_clean_range(start, end); | ||
119 | break; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | #endif /* __KERNEL__ */ | ||
124 | #endif | ||
diff --git a/arch/unicore32/include/asm/dma.h b/arch/unicore32/include/asm/dma.h new file mode 100644 index 00000000000..38dfff9df32 --- /dev/null +++ b/arch/unicore32/include/asm/dma.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/dma.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __UNICORE_DMA_H__ | ||
14 | #define __UNICORE_DMA_H__ | ||
15 | |||
16 | #include <asm/memory.h> | ||
17 | #include <asm-generic/dma.h> | ||
18 | |||
19 | #ifdef CONFIG_PCI | ||
20 | extern int isa_dma_bridge_buggy; | ||
21 | #endif | ||
22 | |||
23 | #endif /* __UNICORE_DMA_H__ */ | ||
diff --git a/arch/unicore32/include/asm/tlbflush.h b/arch/unicore32/include/asm/tlbflush.h new file mode 100644 index 00000000000..e446ac8bb9e --- /dev/null +++ b/arch/unicore32/include/asm/tlbflush.h | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/tlbflush.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_TLBFLUSH_H__ | ||
13 | #define __UNICORE_TLBFLUSH_H__ | ||
14 | |||
15 | #ifndef __ASSEMBLY__ | ||
16 | |||
17 | #include <linux/sched.h> | ||
18 | |||
19 | extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, | ||
20 | struct vm_area_struct *); | ||
21 | extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long); | ||
22 | |||
23 | /* | ||
24 | * TLB Management | ||
25 | * ============== | ||
26 | * | ||
27 | * The arch/unicore/mm/tlb-*.S files implement these methods. | ||
28 | * | ||
29 | * The TLB specific code is expected to perform whatever tests it | ||
30 | * needs to determine if it should invalidate the TLB for each | ||
31 | * call. Start addresses are inclusive and end addresses are | ||
32 | * exclusive; it is safe to round these addresses down. | ||
33 | * | ||
34 | * flush_tlb_all() | ||
35 | * | ||
36 | * Invalidate the entire TLB. | ||
37 | * | ||
38 | * flush_tlb_mm(mm) | ||
39 | * | ||
40 | * Invalidate all TLB entries in a particular address | ||
41 | * space. | ||
42 | * - mm - mm_struct describing address space | ||
43 | * | ||
44 | * flush_tlb_range(mm,start,end) | ||
45 | * | ||
46 | * Invalidate a range of TLB entries in the specified | ||
47 | * address space. | ||
48 | * - mm - mm_struct describing address space | ||
49 | * - start - start address (may not be aligned) | ||
50 | * - end - end address (exclusive, may not be aligned) | ||
51 | * | ||
52 | * flush_tlb_page(vaddr,vma) | ||
53 | * | ||
54 | * Invalidate the specified page in the specified address range. | ||
55 | * - vaddr - virtual address (may not be aligned) | ||
56 | * - vma - vma_struct describing address range | ||
57 | * | ||
58 | * flush_kern_tlb_page(kaddr) | ||
59 | * | ||
60 | * Invalidate the TLB entry for the specified page. The address | ||
61 | * will be in the kernels virtual memory space. Current uses | ||
62 | * only require the D-TLB to be invalidated. | ||
63 | * - kaddr - Kernel virtual memory address | ||
64 | */ | ||
65 | |||
66 | static inline void local_flush_tlb_all(void) | ||
67 | { | ||
68 | const int zero = 0; | ||
69 | |||
70 | /* TLB invalidate all */ | ||
71 | asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop" | ||
72 | : : "r" (zero) : "cc"); | ||
73 | } | ||
74 | |||
75 | static inline void local_flush_tlb_mm(struct mm_struct *mm) | ||
76 | { | ||
77 | const int zero = 0; | ||
78 | |||
79 | if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) { | ||
80 | /* TLB invalidate all */ | ||
81 | asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop" | ||
82 | : : "r" (zero) : "cc"); | ||
83 | } | ||
84 | put_cpu(); | ||
85 | } | ||
86 | |||
87 | static inline void | ||
88 | local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | ||
89 | { | ||
90 | if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { | ||
91 | #ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE | ||
92 | /* iTLB invalidate page */ | ||
93 | asm("movc p0.c6, %0, #5; nop; nop; nop; nop; nop; nop; nop; nop" | ||
94 | : : "r" (uaddr & PAGE_MASK) : "cc"); | ||
95 | /* dTLB invalidate page */ | ||
96 | asm("movc p0.c6, %0, #3; nop; nop; nop; nop; nop; nop; nop; nop" | ||
97 | : : "r" (uaddr & PAGE_MASK) : "cc"); | ||
98 | #else | ||
99 | /* TLB invalidate all */ | ||
100 | asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop" | ||
101 | : : "r" (uaddr & PAGE_MASK) : "cc"); | ||
102 | #endif | ||
103 | } | ||
104 | } | ||
105 | |||
106 | static inline void local_flush_tlb_kernel_page(unsigned long kaddr) | ||
107 | { | ||
108 | #ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE | ||
109 | /* iTLB invalidate page */ | ||
110 | asm("movc p0.c6, %0, #5; nop; nop; nop; nop; nop; nop; nop; nop" | ||
111 | : : "r" (kaddr & PAGE_MASK) : "cc"); | ||
112 | /* dTLB invalidate page */ | ||
113 | asm("movc p0.c6, %0, #3; nop; nop; nop; nop; nop; nop; nop; nop" | ||
114 | : : "r" (kaddr & PAGE_MASK) : "cc"); | ||
115 | #else | ||
116 | /* TLB invalidate all */ | ||
117 | asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop" | ||
118 | : : "r" (kaddr & PAGE_MASK) : "cc"); | ||
119 | #endif | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * flush_pmd_entry | ||
124 | * | ||
125 | * Flush a PMD entry (word aligned, or double-word aligned) to | ||
126 | * RAM if the TLB for the CPU we are running on requires this. | ||
127 | * This is typically used when we are creating PMD entries. | ||
128 | * | ||
129 | * clean_pmd_entry | ||
130 | * | ||
131 | * Clean (but don't drain the write buffer) if the CPU requires | ||
132 | * these operations. This is typically used when we are removing | ||
133 | * PMD entries. | ||
134 | */ | ||
135 | static inline void flush_pmd_entry(pmd_t *pmd) | ||
136 | { | ||
137 | #ifndef CONFIG_CPU_DCACHE_LINE_DISABLE | ||
138 | /* flush dcache line, see dcacheline_flush in proc-macros.S */ | ||
139 | asm("mov r1, %0 << #20\n" | ||
140 | "ldw r2, =_stext\n" | ||
141 | "add r2, r2, r1 >> #20\n" | ||
142 | "ldw r1, [r2+], #0x0000\n" | ||
143 | "ldw r1, [r2+], #0x1000\n" | ||
144 | "ldw r1, [r2+], #0x2000\n" | ||
145 | "ldw r1, [r2+], #0x3000\n" | ||
146 | : : "r" (pmd) : "r1", "r2"); | ||
147 | #else | ||
148 | /* flush dcache all */ | ||
149 | asm("movc p0.c5, %0, #14; nop; nop; nop; nop; nop; nop; nop; nop" | ||
150 | : : "r" (pmd) : "cc"); | ||
151 | #endif | ||
152 | } | ||
153 | |||
154 | static inline void clean_pmd_entry(pmd_t *pmd) | ||
155 | { | ||
156 | #ifndef CONFIG_CPU_DCACHE_LINE_DISABLE | ||
157 | /* clean dcache line */ | ||
158 | asm("movc p0.c5, %0, #11; nop; nop; nop; nop; nop; nop; nop; nop" | ||
159 | : : "r" (__pa(pmd) & ~(L1_CACHE_BYTES - 1)) : "cc"); | ||
160 | #else | ||
161 | /* clean dcache all */ | ||
162 | asm("movc p0.c5, %0, #10; nop; nop; nop; nop; nop; nop; nop; nop" | ||
163 | : : "r" (pmd) : "cc"); | ||
164 | #endif | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * Convert calls to our calling convention. | ||
169 | */ | ||
170 | #define local_flush_tlb_range(vma, start, end) \ | ||
171 | __cpu_flush_user_tlb_range(start, end, vma) | ||
172 | #define local_flush_tlb_kernel_range(s, e) \ | ||
173 | __cpu_flush_kern_tlb_range(s, e) | ||
174 | |||
175 | #define flush_tlb_all local_flush_tlb_all | ||
176 | #define flush_tlb_mm local_flush_tlb_mm | ||
177 | #define flush_tlb_page local_flush_tlb_page | ||
178 | #define flush_tlb_kernel_page local_flush_tlb_kernel_page | ||
179 | #define flush_tlb_range local_flush_tlb_range | ||
180 | #define flush_tlb_kernel_range local_flush_tlb_kernel_range | ||
181 | |||
182 | /* | ||
183 | * if PG_dcache_clean is not set for the page, we need to ensure that any | ||
184 | * cache entries for the kernels virtual memory range are written | ||
185 | * back to the page. | ||
186 | */ | ||
187 | extern void update_mmu_cache(struct vm_area_struct *vma, | ||
188 | unsigned long addr, pte_t *ptep); | ||
189 | |||
190 | extern void do_bad_area(unsigned long addr, unsigned int fsr, | ||
191 | struct pt_regs *regs); | ||
192 | |||
193 | #endif | ||
194 | |||
195 | #endif | ||
diff --git a/arch/unicore32/include/mach/dma.h b/arch/unicore32/include/mach/dma.h new file mode 100644 index 00000000000..3e3224a1052 --- /dev/null +++ b/arch/unicore32/include/mach/dma.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/mach/dma.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __MACH_PUV3_DMA_H__ | ||
13 | #define __MACH_PUV3_DMA_H__ | ||
14 | |||
15 | /* | ||
16 | * The PKUnity has six internal DMA channels. | ||
17 | */ | ||
18 | #define MAX_DMA_CHANNELS 6 | ||
19 | |||
20 | typedef enum { | ||
21 | DMA_PRIO_HIGH = 0, | ||
22 | DMA_PRIO_MEDIUM = 1, | ||
23 | DMA_PRIO_LOW = 2 | ||
24 | } puv3_dma_prio; | ||
25 | |||
26 | /* | ||
27 | * DMA registration | ||
28 | */ | ||
29 | |||
30 | extern int puv3_request_dma(char *name, | ||
31 | puv3_dma_prio prio, | ||
32 | void (*irq_handler)(int, void *), | ||
33 | void (*err_handler)(int, void *), | ||
34 | void *data); | ||
35 | |||
36 | extern void puv3_free_dma(int dma_ch); | ||
37 | |||
38 | #define puv3_stop_dma(ch) (DMAC_CONFIG(ch) &= ~DMAC_CONFIG_EN) | ||
39 | #define puv3_resume_dma(ch) (DMAC_CONFIG(ch) |= DMAC_CONFIG_EN) | ||
40 | |||
41 | #endif /* __MACH_PUV3_DMA_H__ */ | ||
diff --git a/arch/unicore32/kernel/dma.c b/arch/unicore32/kernel/dma.c new file mode 100644 index 00000000000..b8dcc2514e9 --- /dev/null +++ b/arch/unicore32/kernel/dma.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/kernel/dma.c | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> | ||
7 | * Copyright (C) 2001-2010 Guan Xuetao | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/errno.h> | ||
19 | |||
20 | #include <asm/system.h> | ||
21 | #include <asm/irq.h> | ||
22 | #include <mach/hardware.h> | ||
23 | #include <mach/dma.h> | ||
24 | |||
25 | struct dma_channel { | ||
26 | char *name; | ||
27 | puv3_dma_prio prio; | ||
28 | void (*irq_handler)(int, void *); | ||
29 | void (*err_handler)(int, void *); | ||
30 | void *data; | ||
31 | }; | ||
32 | |||
33 | static struct dma_channel dma_channels[MAX_DMA_CHANNELS]; | ||
34 | |||
35 | int puv3_request_dma(char *name, puv3_dma_prio prio, | ||
36 | void (*irq_handler)(int, void *), | ||
37 | void (*err_handler)(int, void *), | ||
38 | void *data) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | int i, found = 0; | ||
42 | |||
43 | /* basic sanity checks */ | ||
44 | if (!name) | ||
45 | return -EINVAL; | ||
46 | |||
47 | local_irq_save(flags); | ||
48 | |||
49 | do { | ||
50 | /* try grabbing a DMA channel with the requested priority */ | ||
51 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { | ||
52 | if ((dma_channels[i].prio == prio) && | ||
53 | !dma_channels[i].name) { | ||
54 | found = 1; | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | /* if requested prio group is full, try a hier priority */ | ||
59 | } while (!found && prio--); | ||
60 | |||
61 | if (found) { | ||
62 | dma_channels[i].name = name; | ||
63 | dma_channels[i].irq_handler = irq_handler; | ||
64 | dma_channels[i].err_handler = err_handler; | ||
65 | dma_channels[i].data = data; | ||
66 | } else { | ||
67 | printk(KERN_WARNING "No more available DMA channels for %s\n", | ||
68 | name); | ||
69 | i = -ENODEV; | ||
70 | } | ||
71 | |||
72 | local_irq_restore(flags); | ||
73 | return i; | ||
74 | } | ||
75 | EXPORT_SYMBOL(puv3_request_dma); | ||
76 | |||
77 | void puv3_free_dma(int dma_ch) | ||
78 | { | ||
79 | unsigned long flags; | ||
80 | |||
81 | if (!dma_channels[dma_ch].name) { | ||
82 | printk(KERN_CRIT | ||
83 | "%s: trying to free channel %d which is already freed\n", | ||
84 | __func__, dma_ch); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | local_irq_save(flags); | ||
89 | dma_channels[dma_ch].name = NULL; | ||
90 | dma_channels[dma_ch].err_handler = NULL; | ||
91 | local_irq_restore(flags); | ||
92 | } | ||
93 | EXPORT_SYMBOL(puv3_free_dma); | ||
94 | |||
95 | static irqreturn_t dma_irq_handler(int irq, void *dev_id) | ||
96 | { | ||
97 | int i, dint = DMAC_ITCSR; | ||
98 | |||
99 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { | ||
100 | if (dint & DMAC_CHANNEL(i)) { | ||
101 | struct dma_channel *channel = &dma_channels[i]; | ||
102 | |||
103 | /* Clear TC interrupt of channel i */ | ||
104 | DMAC_ITCCR = DMAC_CHANNEL(i); | ||
105 | DMAC_ITCCR = 0; | ||
106 | |||
107 | if (channel->name && channel->irq_handler) { | ||
108 | channel->irq_handler(i, channel->data); | ||
109 | } else { | ||
110 | /* | ||
111 | * IRQ for an unregistered DMA channel: | ||
112 | * let's clear the interrupts and disable it. | ||
113 | */ | ||
114 | printk(KERN_WARNING "spurious IRQ for" | ||
115 | " DMA channel %d\n", i); | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | return IRQ_HANDLED; | ||
120 | } | ||
121 | |||
122 | static irqreturn_t dma_err_handler(int irq, void *dev_id) | ||
123 | { | ||
124 | int i, dint = DMAC_IESR; | ||
125 | |||
126 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { | ||
127 | if (dint & DMAC_CHANNEL(i)) { | ||
128 | struct dma_channel *channel = &dma_channels[i]; | ||
129 | |||
130 | /* Clear Err interrupt of channel i */ | ||
131 | DMAC_IECR = DMAC_CHANNEL(i); | ||
132 | DMAC_IECR = 0; | ||
133 | |||
134 | if (channel->name && channel->err_handler) { | ||
135 | channel->err_handler(i, channel->data); | ||
136 | } else { | ||
137 | /* | ||
138 | * IRQ for an unregistered DMA channel: | ||
139 | * let's clear the interrupts and disable it. | ||
140 | */ | ||
141 | printk(KERN_WARNING "spurious IRQ for" | ||
142 | " DMA channel %d\n", i); | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | return IRQ_HANDLED; | ||
147 | } | ||
148 | |||
149 | int __init puv3_init_dma(void) | ||
150 | { | ||
151 | int i, ret; | ||
152 | |||
153 | /* dma channel priorities on v8 processors: | ||
154 | * ch 0 - 1 <--> (0) DMA_PRIO_HIGH | ||
155 | * ch 2 - 3 <--> (1) DMA_PRIO_MEDIUM | ||
156 | * ch 4 - 5 <--> (2) DMA_PRIO_LOW | ||
157 | */ | ||
158 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { | ||
159 | puv3_stop_dma(i); | ||
160 | dma_channels[i].name = NULL; | ||
161 | dma_channels[i].prio = min((i & 0x7) >> 1, DMA_PRIO_LOW); | ||
162 | } | ||
163 | |||
164 | ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); | ||
165 | if (ret) { | ||
166 | printk(KERN_CRIT "Can't register IRQ for DMA\n"); | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | ret = request_irq(IRQ_DMAERR, dma_err_handler, 0, "DMAERR", NULL); | ||
171 | if (ret) { | ||
172 | printk(KERN_CRIT "Can't register IRQ for DMAERR\n"); | ||
173 | free_irq(IRQ_DMA, "DMA"); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | postcore_initcall(puv3_init_dma); | ||
diff --git a/arch/unicore32/mm/cache-ucv2.S b/arch/unicore32/mm/cache-ucv2.S new file mode 100644 index 00000000000..ecaa1727f90 --- /dev/null +++ b/arch/unicore32/mm/cache-ucv2.S | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/mm/cache-ucv2.S | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This is the "shell" of the UniCore-v2 processor support. | ||
13 | */ | ||
14 | #include <linux/linkage.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <asm/assembler.h> | ||
17 | #include <asm/page.h> | ||
18 | |||
19 | #include "proc-macros.S" | ||
20 | |||
21 | /* | ||
22 | * __cpuc_flush_icache_all() | ||
23 | * __cpuc_flush_kern_all() | ||
24 | * __cpuc_flush_user_all() | ||
25 | * | ||
26 | * Flush the entire cache. | ||
27 | */ | ||
28 | ENTRY(__cpuc_flush_icache_all) | ||
29 | /*FALLTHROUGH*/ | ||
30 | ENTRY(__cpuc_flush_kern_all) | ||
31 | /*FALLTHROUGH*/ | ||
32 | ENTRY(__cpuc_flush_user_all) | ||
33 | mov r0, #0 | ||
34 | movc p0.c5, r0, #14 @ Dcache flush all | ||
35 | nop8 | ||
36 | |||
37 | mov r0, #0 | ||
38 | movc p0.c5, r0, #20 @ Icache invalidate all | ||
39 | nop8 | ||
40 | |||
41 | mov pc, lr | ||
42 | |||
43 | /* | ||
44 | * __cpuc_flush_user_range(start, end, flags) | ||
45 | * | ||
46 | * Flush a range of TLB entries in the specified address space. | ||
47 | * | ||
48 | * - start - start address (may not be aligned) | ||
49 | * - end - end address (exclusive, may not be aligned) | ||
50 | * - flags - vm_area_struct flags describing address space | ||
51 | */ | ||
52 | ENTRY(__cpuc_flush_user_range) | ||
53 | cxor.a r2, #0 | ||
54 | beq __cpuc_dma_flush_range | ||
55 | |||
56 | #ifndef CONFIG_CPU_DCACHE_LINE_DISABLE | ||
57 | andn r0, r0, #CACHE_LINESIZE - 1 @ Safety check | ||
58 | sub r1, r1, r0 | ||
59 | csub.a r1, #MAX_AREA_SIZE | ||
60 | bsg 2f | ||
61 | |||
62 | andn r1, r1, #CACHE_LINESIZE - 1 | ||
63 | add r1, r1, #CACHE_LINESIZE | ||
64 | |||
65 | 101: dcacheline_flush r0, r11, r12 | ||
66 | |||
67 | add r0, r0, #CACHE_LINESIZE | ||
68 | sub.a r1, r1, #CACHE_LINESIZE | ||
69 | bns 101b | ||
70 | b 3f | ||
71 | #endif | ||
72 | 2: mov ip, #0 | ||
73 | movc p0.c5, ip, #14 @ Dcache flush all | ||
74 | nop8 | ||
75 | |||
76 | 3: mov ip, #0 | ||
77 | movc p0.c5, ip, #20 @ Icache invalidate all | ||
78 | nop8 | ||
79 | |||
80 | mov pc, lr | ||
81 | |||
82 | /* | ||
83 | * __cpuc_coherent_kern_range(start,end) | ||
84 | * __cpuc_coherent_user_range(start,end) | ||
85 | * | ||
86 | * Ensure that the I and D caches are coherent within specified | ||
87 | * region. This is typically used when code has been written to | ||
88 | * a memory region, and will be executed. | ||
89 | * | ||
90 | * - start - virtual start address of region | ||
91 | * - end - virtual end address of region | ||
92 | */ | ||
93 | ENTRY(__cpuc_coherent_kern_range) | ||
94 | /* FALLTHROUGH */ | ||
95 | ENTRY(__cpuc_coherent_user_range) | ||
96 | #ifndef CONFIG_CPU_DCACHE_LINE_DISABLE | ||
97 | andn r0, r0, #CACHE_LINESIZE - 1 @ Safety check | ||
98 | sub r1, r1, r0 | ||
99 | csub.a r1, #MAX_AREA_SIZE | ||
100 | bsg 2f | ||
101 | |||
102 | andn r1, r1, #CACHE_LINESIZE - 1 | ||
103 | add r1, r1, #CACHE_LINESIZE | ||
104 | |||
105 | @ r0 va2pa r10 | ||
106 | mov r9, #PAGE_SZ | ||
107 | sub r9, r9, #1 @ PAGE_MASK | ||
108 | 101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA | ||
109 | b 103f | ||
110 | 102: cand.a r0, r9 | ||
111 | beq 101b | ||
112 | |||
113 | 103: movc p0.c5, r10, #11 @ Dcache clean line of R10 | ||
114 | nop8 | ||
115 | |||
116 | add r0, r0, #CACHE_LINESIZE | ||
117 | add r10, r10, #CACHE_LINESIZE | ||
118 | sub.a r1, r1, #CACHE_LINESIZE | ||
119 | bns 102b | ||
120 | b 3f | ||
121 | #endif | ||
122 | 2: mov ip, #0 | ||
123 | movc p0.c5, ip, #10 @ Dcache clean all | ||
124 | nop8 | ||
125 | |||
126 | 3: mov ip, #0 | ||
127 | movc p0.c5, ip, #20 @ Icache invalidate all | ||
128 | nop8 | ||
129 | |||
130 | mov pc, lr | ||
131 | |||
132 | /* | ||
133 | * __cpuc_flush_kern_dcache_area(void *addr, size_t size) | ||
134 | * | ||
135 | * - addr - kernel address | ||
136 | * - size - region size | ||
137 | */ | ||
138 | ENTRY(__cpuc_flush_kern_dcache_area) | ||
139 | mov ip, #0 | ||
140 | movc p0.c5, ip, #14 @ Dcache flush all | ||
141 | nop8 | ||
142 | mov pc, lr | ||
143 | |||
144 | /* | ||
145 | * __cpuc_dma_clean_range(start,end) | ||
146 | * - start - virtual start address of region | ||
147 | * - end - virtual end address of region | ||
148 | */ | ||
149 | ENTRY(__cpuc_dma_clean_range) | ||
150 | #ifndef CONFIG_CPU_DCACHE_LINE_DISABLE | ||
151 | andn r0, r0, #CACHE_LINESIZE - 1 | ||
152 | sub r1, r1, r0 | ||
153 | andn r1, r1, #CACHE_LINESIZE - 1 | ||
154 | add r1, r1, #CACHE_LINESIZE | ||
155 | |||
156 | csub.a r1, #MAX_AREA_SIZE | ||
157 | bsg 2f | ||
158 | |||
159 | @ r0 va2pa r10 | ||
160 | mov r9, #PAGE_SZ | ||
161 | sub r9, r9, #1 @ PAGE_MASK | ||
162 | 101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA | ||
163 | b 1f | ||
164 | 102: cand.a r0, r9 | ||
165 | beq 101b | ||
166 | |||
167 | 1: movc p0.c5, r10, #11 @ Dcache clean line of R10 | ||
168 | nop8 | ||
169 | add r0, r0, #CACHE_LINESIZE | ||
170 | add r10, r10, #CACHE_LINESIZE | ||
171 | sub.a r1, r1, #CACHE_LINESIZE | ||
172 | bns 102b | ||
173 | mov pc, lr | ||
174 | #endif | ||
175 | 2: mov ip, #0 | ||
176 | movc p0.c5, ip, #10 @ Dcache clean all | ||
177 | nop8 | ||
178 | |||
179 | mov pc, lr | ||
180 | |||
181 | /* | ||
182 | * __cpuc_dma_inv_range(start,end) | ||
183 | * __cpuc_dma_flush_range(start,end) | ||
184 | * - start - virtual start address of region | ||
185 | * - end - virtual end address of region | ||
186 | */ | ||
187 | __cpuc_dma_inv_range: | ||
188 | /* FALLTHROUGH */ | ||
189 | ENTRY(__cpuc_dma_flush_range) | ||
190 | #ifndef CONFIG_CPU_DCACHE_LINE_DISABLE | ||
191 | andn r0, r0, #CACHE_LINESIZE - 1 | ||
192 | sub r1, r1, r0 | ||
193 | andn r1, r1, #CACHE_LINESIZE - 1 | ||
194 | add r1, r1, #CACHE_LINESIZE | ||
195 | |||
196 | csub.a r1, #MAX_AREA_SIZE | ||
197 | bsg 2f | ||
198 | |||
199 | @ r0 va2pa r10 | ||
200 | 101: dcacheline_flush r0, r11, r12 | ||
201 | |||
202 | add r0, r0, #CACHE_LINESIZE | ||
203 | sub.a r1, r1, #CACHE_LINESIZE | ||
204 | bns 101b | ||
205 | mov pc, lr | ||
206 | #endif | ||
207 | 2: mov ip, #0 | ||
208 | movc p0.c5, ip, #14 @ Dcache flush all | ||
209 | nop8 | ||
210 | |||
211 | mov pc, lr | ||
212 | |||
diff --git a/arch/unicore32/mm/dma-swiotlb.c b/arch/unicore32/mm/dma-swiotlb.c new file mode 100644 index 00000000000..bfa9fbb2bbb --- /dev/null +++ b/arch/unicore32/mm/dma-swiotlb.c | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Contains routines needed to support swiotlb for UniCore32. | ||
3 | * | ||
4 | * Copyright (C) 2010 Guan Xuetao | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | #include <linux/pci.h> | ||
12 | #include <linux/cache.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/swiotlb.h> | ||
16 | #include <linux/bootmem.h> | ||
17 | |||
18 | #include <asm/dma.h> | ||
19 | |||
20 | struct dma_map_ops swiotlb_dma_map_ops = { | ||
21 | .alloc_coherent = swiotlb_alloc_coherent, | ||
22 | .free_coherent = swiotlb_free_coherent, | ||
23 | .map_sg = swiotlb_map_sg_attrs, | ||
24 | .unmap_sg = swiotlb_unmap_sg_attrs, | ||
25 | .dma_supported = swiotlb_dma_supported, | ||
26 | .map_page = swiotlb_map_page, | ||
27 | .unmap_page = swiotlb_unmap_page, | ||
28 | .sync_single_for_cpu = swiotlb_sync_single_for_cpu, | ||
29 | .sync_single_for_device = swiotlb_sync_single_for_device, | ||
30 | .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, | ||
31 | .sync_sg_for_device = swiotlb_sync_sg_for_device, | ||
32 | .mapping_error = swiotlb_dma_mapping_error, | ||
33 | }; | ||
34 | 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 00000000000..93478cc8b26 --- /dev/null +++ b/arch/unicore32/mm/flush.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/mm/flush.c | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/pagemap.h> | ||
15 | |||
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/system.h> | ||
18 | #include <asm/tlbflush.h> | ||
19 | |||
20 | void flush_cache_mm(struct mm_struct *mm) | ||
21 | { | ||
22 | } | ||
23 | |||
24 | void flush_cache_range(struct vm_area_struct *vma, unsigned long start, | ||
25 | unsigned long end) | ||
26 | { | ||
27 | if (vma->vm_flags & VM_EXEC) | ||
28 | __flush_icache_all(); | ||
29 | } | ||
30 | |||
31 | void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, | ||
32 | unsigned long pfn) | ||
33 | { | ||
34 | } | ||
35 | |||
36 | static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, | ||
37 | unsigned long uaddr, void *kaddr, unsigned long len) | ||
38 | { | ||
39 | /* VIPT non-aliasing D-cache */ | ||
40 | if (vma->vm_flags & VM_EXEC) { | ||
41 | unsigned long addr = (unsigned long)kaddr; | ||
42 | |||
43 | __cpuc_coherent_kern_range(addr, addr + len); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * Copy user data from/to a page which is mapped into a different | ||
49 | * processes address space. Really, we want to allow our "user | ||
50 | * space" model to handle this. | ||
51 | * | ||
52 | * Note that this code needs to run on the current CPU. | ||
53 | */ | ||
54 | void copy_to_user_page(struct vm_area_struct *vma, struct page *page, | ||
55 | unsigned long uaddr, void *dst, const void *src, | ||
56 | unsigned long len) | ||
57 | { | ||
58 | memcpy(dst, src, len); | ||
59 | flush_ptrace_access(vma, page, uaddr, dst, len); | ||
60 | } | ||
61 | |||
62 | void __flush_dcache_page(struct address_space *mapping, struct page *page) | ||
63 | { | ||
64 | /* | ||
65 | * Writeback any data associated with the kernel mapping of this | ||
66 | * page. This ensures that data in the physical page is mutually | ||
67 | * coherent with the kernels mapping. | ||
68 | */ | ||
69 | __cpuc_flush_kern_dcache_area(page_address(page), PAGE_SIZE); | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * Ensure cache coherency between kernel mapping and userspace mapping | ||
74 | * of this page. | ||
75 | */ | ||
76 | void flush_dcache_page(struct page *page) | ||
77 | { | ||
78 | struct address_space *mapping; | ||
79 | |||
80 | /* | ||
81 | * The zero page is never written to, so never has any dirty | ||
82 | * cache lines, and therefore never needs to be flushed. | ||
83 | */ | ||
84 | if (page == ZERO_PAGE(0)) | ||
85 | return; | ||
86 | |||
87 | mapping = page_mapping(page); | ||
88 | |||
89 | if (mapping && !mapping_mapped(mapping)) | ||
90 | clear_bit(PG_dcache_clean, &page->flags); | ||
91 | else { | ||
92 | __flush_dcache_page(mapping, page); | ||
93 | if (mapping) | ||
94 | __flush_icache_all(); | ||
95 | set_bit(PG_dcache_clean, &page->flags); | ||
96 | } | ||
97 | } | ||
98 | 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 00000000000..061d455f9a1 --- /dev/null +++ b/arch/unicore32/mm/tlb-ucv2.S | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/mm/tlb-ucv2.S | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/assembler.h> | ||
15 | #include <asm/page.h> | ||
16 | #include <asm/tlbflush.h> | ||
17 | #include "proc-macros.S" | ||
18 | |||
19 | /* | ||
20 | * __cpu_flush_user_tlb_range(start, end, vma) | ||
21 | * | ||
22 | * Invalidate a range of TLB entries in the specified address space. | ||
23 | * | ||
24 | * - start - start address (may not be aligned) | ||
25 | * - end - end address (exclusive, may not be aligned) | ||
26 | * - vma - vma_struct describing address range | ||
27 | */ | ||
28 | ENTRY(__cpu_flush_user_tlb_range) | ||
29 | #ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE | ||
30 | mov r0, r0 >> #PAGE_SHIFT @ align address | ||
31 | mov r0, r0 << #PAGE_SHIFT | ||
32 | vma_vm_flags r2, r2 @ get vma->vm_flags | ||
33 | 1: | ||
34 | movc p0.c6, r0, #3 | ||
35 | nop8 | ||
36 | |||
37 | cand.a r2, #VM_EXEC @ Executable area ? | ||
38 | beq 2f | ||
39 | |||
40 | movc p0.c6, r0, #5 | ||
41 | nop8 | ||
42 | 2: | ||
43 | add r0, r0, #PAGE_SZ | ||
44 | csub.a r0, r1 | ||
45 | beb 1b | ||
46 | #else | ||
47 | movc p0.c6, r0, #2 | ||
48 | nop8 | ||
49 | |||
50 | cand.a r2, #VM_EXEC @ Executable area ? | ||
51 | beq 2f | ||
52 | |||
53 | movc p0.c6, r0, #4 | ||
54 | nop8 | ||
55 | 2: | ||
56 | #endif | ||
57 | mov pc, lr | ||
58 | |||
59 | /* | ||
60 | * __cpu_flush_kern_tlb_range(start,end) | ||
61 | * | ||
62 | * Invalidate a range of kernel TLB entries | ||
63 | * | ||
64 | * - start - start address (may not be aligned) | ||
65 | * - end - end address (exclusive, may not be aligned) | ||
66 | */ | ||
67 | ENTRY(__cpu_flush_kern_tlb_range) | ||
68 | #ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE | ||
69 | mov r0, r0 >> #PAGE_SHIFT @ align address | ||
70 | mov r0, r0 << #PAGE_SHIFT | ||
71 | 1: | ||
72 | movc p0.c6, r0, #3 | ||
73 | nop8 | ||
74 | |||
75 | movc p0.c6, r0, #5 | ||
76 | nop8 | ||
77 | |||
78 | add r0, r0, #PAGE_SZ | ||
79 | csub.a r0, r1 | ||
80 | beb 1b | ||
81 | #else | ||
82 | movc p0.c6, r0, #2 | ||
83 | nop8 | ||
84 | |||
85 | movc p0.c6, r0, #4 | ||
86 | nop8 | ||
87 | #endif | ||
88 | mov pc, lr | ||
89 | |||