Path: blob/master/arch/powerpc/platforms/powermac/cache.S
10818 views
/*1* This file contains low-level cache management functions2* used for sleep and CPU speed changes on Apple machines.3* (In fact the only thing that is Apple-specific is that we assume4* that we can read from ROM at physical address 0xfff00000.)5*6* Copyright (C) 2004 Paul Mackerras ([email protected]) and7* Benjamin Herrenschmidt ([email protected])8*9* This program is free software; you can redistribute it and/or10* modify it under the terms of the GNU General Public License11* as published by the Free Software Foundation; either version12* 2 of the License, or (at your option) any later version.13*14*/1516#include <asm/processor.h>17#include <asm/ppc_asm.h>18#include <asm/cputable.h>1920/*21* Flush and disable all data caches (dL1, L2, L3). This is used22* when going to sleep, when doing a PMU based cpufreq transition,23* or when "offlining" a CPU on SMP machines. This code is over24* paranoid, but I've had enough issues with various CPU revs and25* bugs that I decided it was worth beeing over cautious26*/2728_GLOBAL(flush_disable_caches)29#ifndef CONFIG_6xx30blr31#else32BEGIN_FTR_SECTION33b flush_disable_745x34END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)35BEGIN_FTR_SECTION36b flush_disable_75x37END_FTR_SECTION_IFSET(CPU_FTR_L2CR)38b __flush_disable_L13940/* This is the code for G3 and 74[01]0 */41flush_disable_75x:42mflr r104344/* Turn off EE and DR in MSR */45mfmsr r1146rlwinm r0,r11,0,~MSR_EE47rlwinm r0,r0,0,~MSR_DR48sync49mtmsr r050isync5152/* Stop DST streams */53BEGIN_FTR_SECTION54DSSALL55sync56END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)5758/* Stop DPM */59mfspr r8,SPRN_HID0 /* Save SPRN_HID0 in r8 */60rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */61sync62mtspr SPRN_HID0,r4 /* Disable DPM */63sync6465/* Disp-flush L1. We have a weird problem here that I never66* totally figured out. On 750FX, using the ROM for the flush67* results in a non-working flush. We use that workaround for68* now until I finally understand what's going on. --BenH69*/7071/* ROM base by default */72lis r4,0xfff073mfpvr r374srwi r3,r3,1675cmplwi cr0,r3,0x700076bne+ 1f77/* RAM base on 750FX */78li r4,0791: li r4,0x400080mtctr r4811: lwz r0,0(r4)82addi r4,r4,3283bdnz 1b84sync85isync8687/* Disable / invalidate / enable L1 data */88mfspr r3,SPRN_HID089rlwinm r3,r3,0,~(HID0_DCE | HID0_ICE)90mtspr SPRN_HID0,r391sync92isync93ori r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI)94sync95isync96mtspr SPRN_HID0,r397xori r3,r3,(HID0_DCI|HID0_ICFI)98mtspr SPRN_HID0,r399sync100101/* Get the current enable bit of the L2CR into r4 */102mfspr r5,SPRN_L2CR103/* Set to data-only (pre-745x bit) */104oris r3,r5,L2CR_L2DO@h105b 2f106/* When disabling L2, code must be in L1 */107.balign 321081: mtspr SPRN_L2CR,r31093: sync110isync111b 1f1122: b 3f1133: sync114isync115b 1b1161: /* disp-flush L2. The interesting thing here is that the L2 can be117* up to 2Mb ... so using the ROM, we'll end up wrapping back to memory118* but that is probbaly fine. We disp-flush over 4Mb to be safe119*/120lis r4,2121mtctr r4122lis r4,0xfff01231: lwz r0,0(r4)124addi r4,r4,32125bdnz 1b126sync127isync128lis r4,2129mtctr r4130lis r4,0xfff01311: dcbf 0,r4132addi r4,r4,32133bdnz 1b134sync135isync136137/* now disable L2 */138rlwinm r5,r5,0,~L2CR_L2E139b 2f140/* When disabling L2, code must be in L1 */141.balign 321421: mtspr SPRN_L2CR,r51433: sync144isync145b 1f1462: b 3f1473: sync148isync149b 1b1501: sync151isync152/* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */153oris r4,r5,L2CR_L2I@h154mtspr SPRN_L2CR,r4155sync156isync157158/* Wait for the invalidation to complete */1591: mfspr r3,SPRN_L2CR160rlwinm. r0,r3,0,31,31161bne 1b162163/* Clear L2I */164xoris r4,r4,L2CR_L2I@h165sync166mtspr SPRN_L2CR,r4167sync168169/* now disable the L1 data cache */170mfspr r0,SPRN_HID0171rlwinm r0,r0,0,~(HID0_DCE|HID0_ICE)172mtspr SPRN_HID0,r0173sync174isync175176/* Restore HID0[DPM] to whatever it was before */177sync178mfspr r0,SPRN_HID0179rlwimi r0,r8,0,11,11 /* Turn back HID0[DPM] */180mtspr SPRN_HID0,r0181sync182183/* restore DR and EE */184sync185mtmsr r11186isync187188mtlr r10189blr190191/* This code is for 745x processors */192flush_disable_745x:193/* Turn off EE and DR in MSR */194mfmsr r11195rlwinm r0,r11,0,~MSR_EE196rlwinm r0,r0,0,~MSR_DR197sync198mtmsr r0199isync200201/* Stop prefetch streams */202DSSALL203sync204205/* Disable L2 prefetching */206mfspr r0,SPRN_MSSCR0207rlwinm r0,r0,0,0,29208mtspr SPRN_MSSCR0,r0209sync210isync211lis r4,0212dcbf 0,r4213dcbf 0,r4214dcbf 0,r4215dcbf 0,r4216dcbf 0,r4217dcbf 0,r4218dcbf 0,r4219dcbf 0,r4220221/* Due to a bug with the HW flush on some CPU revs, we occasionally222* experience data corruption. I'm adding a displacement flush along223* with a dcbf loop over a few Mb to "help". The problem isn't totally224* fixed by this in theory, but at least, in practice, I couldn't reproduce225* it even with a big hammer...226*/227228lis r4,0x0002229mtctr r4230li r4,02311:232lwz r0,0(r4)233addi r4,r4,32 /* Go to start of next cache line */234bdnz 1b235isync236237/* Now, flush the first 4MB of memory */238lis r4,0x0002239mtctr r4240li r4,0241sync2421:243dcbf 0,r4244addi r4,r4,32 /* Go to start of next cache line */245bdnz 1b246247/* Flush and disable the L1 data cache */248mfspr r6,SPRN_LDSTCR249lis r3,0xfff0 /* read from ROM for displacement flush */250li r4,0xfe /* start with only way 0 unlocked */251li r5,128 /* 128 lines in each way */2521: mtctr r5253rlwimi r6,r4,0,24,31254mtspr SPRN_LDSTCR,r6255sync256isync2572: lwz r0,0(r3) /* touch each cache line */258addi r3,r3,32259bdnz 2b260rlwinm r4,r4,1,24,30 /* move on to the next way */261ori r4,r4,1262cmpwi r4,0xff /* all done? */263bne 1b264/* now unlock the L1 data cache */265li r4,0266rlwimi r6,r4,0,24,31267sync268mtspr SPRN_LDSTCR,r6269sync270isync271272/* Flush the L2 cache using the hardware assist */273mfspr r3,SPRN_L2CR274cmpwi r3,0 /* check if it is enabled first */275bge 4f276oris r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h277b 2f278/* When disabling/locking L2, code must be in L1 */279.balign 322801: mtspr SPRN_L2CR,r0 /* lock the L2 cache */2813: sync282isync283b 1f2842: b 3f2853: sync286isync287b 1b2881: sync289isync290ori r0,r3,L2CR_L2HWF_745x291sync292mtspr SPRN_L2CR,r0 /* set the hardware flush bit */2933: mfspr r0,SPRN_L2CR /* wait for it to go to 0 */294andi. r0,r0,L2CR_L2HWF_745x295bne 3b296sync297rlwinm r3,r3,0,~L2CR_L2E298b 2f299/* When disabling L2, code must be in L1 */300.balign 323011: mtspr SPRN_L2CR,r3 /* disable the L2 cache */3023: sync303isync304b 1f3052: b 3f3063: sync307isync308b 1b3091: sync310isync311oris r4,r3,L2CR_L2I@h312mtspr SPRN_L2CR,r4313sync314isync3151: mfspr r4,SPRN_L2CR316andis. r0,r4,L2CR_L2I@h317bne 1b318sync319320BEGIN_FTR_SECTION321/* Flush the L3 cache using the hardware assist */3224: mfspr r3,SPRN_L3CR323cmpwi r3,0 /* check if it is enabled */324bge 6f325oris r0,r3,L3CR_L3IO@h326ori r0,r0,L3CR_L3DO327sync328mtspr SPRN_L3CR,r0 /* lock the L3 cache */329sync330isync331ori r0,r0,L3CR_L3HWF332sync333mtspr SPRN_L3CR,r0 /* set the hardware flush bit */3345: mfspr r0,SPRN_L3CR /* wait for it to go to zero */335andi. r0,r0,L3CR_L3HWF336bne 5b337rlwinm r3,r3,0,~L3CR_L3E338sync339mtspr SPRN_L3CR,r3 /* disable the L3 cache */340sync341ori r4,r3,L3CR_L3I342mtspr SPRN_L3CR,r43431: mfspr r4,SPRN_L3CR344andi. r0,r4,L3CR_L3I345bne 1b346sync347END_FTR_SECTION_IFSET(CPU_FTR_L3CR)3483496: mfspr r0,SPRN_HID0 /* now disable the L1 data cache */350rlwinm r0,r0,0,~HID0_DCE351mtspr SPRN_HID0,r0352sync353isync354mtmsr r11 /* restore DR and EE */355isync356blr357#endif /* CONFIG_6xx */358359360