Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003  * This file contains low-level cache management functions
0004  * used for sleep and CPU speed changes on Apple machines.
0005  * (In fact the only thing that is Apple-specific is that we assume
0006  * that we can read from ROM at physical address 0xfff00000.)
0007  *
0008  *    Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
0009  *                       Benjamin Herrenschmidt (benh@kernel.crashing.org)
0010  */
0011 
0012 #include <asm/processor.h>
0013 #include <asm/ppc_asm.h>
0014 #include <asm/cputable.h>
0015 #include <asm/feature-fixups.h>
0016 
0017 /*
0018  * Flush and disable all data caches (dL1, L2, L3). This is used
0019  * when going to sleep, when doing a PMU based cpufreq transition,
0020  * or when "offlining" a CPU on SMP machines. This code is over
0021  * paranoid, but I've had enough issues with various CPU revs and
0022  * bugs that I decided it was worth being over cautious
0023  */
0024 
0025 _GLOBAL(flush_disable_caches)
0026 #ifndef CONFIG_PPC_BOOK3S_32
0027     blr
0028 #else
0029 BEGIN_FTR_SECTION
0030     b   flush_disable_745x
0031 END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
0032 BEGIN_FTR_SECTION
0033     b   flush_disable_75x
0034 END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
0035     b   __flush_disable_L1
0036 
0037 /* This is the code for G3 and 74[01]0 */
0038 flush_disable_75x:
0039     mflr    r10
0040 
0041     /* Turn off EE and DR in MSR */
0042     mfmsr   r11
0043     rlwinm  r0,r11,0,~MSR_EE
0044     rlwinm  r0,r0,0,~MSR_DR
0045     sync
0046     mtmsr   r0
0047     isync
0048 
0049     /* Stop DST streams */
0050 BEGIN_FTR_SECTION
0051     PPC_DSSALL
0052     sync
0053 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
0054 
0055     /* Stop DPM */
0056     mfspr   r8,SPRN_HID0        /* Save SPRN_HID0 in r8 */
0057     rlwinm  r4,r8,0,12,10       /* Turn off HID0[DPM] */
0058     sync
0059     mtspr   SPRN_HID0,r4        /* Disable DPM */
0060     sync
0061 
0062     /* Disp-flush L1. We have a weird problem here that I never
0063      * totally figured out. On 750FX, using the ROM for the flush
0064      * results in a non-working flush. We use that workaround for
0065      * now until I finally understand what's going on. --BenH
0066      */
0067 
0068     /* ROM base by default */
0069     lis r4,0xfff0
0070     mfpvr   r3
0071     srwi    r3,r3,16
0072     cmplwi  cr0,r3,0x7000
0073     bne+    1f
0074     /* RAM base on 750FX */
0075     li  r4,0
0076 1:  li  r4,0x4000
0077     mtctr   r4
0078 1:  lwz r0,0(r4)
0079     addi    r4,r4,32
0080     bdnz    1b
0081     sync
0082     isync
0083 
0084     /* Disable / invalidate / enable L1 data */
0085     mfspr   r3,SPRN_HID0
0086     rlwinm  r3,r3,0,~(HID0_DCE | HID0_ICE)
0087     mtspr   SPRN_HID0,r3
0088     sync
0089     isync
0090     ori r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI)
0091     sync
0092     isync
0093     mtspr   SPRN_HID0,r3
0094     xori    r3,r3,(HID0_DCI|HID0_ICFI)
0095     mtspr   SPRN_HID0,r3
0096     sync
0097 
0098     /* Get the current enable bit of the L2CR into r4 */
0099     mfspr   r5,SPRN_L2CR
0100     /* Set to data-only (pre-745x bit) */
0101     oris    r3,r5,L2CR_L2DO@h
0102     b   2f
0103     /* When disabling L2, code must be in L1 */
0104     .balign 32
0105 1:  mtspr   SPRN_L2CR,r3
0106 3:  sync
0107     isync
0108     b   1f
0109 2:  b   3f
0110 3:  sync
0111     isync
0112     b   1b
0113 1:  /* disp-flush L2. The interesting thing here is that the L2 can be
0114      * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
0115      * but that is probbaly fine. We disp-flush over 4Mb to be safe
0116      */
0117     lis r4,2
0118     mtctr   r4
0119     lis r4,0xfff0
0120 1:  lwz r0,0(r4)
0121     addi    r4,r4,32
0122     bdnz    1b
0123     sync
0124     isync
0125     lis r4,2
0126     mtctr   r4
0127     lis r4,0xfff0
0128 1:  dcbf    0,r4
0129     addi    r4,r4,32
0130     bdnz    1b
0131     sync
0132     isync
0133 
0134     /* now disable L2 */
0135     rlwinm  r5,r5,0,~L2CR_L2E
0136     b   2f
0137     /* When disabling L2, code must be in L1 */
0138     .balign 32
0139 1:  mtspr   SPRN_L2CR,r5
0140 3:  sync
0141     isync
0142     b   1f
0143 2:  b   3f
0144 3:  sync
0145     isync
0146     b   1b
0147 1:  sync
0148     isync
0149     /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
0150     oris    r4,r5,L2CR_L2I@h
0151     mtspr   SPRN_L2CR,r4
0152     sync
0153     isync
0154 
0155     /* Wait for the invalidation to complete */
0156 1:  mfspr   r3,SPRN_L2CR
0157     rlwinm. r0,r3,0,31,31
0158     bne 1b
0159 
0160     /* Clear L2I */
0161     xoris   r4,r4,L2CR_L2I@h
0162     sync
0163     mtspr   SPRN_L2CR,r4
0164     sync
0165 
0166     /* now disable the L1 data cache */
0167     mfspr   r0,SPRN_HID0
0168     rlwinm  r0,r0,0,~(HID0_DCE|HID0_ICE)
0169     mtspr   SPRN_HID0,r0
0170     sync
0171     isync
0172 
0173     /* Restore HID0[DPM] to whatever it was before */
0174     sync
0175     mfspr   r0,SPRN_HID0
0176     rlwimi  r0,r8,0,11,11       /* Turn back HID0[DPM] */
0177     mtspr   SPRN_HID0,r0
0178     sync
0179 
0180     /* restore DR and EE */
0181     sync
0182     mtmsr   r11
0183     isync
0184 
0185     mtlr    r10
0186     blr
0187 _ASM_NOKPROBE_SYMBOL(flush_disable_75x)
0188 
0189 /* This code is for 745x processors */
0190 flush_disable_745x:
0191     /* Turn off EE and DR in MSR */
0192     mfmsr   r11
0193     rlwinm  r0,r11,0,~MSR_EE
0194     rlwinm  r0,r0,0,~MSR_DR
0195     sync
0196     mtmsr   r0
0197     isync
0198 
0199     /* Stop prefetch streams */
0200     PPC_DSSALL
0201     sync
0202 
0203     /* Disable L2 prefetching */
0204     mfspr   r0,SPRN_MSSCR0
0205     rlwinm  r0,r0,0,0,29
0206     mtspr   SPRN_MSSCR0,r0
0207     sync
0208     isync
0209     lis r4,0
0210     dcbf    0,r4
0211     dcbf    0,r4
0212     dcbf    0,r4
0213     dcbf    0,r4
0214     dcbf    0,r4
0215     dcbf    0,r4
0216     dcbf    0,r4
0217     dcbf    0,r4
0218 
0219     /* Due to a bug with the HW flush on some CPU revs, we occasionally
0220      * experience data corruption. I'm adding a displacement flush along
0221      * with a dcbf loop over a few Mb to "help". The problem isn't totally
0222      * fixed by this in theory, but at least, in practice, I couldn't reproduce
0223      * it even with a big hammer...
0224      */
0225 
0226         lis     r4,0x0002
0227         mtctr   r4
0228     li      r4,0
0229 1:
0230         lwz     r0,0(r4)
0231         addi    r4,r4,32                /* Go to start of next cache line */
0232         bdnz    1b
0233         isync
0234 
0235         /* Now, flush the first 4MB of memory */
0236         lis     r4,0x0002
0237         mtctr   r4
0238     li      r4,0
0239         sync
0240 1:
0241         dcbf    0,r4
0242         addi    r4,r4,32                /* Go to start of next cache line */
0243         bdnz    1b
0244 
0245     /* Flush and disable the L1 data cache */
0246     mfspr   r6,SPRN_LDSTCR
0247     lis r3,0xfff0   /* read from ROM for displacement flush */
0248     li  r4,0xfe     /* start with only way 0 unlocked */
0249     li  r5,128      /* 128 lines in each way */
0250 1:  mtctr   r5
0251     rlwimi  r6,r4,0,24,31
0252     mtspr   SPRN_LDSTCR,r6
0253     sync
0254     isync
0255 2:  lwz r0,0(r3)    /* touch each cache line */
0256     addi    r3,r3,32
0257     bdnz    2b
0258     rlwinm  r4,r4,1,24,30   /* move on to the next way */
0259     ori r4,r4,1
0260     cmpwi   r4,0xff     /* all done? */
0261     bne 1b
0262     /* now unlock the L1 data cache */
0263     li  r4,0
0264     rlwimi  r6,r4,0,24,31
0265     sync
0266     mtspr   SPRN_LDSTCR,r6
0267     sync
0268     isync
0269 
0270     /* Flush the L2 cache using the hardware assist */
0271     mfspr   r3,SPRN_L2CR
0272     cmpwi   r3,0        /* check if it is enabled first */
0273     bge 4f
0274     oris    r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
0275     b   2f
0276     /* When disabling/locking L2, code must be in L1 */
0277     .balign 32
0278 1:  mtspr   SPRN_L2CR,r0    /* lock the L2 cache */
0279 3:  sync
0280     isync
0281     b   1f
0282 2:  b   3f
0283 3:  sync
0284     isync
0285     b   1b
0286 1:  sync
0287     isync
0288     ori r0,r3,L2CR_L2HWF_745x
0289     sync
0290     mtspr   SPRN_L2CR,r0    /* set the hardware flush bit */
0291 3:  mfspr   r0,SPRN_L2CR    /* wait for it to go to 0 */
0292     andi.   r0,r0,L2CR_L2HWF_745x
0293     bne 3b
0294     sync
0295     rlwinm  r3,r3,0,~L2CR_L2E
0296     b   2f
0297     /* When disabling L2, code must be in L1 */
0298     .balign 32
0299 1:  mtspr   SPRN_L2CR,r3    /* disable the L2 cache */
0300 3:  sync
0301     isync
0302     b   1f
0303 2:  b   3f
0304 3:  sync
0305     isync
0306     b   1b
0307 1:  sync
0308     isync
0309     oris    r4,r3,L2CR_L2I@h
0310     mtspr   SPRN_L2CR,r4
0311     sync
0312     isync
0313 1:  mfspr   r4,SPRN_L2CR
0314     andis.  r0,r4,L2CR_L2I@h
0315     bne 1b
0316     sync
0317 
0318 BEGIN_FTR_SECTION
0319     /* Flush the L3 cache using the hardware assist */
0320 4:  mfspr   r3,SPRN_L3CR
0321     cmpwi   r3,0        /* check if it is enabled */
0322     bge 6f
0323     oris    r0,r3,L3CR_L3IO@h
0324     ori r0,r0,L3CR_L3DO
0325     sync
0326     mtspr   SPRN_L3CR,r0    /* lock the L3 cache */
0327     sync
0328     isync
0329     ori r0,r0,L3CR_L3HWF
0330     sync
0331     mtspr   SPRN_L3CR,r0    /* set the hardware flush bit */
0332 5:  mfspr   r0,SPRN_L3CR    /* wait for it to go to zero */
0333     andi.   r0,r0,L3CR_L3HWF
0334     bne 5b
0335     rlwinm  r3,r3,0,~L3CR_L3E
0336     sync
0337     mtspr   SPRN_L3CR,r3    /* disable the L3 cache */
0338     sync
0339     ori r4,r3,L3CR_L3I
0340     mtspr   SPRN_L3CR,r4
0341 1:  mfspr   r4,SPRN_L3CR
0342     andi.   r0,r4,L3CR_L3I
0343     bne 1b
0344     sync
0345 END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
0346 
0347 6:  mfspr   r0,SPRN_HID0    /* now disable the L1 data cache */
0348     rlwinm  r0,r0,0,~HID0_DCE
0349     mtspr   SPRN_HID0,r0
0350     sync
0351     isync
0352     mtmsr   r11     /* restore DR and EE */
0353     isync
0354     blr
0355 _ASM_NOKPROBE_SYMBOL(flush_disable_745x)
0356 #endif  /* CONFIG_PPC_BOOK3S_32 */