linux/arch/mn10300/mm/cache-inv-by-reg.S
<<
>>
Prefs
   1/* MN10300 CPU cache invalidation routines, using automatic purge registers
   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#ifndef CONFIG_SMP
  30        .globl  mn10300_icache_inv
  31        .globl  mn10300_icache_inv_page
  32        .globl  mn10300_icache_inv_range
  33        .globl  mn10300_icache_inv_range2
  34        .globl  mn10300_dcache_inv
  35        .globl  mn10300_dcache_inv_page
  36        .globl  mn10300_dcache_inv_range
  37        .globl  mn10300_dcache_inv_range2
  38
  39mn10300_icache_inv              = mn10300_local_icache_inv
  40mn10300_icache_inv_page         = mn10300_local_icache_inv_page
  41mn10300_icache_inv_range        = mn10300_local_icache_inv_range
  42mn10300_icache_inv_range2       = mn10300_local_icache_inv_range2
  43mn10300_dcache_inv              = mn10300_local_dcache_inv
  44mn10300_dcache_inv_page         = mn10300_local_dcache_inv_page
  45mn10300_dcache_inv_range        = mn10300_local_dcache_inv_range
  46mn10300_dcache_inv_range2       = mn10300_local_dcache_inv_range2
  47
  48#endif /* !CONFIG_SMP */
  49
  50###############################################################################
  51#
  52# void mn10300_local_icache_inv(void)
  53# Invalidate the entire icache
  54#
  55###############################################################################
  56        ALIGN
  57        .globl  mn10300_local_icache_inv
  58        .type   mn10300_local_icache_inv,@function
  59mn10300_local_icache_inv:
  60        mov     CHCTR,a0
  61
  62        movhu   (a0),d0
  63        btst    CHCTR_ICEN,d0
  64        beq     mn10300_local_icache_inv_end
  65
  66        invalidate_icache 1
  67
  68mn10300_local_icache_inv_end:
  69        ret     [],0
  70        .size   mn10300_local_icache_inv,.-mn10300_local_icache_inv
  71
  72###############################################################################
  73#
  74# void mn10300_local_dcache_inv(void)
  75# Invalidate the entire dcache
  76#
  77###############################################################################
  78        ALIGN
  79        .globl  mn10300_local_dcache_inv
  80        .type   mn10300_local_dcache_inv,@function
  81mn10300_local_dcache_inv:
  82        mov     CHCTR,a0
  83
  84        movhu   (a0),d0
  85        btst    CHCTR_DCEN,d0
  86        beq     mn10300_local_dcache_inv_end
  87
  88        invalidate_dcache 1
  89        
  90mn10300_local_dcache_inv_end:
  91        ret     [],0
  92        .size   mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
  93
  94###############################################################################
  95#
  96# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
  97# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
  98# void mn10300_local_dcache_inv_page(unsigned long start)
  99# Invalidate a range of addresses on a page in the dcache
 100#
 101###############################################################################
 102        ALIGN
 103        .globl  mn10300_local_dcache_inv_page
 104        .globl  mn10300_local_dcache_inv_range
 105        .globl  mn10300_local_dcache_inv_range2
 106        .type   mn10300_local_dcache_inv_page,@function
 107        .type   mn10300_local_dcache_inv_range,@function
 108        .type   mn10300_local_dcache_inv_range2,@function
 109mn10300_local_dcache_inv_page:
 110        and     ~(PAGE_SIZE-1),d0
 111        mov     PAGE_SIZE,d1
 112mn10300_local_dcache_inv_range2:
 113        add     d0,d1
 114mn10300_local_dcache_inv_range:
 115        # If we are in writeback mode we check the start and end alignments,
 116        # and if they're not cacheline-aligned, we must flush any bits outside
 117        # the range that share cachelines with stuff inside the range
 118#ifdef CONFIG_MN10300_CACHE_WBACK
 119        btst    ~L1_CACHE_TAG_MASK,d0
 120        bne     1f
 121        btst    ~L1_CACHE_TAG_MASK,d1
 122        beq     2f
 1231:
 124        bra     mn10300_local_dcache_flush_inv_range
 1252:
 126#endif /* CONFIG_MN10300_CACHE_WBACK */
 127
 128        movm    [d2,d3,a2],(sp)
 129
 130        mov     CHCTR,a0
 131        movhu   (a0),d2
 132        btst    CHCTR_DCEN,d2
 133        beq     mn10300_local_dcache_inv_range_end
 134
 135        # round the addresses out to be full cachelines, unless we're in
 136        # writeback mode, in which case we would be in flush and invalidate by
 137        # now
 138#ifndef CONFIG_MN10300_CACHE_WBACK
 139        and     L1_CACHE_TAG_MASK,d0    # round start addr down
 140
 141        mov     L1_CACHE_BYTES-1,d2
 142        add     d2,d1
 143        and     L1_CACHE_TAG_MASK,d1    # round end addr up
 144#endif /* !CONFIG_MN10300_CACHE_WBACK */
 145
 146        sub     d0,d1,d2                # calculate the total size
 147        mov     d0,a2                   # A2 = start address
 148        mov     d1,a1                   # A1 = end address
 149
 150        LOCAL_CLI_SAVE(d3)
 151
 152        mov     DCPGCR,a0               # make sure the purger isn't busy
 153        setlb
 154        mov     (a0),d0
 155        btst    DCPGCR_DCPGBSY,d0
 156        lne
 157
 158        # skip initial address alignment calculation if address is zero
 159        mov     d2,d1
 160        cmp     0,a2
 161        beq     1f
 162
 163dcivloop:
 164        /* calculate alignsize
 165         *
 166         * alignsize = L1_CACHE_BYTES;
 167         * while (! start & alignsize) {
 168         *      alignsize <<=1;
 169         * }
 170         * d1 = alignsize;
 171         */
 172        mov     L1_CACHE_BYTES,d1
 173        lsr     1,d1
 174        setlb
 175        add     d1,d1
 176        mov     d1,d0
 177        and     a2,d0
 178        leq
 179
 1801:
 181        /* calculate invsize
 182         *
 183         * if (totalsize > alignsize) {
 184         *      invsize = alignsize;
 185         * } else {
 186         *      invsize = totalsize;
 187         *      tmp = 0x80000000;
 188         *      while (! invsize & tmp) {
 189         *              tmp >>= 1;
 190         *      }
 191         *      invsize = tmp;
 192         * }
 193         * d1 = invsize
 194         */
 195        cmp     d2,d1
 196        bns     2f
 197        mov     d2,d1
 198
 199        mov     0x80000000,d0           # start from 31bit=1
 200        setlb
 201        lsr     1,d0
 202        mov     d0,e0
 203        and     d1,e0
 204        leq
 205        mov     d0,d1
 206
 2072:
 208        /* set mask
 209         *
 210         * mask = ~(invsize-1);
 211         * DCPGMR = mask;
 212         */
 213        mov     d1,d0
 214        add     -1,d0
 215        not     d0
 216        mov     d0,(DCPGMR)
 217
 218        # invalidate area
 219        mov     a2,d0
 220        or      DCPGCR_DCI,d0
 221        mov     d0,(a0)                 # DCPGCR = (mask & start) | DCPGCR_DCI
 222
 223        setlb                           # wait for the purge to complete
 224        mov     (a0),d0
 225        btst    DCPGCR_DCPGBSY,d0
 226        lne
 227
 228        sub     d1,d2                   # decrease size remaining
 229        add     d1,a2                   # increase next start address
 230
 231        /* check invalidating of end address
 232         *
 233         * a2 = a2 + invsize
 234         * if (a2 < end) {
 235         *     goto dcivloop;
 236         * } */
 237        cmp     a1,a2
 238        bns     dcivloop
 239
 240        LOCAL_IRQ_RESTORE(d3)
 241
 242mn10300_local_dcache_inv_range_end:
 243        ret     [d2,d3,a2],12
 244        .size   mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
 245        .size   mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
 246        .size   mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
 247
 248###############################################################################
 249#
 250# void mn10300_local_icache_inv_page(unsigned long start)
 251# void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size)
 252# void mn10300_local_icache_inv_range(unsigned long start, unsigned long end)
 253# Invalidate a range of addresses on a page in the icache
 254#
 255###############################################################################
 256        ALIGN
 257        .globl  mn10300_local_icache_inv_page
 258        .globl  mn10300_local_icache_inv_range
 259        .globl  mn10300_local_icache_inv_range2
 260        .type   mn10300_local_icache_inv_page,@function
 261        .type   mn10300_local_icache_inv_range,@function
 262        .type   mn10300_local_icache_inv_range2,@function
 263mn10300_local_icache_inv_page:
 264        and     ~(PAGE_SIZE-1),d0
 265        mov     PAGE_SIZE,d1
 266mn10300_local_icache_inv_range2:
 267        add     d0,d1
 268mn10300_local_icache_inv_range:
 269        movm    [d2,d3,a2],(sp)
 270
 271        mov     CHCTR,a0
 272        movhu   (a0),d2
 273        btst    CHCTR_ICEN,d2
 274        beq     mn10300_local_icache_inv_range_reg_end
 275
 276        /* calculate alignsize
 277         *
 278         * alignsize = L1_CACHE_BYTES;
 279         * for (i = (end - start - 1) / L1_CACHE_BYTES ;  i > 0; i >>= 1) {
 280         *     alignsize <<= 1;
 281         * }
 282         * d2 = alignsize;
 283         */
 284        mov     L1_CACHE_BYTES,d2
 285        sub     d0,d1,d3
 286        add     -1,d3
 287        lsr     L1_CACHE_SHIFT,d3
 288        beq     2f
 2891:
 290        add     d2,d2
 291        lsr     1,d3
 292        bne     1b
 2932:
 294
 295        /* a1 = end */
 296        mov     d1,a1
 297
 298        LOCAL_CLI_SAVE(d3)
 299
 300        mov     ICIVCR,a0
 301        /* wait for busy bit of area invalidation */
 302        setlb
 303        mov     (a0),d1
 304        btst    ICIVCR_ICIVBSY,d1
 305        lne
 306
 307        /* set mask
 308         *
 309         * mask = ~(alignsize-1);
 310         * ICIVMR = mask;
 311         */
 312        mov     d2,d1
 313        add     -1,d1
 314        not     d1
 315        mov     d1,(ICIVMR)
 316        /* a2 = mask & start */
 317        and     d1,d0,a2
 318
 319icivloop:
 320        /* area invalidate
 321         *
 322         * ICIVCR = (mask & start) | ICIVCR_ICI
 323         */
 324        mov     a2,d0
 325        or      ICIVCR_ICI,d0
 326        mov     d0,(a0)
 327
 328        /* wait for busy bit of area invalidation */
 329        setlb
 330        mov     (a0),d1
 331        btst    ICIVCR_ICIVBSY,d1
 332        lne
 333
 334        /* check invalidating of end address
 335         *
 336         * a2 = a2 + alignsize
 337         * if (a2 < end) {
 338         *     goto icivloop;
 339         * } */
 340        add     d2,a2
 341        cmp     a1,a2
 342        bns     icivloop
 343
 344        LOCAL_IRQ_RESTORE(d3)
 345
 346mn10300_local_icache_inv_range_reg_end:
 347        ret     [d2,d3,a2],12
 348        .size   mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page
 349        .size   mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range
 350        .size   mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2
 351