aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorMike Frysinger <vapier.adi@gmail.com>2008-10-16 11:01:24 -0400
committerBryan Wu <cooloney@kernel.org>2008-10-16 11:01:24 -0400
commitded963a486e08eb89a2c861c3323fe33abf2c6c8 (patch)
tree169f8f45d91ecc0740c2ce429029d5bda3958446 /arch/blackfin
parentf51501551ef5c3f3d3911fbd736664d614014344 (diff)
Blackfin arch: unify/cleanup cache code
- to be correct wrt to end ranges - to be optimal with a one-instruction hardware loop Signed-off-by: Mike Frysinger <vapier.adi@gmail.com> Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/mach-common/cache.S173
1 files changed, 58 insertions, 115 deletions
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
index 85f8c79b3c37..db532181fbde 100644
--- a/arch/blackfin/mach-common/cache.S
+++ b/arch/blackfin/mach-common/cache.S
@@ -1,148 +1,91 @@
1/* 1/*
2 * File: arch/blackfin/mach-common/cache.S 2 * Blackfin cache control code
3 * Based on:
4 * Author: LG Soft India
5 * 3 *
6 * Created: 4 * Copyright 2004-2008 Analog Devices Inc.
7 * Description: cache control support
8 * 5 *
9 * Modified: 6 * Enter bugs at http://blackfin.uclinux.org/
10 * Copyright 2004-2006 Analog Devices Inc.
11 * 7 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/ 8 * Licensed under the GPL-2 or later.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */ 9 */
29 10
30#include <linux/linkage.h> 11#include <linux/linkage.h>
31#include <asm/cplb.h>
32#include <asm/entry.h>
33#include <asm/blackfin.h> 12#include <asm/blackfin.h>
34#include <asm/cache.h> 13#include <asm/cache.h>
14#include <asm/page.h>
35 15
36.text 16.text
37 17
38/* 18/* Since all L1 caches work the same way, we use the same method for flushing
39 * blackfin_cache_flush_range(start, end) 19 * them. Only the actual flush instruction differs. We write this in asm as
40 * Invalidate all cache lines assocoiated with this 20 * GCC can be hard to coax into writing nice hardware loops.
41 * area of memory.
42 * 21 *
43 * start: Start address 22 * Also, we assume the following register setup:
44 * end: End address 23 * R0 = start address
24 * R1 = end address
45 */ 25 */
46ENTRY(_blackfin_icache_flush_range) 26.macro do_flush flushins:req optflushins optnopins label
27
28 /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */
29 R1 += -1;
47 R2 = -L1_CACHE_BYTES; 30 R2 = -L1_CACHE_BYTES;
48 R2 = R0 & R2; 31 R1 = R1 & R2;
49 P0 = R2; 32 R1 += L1_CACHE_BYTES;
50 P1 = R1; 33
51 CSYNC(R3); 34 /* count = (end - start) >> L1_CACHE_SHIFT */
52 IFLUSH [P0]; 35 R2 = R1 - R0;
36 R2 >>= L1_CACHE_SHIFT;
37 P1 = R2;
38
39.ifnb \label
40\label :
41.endif
42 P0 = R0;
43 LSETUP (1f, 2f) LC1 = P1;
531: 441:
54 IFLUSH [P0++]; 45.ifnb \optflushins
55 CC = P0 < P1 (iu); 46 \optflushins [P0];
56 IF CC JUMP 1b (bp); 47.endif
57 IFLUSH [P0]; 48.ifb \optnopins
58 SSYNC(R3); 492:
50.endif
51 \flushins [P0++];
52.ifnb \optnopins
532: \optnopins;
54.endif
55
59 RTS; 56 RTS;
60ENDPROC(_blackfin_icache_flush_range) 57.endm
61 58
62/* 59/* Invalidate all instruction cache lines assocoiated with this memory area */
63 * blackfin_icache_dcache_flush_range(start, end) 60ENTRY(_blackfin_icache_flush_range)
64 * FLUSH all cache lines assocoiated with this 61 do_flush IFLUSH, , nop
65 * area of memory. 62ENDPROC(_blackfin_icache_flush_range)
66 *
67 * start: Start address
68 * end: End address
69 */
70 63
64/* Flush all cache lines assocoiated with this area of memory. */
71ENTRY(_blackfin_icache_dcache_flush_range) 65ENTRY(_blackfin_icache_dcache_flush_range)
72 R2 = -L1_CACHE_BYTES; 66 do_flush IFLUSH, FLUSH
73 R2 = R0 & R2;
74 P0 = R2;
75 P1 = R1;
76 CSYNC(R3);
77 IFLUSH [P0];
781:
79 FLUSH [P0];
80 IFLUSH [P0++];
81 CC = P0 < P1 (iu);
82 IF CC JUMP 1b (bp);
83 IFLUSH [P0];
84 FLUSH [P0];
85 SSYNC(R3);
86 RTS;
87ENDPROC(_blackfin_icache_dcache_flush_range) 67ENDPROC(_blackfin_icache_dcache_flush_range)
88 68
89/* Throw away all D-cached data in specified region without any obligation to 69/* Throw away all D-cached data in specified region without any obligation to
90 * write them back. However, we must clean the D-cached entries around the 70 * write them back. Since the Blackfin ISA does not have an "invalidate"
91 * boundaries of the start and/or end address is not cache aligned. 71 * instruction, we use flush/invalidate. Perhaps as a speed optimization we
92 * 72 * could bang on the DTEST MMRs ...
93 * Start: start address,
94 * end : end address.
95 */ 73 */
96
97ENTRY(_blackfin_dcache_invalidate_range) 74ENTRY(_blackfin_dcache_invalidate_range)
98 R2 = -L1_CACHE_BYTES; 75 do_flush FLUSHINV
99 R2 = R0 & R2;
100 P0 = R2;
101 P1 = R1;
102 CSYNC(R3);
103 FLUSHINV[P0];
1041:
105 FLUSHINV[P0++];
106 CC = P0 < P1 (iu);
107 IF CC JUMP 1b (bp);
108
109 /* If the data crosses a cache line, then we'll be pointing to
110 * the last cache line, but won't have flushed/invalidated it yet,
111 * so do one more.
112 */
113 FLUSHINV[P0];
114 SSYNC(R3);
115 RTS;
116ENDPROC(_blackfin_dcache_invalidate_range) 76ENDPROC(_blackfin_dcache_invalidate_range)
117 77
78/* Flush all data cache lines assocoiated with this memory area */
118ENTRY(_blackfin_dcache_flush_range) 79ENTRY(_blackfin_dcache_flush_range)
119 R2 = -L1_CACHE_BYTES; 80 do_flush FLUSH, , , .Ldfr
120 R2 = R0 & R2;
121 P0 = R2;
122 P1 = R1;
123 CSYNC(R3);
124 FLUSH[P0];
1251:
126 FLUSH[P0++];
127 CC = P0 < P1 (iu);
128 IF CC JUMP 1b (bp);
129
130 /* If the data crosses a cache line, then we'll be pointing to
131 * the last cache line, but won't have flushed it yet, so do
132 * one more.
133 */
134 FLUSH[P0];
135 SSYNC(R3);
136 RTS;
137ENDPROC(_blackfin_dcache_flush_range) 81ENDPROC(_blackfin_dcache_flush_range)
138 82
83/* Our headers convert the page structure to an address, so just need to flush
84 * its contents like normal. We know the start address is page aligned (which
85 * greater than our cache alignment), as is the end address. So just jump into
86 * the middle of the dcache flush function.
87 */
139ENTRY(_blackfin_dflush_page) 88ENTRY(_blackfin_dflush_page)
140 P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); 89 P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
141 P0 = R0; 90 jump .Ldfr;
142 CSYNC(R3);
143 FLUSH[P0];
144 LSETUP (.Lfl1, .Lfl1) LC0 = P1;
145.Lfl1: FLUSH [P0++];
146 SSYNC(R3);
147 RTS;
148ENDPROC(_blackfin_dflush_page) 91ENDPROC(_blackfin_dflush_page)