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#include <asm/irqflags.h> 17#include <asm/cacheflush.h> 18#include "cache.inc" 19 20#define mn10300_local_dcache_inv_range_intr_interval \ 21 +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) 22 23#if mn10300_local_dcache_inv_range_intr_interval > 0xff 24#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less 25#endif 26 27 .am33_2 28 29 .globl mn10300_local_icache_inv_page 30 .globl mn10300_local_icache_inv_range 31 .globl mn10300_local_icache_inv_range2 32 33mn10300_local_icache_inv_page = mn10300_local_icache_inv 34mn10300_local_icache_inv_range = mn10300_local_icache_inv 35mn10300_local_icache_inv_range2 = mn10300_local_icache_inv 36 37#ifndef CONFIG_SMP 38 .globl mn10300_icache_inv 39 .globl mn10300_icache_inv_page 40 .globl mn10300_icache_inv_range 41 .globl mn10300_icache_inv_range2 42 .globl mn10300_dcache_inv 43 .globl mn10300_dcache_inv_page 44 .globl mn10300_dcache_inv_range 45 .globl mn10300_dcache_inv_range2 46 47mn10300_icache_inv = mn10300_local_icache_inv 48mn10300_icache_inv_page = mn10300_local_icache_inv_page 49mn10300_icache_inv_range = mn10300_local_icache_inv_range 50mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2 51mn10300_dcache_inv = mn10300_local_dcache_inv 52mn10300_dcache_inv_page = mn10300_local_dcache_inv_page 53mn10300_dcache_inv_range = mn10300_local_dcache_inv_range 54mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2 55 56#endif /* !CONFIG_SMP */ 57 58############################################################################### 59# 60# void mn10300_local_icache_inv(void) 61# Invalidate the entire icache 62# 63############################################################################### 64 ALIGN 65 .globl mn10300_local_icache_inv 66 .type mn10300_local_icache_inv,@function 67mn10300_local_icache_inv: 68 mov CHCTR,a0 69 70 movhu (a0),d0 71 btst CHCTR_ICEN,d0 72 beq mn10300_local_icache_inv_end 73 74 invalidate_icache 1 75 76mn10300_local_icache_inv_end: 77 ret [],0 78 .size mn10300_local_icache_inv,.-mn10300_local_icache_inv 79 80############################################################################### 81# 82# void mn10300_local_dcache_inv(void) 83# Invalidate the entire dcache 84# 85############################################################################### 86 ALIGN 87 .globl mn10300_local_dcache_inv 88 .type mn10300_local_dcache_inv,@function 89mn10300_local_dcache_inv: 90 mov CHCTR,a0 91 92 movhu (a0),d0 93 btst CHCTR_DCEN,d0 94 beq mn10300_local_dcache_inv_end 95 96 invalidate_dcache 1 97 98mn10300_local_dcache_inv_end: 99 ret [],0 100 .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv 101 102############################################################################### 103# 104# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end) 105# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size) 106# void mn10300_local_dcache_inv_page(unsigned long start) 107# Invalidate a range of addresses on a page in the dcache 108# 109############################################################################### 110 ALIGN 111 .globl mn10300_local_dcache_inv_page 112 .globl mn10300_local_dcache_inv_range 113 .globl mn10300_local_dcache_inv_range2 114 .type mn10300_local_dcache_inv_page,@function 115 .type mn10300_local_dcache_inv_range,@function 116 .type mn10300_local_dcache_inv_range2,@function 117mn10300_local_dcache_inv_page: 118 and ~(PAGE_SIZE-1),d0 119 mov PAGE_SIZE,d1 120mn10300_local_dcache_inv_range2: 121 add d0,d1 122mn10300_local_dcache_inv_range: 123 # If we are in writeback mode we check the start and end alignments, 124 # and if they're not cacheline-aligned, we must flush any bits outside 125 # the range that share cachelines with stuff inside the range 126#ifdef CONFIG_MN10300_CACHE_WBACK 127 btst ~L1_CACHE_TAG_MASK,d0 128 bne 1f 129 btst ~L1_CACHE_TAG_MASK,d1 130 beq 2f 1311: 132 bra mn10300_local_dcache_flush_inv_range 1332: 134#endif /* CONFIG_MN10300_CACHE_WBACK */ 135 136 movm [d2,d3,a2],(sp) 137 138 mov CHCTR,a2 139 movhu (a2),d2 140 btst CHCTR_DCEN,d2 141 beq mn10300_local_dcache_inv_range_end 142 143#ifndef CONFIG_MN10300_CACHE_WBACK 144 and L1_CACHE_TAG_MASK,d0 # round start addr down 145 146 add L1_CACHE_BYTES,d1 # round end addr up 147 and L1_CACHE_TAG_MASK,d1 148#endif /* !CONFIG_MN10300_CACHE_WBACK */ 149 mov d0,a1 150 151 clr d2 # we're going to clear tag RAM 152 # entries 153 154 # read the tags from the tag RAM, and if they indicate a valid dirty 155 # cache line then invalidate that line 156 mov DCACHE_TAG(0,0),a0 157 mov a1,d0 158 and L1_CACHE_TAG_ENTRY,d0 159 add d0,a0 # starting dcache tag RAM 160 # access address 161 162 sub a1,d1 163 lsr L1_CACHE_SHIFT,d1 # total number of entries to 164 # examine 165 166 and ~(L1_CACHE_DISPARITY-1),a1 # determine comparator base 167 168mn10300_local_dcache_inv_range_outer_loop: 169 LOCAL_CLI_SAVE(d3) 170 171 # disable the dcache 172 movhu (a2),d0 173 and ~CHCTR_DCEN,d0 174 movhu d0,(a2) 175 176 # and wait for it to calm down 177 setlb 178 movhu (a2),d0 179 btst CHCTR_DCBUSY,d0 180 lne 181 182mn10300_local_dcache_inv_range_loop: 183 184 # process the way 0 slot 185 mov (L1_CACHE_WAYDISP*0,a0),d0 # read the tag in the way 0 slot 186 btst L1_CACHE_TAG_VALID,d0 187 beq mn10300_local_dcache_inv_range_skip_0 # jump if this cacheline 188 # is not valid 189 190 xor a1,d0 191 lsr 12,d0 192 bne mn10300_local_dcache_inv_range_skip_0 # jump if not this cacheline 193 194 mov d2,(L1_CACHE_WAYDISP*0,a0) # kill the tag 195 196mn10300_local_dcache_inv_range_skip_0: 197 198 # process the way 1 slot 199 mov (L1_CACHE_WAYDISP*1,a0),d0 # read the tag in the way 1 slot 200 btst L1_CACHE_TAG_VALID,d0 201 beq mn10300_local_dcache_inv_range_skip_1 # jump if this cacheline 202 # is not valid 203 204 xor a1,d0 205 lsr 12,d0 206 bne mn10300_local_dcache_inv_range_skip_1 # jump if not this cacheline 207 208 mov d2,(L1_CACHE_WAYDISP*1,a0) # kill the tag 209 210mn10300_local_dcache_inv_range_skip_1: 211 212 # process the way 2 slot 213 mov (L1_CACHE_WAYDISP*2,a0),d0 # read the tag in the way 2 slot 214 btst L1_CACHE_TAG_VALID,d0 215 beq mn10300_local_dcache_inv_range_skip_2 # jump if this cacheline 216 # is not valid 217 218 xor a1,d0 219 lsr 12,d0 220 bne mn10300_local_dcache_inv_range_skip_2 # jump if not this cacheline 221 222 mov d2,(L1_CACHE_WAYDISP*2,a0) # kill the tag 223 224mn10300_local_dcache_inv_range_skip_2: 225 226 # process the way 3 slot 227 mov (L1_CACHE_WAYDISP*3,a0),d0 # read the tag in the way 3 slot 228 btst L1_CACHE_TAG_VALID,d0 229 beq mn10300_local_dcache_inv_range_skip_3 # jump if this cacheline 230 # is not valid 231 232 xor a1,d0 233 lsr 12,d0 234 bne mn10300_local_dcache_inv_range_skip_3 # jump if not this cacheline 235 236 mov d2,(L1_CACHE_WAYDISP*3,a0) # kill the tag 237 238mn10300_local_dcache_inv_range_skip_3: 239 240 # approx every N steps we re-enable the cache and see if there are any 241 # interrupts to be processed 242 # we also break out if we've reached the end of the loop 243 # (the bottom nibble of the count is zero in both cases) 244 add L1_CACHE_BYTES,a0 245 add L1_CACHE_BYTES,a1 246 and ~L1_CACHE_WAYDISP,a0 247 add -1,d1 248 btst mn10300_local_dcache_inv_range_intr_interval,d1 249 bne mn10300_local_dcache_inv_range_loop 250 251 # wait for the cache to finish what it's doing 252 setlb 253 movhu (a2),d0 254 btst CHCTR_DCBUSY,d0 255 lne 256 257 # and reenable it 258 or CHCTR_DCEN,d0 259 movhu d0,(a2) 260 movhu (a2),d0 261 262 # re-enable interrupts 263 # - we don't bother with delay NOPs as we'll have enough instructions 264 # before we disable interrupts again to give the interrupts a chance 265 # to happen 266 LOCAL_IRQ_RESTORE(d3) 267 268 # go around again if the counter hasn't yet reached zero 269 add 0,d1 270 bne mn10300_local_dcache_inv_range_outer_loop 271 272mn10300_local_dcache_inv_range_end: 273 ret [d2,d3,a2],12 274 .size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page 275 .size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range 276 .size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2 277