| David Howells | b920de1 | 2008-02-08 04:19:31 -0800 | [diff] [blame] | 1 | /* MN10300 CPU core caching routines | 
|  | 2 | * | 
|  | 3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 
|  | 4 | * Written by David Howells (dhowells@redhat.com) | 
|  | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or | 
|  | 7 | * modify it under the terms of the GNU General Public Licence | 
|  | 8 | * as published by the Free Software Foundation; either version | 
|  | 9 | * 2 of the Licence, or (at your option) any later version. | 
|  | 10 | */ | 
|  | 11 | #include <linux/sys.h> | 
|  | 12 | #include <linux/linkage.h> | 
|  | 13 | #include <asm/smp.h> | 
|  | 14 | #include <asm/page.h> | 
|  | 15 | #include <asm/cache.h> | 
|  | 16 |  | 
|  | 17 | #define mn10300_dcache_inv_range_intr_interval \ | 
|  | 18 | +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) | 
|  | 19 |  | 
|  | 20 | #if mn10300_dcache_inv_range_intr_interval > 0xff | 
|  | 21 | #error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less | 
|  | 22 | #endif | 
|  | 23 |  | 
|  | 24 | .am33_2 | 
|  | 25 |  | 
|  | 26 | .globl mn10300_icache_inv | 
|  | 27 | .globl mn10300_dcache_inv | 
|  | 28 | .globl mn10300_dcache_inv_range | 
|  | 29 | .globl mn10300_dcache_inv_range2 | 
|  | 30 | .globl mn10300_dcache_inv_page | 
|  | 31 |  | 
|  | 32 | ############################################################################### | 
|  | 33 | # | 
|  | 34 | # void mn10300_icache_inv(void) | 
|  | 35 | # Invalidate the entire icache | 
|  | 36 | # | 
|  | 37 | ############################################################################### | 
|  | 38 | ALIGN | 
|  | 39 | mn10300_icache_inv: | 
|  | 40 | mov	CHCTR,a0 | 
|  | 41 |  | 
|  | 42 | movhu	(a0),d0 | 
|  | 43 | btst	CHCTR_ICEN,d0 | 
|  | 44 | beq	mn10300_icache_inv_end | 
|  | 45 |  | 
|  | 46 | mov	epsw,d1 | 
|  | 47 | and	~EPSW_IE,epsw | 
|  | 48 | nop | 
|  | 49 | nop | 
|  | 50 |  | 
|  | 51 | # disable the icache | 
|  | 52 | and	~CHCTR_ICEN,d0 | 
|  | 53 | movhu	d0,(a0) | 
|  | 54 |  | 
|  | 55 | # and wait for it to calm down | 
|  | 56 | setlb | 
|  | 57 | movhu	(a0),d0 | 
|  | 58 | btst	CHCTR_ICBUSY,d0 | 
|  | 59 | lne | 
|  | 60 |  | 
|  | 61 | # invalidate | 
|  | 62 | or	CHCTR_ICINV,d0 | 
|  | 63 | movhu	d0,(a0) | 
|  | 64 |  | 
|  | 65 | # wait for the cache to finish | 
|  | 66 | mov	CHCTR,a0 | 
|  | 67 | setlb | 
|  | 68 | movhu	(a0),d0 | 
|  | 69 | btst	CHCTR_ICBUSY,d0 | 
|  | 70 | lne | 
|  | 71 |  | 
|  | 72 | # and reenable it | 
|  | 73 | and	~CHCTR_ICINV,d0 | 
|  | 74 | or	CHCTR_ICEN,d0 | 
|  | 75 | movhu	d0,(a0) | 
|  | 76 | movhu	(a0),d0 | 
|  | 77 |  | 
|  | 78 | mov	d1,epsw | 
|  | 79 |  | 
|  | 80 | mn10300_icache_inv_end: | 
|  | 81 | ret	[],0 | 
|  | 82 |  | 
|  | 83 | ############################################################################### | 
|  | 84 | # | 
|  | 85 | # void mn10300_dcache_inv(void) | 
|  | 86 | # Invalidate the entire dcache | 
|  | 87 | # | 
|  | 88 | ############################################################################### | 
|  | 89 | ALIGN | 
|  | 90 | mn10300_dcache_inv: | 
|  | 91 | mov	CHCTR,a0 | 
|  | 92 |  | 
|  | 93 | movhu	(a0),d0 | 
|  | 94 | btst	CHCTR_DCEN,d0 | 
|  | 95 | beq	mn10300_dcache_inv_end | 
|  | 96 |  | 
|  | 97 | mov	epsw,d1 | 
|  | 98 | and	~EPSW_IE,epsw | 
|  | 99 | nop | 
|  | 100 | nop | 
|  | 101 |  | 
|  | 102 | # disable the dcache | 
|  | 103 | and	~CHCTR_DCEN,d0 | 
|  | 104 | movhu	d0,(a0) | 
|  | 105 |  | 
|  | 106 | # and wait for it to calm down | 
|  | 107 | setlb | 
|  | 108 | movhu	(a0),d0 | 
|  | 109 | btst	CHCTR_DCBUSY,d0 | 
|  | 110 | lne | 
|  | 111 |  | 
|  | 112 | # invalidate | 
|  | 113 | or	CHCTR_DCINV,d0 | 
|  | 114 | movhu	d0,(a0) | 
|  | 115 |  | 
|  | 116 | # wait for the cache to finish | 
|  | 117 | mov	CHCTR,a0 | 
|  | 118 | setlb | 
|  | 119 | movhu	(a0),d0 | 
|  | 120 | btst	CHCTR_DCBUSY,d0 | 
|  | 121 | lne | 
|  | 122 |  | 
|  | 123 | # and reenable it | 
|  | 124 | and	~CHCTR_DCINV,d0 | 
|  | 125 | or	CHCTR_DCEN,d0 | 
|  | 126 | movhu	d0,(a0) | 
|  | 127 | movhu	(a0),d0 | 
|  | 128 |  | 
|  | 129 | mov	d1,epsw | 
|  | 130 |  | 
|  | 131 | mn10300_dcache_inv_end: | 
|  | 132 | ret	[],0 | 
|  | 133 |  | 
|  | 134 | ############################################################################### | 
|  | 135 | # | 
|  | 136 | # void mn10300_dcache_inv_range(unsigned start, unsigned end) | 
|  | 137 | # void mn10300_dcache_inv_range2(unsigned start, unsigned size) | 
|  | 138 | # void mn10300_dcache_inv_page(unsigned start) | 
|  | 139 | # Invalidate a range of addresses on a page in the dcache | 
|  | 140 | # | 
|  | 141 | ############################################################################### | 
|  | 142 | ALIGN | 
|  | 143 | mn10300_dcache_inv_page: | 
|  | 144 | mov	PAGE_SIZE,d1 | 
|  | 145 | mn10300_dcache_inv_range2: | 
|  | 146 | add	d0,d1 | 
|  | 147 | mn10300_dcache_inv_range: | 
|  | 148 | movm	[d2,d3,a2],(sp) | 
|  | 149 | mov	CHCTR,a2 | 
|  | 150 |  | 
|  | 151 | movhu	(a2),d2 | 
|  | 152 | btst	CHCTR_DCEN,d2 | 
|  | 153 | beq	mn10300_dcache_inv_range_end | 
|  | 154 |  | 
|  | 155 | and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0	# round start | 
|  | 156 | # addr down | 
|  | 157 | mov	d0,a1 | 
|  | 158 |  | 
|  | 159 | add	L1_CACHE_BYTES,d1			# round end addr up | 
|  | 160 | and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | 
|  | 161 |  | 
|  | 162 | clr	d2				# we're going to clear tag ram | 
|  | 163 | # entries | 
|  | 164 |  | 
|  | 165 | # read the tags from the tag RAM, and if they indicate a valid dirty | 
|  | 166 | # cache line then invalidate that line | 
|  | 167 | mov	DCACHE_TAG(0,0),a0 | 
|  | 168 | mov	a1,d0 | 
|  | 169 | and	L1_CACHE_TAG_ENTRY,d0 | 
|  | 170 | add	d0,a0				# starting dcache tag RAM | 
|  | 171 | # access address | 
|  | 172 |  | 
|  | 173 | sub	a1,d1 | 
|  | 174 | lsr	L1_CACHE_SHIFT,d1		# total number of entries to | 
|  | 175 | # examine | 
|  | 176 |  | 
|  | 177 | and	~(L1_CACHE_DISPARITY-1),a1	# determine comparator base | 
|  | 178 |  | 
|  | 179 | mn10300_dcache_inv_range_outer_loop: | 
|  | 180 | # disable interrupts | 
|  | 181 | mov	epsw,d3 | 
|  | 182 | and	~EPSW_IE,epsw | 
|  | 183 | nop					# note that reading CHCTR and | 
|  | 184 | # AND'ing D0 occupy two delay | 
|  | 185 | # slots after disabling | 
|  | 186 | # interrupts | 
|  | 187 |  | 
|  | 188 | # disable the dcache | 
|  | 189 | movhu	(a2),d0 | 
|  | 190 | and	~CHCTR_DCEN,d0 | 
|  | 191 | movhu	d0,(a2) | 
|  | 192 |  | 
|  | 193 | # and wait for it to calm down | 
|  | 194 | setlb | 
|  | 195 | movhu	(a2),d0 | 
|  | 196 | btst	CHCTR_DCBUSY,d0 | 
|  | 197 | lne | 
|  | 198 |  | 
|  | 199 | mn10300_dcache_inv_range_loop: | 
|  | 200 |  | 
|  | 201 | # process the way 0 slot | 
|  | 202 | mov	(L1_CACHE_WAYDISP*0,a0),d0	# read the tag in the way 0 slot | 
|  | 203 | btst	L1_CACHE_TAG_VALID,d0 | 
|  | 204 | beq	mn10300_dcache_inv_range_skip_0	# jump if this cacheline is not | 
|  | 205 | # valid | 
|  | 206 |  | 
|  | 207 | xor	a1,d0 | 
|  | 208 | lsr	12,d0 | 
|  | 209 | bne	mn10300_dcache_inv_range_skip_0	# jump if not this cacheline | 
|  | 210 |  | 
|  | 211 | mov	d2,(a0)				# kill the tag | 
|  | 212 |  | 
|  | 213 | mn10300_dcache_inv_range_skip_0: | 
|  | 214 |  | 
|  | 215 | # process the way 1 slot | 
|  | 216 | mov	(L1_CACHE_WAYDISP*1,a0),d0	# read the tag in the way 1 slot | 
|  | 217 | btst	L1_CACHE_TAG_VALID,d0 | 
|  | 218 | beq	mn10300_dcache_inv_range_skip_1	# jump if this cacheline is not | 
|  | 219 | # valid | 
|  | 220 |  | 
|  | 221 | xor	a1,d0 | 
|  | 222 | lsr	12,d0 | 
|  | 223 | bne	mn10300_dcache_inv_range_skip_1	# jump if not this cacheline | 
|  | 224 |  | 
|  | 225 | mov	d2,(a0)				# kill the tag | 
|  | 226 |  | 
|  | 227 | mn10300_dcache_inv_range_skip_1: | 
|  | 228 |  | 
|  | 229 | # process the way 2 slot | 
|  | 230 | mov	(L1_CACHE_WAYDISP*2,a0),d0	# read the tag in the way 2 slot | 
|  | 231 | btst	L1_CACHE_TAG_VALID,d0 | 
|  | 232 | beq	mn10300_dcache_inv_range_skip_2	# jump if this cacheline is not | 
|  | 233 | # valid | 
|  | 234 |  | 
|  | 235 | xor	a1,d0 | 
|  | 236 | lsr	12,d0 | 
|  | 237 | bne	mn10300_dcache_inv_range_skip_2	# jump if not this cacheline | 
|  | 238 |  | 
|  | 239 | mov	d2,(a0)				# kill the tag | 
|  | 240 |  | 
|  | 241 | mn10300_dcache_inv_range_skip_2: | 
|  | 242 |  | 
|  | 243 | # process the way 3 slot | 
|  | 244 | mov	(L1_CACHE_WAYDISP*3,a0),d0	# read the tag in the way 3 slot | 
|  | 245 | btst	L1_CACHE_TAG_VALID,d0 | 
|  | 246 | beq	mn10300_dcache_inv_range_skip_3	# jump if this cacheline is not | 
|  | 247 | # valid | 
|  | 248 |  | 
|  | 249 | xor	a1,d0 | 
|  | 250 | lsr	12,d0 | 
|  | 251 | bne	mn10300_dcache_inv_range_skip_3	# jump if not this cacheline | 
|  | 252 |  | 
|  | 253 | mov	d2,(a0)				# kill the tag | 
|  | 254 |  | 
|  | 255 | mn10300_dcache_inv_range_skip_3: | 
|  | 256 |  | 
|  | 257 | # approx every N steps we re-enable the cache and see if there are any | 
|  | 258 | # interrupts to be processed | 
|  | 259 | # we also break out if we've reached the end of the loop | 
|  | 260 | # (the bottom nibble of the count is zero in both cases) | 
|  | 261 | add	L1_CACHE_BYTES,a0 | 
|  | 262 | add	L1_CACHE_BYTES,a1 | 
|  | 263 | add	-1,d1 | 
|  | 264 | btst	mn10300_dcache_inv_range_intr_interval,d1 | 
|  | 265 | bne	mn10300_dcache_inv_range_loop | 
|  | 266 |  | 
|  | 267 | # wait for the cache to finish what it's doing | 
|  | 268 | setlb | 
|  | 269 | movhu	(a2),d0 | 
|  | 270 | btst	CHCTR_DCBUSY,d0 | 
|  | 271 | lne | 
|  | 272 |  | 
|  | 273 | # and reenable it | 
|  | 274 | or	CHCTR_DCEN,d0 | 
|  | 275 | movhu	d0,(a2) | 
|  | 276 | movhu	(a2),d0 | 
|  | 277 |  | 
|  | 278 | # re-enable interrupts | 
|  | 279 | # - we don't bother with delay NOPs as we'll have enough instructions | 
|  | 280 | #   before we disable interrupts again to give the interrupts a chance | 
|  | 281 | #   to happen | 
|  | 282 | mov	d3,epsw | 
|  | 283 |  | 
|  | 284 | # go around again if the counter hasn't yet reached zero | 
|  | 285 | add	0,d1 | 
|  | 286 | bne	mn10300_dcache_inv_range_outer_loop | 
|  | 287 |  | 
|  | 288 | mn10300_dcache_inv_range_end: | 
|  | 289 | ret	[d2,d3,a2],12 |