linux/arch/powerpc/platforms/powermac/cache.S
<<
>>
Prefs
   1/*
   2 * This file contains low-level cache management functions
   3 * used for sleep and CPU speed changes on Apple machines.
   4 * (In fact the only thing that is Apple-specific is that we assume
   5 * that we can read from ROM at physical address 0xfff00000.)
   6 *
   7 *    Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
   8 *                       Benjamin Herrenschmidt (benh@kernel.crashing.org)
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License
  12 * as published by the Free Software Foundation; either version
  13 * 2 of the License, or (at your option) any later version.
  14 *
  15 */
  16
  17#include <asm/processor.h>
  18#include <asm/ppc_asm.h>
  19#include <asm/cputable.h>
  20
  21/*
  22 * Flush and disable all data caches (dL1, L2, L3). This is used
  23 * when going to sleep, when doing a PMU based cpufreq transition,
  24 * or when "offlining" a CPU on SMP machines. This code is over
  25 * paranoid, but I've had enough issues with various CPU revs and
  26 * bugs that I decided it was worth beeing over cautious
  27 */
  28
  29_GLOBAL(flush_disable_caches)
  30#ifndef CONFIG_6xx
  31        blr
  32#else
  33BEGIN_FTR_SECTION
  34        b       flush_disable_745x
  35END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
  36BEGIN_FTR_SECTION
  37        b       flush_disable_75x
  38END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
  39        b       __flush_disable_L1
  40
  41/* This is the code for G3 and 74[01]0 */
  42flush_disable_75x:
  43        mflr    r10
  44
  45        /* Turn off EE and DR in MSR */
  46        mfmsr   r11
  47        rlwinm  r0,r11,0,~MSR_EE
  48        rlwinm  r0,r0,0,~MSR_DR
  49        sync
  50        mtmsr   r0
  51        isync
  52
  53        /* Stop DST streams */
  54BEGIN_FTR_SECTION
  55        DSSALL
  56        sync
  57END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
  58
  59        /* Stop DPM */
  60        mfspr   r8,SPRN_HID0            /* Save SPRN_HID0 in r8 */
  61        rlwinm  r4,r8,0,12,10           /* Turn off HID0[DPM] */
  62        sync
  63        mtspr   SPRN_HID0,r4            /* Disable DPM */
  64        sync
  65
  66        /* Disp-flush L1. We have a weird problem here that I never
  67         * totally figured out. On 750FX, using the ROM for the flush
  68         * results in a non-working flush. We use that workaround for
  69         * now until I finally understand what's going on. --BenH
  70         */
  71
  72        /* ROM base by default */
  73        lis     r4,0xfff0
  74        mfpvr   r3
  75        srwi    r3,r3,16
  76        cmplwi  cr0,r3,0x7000
  77        bne+    1f
  78        /* RAM base on 750FX */
  79        li      r4,0
  801:      li      r4,0x4000
  81        mtctr   r4
  821:      lwz     r0,0(r4)
  83        addi    r4,r4,32
  84        bdnz    1b
  85        sync
  86        isync
  87
  88        /* Disable / invalidate / enable L1 data */
  89        mfspr   r3,SPRN_HID0
  90        rlwinm  r3,r3,0,~(HID0_DCE | HID0_ICE)
  91        mtspr   SPRN_HID0,r3
  92        sync
  93        isync
  94        ori     r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI)
  95        sync
  96        isync
  97        mtspr   SPRN_HID0,r3
  98        xori    r3,r3,(HID0_DCI|HID0_ICFI)
  99        mtspr   SPRN_HID0,r3
 100        sync
 101
 102        /* Get the current enable bit of the L2CR into r4 */
 103        mfspr   r5,SPRN_L2CR
 104        /* Set to data-only (pre-745x bit) */
 105        oris    r3,r5,L2CR_L2DO@h
 106        b       2f
 107        /* When disabling L2, code must be in L1 */
 108        .balign 32
 1091:      mtspr   SPRN_L2CR,r3
 1103:      sync
 111        isync
 112        b       1f
 1132:      b       3f
 1143:      sync
 115        isync
 116        b       1b
 1171:      /* disp-flush L2. The interesting thing here is that the L2 can be
 118         * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
 119         * but that is probbaly fine. We disp-flush over 4Mb to be safe
 120         */
 121        lis     r4,2
 122        mtctr   r4
 123        lis     r4,0xfff0
 1241:      lwz     r0,0(r4)
 125        addi    r4,r4,32
 126        bdnz    1b
 127        sync
 128        isync
 129        lis     r4,2
 130        mtctr   r4
 131        lis     r4,0xfff0
 1321:      dcbf    0,r4
 133        addi    r4,r4,32
 134        bdnz    1b
 135        sync
 136        isync
 137
 138        /* now disable L2 */
 139        rlwinm  r5,r5,0,~L2CR_L2E
 140        b       2f
 141        /* When disabling L2, code must be in L1 */
 142        .balign 32
 1431:      mtspr   SPRN_L2CR,r5
 1443:      sync
 145        isync
 146        b       1f
 1472:      b       3f
 1483:      sync
 149        isync
 150        b       1b
 1511:      sync
 152        isync
 153        /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
 154        oris    r4,r5,L2CR_L2I@h
 155        mtspr   SPRN_L2CR,r4
 156        sync
 157        isync
 158
 159        /* Wait for the invalidation to complete */
 1601:      mfspr   r3,SPRN_L2CR
 161        rlwinm. r0,r3,0,31,31
 162        bne     1b
 163
 164        /* Clear L2I */
 165        xoris   r4,r4,L2CR_L2I@h
 166        sync
 167        mtspr   SPRN_L2CR,r4
 168        sync
 169
 170        /* now disable the L1 data cache */
 171        mfspr   r0,SPRN_HID0
 172        rlwinm  r0,r0,0,~(HID0_DCE|HID0_ICE)
 173        mtspr   SPRN_HID0,r0
 174        sync
 175        isync
 176
 177        /* Restore HID0[DPM] to whatever it was before */
 178        sync
 179        mfspr   r0,SPRN_HID0
 180        rlwimi  r0,r8,0,11,11           /* Turn back HID0[DPM] */
 181        mtspr   SPRN_HID0,r0
 182        sync
 183
 184        /* restore DR and EE */
 185        sync
 186        mtmsr   r11
 187        isync
 188
 189        mtlr    r10
 190        blr
 191
 192/* This code is for 745x processors */
 193flush_disable_745x:
 194        /* Turn off EE and DR in MSR */
 195        mfmsr   r11
 196        rlwinm  r0,r11,0,~MSR_EE
 197        rlwinm  r0,r0,0,~MSR_DR
 198        sync
 199        mtmsr   r0
 200        isync
 201
 202        /* Stop prefetch streams */
 203        DSSALL
 204        sync
 205
 206        /* Disable L2 prefetching */
 207        mfspr   r0,SPRN_MSSCR0
 208        rlwinm  r0,r0,0,0,29
 209        mtspr   SPRN_MSSCR0,r0
 210        sync
 211        isync
 212        lis     r4,0
 213        dcbf    0,r4
 214        dcbf    0,r4
 215        dcbf    0,r4
 216        dcbf    0,r4
 217        dcbf    0,r4
 218        dcbf    0,r4
 219        dcbf    0,r4
 220        dcbf    0,r4
 221
 222        /* Due to a bug with the HW flush on some CPU revs, we occasionally
 223         * experience data corruption. I'm adding a displacement flush along
 224         * with a dcbf loop over a few Mb to "help". The problem isn't totally
 225         * fixed by this in theory, but at least, in practice, I couldn't reproduce
 226         * it even with a big hammer...
 227         */
 228
 229        lis     r4,0x0002
 230        mtctr   r4
 231        li      r4,0
 2321:
 233        lwz     r0,0(r4)
 234        addi    r4,r4,32                /* Go to start of next cache line */
 235        bdnz    1b
 236        isync
 237
 238        /* Now, flush the first 4MB of memory */
 239        lis     r4,0x0002
 240        mtctr   r4
 241        li      r4,0
 242        sync
 2431:
 244        dcbf    0,r4
 245        addi    r4,r4,32                /* Go to start of next cache line */
 246        bdnz    1b
 247
 248        /* Flush and disable the L1 data cache */
 249        mfspr   r6,SPRN_LDSTCR
 250        lis     r3,0xfff0       /* read from ROM for displacement flush */
 251        li      r4,0xfe         /* start with only way 0 unlocked */
 252        li      r5,128          /* 128 lines in each way */
 2531:      mtctr   r5
 254        rlwimi  r6,r4,0,24,31
 255        mtspr   SPRN_LDSTCR,r6
 256        sync
 257        isync
 2582:      lwz     r0,0(r3)        /* touch each cache line */
 259        addi    r3,r3,32
 260        bdnz    2b
 261        rlwinm  r4,r4,1,24,30   /* move on to the next way */
 262        ori     r4,r4,1
 263        cmpwi   r4,0xff         /* all done? */
 264        bne     1b
 265        /* now unlock the L1 data cache */
 266        li      r4,0
 267        rlwimi  r6,r4,0,24,31
 268        sync
 269        mtspr   SPRN_LDSTCR,r6
 270        sync
 271        isync
 272
 273        /* Flush the L2 cache using the hardware assist */
 274        mfspr   r3,SPRN_L2CR
 275        cmpwi   r3,0            /* check if it is enabled first */
 276        bge     4f
 277        oris    r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
 278        b       2f
 279        /* When disabling/locking L2, code must be in L1 */
 280        .balign 32
 2811:      mtspr   SPRN_L2CR,r0    /* lock the L2 cache */
 2823:      sync
 283        isync
 284        b       1f
 2852:      b       3f
 2863:      sync
 287        isync
 288        b       1b
 2891:      sync
 290        isync
 291        ori     r0,r3,L2CR_L2HWF_745x
 292        sync
 293        mtspr   SPRN_L2CR,r0    /* set the hardware flush bit */
 2943:      mfspr   r0,SPRN_L2CR    /* wait for it to go to 0 */
 295        andi.   r0,r0,L2CR_L2HWF_745x
 296        bne     3b
 297        sync
 298        rlwinm  r3,r3,0,~L2CR_L2E
 299        b       2f
 300        /* When disabling L2, code must be in L1 */
 301        .balign 32
 3021:      mtspr   SPRN_L2CR,r3    /* disable the L2 cache */
 3033:      sync
 304        isync
 305        b       1f
 3062:      b       3f
 3073:      sync
 308        isync
 309        b       1b
 3101:      sync
 311        isync
 312        oris    r4,r3,L2CR_L2I@h
 313        mtspr   SPRN_L2CR,r4
 314        sync
 315        isync
 3161:      mfspr   r4,SPRN_L2CR
 317        andis.  r0,r4,L2CR_L2I@h
 318        bne     1b
 319        sync
 320
 321BEGIN_FTR_SECTION
 322        /* Flush the L3 cache using the hardware assist */
 3234:      mfspr   r3,SPRN_L3CR
 324        cmpwi   r3,0            /* check if it is enabled */
 325        bge     6f
 326        oris    r0,r3,L3CR_L3IO@h
 327        ori     r0,r0,L3CR_L3DO
 328        sync
 329        mtspr   SPRN_L3CR,r0    /* lock the L3 cache */
 330        sync
 331        isync
 332        ori     r0,r0,L3CR_L3HWF
 333        sync
 334        mtspr   SPRN_L3CR,r0    /* set the hardware flush bit */
 3355:      mfspr   r0,SPRN_L3CR    /* wait for it to go to zero */
 336        andi.   r0,r0,L3CR_L3HWF
 337        bne     5b
 338        rlwinm  r3,r3,0,~L3CR_L3E
 339        sync
 340        mtspr   SPRN_L3CR,r3    /* disable the L3 cache */
 341        sync
 342        ori     r4,r3,L3CR_L3I
 343        mtspr   SPRN_L3CR,r4
 3441:      mfspr   r4,SPRN_L3CR
 345        andi.   r0,r4,L3CR_L3I
 346        bne     1b
 347        sync
 348END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
 349
 3506:      mfspr   r0,SPRN_HID0    /* now disable the L1 data cache */
 351        rlwinm  r0,r0,0,~HID0_DCE
 352        mtspr   SPRN_HID0,r0
 353        sync
 354        isync
 355        mtmsr   r11             /* restore DR and EE */
 356        isync
 357        blr
 358#endif  /* CONFIG_6xx */
 359