arch/tile: core support for Tilera 32-bit chips.
[linux-2.6-block.git] / arch / tile / include / asm / cacheflush.h
1 /*
2  * Copyright 2010 Tilera Corporation. All Rights Reserved.
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful, but
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  *   NON INFRINGEMENT.  See the GNU General Public License for
12  *   more details.
13  */
14
15 #ifndef _ASM_TILE_CACHEFLUSH_H
16 #define _ASM_TILE_CACHEFLUSH_H
17
18 #include <arch/chip.h>
19
20 /* Keep includes the same across arches.  */
21 #include <linux/mm.h>
22 #include <linux/cache.h>
23 #include <asm/system.h>
24
25 /* Caches are physically-indexed and so don't need special treatment */
26 #define flush_cache_all()                       do { } while (0)
27 #define flush_cache_mm(mm)                      do { } while (0)
28 #define flush_cache_dup_mm(mm)                  do { } while (0)
29 #define flush_cache_range(vma, start, end)      do { } while (0)
30 #define flush_cache_page(vma, vmaddr, pfn)      do { } while (0)
31 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
32 #define flush_dcache_page(page)                 do { } while (0)
33 #define flush_dcache_mmap_lock(mapping)         do { } while (0)
34 #define flush_dcache_mmap_unlock(mapping)       do { } while (0)
35 #define flush_cache_vmap(start, end)            do { } while (0)
36 #define flush_cache_vunmap(start, end)          do { } while (0)
37 #define flush_icache_page(vma, pg)              do { } while (0)
38 #define flush_icache_user_range(vma, pg, adr, len)      do { } while (0)
39
40 /* See "arch/tile/lib/__invalidate_icache.S". */
41 extern void __invalidate_icache(unsigned long start, unsigned long size);
42
43 /* Flush the icache just on this cpu */
44 static inline void __flush_icache_range(unsigned long start, unsigned long end)
45 {
46         __invalidate_icache(start, end - start);
47 }
48
49 /* Flush the entire icache on this cpu. */
50 #define __flush_icache() __flush_icache_range(0, CHIP_L1I_CACHE_SIZE())
51
52 #ifdef CONFIG_SMP
53 /*
54  * When the kernel writes to its own text we need to do an SMP
55  * broadcast to make the L1I coherent everywhere.  This includes
56  * module load and single step.
57  */
58 extern void flush_icache_range(unsigned long start, unsigned long end);
59 #else
60 #define flush_icache_range __flush_icache_range
61 #endif
62
63 /*
64  * An update to an executable user page requires icache flushing.
65  * We could carefully update only tiles that are running this process,
66  * and rely on the fact that we flush the icache on every context
67  * switch to avoid doing extra work here.  But for now, I'll be
68  * conservative and just do a global icache flush.
69  */
70 static inline void copy_to_user_page(struct vm_area_struct *vma,
71                                      struct page *page, unsigned long vaddr,
72                                      void *dst, void *src, int len)
73 {
74         memcpy(dst, src, len);
75         if (vma->vm_flags & VM_EXEC) {
76                 flush_icache_range((unsigned long) dst,
77                                    (unsigned long) dst + len);
78         }
79 }
80
81 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
82         memcpy((dst), (src), (len))
83
84 /*
85  * Invalidate a VA range; pads to L2 cacheline boundaries.
86  *
87  * Note that on TILE64, __inv_buffer() actually flushes modified
88  * cache lines in addition to invalidating them, i.e., it's the
89  * same as __finv_buffer().
90  */
91 static inline void __inv_buffer(void *buffer, size_t size)
92 {
93         char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
94         char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
95         while (next < finish) {
96                 __insn_inv(next);
97                 next += CHIP_INV_STRIDE();
98         }
99 }
100
101 /* Flush a VA range; pads to L2 cacheline boundaries. */
102 static inline void __flush_buffer(void *buffer, size_t size)
103 {
104         char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
105         char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
106         while (next < finish) {
107                 __insn_flush(next);
108                 next += CHIP_FLUSH_STRIDE();
109         }
110 }
111
112 /* Flush & invalidate a VA range; pads to L2 cacheline boundaries. */
113 static inline void __finv_buffer(void *buffer, size_t size)
114 {
115         char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
116         char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
117         while (next < finish) {
118                 __insn_finv(next);
119                 next += CHIP_FINV_STRIDE();
120         }
121 }
122
123
124 /* Invalidate a VA range, then memory fence. */
125 static inline void inv_buffer(void *buffer, size_t size)
126 {
127         __inv_buffer(buffer, size);
128         mb_incoherent();
129 }
130
131 /* Flush a VA range, then memory fence. */
132 static inline void flush_buffer(void *buffer, size_t size)
133 {
134         __flush_buffer(buffer, size);
135         mb_incoherent();
136 }
137
138 /* Flush & invalidate a VA range, then memory fence. */
139 static inline void finv_buffer(void *buffer, size_t size)
140 {
141         __finv_buffer(buffer, size);
142         mb_incoherent();
143 }
144
145 #endif /* _ASM_TILE_CACHEFLUSH_H */