author | hgs |
Thu, 10 Jun 2010 11:48:01 +0100 | |
changeset 148 | 31ea0f8e3c99 |
parent 90 | 947f0dc9f7a8 |
permissions | -rw-r--r-- |
0 | 1 |
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
2 |
// All rights reserved. |
|
3 |
// This component and the accompanying materials are made available |
|
4 |
// under the terms of the License "Eclipse Public License v1.0" |
|
5 |
// which accompanies this distribution, and is available |
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 |
// |
|
8 |
// Initial Contributors: |
|
9 |
// Nokia Corporation - initial contribution. |
|
10 |
// |
|
11 |
// Contributors: |
|
12 |
// |
|
13 |
// Description: |
|
14 |
// eka\kernel\arm\cachel2.cpp |
|
15 |
// |
|
16 |
// Support for the following external cache controllers: |
|
17 |
// - L210 |
|
18 |
// - L220 |
|
19 |
// - PL310 |
|
20 |
// |
|
21 |
||
22 |
/* Errata status: |
|
23 |
* |
|
24 |
* General note that applies to all errata: |
|
25 |
* External cache configuration in bootstrap is implemented in baseport (usually HardwareInitialise |
|
26 |
* procedure). Baseport should ensure errata fixes are properly implemented in bootstrap. |
|
27 |
* |
|
28 |
* L210 Errata status: |
|
29 |
* |
|
30 |
* - Incorrect IDLE assertion on BUSY to IDLE transaction transition on master ports. |
|
31 |
* There is no Software work-around for this erratum. |
|
32 |
* |
|
33 |
* - BWABT event only asserted if abort response is received on the last access of buffered write |
|
34 |
* or eviction transaction. |
|
35 |
* There is no Software work-around for this erratum. |
|
36 |
* |
|
37 |
* - IDLE can be active while a transaction starts on a master port (HTRANSMx = NSEQ). |
|
38 |
* There is no Software work-around for this erratum. |
|
39 |
* |
|
40 |
* - Abort response can be lost on a nonbufferable write access with master port in 32-bit configuration. |
|
41 |
* There is no Software work-around for this erratum. |
|
42 |
* |
|
43 |
* - Evictions can cause write data from write buffer to be overwritten. |
|
44 |
* The work-around for this erratum is to use the L210 as a write-through cache only, which |
|
45 |
* is enforced in baseport. |
|
46 |
* |
|
47 |
* - Incorrect eviction buffer request deassertion can cause WAW hazard or outof-date data read. |
|
48 |
* The work-around for this erratum is to use the L210 as a write-through cache only, which |
|
49 |
* is enforced in baseport. |
|
50 |
* |
|
51 |
* - Read-after-write hazards can be incorrectly handled between write allocation linefills and |
|
52 |
* dirty data evictions in three master ports configuration. |
|
53 |
* The software work-around for this erratum is to change memory regions attributes so that |
|
54 |
* allocate on read miss only policy is used for all outer write-back regions. |
|
55 |
* Note: |
|
56 |
* Write allocate is supported only for systems using ARMv6 extensions only |
|
57 |
* Status: |
|
58 |
* Fix not implemented. |
|
59 |
* |
|
60 |
* - Starting a background maintenance operation while a line is sitting in the writeallocate buffer |
|
61 |
* can prevent that line from being allocated |
|
62 |
* The software work-around is to perform an explicit Cache Sync operation before initiating a |
|
63 |
* background clean or clean-and-invalidate cache maintenance operation. |
|
64 |
* Status: |
|
65 |
* Fix implemented unconditionally because Kernel is using background maintenance |
|
66 |
* operation only during soft restart and performance issue is minimal/nonexistant. |
|
67 |
* |
|
68 |
* - The Cache Sync operation does not guarantee that the Eviction Buffer is empty |
|
69 |
* From ARM Support: |
|
70 |
* To insure the error does not occur, you can do a Cache Sync operation followed by a SWP |
|
71 |
* to non-cacheable memory. |
|
72 |
* Status: |
|
73 |
* Fix implemented in Kernel when |
|
74 |
* __ARM_L210_ERRATA_CACHESYNC_DOESNT_FLUSH_EVICTION_BUFFER_FIXED |
|
75 |
* is not defined in variant.mmh |
|
76 |
* |
|
77 |
* L220 Errata status: |
|
78 |
* |
|
79 |
* - 484863: The Cache Sync operation does not guarantee that the Eviction Buffer is empty. |
|
80 |
* The software workaround is to do a dummy STR to Non-cacheable Normal Memory before launching |
|
81 |
* the Cache Sync operation. Baseport (in bootstrap) MUST ensure that memory mapping of |
|
82 |
* BTP_Uncached entry in BootTable is either: |
|
83 |
* - MEMORY_UNCACHED (memory type remapping on) or, |
|
84 |
* - CACHE_BUFC (memory type remapping off) |
|
85 |
* Status: |
|
86 |
* Fix implemented in Kernel when |
|
87 |
* __ARM_L220_ERRATUM_484863_FIXED |
|
88 |
* is not defined in variant.mmh |
|
89 |
* |
|
90 |
* PL310 Errata status: |
|
91 |
* |
|
92 |
* - 504326: Prefetching can be done on wrong address or wrong memory area. |
|
93 |
* Status: |
|
94 |
* No need for the fix in Kernel as it doesn't do prefetching. |
|
95 |
* When PL310 is configured in bootstrap, baseport should keep the Instruction |
|
96 |
* and Data Prefetch features disabled, as they are by default. |
|
97 |
* |
|
98 |
* - 539766: Non Secure Invalidate by Way maintenance operation does not work properly. |
|
99 |
* Description: |
|
100 |
* Invalidate by Way in non-secure world may corrupt secure cache lines. |
|
101 |
* Status: |
|
102 |
* Unconditionaly fixed. Kernal maintains only a single way in one go. |
|
103 |
* When intialising PL310, baseport should make sure to invalide only a single |
|
104 |
* way in one go. |
|
105 |
* |
|
106 |
* - 540921: Parity must be disabled in exclusive cache configuration. |
|
107 |
* Status: |
|
108 |
* No need for the fix in Kernel as PL310 is initialised by baseport. |
|
109 |
* When intialising PL310, baseport should make sure not to enable both |
|
110 |
* parity and exclusive mode. |
|
111 |
* |
|
112 |
* - 588369: Clean&Invalidate maintenance operations do not invalidate clean lines. |
|
113 |
* Status: |
|
114 |
* Fix implemented in Kernel when |
|
115 |
* __ARM_PL310_ERRATUM_588369_FIXED |
|
116 |
* is not defined in variant.mmh |
|
117 |
* CleanAndInvalidateByPA is replaced by CleanByPA and InvalidateByPA. |
|
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
118 |
* CleanAndInvalidateByIndexWay is made sure never to happen. |
0 | 119 |
* CleanAndInvalidateByWay is made sure never to happen. |
120 |
* Coherancy problem mentioned in the workaround is not relevant. |
|
121 |
* |
|
122 |
* - 588371: Potential data corruption when an AXI locked access is received while a |
|
123 |
* prefetch is treated. |
|
124 |
* Status: |
|
125 |
* No need for the fix in Kernel as PL310 SWP instruction is depricated since ARMv6. |
|
126 |
* |
|
127 |
* - 501023: Address Filtering register content cannot be read. |
|
128 |
* Status: |
|
129 |
* No need for the fix in Kernel it doesn't access access filtering registers. |
|
130 |
* |
|
131 |
* - 502117: Address Filtering registers may not have appropriate values out of reset. |
|
132 |
* Status: |
|
133 |
* No need for the fix in Kernel it doesn't access access filtering registers. |
|
134 |
* |
|
135 |
* - 588375: Potential deadlock when evictions or store buffer writes are issued by |
|
136 |
* different master ports. |
|
137 |
* Status: |
|
138 |
* Not fixed in Kernel as there is no software workaround for this erratum. |
|
90
947f0dc9f7a8
Revision: 201015
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
36
diff
changeset
|
139 |
* |
947f0dc9f7a8
Revision: 201015
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
36
diff
changeset
|
140 |
* - 727915: Background Clean & Invalidate by Way operation can cause data corruption |
947f0dc9f7a8
Revision: 201015
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
36
diff
changeset
|
141 |
* Status: |
947f0dc9f7a8
Revision: 201015
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
36
diff
changeset
|
142 |
* There was no need to fix anything as PL310 cache maintenance doesn't use any |
947f0dc9f7a8
Revision: 201015
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
36
diff
changeset
|
143 |
* _Maintain_ByWay operation. (It is only used in ExternalCache::AtomicSync on |
947f0dc9f7a8
Revision: 201015
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
36
diff
changeset
|
144 |
* L210 & L220.) |
0 | 145 |
*/ |
146 |
||
147 |
#include <arm.h> |
|
148 |
#include "cache_maintenance.h" |
|
149 |
#include <nkern.h> |
|
150 |
||
151 |
#ifdef __HAS_EXTERNAL_CACHE__ |
|
152 |
||
153 |
//L2 Cache globals |
|
154 |
SCacheInfo ExternalCache::Info; |
|
155 |
TLinAddr ExternalCache::Base; |
|
156 |
#if defined(__ARM_PL310_CACHE__) |
|
157 |
#if defined(__SMP__) |
|
158 |
TSpinLock ExternalCache::iLock(TSpinLock::EOrderCacheMaintenance); |
|
159 |
#else |
|
160 |
// Any order will do here |
|
161 |
TSpinLock ExternalCache::iLock(TSpinLock::EOrderGenericIrqLow0); |
|
162 |
#endif |
|
163 |
#endif // defined(__ARM_PL310_CACHE__) |
|
164 |
||
165 |
||
166 |
#if defined (__ARM_L220_CACHE__) |
|
167 |
// These two macros that deal with disabling/restoring interrupts |
|
168 |
// when L220 accesses controll register. They are defined here to |
|
169 |
// improve readability of the code below. |
|
170 |
||
171 |
#define L220_COMMAND_PREAMBLE \ |
|
172 |
TInt irq = NKern::DisableAllInterrupts(); \ |
|
173 |
while (*ctrlReg & 1) __chill(); |
|
174 |
||
175 |
#define L220_COMMAND_POSTAMBLE \ |
|
176 |
NKern::RestoreInterrupts(irq); |
|
177 |
||
178 |
#else // defined (__ARM_L220_CACHE__) |
|
179 |
#define L220_COMMAND_PREAMBLE |
|
180 |
#define L220_COMMAND_POSTAMBLE |
|
181 |
#endif // else defined (__ARM_L220_CACHE__) |
|
182 |
||
183 |
||
184 |
||
185 |
#if defined(__ARM_PL310_CACHE__) |
|
186 |
// These three macros that deal with pl310 spin lock are |
|
187 |
// defined here to improve readability of the code below. |
|
188 |
#define PL310_SPIN_LOCK \ |
|
189 |
TInt lockCounter = KMaxCacheLinesPerSpinLock; \ |
|
190 |
TInt spinLockIrq = Lock(); |
|
191 |
||
192 |
#define PL310_SPIN_FLASH \ |
|
193 |
if (!--lockCounter) \ |
|
194 |
{ \ |
|
195 |
lockCounter = KMaxCacheLinesPerSpinLock; \ |
|
196 |
FlashLock(spinLockIrq); \ |
|
197 |
} |
|
198 |
||
199 |
#define PL310_SPIN_UNLOCK \ |
|
200 |
Unlock(spinLockIrq); |
|
201 |
||
202 |
#else //defined(__ARM_PL310_CACHE__) |
|
203 |
#define PL310_SPIN_LOCK |
|
204 |
#define PL310_SPIN_FLASH |
|
205 |
#define PL310_SPIN_UNLOCK |
|
206 |
#endif // else defined(__ARM_PL310_CACHE__) |
|
207 |
||
208 |
||
209 |
||
210 |
#define CACHEL2FAULT() ExternalCacheFault(__LINE__) |
|
211 |
void ExternalCacheFault(TInt aLine) |
|
212 |
{ |
|
213 |
Kern::Fault("ExternalCacheFault",aLine); |
|
214 |
} |
|
215 |
||
216 |
void ExternalCache::Init1() |
|
217 |
{ |
|
218 |
TInt waySize = 0; // Number of bytes in a way |
|
219 |
||
220 |
Base = TheSuperPage().iArmL2CacheBase; |
|
221 |
TInt auxCtrl = *(TInt*)(Base+ARML2C_AuxiliaryControl); |
|
222 |
__KTRACE_OPT(KBOOT,Kern::Printf("ExternalCache::Init1 L2CacheBase=%x AuxCtrl reg=%x", Base, auxCtrl)); |
|
223 |
||
224 |
//Calculate the number of ways |
|
225 |
switch((auxCtrl & ARML2C_WaySize_Mask) >> ARML2C_WaySize_Shift) |
|
226 |
{ |
|
227 |
case 0: waySize = 0x4000; break; |
|
228 |
case 1: waySize = 0x4000; break; |
|
229 |
case 2: waySize = 0x8000; break; |
|
230 |
case 3: waySize = 0x10000; break; |
|
231 |
case 4: waySize = 0x20000; break; |
|
232 |
#if defined (__ARM_L210_CACHE__) || defined (__ARM_L220_CACHE__) |
|
233 |
default: waySize = 0x40000; break; |
|
234 |
#elif defined(__ARM_PL310_CACHE__) |
|
235 |
case 5: waySize = 0x40000; break; |
|
236 |
case 6: waySize = 0x80000; break; |
|
237 |
default: waySize = 0x80000; break; |
|
238 |
#endif |
|
239 |
} |
|
240 |
||
241 |
#if defined (__ARM_L210_CACHE__) || defined (__ARM_L220_CACHE__) |
|
242 |
Info.iAssoc = (auxCtrl & ARML2C_Assoc_Mask)>> ARML2C_Assoc_Shift; |
|
243 |
if (Info.iAssoc > 8) |
|
244 |
Info.iAssoc = 8; |
|
245 |
||
246 |
#elif defined(__ARM_PL310_CACHE__) |
|
247 |
Info.iAssoc = auxCtrl & ARML2C_Assoc_Mask ? 16 : 8; |
|
248 |
#endif |
|
249 |
||
250 |
Info.iSize = (waySize * Info.iAssoc) >> 5; // >>5 as iSize is counted in lines |
|
251 |
Info.iLineLength=32; // It is always 32 |
|
252 |
Info.iLineLenLog2=5; |
|
253 |
Info.iInvalidateThreshold=Info.iSize*8; //if invalidate region >=8*CacheSize, will flush entire cache |
|
254 |
Info.iCleanThreshold=Info.iSize*4; //if clean region >=4*CacheSize, will clean entire cache |
|
255 |
Info.iCleanAndInvalidateThreshold=Info.iSize*4; //if flush region >=4*CacheSize, will flush entire cache |
|
256 |
||
257 |
#ifdef _DEBUG |
|
258 |
SCacheInfo& c=Info; |
|
259 |
__KTRACE_OPT(KBOOT,Kern::Printf("External Cache:")); |
|
260 |
__KTRACE_OPT(KBOOT,Kern::Printf("Size %04x LineLength %04x Assoc %04x",c.iSize,c.iLineLength,c.iAssoc)); |
|
261 |
__KTRACE_OPT(KBOOT,Kern::Printf("InvalidateThreshold %04x CleanThreshold %04x CleanAndInvalidateThreshold %04x",c.iInvalidateThreshold,c.iCleanThreshold,c.iCleanAndInvalidateThreshold)); |
|
262 |
__KTRACE_OPT(KBOOT,Kern::Printf("LineLenLog2 %02x PreemptBlock %02x",c.iLineLenLog2,c.iPreemptBlock)); |
|
263 |
#endif |
|
264 |
} |
|
265 |
||
266 |
void ExternalCache::Clean(TLinAddr aBase, TUint aSize) |
|
267 |
{ |
|
268 |
__KTRACE_OPT(KMMU, Kern::Printf("ExternalCache::Clean base=%xH, size=%xH", aBase, aSize)); |
|
269 |
if (aSize>=Info.CleanThresholdBytes()) |
|
270 |
Maintain_All((TInt*)(Base+ARML2C_CleanByIndexWay)); |
|
271 |
else |
|
272 |
Maintain_Region(aBase, aSize, (TInt*)(Base+ARML2C_CleanLineByPA)); |
|
273 |
||
274 |
DrainBuffers(); |
|
275 |
} |
|
276 |
||
277 |
void ExternalCache::Invalidate(TLinAddr aBase, TUint aSize) |
|
278 |
{ |
|
279 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::Purge base=%xH, size=%xH", aBase, aSize)); |
|
280 |
||
281 |
#if defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
282 |
//Cannot Clean&Invalidate all cache, so do not bother checking the threshold |
0 | 283 |
Maintain_Region(aBase, aSize, (TInt*)(Base+ARML2C_InvalidateLineByPA)); |
284 |
#else // defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
285 |
||
286 |
if (aSize>=Info.InvalidateThresholdBytes()) |
|
287 |
{ |
|
288 |
Maintain_All((TInt*)(Base+ARML2C_CleanInvalidateByIndexWay)); |
|
289 |
DrainBuffers(); |
|
290 |
} |
|
291 |
else |
|
292 |
{ |
|
293 |
Maintain_Region(aBase, aSize, (TInt*)(Base+ARML2C_InvalidateLineByPA)); |
|
294 |
} |
|
295 |
#endif //else defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
296 |
} |
|
297 |
||
298 |
void ExternalCache::CleanAndInvalidate(TLinAddr aBase, TUint aSize) |
|
299 |
{ |
|
300 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::CleanAndInvalidate base=%xH, size=%xH", aBase, aSize)); |
|
301 |
#if defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
302 |
//Cannot Clean&Invalidate all cache, so do not bother checking the threshold |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
303 |
Maintain_Region(aBase, aSize, (TInt*)(Base+ARML2C_CleanInvalidateLineByPA)); |
0 | 304 |
#else //defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
305 |
||
306 |
if (aSize>=Info.CleanAndInvalidateThresholdBytes()) |
|
307 |
Maintain_All((TInt*)(Base+ARML2C_CleanInvalidateByIndexWay)); |
|
308 |
else |
|
309 |
Maintain_Region(aBase, aSize, (TInt*)(Base+ARML2C_CleanInvalidateLineByPA)); |
|
310 |
#endif |
|
311 |
DrainBuffers(); |
|
312 |
} |
|
313 |
||
314 |
void ExternalCache::AtomicSync() |
|
315 |
{ |
|
148 | 316 |
// This methos is called during reboot or power down sequence and therefore is not allowed |
317 |
// to do Kernel calls that may hold spin lock - such as Kern::Print or precondition checkings. |
|
318 |
// CHECK_PRECONDITIONS(MASK_INTERRUPTS_DISABLED,"ExternalCache::AtomicSync"); |
|
319 |
// __KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::AtomicSync")); |
|
0 | 320 |
#if defined(__ARM_PL310_CACHE__) |
148 | 321 |
// Do not use maintain-by-way operations on PL310 (due to erratum 727915 for example) |
322 |
// Also, do not use ARML2C_CleanInvalidateByIndexWay (erratum 588369) |
|
323 |
// Do not hold spin lock as it is assumed this is the only running CPU. |
|
324 |
TInt indexNo = Info.iSize>>3; // This is the number of cache lines in each way. Assoc is always 8 in this cache |
|
325 |
volatile TInt* ctrlReg = (volatile TInt*)(Base+ARML2C_CleanByIndexWay); |
|
326 |
TInt way,index; |
|
327 |
for (way = 0 ; way <Info.iAssoc ; way++) |
|
328 |
{ |
|
329 |
for (index = 0 ; index <indexNo ; index++) |
|
330 |
{ |
|
331 |
*ctrlReg = (way<<ARML2C_WayShift) | (index<<ARML2C_IndexShift); //This will maintain a single cache line |
|
332 |
} |
|
333 |
} |
|
0 | 334 |
#else //defined(__ARM_PL310_CACHE__) |
335 |
||
336 |
#if defined (__ARM_L210_CACHE__) |
|
337 |
// Flush buffers before starting background clean+invalidate. |
|
338 |
// This is the fix for an erratum (see the top of the file). |
|
339 |
DrainBuffers(); |
|
340 |
#endif |
|
341 |
||
342 |
#if defined (__ARM_L220_CACHE__) |
|
343 |
{ |
|
344 |
// Loop if there is ongoing background operation. |
|
345 |
volatile TInt* cacheSync = (volatile TInt*)(Base+ARML2C_CacheSync); |
|
346 |
while (*cacheSync & 1) __chill(); |
|
347 |
} |
|
348 |
#endif |
|
349 |
||
350 |
int wayShift; |
|
351 |
// Clean and invalidate cache way-after-the-way. Maintenance of multiple ways at |
|
352 |
// the same time is the subject of numerous errata. |
|
353 |
for (wayShift=1; wayShift < 0x100; wayShift<<=1)//8 loops (for 8 ways), with wayShift values 1,2,4,...,0x80 |
|
354 |
{ |
|
355 |
volatile TInt* ctrlReg = (volatile TInt*)(Base+ARML2C_CleanInvalidateByWay); |
|
356 |
*ctrlReg = wayShift; |
|
357 |
while(*ctrlReg) __chill(); |
|
358 |
} |
|
359 |
||
360 |
DrainBuffers(); |
|
361 |
#endif |
|
362 |
return; |
|
363 |
} |
|
364 |
||
365 |
void ExternalCache::InvalidatePhysicalMemory(TPhysAddr aAddr, TUint aSize) |
|
366 |
{ |
|
367 |
if (aSize == 0) |
|
368 |
return; |
|
369 |
||
370 |
volatile TInt* ctrlReg = (volatile TInt*)(Base+ARML2C_InvalidateLineByPA); |
|
371 |
TUint32 endAddr = aAddr+aSize; // (Exclusive) |
|
372 |
if (endAddr<aAddr) |
|
373 |
endAddr = 0xffffffff; |
|
374 |
||
375 |
aAddr &= ~(Info.iLineLength-1); // Align starting address to line length. |
|
376 |
||
377 |
PL310_SPIN_LOCK; |
|
378 |
lineLoop: |
|
379 |
L220_COMMAND_PREAMBLE; |
|
380 |
*ctrlReg = aAddr; //This will invalidate the line from the external cache |
|
381 |
L220_COMMAND_POSTAMBLE; |
|
382 |
PL310_SPIN_FLASH; |
|
383 |
||
384 |
aAddr+=Info.iLineLength; |
|
385 |
if (aAddr<endAddr) goto lineLoop; |
|
386 |
||
387 |
PL310_SPIN_UNLOCK; |
|
388 |
} |
|
389 |
||
390 |
void ExternalCache::CleanPhysicalMemory(TPhysAddr aAddr, TUint aSize) |
|
391 |
{ |
|
392 |
if (aSize == 0) |
|
393 |
return; |
|
394 |
||
395 |
volatile TInt* ctrlReg = (volatile TInt*)(Base+ARML2C_CleanLineByPA); |
|
396 |
TUint32 endAddr = aAddr+aSize; // (Exclusive) |
|
397 |
if (endAddr<aAddr) |
|
398 |
endAddr = 0xffffffff; |
|
399 |
aAddr &= ~(Info.iLineLength-1); // Align starting address to line length. |
|
400 |
||
401 |
PL310_SPIN_LOCK; |
|
402 |
lineLoop: |
|
403 |
L220_COMMAND_PREAMBLE; |
|
404 |
*ctrlReg = aAddr; //This will clean the line from the external cache |
|
405 |
L220_COMMAND_POSTAMBLE; |
|
406 |
PL310_SPIN_FLASH; |
|
407 |
||
408 |
aAddr+=Info.iLineLength; |
|
409 |
if (aAddr<endAddr) goto lineLoop; |
|
410 |
||
411 |
PL310_SPIN_UNLOCK; |
|
412 |
DrainBuffers(); |
|
413 |
} |
|
414 |
||
415 |
void ExternalCache::CleanAndInvalidatePhysicalMemory(TPhysAddr aAddr, TUint aSize) |
|
416 |
{ |
|
417 |
if (aSize == 0) |
|
418 |
return; |
|
419 |
||
420 |
TUint32 endAddr = aAddr+aSize; // (Exclusive) |
|
421 |
if (endAddr<aAddr) |
|
422 |
endAddr = 0xffffffff; |
|
423 |
aAddr &= ~(Info.iLineLength-1); // Align starting address to line length. |
|
424 |
||
425 |
PL310_SPIN_LOCK; |
|
426 |
||
427 |
#if defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
428 |
volatile TInt* cleanReg = (volatile TInt*)(Base+ARML2C_CleanLineByPA); |
0 | 429 |
volatile TInt* invalidateReg = (volatile TInt*)(Base+ARML2C_InvalidateLineByPA); |
430 |
||
431 |
lineLoop: |
|
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
432 |
TInt ret = NKern::DisableAllInterrupts(); |
0 | 433 |
*cleanReg = aAddr; |
434 |
*invalidateReg = aAddr; |
|
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
435 |
NKern::RestoreInterrupts(ret); |
0 | 436 |
|
437 |
#else // #idefined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
438 |
||
439 |
volatile TInt* ctrlReg = (volatile TInt*)(Base+ARML2C_CleanInvalidateLineByPA); |
|
440 |
||
441 |
lineLoop: |
|
442 |
L220_COMMAND_PREAMBLE; |
|
443 |
*ctrlReg = aAddr; //This will clean&invalidate the line from the external cache |
|
444 |
L220_COMMAND_POSTAMBLE; |
|
445 |
#endif //else defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
446 |
||
447 |
PL310_SPIN_FLASH; |
|
448 |
||
449 |
aAddr+=Info.iLineLength; |
|
450 |
if (aAddr<endAddr) goto lineLoop; |
|
451 |
||
452 |
PL310_SPIN_UNLOCK; |
|
453 |
DrainBuffers(); |
|
454 |
} |
|
455 |
||
456 |
void ExternalCache::Maintain_Region(TLinAddr aBase, TUint aSize, TInt* aCtrlReg) |
|
457 |
{ |
|
458 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::Maintain_Region %08xH+%08xH, reg=%xH", aBase, aSize, aCtrlReg)); |
|
459 |
||
460 |
if (aSize == 0) |
|
461 |
return; |
|
462 |
||
463 |
volatile TInt* ctrlReg = aCtrlReg; |
|
464 |
TInt lineLength = Info.iLineLength; |
|
465 |
//Round down aBase to line length and recalculate aSize accordingly. |
|
466 |
TInt diff = aBase & (lineLength-1); |
|
467 |
aBase -= diff; |
|
468 |
//Ensure size doesn't overflow |
|
469 |
if ( ((TInt)(aSize)<0) && (((TInt)(aSize)+diff)>0) ) |
|
470 |
aSize = 0xffffffff; |
|
471 |
else |
|
472 |
aSize += diff; |
|
473 |
||
474 |
// Find the starting physical address. If VA is invalid, try the next page. |
|
475 |
findStartingPA: |
|
476 |
TPhysAddr physAddress = Epoc::LinearToPhysical(aBase); |
|
477 |
if (physAddress == KPhysAddrInvalid) |
|
478 |
{ |
|
479 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::Maintain_Region invalid VA:%xH", aBase)); |
|
480 |
diff = KPageSize - (aBase&KPageMask); |
|
481 |
aBase+=diff; |
|
482 |
if ((TInt)aSize>0 && ((TInt)aSize<=diff)) |
|
483 |
return; |
|
484 |
aSize-=diff; |
|
485 |
goto findStartingPA; |
|
486 |
} |
|
487 |
||
488 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::Maintain_Region VA:%xH > PA:%xH", aBase, physAddress)); |
|
489 |
aBase &= ~KPageMask; //The rest of the function expects aBase to be page aligned. |
|
490 |
||
491 |
PL310_SPIN_LOCK; |
|
492 |
lineLoop: |
|
493 |
||
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
494 |
#if defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
495 |
if((TInt)aCtrlReg == Base+ARML2C_CleanInvalidateLineByPA) |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
496 |
{ |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
497 |
// CleanInvalidateLineByPA is broken |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
498 |
volatile TInt* cleanReg = (volatile TInt*)(Base+ARML2C_CleanLineByPA); |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
499 |
volatile TInt* invalidateReg = (volatile TInt*)(Base+ARML2C_InvalidateLineByPA); |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
500 |
TInt ret = NKern::DisableAllInterrupts(); |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
501 |
*cleanReg = physAddress; |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
502 |
*invalidateReg = physAddress; |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
503 |
NKern::RestoreInterrupts(ret); |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
504 |
} |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
505 |
else |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
506 |
*ctrlReg = physAddress; //This will clean, purge or flush the line |
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
507 |
|
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
508 |
#else |
0 | 509 |
L220_COMMAND_PREAMBLE; |
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
510 |
*ctrlReg = physAddress; //This will clean, purge or flush the line |
0 | 511 |
L220_COMMAND_POSTAMBLE; |
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
512 |
#endif |
0 | 513 |
PL310_SPIN_FLASH; |
514 |
||
515 |
if ((TInt)aSize>0 && ((TInt)aSize<=lineLength)) |
|
516 |
goto endOfRegion; |
|
517 |
||
518 |
aSize=aSize-lineLength; |
|
519 |
physAddress+=lineLength; |
|
520 |
||
521 |
if ((physAddress & KPageMask)) |
|
522 |
goto lineLoop; |
|
523 |
||
524 |
//Drop here when the end of the page is reached. |
|
525 |
endOfPage: |
|
526 |
aBase += KPageSize; |
|
527 |
physAddress = Epoc::LinearToPhysical(aBase); |
|
528 |
if (physAddress == KPhysAddrInvalid) |
|
529 |
{ |
|
530 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::Maintain_Region Invalid VA %xH", aBase)); |
|
531 |
if ((TInt)aSize>0 && ((TInt)aSize<=KPageSize)) |
|
532 |
goto endOfRegion; |
|
533 |
aSize-=KPageSize; |
|
534 |
goto endOfPage; |
|
535 |
} |
|
536 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::Maintain_Region VA:%xH > PA:%xH", aBase, physAddress)); |
|
537 |
goto lineLoop; |
|
538 |
||
539 |
endOfRegion: |
|
540 |
PL310_SPIN_UNLOCK; |
|
541 |
return; |
|
542 |
} |
|
543 |
||
544 |
void ExternalCache::Maintain_All(TInt* aCtrlReg) |
|
545 |
{ |
|
546 |
||
547 |
__KTRACE_OPT(KMMU,Kern::Printf("ExternalCache::Maintain_All %xH", aCtrlReg)); |
|
548 |
||
549 |
#if defined(__ARM_PL310_CACHE__) && !defined(__ARM_PL310_ERRATUM_588369_FIXED) |
|
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
550 |
//CleanAndInvalidateByIndexWay is broken |
0 | 551 |
__ASSERT_DEBUG((TInt)aCtrlReg != Base+ARML2C_CleanInvalidateByIndexWay, CACHEL2FAULT()); |
552 |
#endif |
|
553 |
||
554 |
TInt indexNo = Info.iSize>>3; // This is the number of cache lines in each way. Assoc is always 8 in this cache |
|
555 |
volatile TInt* ctrlReg = aCtrlReg; |
|
556 |
||
557 |
PL310_SPIN_LOCK; |
|
558 |
TInt way,index; |
|
559 |
for (way = 0 ; way <Info.iAssoc ; way++) |
|
560 |
{ |
|
561 |
for (index = 0 ; index <indexNo ; index++) |
|
562 |
{ |
|
563 |
L220_COMMAND_PREAMBLE; |
|
90
947f0dc9f7a8
Revision: 201015
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
36
diff
changeset
|
564 |
*ctrlReg = (way<<ARML2C_WayShift) | (index<<ARML2C_IndexShift); //this will maintain a single cache line |
15
4122176ea935
Revision: 200948 + Removing redundant base integration tests and fixing build errors
John Imhofe <john.imhofe@nokia.com>
parents:
0
diff
changeset
|
565 |
L220_COMMAND_POSTAMBLE; |
0 | 566 |
PL310_SPIN_FLASH; |
567 |
} |
|
568 |
} |
|
569 |
PL310_SPIN_UNLOCK; |
|
570 |
} |
|
571 |
||
572 |
#if defined(__ARM_PL310_CACHE__) |
|
573 |
TInt ExternalCache::Lock() |
|
574 |
{ |
|
575 |
return __SPIN_LOCK_IRQSAVE(iLock); |
|
576 |
} |
|
577 |
||
578 |
void ExternalCache::FlashLock(TInt aIrq) |
|
579 |
{ |
|
580 |
__SPIN_FLASH_IRQRESTORE(iLock, aIrq); |
|
581 |
} |
|
582 |
||
583 |
void ExternalCache::Unlock(TInt aIrq) |
|
584 |
{ |
|
585 |
__SPIN_UNLOCK_IRQRESTORE(iLock, aIrq); |
|
586 |
} |
|
587 |
#endif // defined(__ARM_PL310_CACHE__) |
|
588 |
||
589 |
#endif // defined (__HAS_EXTERNAL_CACHE__) |