ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / v850 / kernel / v850e2_cache.c
1 /*
2  * arch/v850/kernel/v850e2_cache.c -- Cache control for V850E2 cache
3  *      memories
4  *
5  *  Copyright (C) 2003  NEC Electronics Corporation
6  *  Copyright (C) 2003  Miles Bader <miles@gnu.org>
7  *
8  * This file is subject to the terms and conditions of the GNU General
9  * Public License.  See the file COPYING in the main directory of this
10  * archive for more details.
11  *
12  * Written by Miles Bader <miles@gnu.org>
13  */
14
15 #include <linux/mm.h>
16
17 #include <asm/v850e2_cache.h>
18
19 /* Cache operations we can do.  The encoding corresponds directly to the
20    value we need to write into the COPR register.  */
21 enum cache_op {
22         OP_SYNC_IF_DIRTY           = V850E2_CACHE_COPR_CFC(0), /* 000 */
23         OP_SYNC_IF_VALID           = V850E2_CACHE_COPR_CFC(1), /* 001 */
24         OP_SYNC_IF_VALID_AND_CLEAR = V850E2_CACHE_COPR_CFC(3), /* 011 */
25         OP_WAY_CLEAR               = V850E2_CACHE_COPR_CFC(4), /* 100 */
26         OP_FILL                    = V850E2_CACHE_COPR_CFC(5), /* 101 */
27         OP_CLEAR                   = V850E2_CACHE_COPR_CFC(6), /* 110 */
28         OP_CREATE_DIRTY            = V850E2_CACHE_COPR_CFC(7)  /* 111 */
29 };
30
31 /* Which cache to use.  This encoding also corresponds directly to the
32    value we need to write into the COPR register. */
33 enum cache {
34         ICACHE = 0,
35         DCACHE = V850E2_CACHE_COPR_LBSL
36 };
37
38 /* Returns ADDR rounded down to the beginning of its cache-line.  */
39 #define CACHE_LINE_ADDR(addr)  \
40    ((addr) & ~(V850E2_CACHE_LINE_SIZE - 1))
41 /* Returns END_ADDR rounded up to the `limit' of its cache-line.  */
42 #define CACHE_LINE_END_ADDR(end_addr)  \
43    CACHE_LINE_ADDR(end_addr + (V850E2_CACHE_LINE_SIZE - 1))
44
45 \f
46 /* Low-level cache ops.  */
47
48 /* Apply cache-op OP to all entries in CACHE.  */
49 static inline void cache_op_all (enum cache_op op, enum cache cache)
50 {
51         int cmd = op | cache | V850E2_CACHE_COPR_WSLE | V850E2_CACHE_COPR_STRT;
52
53         if (op != OP_WAY_CLEAR) {
54                 /* The WAY_CLEAR operation does the whole way, but other
55                    ops take begin-index and count params; we just indicate
56                    the entire cache.  */
57                 V850E2_CACHE_CADL = 0;
58                 V850E2_CACHE_CADH = 0;
59                 V850E2_CACHE_CCNT = V850E2_CACHE_WAY_SIZE - 1;
60         }
61
62         V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(0); /* way 0 */
63         V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(1); /* way 1 */
64         V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(2); /* way 2 */
65         V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(3); /* way 3 */
66 }
67
68 /* Apply cache-op OP to all entries in CACHE covering addresses ADDR
69    through ADDR+LEN.  */
70 static inline void cache_op_range (enum cache_op op, u32 addr, u32 len,
71                                    enum cache cache)
72 {
73         u32 start = CACHE_LINE_ADDR (addr);
74         u32 end = CACHE_LINE_END_ADDR (addr + len);
75         u32 num_lines = (end - start) >> V850E2_CACHE_LINE_SIZE_BITS;
76
77         V850E2_CACHE_CADL = start & 0xFFFF;
78         V850E2_CACHE_CADH = start >> 16;
79         V850E2_CACHE_CCNT = num_lines - 1;
80
81         V850E2_CACHE_COPR = op | cache | V850E2_CACHE_COPR_STRT;
82 }
83
84 \f
85 /* High-level ops.  */
86
87 static void cache_exec_after_store_all (void)
88 {
89         cache_op_all (OP_SYNC_IF_DIRTY, DCACHE);
90         cache_op_all (OP_WAY_CLEAR, ICACHE);
91 }
92
93 static void cache_exec_after_store_range (u32 start, u32 len)
94 {
95         cache_op_range (OP_SYNC_IF_DIRTY, start, len, DCACHE);
96         cache_op_range (OP_CLEAR, start, len, ICACHE);
97 }
98
99 \f
100 /* Exported functions.  */
101
102 void flush_icache (void)
103 {
104         cache_exec_after_store_all ();
105 }
106
107 void flush_icache_range (unsigned long start, unsigned long end)
108 {
109         cache_exec_after_store_range (start, end - start);
110 }
111
112 void flush_icache_page (struct vm_area_struct *vma, struct page *page)
113 {
114         cache_exec_after_store_range (page_to_virt (page), PAGE_SIZE);
115 }
116
117 void flush_icache_user_range (struct vm_area_struct *vma, struct page *page,
118                               unsigned long addr, int len)
119 {
120         cache_exec_after_store_range (addr, len);
121 }
122
123 void flush_cache_sigtramp (unsigned long addr)
124 {
125         /* For the exact size, see signal.c, but 16 bytes should be enough.  */
126         cache_exec_after_store_range (addr, 16);
127 }