1 // Copyright (c) 1998-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 "Symbian Foundation License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <plat_priv.h> |
|
17 #include "mramalloc.h" |
|
18 |
|
19 struct SGroup |
|
20 { |
|
21 TBitMapAllocator* iBma; |
|
22 TPhysAddr iPhysBase; |
|
23 TInt iNumBase; |
|
24 TUint8 iPwrBlock; |
|
25 }; |
|
26 |
|
27 class DRamAllocator : public DRamAllocatorBase |
|
28 { |
|
29 public: |
|
30 virtual TInt Create(const SRamInfo& aInfo, const SRamBank* aPowerBanks); |
|
31 virtual TInt MarkPageAllocated(TPhysAddr aAddr); |
|
32 virtual TInt FreeRamPage(TPhysAddr aAddr); |
|
33 virtual void FreeRamPages(TPhysAddr* aPageList, TInt aNumPages); |
|
34 virtual TInt AllocRamPages(TPhysAddr* aPageList, TInt aNumPages); |
|
35 virtual TInt AllocContiguousRam(TInt aNumPages, TPhysAddr& aPhysAddr, TInt aAlign=0); |
|
36 virtual TInt SetPhysicalRamState(TPhysAddr aBase, TInt aSize, TBool aState); |
|
37 virtual TUint TotalPhysicalRamPages() {return iTotalRamPages;}; |
|
38 #ifdef KMMU |
|
39 void DebugDump(); |
|
40 #endif |
|
41 private: |
|
42 SGroup* GetGroupAndOffset(TPhysAddr aAddr, TInt& aOffset); |
|
43 void MarkPagesAllocated(TInt aPageNum, TInt aCount); |
|
44 TInt FindContiguousRam(TInt aNumPages, TInt aAlignWrtPage, TUint8* aPermute, TInt& aPageNum); |
|
45 private: |
|
46 enum TPanic |
|
47 { |
|
48 // don't use 0 |
|
49 EDoNotUse=0, |
|
50 EBytesFromStartInvalid, |
|
51 EBytesFromEndInvalid, |
|
52 EAreasTooSmall, |
|
53 ETooManyPowerBlocks, |
|
54 EInvalidPowerBlocks, |
|
55 EDoMarkPagesAllocated1, |
|
56 EAllocRamPagesInconsistent, |
|
57 }; |
|
58 private: |
|
59 TInt iTotalRamPages; |
|
60 TInt iNumGroups; // group corresponds to BMA |
|
61 TInt iAreaSize; // size of an area in bytes |
|
62 TInt iAreaShift; // log2(areasize) |
|
63 TUint32 iAreaMask; // iAreaSize-1 |
|
64 TInt iAreaPages; // size of an area in pages |
|
65 TInt iAreaPageShift; // log2(areapages) |
|
66 TUint32 iAreaPageMask; // iAreaPages-1 |
|
67 TInt iNumAreas; // number of areas recognised (size of iPhysAddrLUT) |
|
68 SGroup* iGroups; // per-group info |
|
69 TUint8* iGroupPowerOrder; // table of indices into above tables in power block order |
|
70 TUint8* iPhysAddrLUT; // table of indices indexed by (physaddr-physaddrbase)>>areashift |
|
71 TUint8* iPageNumLUT; // table of indices indexed by pagenum>>areapageshift |
|
72 TPhysAddr iPhysAddrBase; // lowest valid physical address |
|
73 TPhysAddr iPhysAddrTop; // highest valid physical address+1 |
|
74 }; |
|
75 |
|
76 DRamAllocatorBase* DRamAllocatorBase::New() |
|
77 { |
|
78 return new DRamAllocator; |
|
79 } |
|
80 |
|
81 DRamAllocatorBase* DRamAllocatorBase::New(const SRamInfo& aInfo, TInt aPageShift, const SRamBank* aPowerBanks) |
|
82 { |
|
83 DRamAllocatorBase* pA=New(); |
|
84 if (!pA) |
|
85 Panic(KErrNoMemory); |
|
86 pA->iPageShift=aPageShift; |
|
87 pA->iPageSize=1<<aPageShift; |
|
88 TInt r=pA->Create(aInfo,aPowerBanks); |
|
89 if (r!=KErrNone) |
|
90 Panic(r); |
|
91 return pA; |
|
92 } |
|
93 |
|
94 void DRamAllocatorBase::Panic(TInt aPanic) |
|
95 { |
|
96 Kern::Fault("RAM-ALLOC", aPanic); |
|
97 } |
|
98 |
|
99 #ifdef KMMU |
|
100 void HexDump32(const TAny* a, TInt n, const char* s) |
|
101 { |
|
102 const TUint32* p=(const TUint32*)a; |
|
103 Kern::Printf(s); |
|
104 TInt i=0; |
|
105 while(n) |
|
106 { |
|
107 TBuf8<80> b; |
|
108 b.AppendNumFixedWidth(i,EHex,4); |
|
109 b.Append(':'); |
|
110 TInt m=Min(n,4); |
|
111 n-=m; |
|
112 i+=m; |
|
113 while(m--) |
|
114 { |
|
115 b.Append(' '); |
|
116 b.AppendNumFixedWidth(*p++,EHex,8); |
|
117 } |
|
118 Kern::Printf("%S",&b); |
|
119 } |
|
120 } |
|
121 |
|
122 void HexDump8(const TAny* a, TInt n, const char* s) |
|
123 { |
|
124 const TUint8* p=(const TUint8*)a; |
|
125 Kern::Printf(s); |
|
126 TInt i=0; |
|
127 while(n) |
|
128 { |
|
129 TBuf8<80> b; |
|
130 b.AppendNumFixedWidth(i,EHex,4); |
|
131 b.Append(':'); |
|
132 TInt m=Min(n,16); |
|
133 n-=m; |
|
134 i+=m; |
|
135 while(m--) |
|
136 { |
|
137 b.Append(' '); |
|
138 b.AppendNumFixedWidth(*p++,EHex,2); |
|
139 } |
|
140 Kern::Printf("%S",&b); |
|
141 } |
|
142 } |
|
143 |
|
144 void DRamAllocator::DebugDump() |
|
145 { |
|
146 Kern::Printf("PageSize=%08x PageShift=%d",iPageSize,iPageShift); |
|
147 Kern::Printf("AreaSize=%08x AreaShift=%d AreaMask=%08x",iAreaSize,iAreaShift,iAreaMask); |
|
148 Kern::Printf("AreaPages=%08x AreaPageShift=%d AreaPageMask=%08x",iAreaPages,iAreaPageShift,iAreaPageMask); |
|
149 Kern::Printf("Total Pages=%08x Total Free=%08x",iTotalRamPages,iTotalFreeRamPages); |
|
150 Kern::Printf("Number of areas=%08x, number of groups=%08x",iNumAreas,iNumGroups); |
|
151 Kern::Printf("Number of power blocks=%d, PowerState=%08x",iNumPowerBlocks,iPowerState); |
|
152 Kern::Printf("PhysAddrBase=%08x, PhysAddrTop=%08x",iPhysAddrBase,iPhysAddrTop); |
|
153 |
|
154 TInt i; |
|
155 Kern::Printf("Group Info:"); |
|
156 for (i=0; i<iNumGroups; ++i) |
|
157 { |
|
158 SGroup& g=iGroups[i]; |
|
159 TBitMapAllocator& b=*g.iBma; |
|
160 Kern::Printf("%02x: Avail %08x Size %08x Phys %08x Num %08x Pwr %02x",i,b.iAvail,b.iSize, |
|
161 g.iPhysBase,g.iNumBase,g.iPwrBlock); |
|
162 } |
|
163 if (iGroupPowerOrder) |
|
164 HexDump8(iGroupPowerOrder,iNumGroups,"GroupPowerOrder:"); |
|
165 HexDump8(iPhysAddrLUT,iNumAreas,"PhysAddrLUT:"); |
|
166 HexDump8(iPageNumLUT,iTotalRamPages>>iAreaPageShift,"PageNumLUT:"); |
|
167 HexDump32(iPowerBlockPages,iNumPowerBlocks,"PowerBlockPages:"); |
|
168 } |
|
169 #endif |
|
170 |
|
171 TInt CountBanks(const SRamBank* aBankList) |
|
172 { |
|
173 TInt banks=0; |
|
174 for (; aBankList->iSize; ++banks, ++aBankList); |
|
175 return banks; |
|
176 } |
|
177 |
|
178 TInt CalcAreaShift(const SRamBank* aBankList) |
|
179 { |
|
180 TUint32 mask=0; |
|
181 for (; aBankList->iSize; ++aBankList) |
|
182 { |
|
183 TUint32 base=aBankList->iBase; |
|
184 TUint32 end=base+aBankList->iSize-1; |
|
185 __KTRACE_OPT(KBOOT,Kern::Printf("Base=%08x End=%08x",base,end)); |
|
186 mask|=base; |
|
187 mask|=~end; |
|
188 } |
|
189 return __e32_find_ls1_32(mask); |
|
190 } |
|
191 |
|
192 TUint32 TotalBankSize(const SRamBank* aBankList) |
|
193 { |
|
194 TUint32 size=0; |
|
195 for (; aBankList->iSize; ++aBankList) |
|
196 size+=aBankList->iSize; |
|
197 return size; |
|
198 } |
|
199 |
|
200 TInt DRamAllocator::Create(const SRamInfo& a, const SRamBank* aP) |
|
201 { |
|
202 __KTRACE_OPT(KMMU,Kern::Printf("DRamAllocator::Create")); |
|
203 |
|
204 TInt num_boot_banks=CountBanks(a.iBanks); |
|
205 TUint32 total_ram_size=TotalBankSize(a.iBanks); |
|
206 __KTRACE_OPT(KMMU,Kern::Printf("#banks from bootstrap=%d",num_boot_banks)); |
|
207 __KTRACE_OPT(KMMU,Kern::Printf("Total size=%08x",total_ram_size)); |
|
208 iTotalRamPages=total_ram_size>>iPageShift; |
|
209 iTotalFreeRamPages=iTotalRamPages; |
|
210 __KTRACE_OPT(KMMU,Kern::Printf("Total size=%08x, total pages=%08x",total_ram_size,iTotalRamPages)); |
|
211 |
|
212 __KTRACE_OPT(KMMU,Kern::Printf("Calculate area shift from bootstrap blocks")); |
|
213 iAreaShift=CalcAreaShift(a.iBanks); |
|
214 __KTRACE_OPT(KMMU,Kern::Printf("iAreaShift=%d",iAreaShift)); |
|
215 iNumPowerBlocks=1; |
|
216 if (aP) |
|
217 { |
|
218 iNumPowerBlocks=CountBanks(aP); |
|
219 __KTRACE_OPT(KMMU,Kern::Printf("iNumPowerBlocks=%d",iNumPowerBlocks)); |
|
220 if (iNumPowerBlocks>32) |
|
221 return ETooManyPowerBlocks; |
|
222 __KTRACE_OPT(KMMU,Kern::Printf("Calculate area shift from power blocks")); |
|
223 TInt as=CalcAreaShift(aP); |
|
224 __KTRACE_OPT(KMMU,Kern::Printf("area shift=%d",as)); |
|
225 if (as<iAreaShift) |
|
226 iAreaShift=as; |
|
227 } |
|
228 if (iAreaShift<16 || iAreaShift<iPageShift) |
|
229 return EAreasTooSmall; |
|
230 iAreaSize=1<<iAreaShift; |
|
231 iAreaMask=iAreaSize-1; |
|
232 iAreaPageShift=iAreaShift-iPageShift; |
|
233 iAreaPages=1<<iAreaPageShift; |
|
234 iAreaPageMask=iAreaPages-1; |
|
235 __KTRACE_OPT(KMMU,Kern::Printf("iAreaShift=%d",iAreaShift)); |
|
236 |
|
237 iPhysAddrBase=a.iBanks[0].iBase; |
|
238 const SRamBank& last_boot_bank=a.iBanks[num_boot_banks-1]; |
|
239 iPhysAddrTop=last_boot_bank.iBase+last_boot_bank.iSize; |
|
240 __KTRACE_OPT(KMMU,Kern::Printf("PA base=%08x, PA top=%08x",iPhysAddrBase,iPhysAddrTop)); |
|
241 iNumAreas=(iPhysAddrTop-iPhysAddrBase)>>iAreaShift; |
|
242 __KTRACE_OPT(KMMU,Kern::Printf("iNumAreas=%08x",iNumAreas)); |
|
243 |
|
244 iPhysAddrLUT=(TUint8*)Kern::Alloc(iNumAreas); |
|
245 if (!iPhysAddrLUT) |
|
246 return KErrNoMemory; |
|
247 iPageNumLUT=(TUint8*)Kern::Alloc(iNumAreas); // overallocate temporarily |
|
248 if (!iPageNumLUT) |
|
249 return KErrNoMemory; |
|
250 iPowerBlockPages=(TInt*)Kern::AllocZ(iNumPowerBlocks*sizeof(TInt)); |
|
251 if (!iPowerBlockPages) |
|
252 return KErrNoMemory; |
|
253 |
|
254 // coalesce contiguous boot banks |
|
255 SRamBank* phys_banks = (SRamBank*)Kern::Alloc(num_boot_banks*sizeof(SRamBank)); |
|
256 if (!phys_banks) |
|
257 return KErrNoMemory; |
|
258 SRamBank* pD=phys_banks; |
|
259 const SRamBank* pBoot=a.iBanks; |
|
260 const SRamBank* pE=pBoot+num_boot_banks; |
|
261 TPhysAddr base=0; |
|
262 TPhysAddr end=0; |
|
263 for (; pBoot<=pE; ++pBoot) |
|
264 { |
|
265 if (pBoot==pE || pBoot->iBase!=end) |
|
266 { |
|
267 if (end) |
|
268 { |
|
269 pD->iBase=base; |
|
270 pD->iSize=end-base; |
|
271 ++pD; |
|
272 __KTRACE_OPT(KMMU,Kern::Printf("Coalesced bank: %08x-%08x",base,end)); |
|
273 } |
|
274 if (pBoot<pE) |
|
275 { |
|
276 base=pBoot->iBase; |
|
277 end=base+pBoot->iSize; |
|
278 } |
|
279 } |
|
280 else |
|
281 end+=pBoot->iSize; |
|
282 } |
|
283 SRamBank* pPhysEnd=pD; |
|
284 __KTRACE_OPT(KMMU,Kern::Printf("#Coalesced banks: %d",pD-phys_banks)); |
|
285 |
|
286 // work out groups |
|
287 TInt start_area; |
|
288 TInt num_areas; |
|
289 TInt phys_bank; |
|
290 TInt pwr_bank; |
|
291 memset(iPhysAddrLUT,0xff,iNumAreas); |
|
292 pD=phys_banks; |
|
293 for (; pD<pPhysEnd; ++pD) |
|
294 { |
|
295 start_area=(pD->iBase-iPhysAddrBase)>>iAreaShift; |
|
296 num_areas=pD->iSize>>iAreaShift; |
|
297 phys_bank=pD-phys_banks; |
|
298 memset(iPhysAddrLUT+start_area, phys_bank, num_areas); |
|
299 } |
|
300 |
|
301 if (aP) |
|
302 { |
|
303 memset(iPageNumLUT,0xff,iNumAreas); |
|
304 const SRamBank* pB=aP; |
|
305 const SRamBank* pPwrEnd=aP+iNumPowerBlocks; |
|
306 for (; pB<pPwrEnd; ++pB) |
|
307 { |
|
308 start_area=(Max(pB->iBase,iPhysAddrBase)-iPhysAddrBase)>>iAreaShift; |
|
309 num_areas=(TInt)Min(TUint32(pB->iSize)>>iAreaShift, TUint32(iNumAreas-start_area)); |
|
310 pwr_bank=pB-aP; |
|
311 memset(iPageNumLUT+start_area, pwr_bank, num_areas); |
|
312 } |
|
313 } |
|
314 Kern::Free(phys_banks); |
|
315 |
|
316 phys_bank=0xff; |
|
317 pwr_bank=-1; |
|
318 TInt area; |
|
319 iNumGroups=0; |
|
320 for (area=0; area<=iNumAreas; ++area) |
|
321 { |
|
322 TInt pb=(area<iNumAreas)?iPhysAddrLUT[area]:0xff; |
|
323 TInt pwb=aP?((area<iNumAreas)?iPageNumLUT[area]:0xff):-1; |
|
324 __KTRACE_OPT(KMMU,Kern::Printf("Area %04x (%08x) : pb=%02x pwb=%02x",area,iPhysAddrBase+(area<<iAreaShift),pb,pwb)); |
|
325 if (pb!=phys_bank || pwb!=pwr_bank) |
|
326 { |
|
327 if (pb!=0xff && pwb==0xff) |
|
328 return EInvalidPowerBlocks; |
|
329 if (phys_bank!=0xff) |
|
330 ++iNumGroups; |
|
331 phys_bank=pb; |
|
332 if (aP) |
|
333 pwr_bank=pwb; |
|
334 } |
|
335 } |
|
336 __KTRACE_OPT(KMMU,Kern::Printf("iNumGroups=%d",iNumGroups)); |
|
337 iGroups=(SGroup*)Kern::Alloc(iNumGroups*sizeof(SGroup)); |
|
338 if (!iGroups) |
|
339 return KErrNoMemory; |
|
340 if (aP) |
|
341 { |
|
342 iGroupPowerOrder = (TUint8*)Kern::Alloc(iNumGroups); |
|
343 if (!iGroupPowerOrder) |
|
344 return KErrNoMemory; |
|
345 } |
|
346 start_area=0; |
|
347 phys_bank=0xff; |
|
348 pwr_bank=0; |
|
349 TInt group=0; |
|
350 TInt page_number=0; |
|
351 for (area=0; area<=iNumAreas; ++area) |
|
352 { |
|
353 TInt pb=(area<iNumAreas)?iPhysAddrLUT[area]:0xff; |
|
354 TInt pwb=aP?((area<iNumAreas)?iPageNumLUT[area]:0xff):0; |
|
355 if (pb!=phys_bank || (aP && pwb!=pwr_bank)) |
|
356 { |
|
357 TInt group_num_areas=area-start_area; |
|
358 if (phys_bank!=0xff) |
|
359 { |
|
360 SGroup& g=iGroups[group]; |
|
361 TInt group_num_pages=TUint32(group_num_areas)<<iAreaPageShift; |
|
362 g.iBma=TBitMapAllocator::New(group_num_pages, ETrue); |
|
363 if (!g.iBma) |
|
364 return KErrNoMemory; |
|
365 g.iPhysBase=(TPhysAddr(start_area)<<iAreaShift)+iPhysAddrBase; |
|
366 g.iNumBase=page_number; |
|
367 memset(iPhysAddrLUT+start_area, group, group_num_areas); |
|
368 memset(iPageNumLUT+(page_number>>iAreaPageShift), group, group_num_areas); |
|
369 page_number+=group_num_pages; |
|
370 g.iPwrBlock=pwr_bank; |
|
371 __KTRACE_OPT(KMMU,Kern::Printf("Group %d: PhysBase=%08x NumBase=%08x PwrBlock=%02x NumPages=%08x", |
|
372 group, g.iPhysBase, g.iNumBase, g.iPwrBlock, group_num_pages)); |
|
373 ++group; |
|
374 } |
|
375 start_area=area; |
|
376 phys_bank=pb; |
|
377 if (aP) |
|
378 pwr_bank=pwb; |
|
379 } |
|
380 } |
|
381 |
|
382 // shrink iPageNumLUT to correct size |
|
383 iPageNumLUT=(TUint8*)Kern::ReAlloc(iPageNumLUT, iTotalRamPages>>iAreaPageShift); |
|
384 |
|
385 if (aP) |
|
386 { |
|
387 // work out power block ordering of groups |
|
388 TBool identity=ETrue; |
|
389 TInt last_pwb=-1; |
|
390 group=0; |
|
391 while(group<iNumGroups) |
|
392 { |
|
393 TInt first_pwb=256; |
|
394 TInt i=0; |
|
395 TInt j=0; |
|
396 for (; i<iNumGroups; ++i) |
|
397 { |
|
398 TInt gpwb=iGroups[i].iPwrBlock; |
|
399 if (gpwb>last_pwb && gpwb<first_pwb) |
|
400 { |
|
401 j=i; |
|
402 first_pwb=gpwb; |
|
403 } |
|
404 } |
|
405 do { |
|
406 if (j!=group) |
|
407 identity=EFalse; |
|
408 iGroupPowerOrder[group++]=j++; |
|
409 } while (j<iNumGroups && iGroups[j].iPwrBlock==first_pwb); |
|
410 last_pwb=first_pwb; |
|
411 } |
|
412 if (identity) |
|
413 { |
|
414 // power order and physical address order coincide so no need to keep iGroupPowerOrder |
|
415 Kern::Free(iGroupPowerOrder); |
|
416 iGroupPowerOrder=NULL; |
|
417 } |
|
418 } |
|
419 |
|
420 // Now mark any reserved regions as allocated |
|
421 const SRamBank* pB = pE + 1; // first reserved block specifier |
|
422 for (; pB->iSize; ++pB) |
|
423 { |
|
424 __KTRACE_OPT(KMMU, Kern::Printf("Reserve physical block %08x+%x", pB->iBase, pB->iSize)); |
|
425 TInt r = SetPhysicalRamState(pB->iBase, pB->iSize, EFalse); |
|
426 __KTRACE_OPT(KMMU, Kern::Printf("Reserve returns %d", r)); |
|
427 if (r!=KErrNone) |
|
428 return r; |
|
429 } |
|
430 |
|
431 __KTRACE_OPT(KMMU,DebugDump()); |
|
432 return KErrNone; |
|
433 } |
|
434 |
|
435 SGroup* DRamAllocator::GetGroupAndOffset(TPhysAddr aAddr, TInt& aOffset) |
|
436 { |
|
437 if (aAddr<iPhysAddrBase || aAddr>=iPhysAddrTop) |
|
438 return NULL; |
|
439 TInt area=TInt((aAddr-iPhysAddrBase)>>iAreaShift); |
|
440 TInt group=iPhysAddrLUT[area]; |
|
441 if (group==0xff) |
|
442 return NULL; |
|
443 SGroup& g=iGroups[group]; |
|
444 aOffset=(aAddr-g.iPhysBase)>>iPageShift; |
|
445 return &g; |
|
446 } |
|
447 |
|
448 void DRamAllocator::MarkPagesAllocated(TInt aPageNum, TInt aCount) |
|
449 { |
|
450 __KTRACE_OPT(KMMU,Kern::Printf("DRamAllocator::MarkPagesAllocated(%x+%x)",aPageNum,aCount)); |
|
451 if ((TUint32(aPageNum)>=TUint32(iTotalRamPages)) || (TUint32(aCount)>TUint32(iTotalRamPages-aPageNum))) |
|
452 Panic(EDoMarkPagesAllocated1); |
|
453 TInt area=aPageNum>>iAreaPageShift; |
|
454 SGroup* pG=iGroups+iPageNumLUT[area]; |
|
455 iTotalFreeRamPages-=aCount; |
|
456 while(aCount) |
|
457 { |
|
458 TInt gpnb=pG->iNumBase; |
|
459 TBitMapAllocator& bma=*pG->iBma; |
|
460 TInt gsz=bma.iSize; |
|
461 TInt ix=aPageNum-gpnb; |
|
462 TInt count=Min(gsz-ix,aCount); |
|
463 bma.Alloc(ix,count); |
|
464 TInt pwb=pG->iPwrBlock; |
|
465 iPowerBlockPages[pwb]+=count; |
|
466 iPowerState|=(1u<<pwb); |
|
467 aCount-=count; |
|
468 aPageNum+=count; |
|
469 ++pG; |
|
470 } |
|
471 } |
|
472 |
|
473 TInt DRamAllocator::MarkPageAllocated(TPhysAddr aAddr) |
|
474 { |
|
475 __KTRACE_OPT(KMMU,Kern::Printf("DRamAllocator::MarkPageAllocated %08x",aAddr)); |
|
476 TInt n; |
|
477 SGroup* g=GetGroupAndOffset(aAddr,n); |
|
478 if (!g) |
|
479 return KErrArgument; |
|
480 __KTRACE_OPT(KMMU2,Kern::Printf("Group %d index %04x",g-iGroups,n)); |
|
481 TBitMapAllocator& bma=*g->iBma; |
|
482 if (bma.NotFree(n,1)) |
|
483 { |
|
484 __KTRACE_OPT(KMMU,Kern::Printf("Page already allocated")); |
|
485 return KErrAlreadyExists; // page is already allocated |
|
486 } |
|
487 bma.Alloc(n,1); |
|
488 --iTotalFreeRamPages; |
|
489 TInt pwb=g->iPwrBlock; |
|
490 if (++iPowerBlockPages[pwb]==1) |
|
491 iPowerState|=(1u<<pwb); |
|
492 __KTRACE_OPT(KMMU,Kern::Printf("Total free RAM pages now = %d",iTotalFreeRamPages)); |
|
493 return KErrNone; |
|
494 } |
|
495 |
|
496 TInt DRamAllocator::FreeRamPage(TPhysAddr aAddr) |
|
497 { |
|
498 __KTRACE_OPT(KMMU,Kern::Printf("FreeRamPage %08x",aAddr)); |
|
499 TInt n; |
|
500 SGroup* g=GetGroupAndOffset(aAddr,n); |
|
501 if (!g) |
|
502 return KErrArgument; |
|
503 __KTRACE_OPT(KMMU2,Kern::Printf("Group %d index %04x",g-iGroups,n)); |
|
504 TBitMapAllocator& bma=*g->iBma; |
|
505 bma.Free(n); |
|
506 ++iTotalFreeRamPages; |
|
507 TInt pwb=g->iPwrBlock; |
|
508 if (--iPowerBlockPages[pwb]==0) |
|
509 iPowerState&=~(1u<<pwb); |
|
510 return KErrNone; |
|
511 } |
|
512 |
|
513 void DRamAllocator::FreeRamPages(TPhysAddr* aPageList, TInt aNumPages) |
|
514 { |
|
515 __KTRACE_OPT(KMMU,Kern::Printf("FreeRamPages count=%08x",aNumPages)); |
|
516 while(aNumPages--) |
|
517 { |
|
518 TPhysAddr first_pa=*aPageList++; |
|
519 if (first_pa==NULL_PAGE) |
|
520 continue; |
|
521 TInt ix; |
|
522 SGroup* g=GetGroupAndOffset(first_pa,ix); |
|
523 if (!g) |
|
524 continue; |
|
525 TBitMapAllocator& bma=*g->iBma; |
|
526 TInt gp_rem=bma.iSize-ix; |
|
527 __KTRACE_OPT(KMMU,Kern::Printf("1st PA=%08x Group %d index %04x",first_pa,g-iGroups,ix)); |
|
528 TInt n=1; |
|
529 TPhysAddr pa=first_pa+iPageSize; |
|
530 while (--gp_rem && aNumPages && *aPageList==pa) |
|
531 { |
|
532 ++n; |
|
533 --aNumPages; |
|
534 ++aPageList; |
|
535 pa+=iPageSize; |
|
536 } |
|
537 __KTRACE_OPT(KMMU2,Kern::Printf("%d consecutive pages, gp_rem=%x, %d remaining pages",n,gp_rem,aNumPages)); |
|
538 bma.Free(ix,n); |
|
539 iTotalFreeRamPages+=n; |
|
540 TInt pwb=g->iPwrBlock; |
|
541 if ((iPowerBlockPages[pwb]-=n)==0) |
|
542 iPowerState&=~(1u<<pwb); |
|
543 } |
|
544 } |
|
545 |
|
546 /** |
|
547 @return 0 on success, on failure, the number of extra pages required to fulfill the request |
|
548 */ |
|
549 TInt DRamAllocator::AllocRamPages(TPhysAddr* aPageList, TInt aNumPages) |
|
550 { |
|
551 __KTRACE_OPT(KMMU,Kern::Printf("AllocRamPages %x",aNumPages)); |
|
552 TInt numMissing = aNumPages-iTotalFreeRamPages; |
|
553 if (numMissing>0) |
|
554 return numMissing; |
|
555 iTotalFreeRamPages-=aNumPages; |
|
556 TInt gix; |
|
557 for (gix=0; aNumPages && gix<iNumGroups; ++gix) |
|
558 { |
|
559 TInt group=iGroupPowerOrder?iGroupPowerOrder[gix]:gix; |
|
560 SGroup& g=iGroups[group]; |
|
561 TBitMapAllocator& bma=*g.iBma; |
|
562 TPhysAddr gpb=g.iPhysBase; |
|
563 TInt got=bma.AllocList(aNumPages, (TInt*)aPageList); |
|
564 if (got) |
|
565 { |
|
566 TInt pwb=g.iPwrBlock; |
|
567 TPhysAddr* pE=aPageList+got; |
|
568 while(aPageList<pE) |
|
569 { |
|
570 TInt ix=*aPageList; |
|
571 *aPageList++=gpb+(ix<<iPageShift); |
|
572 __KTRACE_OPT(KMMU,Kern::Printf("Got page @%08x",gpb+(ix<<iPageShift))); |
|
573 } |
|
574 aNumPages-=got; |
|
575 iPowerBlockPages[pwb]+=got; |
|
576 iPowerState |= (1u<<pwb); |
|
577 } |
|
578 } |
|
579 __ASSERT_ALWAYS(aNumPages==0, Panic(EAllocRamPagesInconsistent)); |
|
580 return 0; |
|
581 } |
|
582 |
|
583 TInt DRamAllocator::FindContiguousRam(TInt aNumPages, TInt aAlignWrtPage, TUint8* aPermute, TInt& aPageNum) |
|
584 { |
|
585 __KTRACE_OPT(KMMU,Kern::Printf("FindContiguousRam np=%d align=%d",aNumPages,aAlignWrtPage)); |
|
586 TUint32 alignsize=1u<<aAlignWrtPage; |
|
587 TUint32 alignmask=alignsize-1; |
|
588 __KTRACE_OPT(KMMU,Kern::Printf("alignsize=%08x alignmask=%08x",alignsize,alignmask)); |
|
589 TInt base=KErrNotFound; |
|
590 TInt gplen=0; |
|
591 TInt carry=0; |
|
592 TInt gix; |
|
593 for (gix=0; gix<iNumGroups; ++gix) |
|
594 { |
|
595 TInt group=aPermute?aPermute[gix]:gix; |
|
596 SGroup& g=iGroups[group]; |
|
597 TBitMapAllocator& bma=*g.iBma; |
|
598 TInt gpb=TInt(g.iPhysBase>>iPageShift); |
|
599 if (gpb!=base+gplen) |
|
600 { |
|
601 // this group is not contiguous with previous one |
|
602 carry=0; |
|
603 } |
|
604 base=gpb; |
|
605 gplen=bma.iSize; |
|
606 __KTRACE_OPT(KMMU,Kern::Printf("FCR: base=%08x gplen=%08x carry=%08x",base,gplen,carry)); |
|
607 TInt l; |
|
608 TInt r=bma.AllocAligned(aNumPages, aAlignWrtPage, base, EFalse, carry, l); |
|
609 __KTRACE_OPT(KMMU,Kern::Printf("FCR: r=%08x",r)); |
|
610 if (r>=0) |
|
611 { |
|
612 TInt p=(base+r-carry+alignmask)&~alignmask; |
|
613 aPageNum=g.iNumBase+p-base; |
|
614 return p; |
|
615 } |
|
616 } |
|
617 return KErrNotFound; |
|
618 } |
|
619 |
|
620 TInt DRamAllocator::AllocContiguousRam(TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign) |
|
621 { |
|
622 __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam size %08x align %d",aSize,aAlign)); |
|
623 TInt npages=(aSize+iPageSize-1)>>iPageShift; |
|
624 TInt align_wrt_page=Max(aAlign-iPageShift,0); |
|
625 |
|
626 TInt pagenum; |
|
627 TInt found=FindContiguousRam(npages, align_wrt_page, iGroupPowerOrder, pagenum); |
|
628 if (found<0 && iGroupPowerOrder) |
|
629 found=FindContiguousRam(npages, align_wrt_page, NULL, pagenum); |
|
630 if (found<0) |
|
631 return KErrNoMemory; |
|
632 aPhysAddr=TPhysAddr(found)<<iPageShift; |
|
633 __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %08x(%x)",aPhysAddr,pagenum)); |
|
634 MarkPagesAllocated(pagenum, npages); |
|
635 return KErrNone; |
|
636 } |
|
637 |
|
638 TInt DRamAllocator::SetPhysicalRamState(TPhysAddr aBase, TInt aSize, TBool aState) |
|
639 { |
|
640 __KTRACE_OPT(KMMU,Kern::Printf("SetPhysicalRamState(%08x,%x,%d)",aBase,aSize,aState?1:0)); |
|
641 TUint32 m=iPageSize-1; |
|
642 aSize+=(aBase&m); |
|
643 aBase&=~m; |
|
644 TInt npages=(aSize+m)>>iPageShift; |
|
645 __KTRACE_OPT(KMMU,Kern::Printf("Rounded base %08x npages=%x",aBase,npages)); |
|
646 TInt ix0; |
|
647 SGroup* g0=GetGroupAndOffset(aBase,ix0); |
|
648 if (!g0) |
|
649 return KErrArgument; |
|
650 if ((TUint32)aSize>iPhysAddrTop-aBase) |
|
651 return KErrArgument; |
|
652 SGroup* g=g0; |
|
653 SGroup* gE=iGroups+iNumGroups; |
|
654 TPhysAddr base=aBase; |
|
655 TInt n=npages; |
|
656 TInt ix=ix0; |
|
657 TInt r=KErrNone; |
|
658 TInt c=-1; |
|
659 __KTRACE_OPT(KMMU2,Kern::Printf("Group %d index %x g=%08x gE=%08x n=%x base=%08x",g-iGroups,ix,g,gE,n,base)); |
|
660 for (; n && g<gE && g->iPhysBase+(ix<<iPageShift)==base ; ++g, n-=c, ix=0, base+=(TPhysAddr(c)<<iPageShift)) |
|
661 { |
|
662 TBitMapAllocator& bma=*g->iBma; |
|
663 TInt gp_rem=bma.iSize-ix; |
|
664 c=Min(n, gp_rem); |
|
665 __KTRACE_OPT(KMMU2,Kern::Printf("Group %d pages %x+%x base %08x",g-iGroups,ix,c,base)); |
|
666 if(aState) |
|
667 { |
|
668 if(bma.NotAllocated(ix,c)) |
|
669 r=KErrGeneral; |
|
670 } |
|
671 else |
|
672 { |
|
673 if(bma.NotFree(ix,c)) |
|
674 r=KErrInUse; |
|
675 } |
|
676 } |
|
677 if (n) |
|
678 return KErrArgument; // not all of the specified range exists |
|
679 if (r!=KErrNone) |
|
680 return r; // some pages were already free/allocated |
|
681 iTotalFreeRamPages += (aState ? npages : -npages); |
|
682 for (g=g0, n=npages, ix=ix0; n; ++g, n-=c, ix=0) |
|
683 { |
|
684 TBitMapAllocator& bma=*g->iBma; |
|
685 TInt pwb=g->iPwrBlock; |
|
686 TInt& p=iPowerBlockPages[pwb]; |
|
687 TUint32 pm=1u<<pwb; |
|
688 TInt gp_rem=bma.iSize-ix; |
|
689 c=Min(n, gp_rem); |
|
690 __KTRACE_OPT(KMMU2,Kern::Printf("Group %d pages %x+%x base %08x",g-iGroups,ix,c,base)); |
|
691 aState ? (bma.Free(ix,c), (p||(iPowerState|=pm)), p+=c) : (bma.Alloc(ix,c), ((p-=c)||(iPowerState&=~pm)) ); |
|
692 } |
|
693 return KErrNone; |
|
694 } |
|
695 |
|