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 39mn10300_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 80mn10300_icache_inv_end: 81 ret [],0 82 83############################################################################### 84# 85# void mn10300_dcache_inv(void) 86# Invalidate the entire dcache 87# 88############################################################################### 89 ALIGN 90mn10300_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 131mn10300_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 143mn10300_dcache_inv_page: 144 mov PAGE_SIZE,d1 145mn10300_dcache_inv_range2: 146 add d0,d1 147mn10300_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 179mn10300_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 199mn10300_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 213mn10300_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 227mn10300_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 241mn10300_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 255mn10300_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 288mn10300_dcache_inv_range_end: 289 ret [d2,d3,a2],12 290