|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This material, including documentation and any related computer |
|
5 * programs, is protected by copyright controlled by Nokia. All |
|
6 * rights are reserved. Copying, including reproducing, storing |
|
7 * adapting or translating, any or all of this material requires the |
|
8 * prior written consent of Nokia. This material also contains |
|
9 * confidential information which may not be disclosed to others |
|
10 * without the prior written consent of Nokia. |
|
11 * |
|
12 * Initial Contributors: |
|
13 * Nokia Corporation - initial contribution. |
|
14 * |
|
15 * Contributors: |
|
16 * |
|
17 * Description: Device-driver for naviEngine PCI testing |
|
18 * |
|
19 */ |
|
20 |
|
21 #include <kernel/kernel.h> |
|
22 #include <kernel/kern_priv.h> |
|
23 #include <pci.h> |
|
24 #include <naviengine.h> |
|
25 #include <kernel/cache.h> |
|
26 #include "allocator.h" |
|
27 #include "pci-ne.h" |
|
28 #include "pci_priv.h" |
|
29 #include <platform.h> |
|
30 #include "t_pci.h" |
|
31 #include "../../naviengine_assp/naviengine_pci.h" |
|
32 |
|
33 #define TEST(X) __NK_ASSERT_ALWAYS(X) |
|
34 #define TEST_KERRNONE(X) if((X) !=KErrNone) {\ |
|
35 Kern::Printf("Assertion Failed X=%d", (X)); FAULT();} |
|
36 |
|
37 #define FUNC_LOG() __KTRACE_OPT(KPCI, Kern::Printf(__PRETTY_FUNCTION__)) |
|
38 |
|
39 |
|
40 void TestAllocator(); |
|
41 |
|
42 /** |
|
43 So that the test app can get notification |
|
44 when PCI DChunks' cleanup operation has run |
|
45 we will replace their cleanup object with this |
|
46 one, which will call the original object's destroy |
|
47 function as well completing a notification |
|
48 */ |
|
49 class TPciCleanupWrapper : public TChunkCleanup |
|
50 { |
|
51 public: |
|
52 |
|
53 ~TPciCleanupWrapper() |
|
54 { |
|
55 delete iOriginal; |
|
56 Kern::DestroyClientRequest(iClientRequest); |
|
57 iClient->Close(NULL); |
|
58 } |
|
59 |
|
60 static TPciCleanupWrapper* Create(TRequestStatus* aRequestStatus) |
|
61 { |
|
62 __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create aRequestStatus=0x%08x", aRequestStatus)); |
|
63 TClientRequest* request = NULL; |
|
64 TInt r = Kern::CreateClientRequest(request); |
|
65 if(r != KErrNone) |
|
66 { |
|
67 __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create Failed to create client request r=%d", r)); |
|
68 return NULL; |
|
69 } |
|
70 |
|
71 r = request->SetStatus(aRequestStatus); |
|
72 if(r != KErrNone) |
|
73 { |
|
74 __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create Failed to set status r=%d", r)); |
|
75 Kern::DestroyClientRequest(request); |
|
76 return NULL; |
|
77 } |
|
78 |
|
79 return new TPciCleanupWrapper(request); |
|
80 } |
|
81 |
|
82 /** |
|
83 Insert the cleanup object into aChunk, remembering |
|
84 the original one |
|
85 |
|
86 @param aChunk a chunk known to have TChunkCleanup derived cleanup object |
|
87 */ |
|
88 void Insert(DChunk* aChunk) |
|
89 { |
|
90 __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Insert aChunk=0x%08x", aChunk)); |
|
91 __NK_ASSERT_DEBUG(aChunk); |
|
92 __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper replace 0x%08x with 0x%08x", aChunk->iDestroyedDfc, this)); |
|
93 iOriginal = static_cast<TChunkCleanup*>(aChunk->iDestroyedDfc); |
|
94 |
|
95 __NK_ASSERT_DEBUG(iOriginal); |
|
96 aChunk->iDestroyedDfc = this; |
|
97 } |
|
98 |
|
99 /** |
|
100 Run the original object's destroy method |
|
101 then notify client |
|
102 */ |
|
103 void Destroy() |
|
104 { |
|
105 __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Destroy\n")); |
|
106 iOriginal->Destroy(); |
|
107 |
|
108 __NK_ASSERT_ALWAYS(iClientRequest->IsReady()); |
|
109 Kern::QueueRequestComplete(iClient, iClientRequest, KErrNone); |
|
110 } |
|
111 |
|
112 private: |
|
113 TPciCleanupWrapper(TClientRequest* aRequest) |
|
114 :TChunkCleanup(), iOriginal(NULL), iClientRequest(aRequest), iClient(&Kern::CurrentThread()) |
|
115 { |
|
116 __ASSERT_CRITICAL; |
|
117 iClient->Open(); //don't allow thread object to be destroyed before we signal |
|
118 } |
|
119 |
|
120 |
|
121 TChunkCleanup* iOriginal; |
|
122 TClientRequest* iClientRequest; |
|
123 DThread* const iClient; |
|
124 }; |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 //This information will come from the pci driver |
|
130 //if this code is ever made generic |
|
131 TPciTestInfo KTestInfo = |
|
132 { |
|
133 TPciDevice(0x1033, 0x35, 0), |
|
134 TPciTestInfo::TAddrSpaceTest(0, 0x00351033, 0), |
|
135 TPciTestInfo::TAddrSpaceTest(KPciBar0, 0, 0xFFF), |
|
136 0, |
|
137 TPciTestInfo::TAddrSpaceTest(0x34, 0x2EDF, 0), |
|
138 TPciTestInfo::TAddrSpaceTest(0x20, 0, 0xF), |
|
139 KNeBridgeNumberOfBars |
|
140 }; |
|
141 |
|
142 /** |
|
143 Class for a DChunk to remove a DPlatHwChunk chunk |
|
144 */ |
|
145 class TPciPlatChunkCleanup : public TChunkCleanup |
|
146 { |
|
147 public: |
|
148 TPciPlatChunkCleanup(TInt aPciFunction, DPlatChunkHw* aPciPlatChunk); |
|
149 virtual void Destroy(); |
|
150 public: |
|
151 TInt iPciFunction; |
|
152 DPlatChunkHw* iPciChunk; |
|
153 }; |
|
154 |
|
155 TPciPlatChunkCleanup::TPciPlatChunkCleanup(TInt aPciFunction, DPlatChunkHw* aPciPlatChunk) |
|
156 : TChunkCleanup(), iPciFunction(aPciFunction), iPciChunk(aPciPlatChunk) |
|
157 { |
|
158 } |
|
159 |
|
160 void TPciPlatChunkCleanup::Destroy() |
|
161 { |
|
162 __KTRACE_OPT(KPCI, Kern::Printf("SHAREDCHUNK ChunkDestroyed DFC\n")); |
|
163 TInt r = Pci::RemoveChunk(iPciFunction, iPciChunk); |
|
164 __NK_ASSERT_ALWAYS(r==KErrNone); |
|
165 } |
|
166 |
|
167 /** |
|
168 Cleanup class to remove the mapping for an externally |
|
169 mapped chunk |
|
170 */ |
|
171 class TPciMappedChunkCleanup : public TChunkCleanup |
|
172 { |
|
173 public: |
|
174 TPciMappedChunkCleanup (TInt aPciFunction,TUint32 aPhysicalAddress); |
|
175 virtual void Destroy(); |
|
176 public: |
|
177 TInt iPciFunction; |
|
178 TUint32 iPhysicalAddress; |
|
179 }; |
|
180 |
|
181 TPciMappedChunkCleanup::TPciMappedChunkCleanup(TInt aPciFunction,TUint32 aPhysicalAddress) |
|
182 : TChunkCleanup(), iPciFunction(aPciFunction),iPhysicalAddress(aPhysicalAddress) |
|
183 { |
|
184 } |
|
185 |
|
186 void TPciMappedChunkCleanup::Destroy() |
|
187 { |
|
188 //remove mapping |
|
189 TInt r = Pci::RemoveMapping(iPciFunction, iPhysicalAddress); |
|
190 __NK_ASSERT_ALWAYS(r==KErrNone); |
|
191 __KTRACE_OPT(KPCI, Kern::Printf("MAPPING REMOVED ChunkDestroyed DFC\n")); |
|
192 } |
|
193 |
|
194 class DPciTestChannel : public DLogicalChannelBase |
|
195 { |
|
196 public: |
|
197 DPciTestChannel(); |
|
198 virtual ~DPciTestChannel(); |
|
199 TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); |
|
200 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); |
|
201 |
|
202 private: |
|
203 TInt OpenPciDChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus); |
|
204 TInt OpenPciPlatHwChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus); |
|
205 TInt OpenPciMappedChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus); |
|
206 TInt CreateSharedChunk(TInt aPciChunkSize, TUint32 aAttributes, DChunk*& aChunk, TLinAddr& aVirt, TPhysAddr& aPhysicalAddress); |
|
207 TInt OpenPciWindowChunk(); |
|
208 void RunUnitTests(); |
|
209 |
|
210 private: |
|
211 const TPciTestInfo& iTestInfo; |
|
212 TInt iFunction; ///< PCI function number this channel is associated with |
|
213 }; |
|
214 |
|
215 DPciTestChannel::DPciTestChannel() |
|
216 : iTestInfo(KTestInfo), iFunction(-1) |
|
217 { |
|
218 FUNC_LOG(); |
|
219 } |
|
220 |
|
221 DPciTestChannel::~DPciTestChannel() |
|
222 { |
|
223 FUNC_LOG(); |
|
224 } |
|
225 |
|
226 TInt DPciTestChannel::DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer) |
|
227 { |
|
228 if(aInfo == NULL) |
|
229 return KErrNone; //Not a device specific channel |
|
230 |
|
231 TPciDevice dev; |
|
232 TPckg<TPciDevice> devPckg(dev); |
|
233 TInt r = Kern::ThreadDesRead(&Kern::CurrentThread(), aInfo, devPckg, 0, KChunkShiftBy0); |
|
234 if(r != KErrNone) |
|
235 return r; |
|
236 |
|
237 NKern::ThreadEnterCS(); |
|
238 RArray<TInt> indicies; |
|
239 r = Pci::Probe(indicies, dev.iVendorId, dev.iDeviceId); |
|
240 |
|
241 if((KErrNone == r) && (dev.iInstance < indicies.Count())) |
|
242 { |
|
243 iFunction = indicies[dev.iInstance]; |
|
244 } |
|
245 else |
|
246 { |
|
247 r = KErrNotFound; |
|
248 } |
|
249 |
|
250 indicies.Close(); |
|
251 NKern::ThreadLeaveCS(); |
|
252 return r; |
|
253 } |
|
254 |
|
255 TInt DPciTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2) |
|
256 { |
|
257 switch (aFunction) |
|
258 { |
|
259 case EGetTestInfo: |
|
260 { |
|
261 TDes8& dest(*(TDes8*)a1); |
|
262 TPckgC<TPciTestInfo> info(iTestInfo); |
|
263 Kern::KUDesPut(dest, info); |
|
264 return KErrNone; |
|
265 } |
|
266 case EAccessConfigSpace: |
|
267 { |
|
268 TPckgBuf<TUserConfigSpace> pckg; |
|
269 Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1)); |
|
270 |
|
271 TAddrSpace* configSpace = Pci::GetConfigSpace(iFunction); |
|
272 if(configSpace == NULL) |
|
273 { |
|
274 Kern::PanicCurrentThread(KPciTest, KErrGeneral); |
|
275 return KErrGeneral; |
|
276 } |
|
277 return pckg().KRun(*configSpace); |
|
278 } |
|
279 case EAccessMemorySpace: |
|
280 { |
|
281 TPckgBuf<TUserMemorySpace> pckg; |
|
282 Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1)); |
|
283 |
|
284 TAddrSpace* memSpace = Pci::GetMemorySpace(iFunction, pckg().BarIndex()); |
|
285 if(memSpace == NULL) |
|
286 { |
|
287 Kern::PanicCurrentThread(KPciTest, KErrGeneral); |
|
288 return KErrGeneral; |
|
289 } |
|
290 return pckg().KRun(*memSpace); |
|
291 } |
|
292 case EOpenPciWindowChunk: |
|
293 { |
|
294 TInt rHandle = 0; |
|
295 rHandle = OpenPciWindowChunk(); |
|
296 return rHandle; |
|
297 } |
|
298 case EOpenPciDChunk: //Fall-through |
|
299 case EOpenPciPlatHwChunk: |
|
300 case EOpenPciMappedChunk: |
|
301 { |
|
302 TPckgBuf<TPciChunkCreateInfo> pckg; |
|
303 Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1)); |
|
304 |
|
305 TUint32 pciAddr; |
|
306 TInt rHandle = 0; |
|
307 switch (aFunction) |
|
308 { |
|
309 case EOpenPciDChunk: |
|
310 { |
|
311 rHandle = OpenPciDChunk(pciAddr, pckg().iSize, pckg().iStatus); |
|
312 break; |
|
313 } |
|
314 case EOpenPciPlatHwChunk: |
|
315 { |
|
316 rHandle = OpenPciPlatHwChunk(pciAddr, pckg().iSize, pckg().iStatus); |
|
317 break; |
|
318 } |
|
319 case EOpenPciMappedChunk: |
|
320 { |
|
321 rHandle = OpenPciMappedChunk(pciAddr, pckg().iSize, pckg().iStatus); |
|
322 break; |
|
323 } |
|
324 default: |
|
325 { |
|
326 FAULT(); |
|
327 } |
|
328 } |
|
329 //write back PCI address to user |
|
330 umemput(pckg().iPciAddress,&pciAddr,sizeof(pciAddr)); |
|
331 return rHandle; |
|
332 } |
|
333 case ERunUnitTests: |
|
334 { |
|
335 RunUnitTests(); |
|
336 return KErrNone; |
|
337 } |
|
338 default: |
|
339 return KErrNotSupported; |
|
340 } |
|
341 } |
|
342 |
|
343 /** |
|
344 This function runs tests for the address allocator |
|
345 */ |
|
346 void DPciTestChannel::RunUnitTests() |
|
347 { |
|
348 // Enter critical section |
|
349 NKern::ThreadEnterCS(); |
|
350 |
|
351 TestAllocator(); |
|
352 |
|
353 // Finished |
|
354 NKern::ThreadLeaveCS(); |
|
355 } |
|
356 |
|
357 |
|
358 /** |
|
359 This function creates and opens a PCI DChunk and returns the PCI addresss |
|
360 @param aPciAddr on return contains the pci address |
|
361 @param aPciChunkSize contains the size of the PCI DChunk which is to be created |
|
362 */ |
|
363 TInt DPciTestChannel::OpenPciDChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus) |
|
364 { |
|
365 //Chunk Attributes |
|
366 TChunkCreateInfo aInfo; |
|
367 aInfo.iType = TChunkCreateInfo::ESharedKernelMultiple; |
|
368 aInfo.iMapAttr = EMapAttrSupRw|EMapAttrFullyBlocking; |
|
369 aInfo.iOwnsMemory = EFalse; // We'll be using our own devices memory |
|
370 |
|
371 DChunk* pciChunk; |
|
372 pciChunk=NULL; |
|
373 |
|
374 // Enter critical section |
|
375 NKern::ThreadEnterCS(); |
|
376 |
|
377 //Create DChunk |
|
378 TInt r = Pci::CreateChunk(iFunction, pciChunk, aInfo,0,aPciChunkSize,aPciAddr); |
|
379 if(r!=KErrNone) |
|
380 { |
|
381 // Failed to create DChunk |
|
382 __KTRACE_OPT(KPCI,Kern::Printf("Failed to create DChunk: Error code is=%d", r) ); |
|
383 NKern::ThreadLeaveCS(); // Finished |
|
384 return r; |
|
385 } |
|
386 else |
|
387 { |
|
388 TInt rHandle = KErrGeneral; |
|
389 if(aStatus) |
|
390 { |
|
391 TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus); |
|
392 if(wrapper == NULL) |
|
393 { |
|
394 __KTRACE_OPT(KPCI,Kern::Printf("Creation of TPciCleanupWrapper failed")); |
|
395 goto End; |
|
396 } |
|
397 wrapper->Insert(pciChunk); |
|
398 } |
|
399 |
|
400 __KTRACE_OPT(KPCI,Kern::Printf("Created DChunk: PCI_ADDRESS=0x%08x",aPciAddr)); |
|
401 rHandle = Kern::MakeHandleAndOpen(NULL, pciChunk);//Get DChunk handle |
|
402 |
|
403 End: |
|
404 pciChunk->Close(NULL); // Close DChunk |
|
405 NKern::ThreadLeaveCS(); // Finished |
|
406 return rHandle; |
|
407 } |
|
408 } |
|
409 |
|
410 /** |
|
411 This function creates and opens a PCI DPlatChunk and returns the PCI addresss. |
|
412 A DPlatChunk is intially created and then a DChunk is set to point to the same |
|
413 memory as the DPlatChunk.This is done so that it can be accessed on the user side. |
|
414 @param aPciAddr on return contains the pci address |
|
415 @param aPciChunkSize contains the size of the PCI PlatHwChunk which is to be created |
|
416 */ |
|
417 TInt DPciTestChannel::OpenPciPlatHwChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus) |
|
418 { |
|
419 TUint32 pciPhysicalAddr; |
|
420 TUint32 pciChunkMapAttr; |
|
421 TLinAddr pciChunkKernelAddr; |
|
422 |
|
423 DPlatChunkHw* pciPlatChunk; |
|
424 pciPlatChunk=NULL; |
|
425 |
|
426 // Enter critical section |
|
427 NKern::ThreadEnterCS(); |
|
428 |
|
429 //Create DPlatChunkHw |
|
430 TInt r = Pci::CreateChunk(iFunction,pciPlatChunk,aPciChunkSize,(EMapAttrSupRw|EMapAttrFullyBlocking),aPciAddr); |
|
431 if(r!=KErrNone) |
|
432 { |
|
433 // Failed to create DPlatChunkHw |
|
434 __KTRACE_OPT(KPCI,Kern::Printf("Failed to create DPlatChunkHw chunk: Error code is=%d", r)); |
|
435 NKern::ThreadLeaveCS(); // Finished |
|
436 return r; |
|
437 } |
|
438 |
|
439 //Get physical addresss |
|
440 pciPhysicalAddr = pciPlatChunk->PhysicalAddress(); |
|
441 |
|
442 // Create DChunk cleanup object |
|
443 TPciPlatChunkCleanup* cleanup = new TPciPlatChunkCleanup(iFunction, pciPlatChunk); |
|
444 if(!cleanup) |
|
445 { |
|
446 pciPlatChunk->Close(NULL); //close pciPlatChunk |
|
447 NKern::ThreadLeaveCS(); |
|
448 return KErrNoMemory; |
|
449 } |
|
450 |
|
451 //Chunk Attributes for DChunk |
|
452 TChunkCreateInfo chunkinfo; |
|
453 chunkinfo.iType = TChunkCreateInfo::ESharedKernelMultiple; |
|
454 chunkinfo.iMaxSize = 0x4000; |
|
455 chunkinfo.iMapAttr = EMapAttrSupRw|EMapAttrFullyBlocking; // No caching |
|
456 chunkinfo.iOwnsMemory = EFalse; // Use memory from system's free pool |
|
457 chunkinfo.iDestroyedDfc = cleanup; |
|
458 |
|
459 DChunk* pciDChunk; |
|
460 |
|
461 //Create DChunk |
|
462 r = Kern::ChunkCreate(chunkinfo, pciDChunk, pciChunkKernelAddr, pciChunkMapAttr); |
|
463 if(r!=KErrNone) |
|
464 { |
|
465 pciPlatChunk->Close(NULL); //close pciPlatChunk |
|
466 delete cleanup; |
|
467 NKern::ThreadLeaveCS(); |
|
468 return r; |
|
469 } |
|
470 |
|
471 pciPlatChunk=NULL; // pciDChunk now owns chunk |
|
472 |
|
473 if(aStatus) |
|
474 { |
|
475 TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus); |
|
476 if(wrapper == NULL) |
|
477 { |
|
478 pciDChunk->Close(NULL); // Close pciDChunk |
|
479 NKern::ThreadLeaveCS(); // Finished |
|
480 return KErrGeneral; |
|
481 } |
|
482 wrapper->Insert(pciDChunk); |
|
483 } |
|
484 |
|
485 //Commit memory to a DChunk using DPlatChunkHw physical address |
|
486 r = Kern::ChunkCommitPhysical(pciDChunk,0,aPciChunkSize,pciPhysicalAddr); |
|
487 if(r!=KErrNone) |
|
488 { |
|
489 // Failed to commit memory |
|
490 Kern::Printf("Commit failed: Error code is=%d", r); |
|
491 __KTRACE_OPT(KPCI,Kern::Printf("Commit failed: Error code is=%d", r)); |
|
492 |
|
493 // Close chunk, which will then get deleted at some point |
|
494 Kern::ChunkClose(pciDChunk); |
|
495 NKern::ThreadLeaveCS(); |
|
496 return r; |
|
497 } |
|
498 |
|
499 //Close pciPlatChunk using pciDChunk as pciDChunk now owns it |
|
500 const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciDChunk); //Get DChunk handle |
|
501 pciDChunk->Close(NULL); // Close pciDChunk |
|
502 NKern::ThreadLeaveCS(); // Finished |
|
503 return rHandle; |
|
504 } |
|
505 |
|
506 /** |
|
507 This function creates and opens a PCI mapped DChunk and returns the PCI addresss |
|
508 @param aPciAddr on return contains the pci address |
|
509 @param aPciChunkSize contains the size of the PCI DChunk which is to be created |
|
510 */ |
|
511 TInt DPciTestChannel::OpenPciMappedChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus) |
|
512 { |
|
513 TLinAddr virt=NULL; |
|
514 TPhysAddr physicalAddress=NULL; |
|
515 DChunk* pciChunk=NULL; |
|
516 TUint32 pciAttributes=EMapAttrSupRw|EMapAttrFullyBlocking; |
|
517 |
|
518 // Enter critical section |
|
519 NKern::ThreadEnterCS(); |
|
520 |
|
521 //create DChunk |
|
522 TInt r = CreateSharedChunk(aPciChunkSize, pciAttributes, pciChunk, virt, physicalAddress); |
|
523 if(r!=KErrNone) |
|
524 { |
|
525 __KTRACE_OPT(KPCI,Kern::Printf("Create shared Chunk failed: Error code is=%d", r)); |
|
526 return r; |
|
527 } |
|
528 |
|
529 __NK_ASSERT_ALWAYS(pciChunk); |
|
530 |
|
531 //create mapping |
|
532 r=Pci::CreateMapping(iFunction, physicalAddress, aPciChunkSize, aPciAddr); |
|
533 if(r!=KErrNone) |
|
534 { |
|
535 pciChunk->Close(NULL); |
|
536 __KTRACE_OPT(KPCI,Kern::Printf("Create mapping failed: Error code is=%d", r)); |
|
537 return r; |
|
538 } |
|
539 |
|
540 |
|
541 // Create DChunk cleanup object |
|
542 TPciMappedChunkCleanup* cleanup = new TPciMappedChunkCleanup(iFunction, physicalAddress); |
|
543 if(!cleanup) |
|
544 { |
|
545 pciChunk->Close(NULL); |
|
546 NKern::ThreadLeaveCS(); |
|
547 return KErrNoMemory; |
|
548 } |
|
549 |
|
550 //must add the cleanup dfc to the chunk after creation |
|
551 //since the cleanup parameters aren't known |
|
552 //till after creating it and allocating memory to it |
|
553 pciChunk->iDestroyedDfc = cleanup; |
|
554 |
|
555 if(aStatus) |
|
556 { |
|
557 TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus); |
|
558 if(wrapper == NULL) |
|
559 { |
|
560 pciChunk->Close(NULL); // Close pciDChunk |
|
561 NKern::ThreadLeaveCS(); |
|
562 return KErrGeneral; |
|
563 } |
|
564 wrapper->Insert(pciChunk); |
|
565 } |
|
566 |
|
567 //Get DChunk handle |
|
568 const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciChunk); |
|
569 |
|
570 // Close DChunk |
|
571 pciChunk->Close(NULL); |
|
572 |
|
573 // Finished |
|
574 NKern::ThreadLeaveCS(); |
|
575 return rHandle; |
|
576 } |
|
577 |
|
578 /** |
|
579 This function creates and opens a PCI Window Chunk and returns the PCI Window addresss |
|
580 @param aPciChunkSize contains the size of the PCI Window DChunk which is to be created |
|
581 */ |
|
582 TInt DPciTestChannel::OpenPciWindowChunk() |
|
583 { |
|
584 TUint32 pciChunkMapAttr; |
|
585 TLinAddr pciChunkKernelAddr=NULL; |
|
586 DChunk* pciWindowChunk=NULL; |
|
587 |
|
588 //Chunk Attributes for DChunk |
|
589 TChunkCreateInfo chunkinfo; |
|
590 chunkinfo.iType = TChunkCreateInfo::ESharedKernelMultiple; |
|
591 chunkinfo.iMaxSize = 0x2000; |
|
592 chunkinfo.iMapAttr = EMapAttrSupRw|EMapAttrFullyBlocking; // No caching |
|
593 chunkinfo.iOwnsMemory = EFalse; // Use memory from system's free pool |
|
594 |
|
595 // Enter critical section |
|
596 NKern::ThreadEnterCS(); |
|
597 |
|
598 //Create shared chunk for PCI window |
|
599 TInt r = Kern::ChunkCreate(chunkinfo, pciWindowChunk, pciChunkKernelAddr, pciChunkMapAttr); |
|
600 if(r!=KErrNone) |
|
601 { |
|
602 // Failed to create DChunk |
|
603 __KTRACE_OPT(KPCI,Kern::Printf("Failed to create DChunk: Error code is=%d", r) ); |
|
604 NKern::ThreadLeaveCS(); |
|
605 return r; |
|
606 } |
|
607 |
|
608 //This address is PSL specific. This will have to be changed |
|
609 //if d_pci.cpp is ever made generic |
|
610 TUint32 pciPhysicalAddr = KHwUSBHPhys; // Internal PCI window address |
|
611 |
|
612 //Commit memory to a DChunk using Internal PCI window address |
|
613 r = Kern::ChunkCommitPhysical(pciWindowChunk,0,KHwUSBHInternalPciWindowSize, pciPhysicalAddr); |
|
614 if(r!=KErrNone) |
|
615 { |
|
616 // Failed to commit memory |
|
617 Kern::Printf("Commit failed: Error code is=%d", r); |
|
618 __KTRACE_OPT(KPCI,Kern::Printf("Commit failed: Error code is=%d", r)); |
|
619 |
|
620 // Close chunk, which will then get deleted at some point |
|
621 Kern::ChunkClose(pciWindowChunk); |
|
622 NKern::ThreadLeaveCS(); |
|
623 return r; |
|
624 } |
|
625 |
|
626 //Close pciPlatChunk using pciDChunk as pciDChunk now owns it |
|
627 const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciWindowChunk); //Get PCI Window DChunk handle |
|
628 pciWindowChunk->Close(NULL); // Close pci window chunk |
|
629 NKern::ThreadLeaveCS(); // Finished |
|
630 return rHandle; |
|
631 } |
|
632 |
|
633 /** |
|
634 This function creates and opens a shared chunk. The chunk is then commited to a contiguous memory |
|
635 @param aPciChunkSize contains the size of the PCI DChunk which is to be created |
|
636 @param aAttributes on return, this is set to the mmu mapping attributes used for the chunk |
|
637 @param aChunk on return, a reference to the shared chunk |
|
638 @param aVirt on return, this is set to the virtual address shared chunk |
|
639 @param aPhysicalAddress on return, this is set to the physical address of the first page of memory |
|
640 which was committed. |
|
641 */ |
|
642 TInt DPciTestChannel::CreateSharedChunk(TInt aPciChunkSize, TUint32 aAttributes, DChunk*& aChunk, TLinAddr& aVirt, TPhysAddr& aPhysicalAddress) |
|
643 { |
|
644 __NK_ASSERT_DEBUG(aChunk==NULL); |
|
645 aPciChunkSize = Kern::RoundToPageSize(aPciChunkSize); |
|
646 DChunk* pC=NULL; |
|
647 |
|
648 // Enter critical section |
|
649 NKern::ThreadEnterCS(); |
|
650 |
|
651 //Chunk Attributes for DChunk |
|
652 TChunkCreateInfo info; |
|
653 info.iType=TChunkCreateInfo::ESharedKernelSingle; |
|
654 info.iMaxSize=aPciChunkSize; |
|
655 info.iMapAttr=aAttributes; |
|
656 info.iOwnsMemory=ETrue; |
|
657 |
|
658 //Create DChunk |
|
659 TInt r=Kern::ChunkCreate(info, pC, aVirt, aAttributes); |
|
660 if(r!=KErrNone) |
|
661 { |
|
662 NKern::ThreadLeaveCS(); |
|
663 return r; |
|
664 } |
|
665 //Commit DChunk to Contiguous memory |
|
666 r = Kern::ChunkCommitContiguous(pC, 0, aPciChunkSize, aPhysicalAddress); |
|
667 if(r==KErrNone) |
|
668 { |
|
669 aChunk=pC; |
|
670 } |
|
671 else |
|
672 { |
|
673 Kern::ChunkClose(pC); |
|
674 __KTRACE_OPT(KPCI,Kern::Printf("Commit DChunk to Contiguous memory Failed : Error code is=%d",r)); |
|
675 return r; |
|
676 } |
|
677 |
|
678 NKern::ThreadLeaveCS(); // Finished |
|
679 __KTRACE_OPT(KPCI, Kern::Printf("Created SC: size=0x%08x, virtual= 0x%08x, phys=0x%08x", aPciChunkSize, aVirt, aPhysicalAddress)); |
|
680 return r; |
|
681 } |
|
682 |
|
683 class DPciDevice : public DLogicalDevice |
|
684 { |
|
685 public: |
|
686 DPciDevice(); |
|
687 ~DPciDevice(); |
|
688 TInt Install(); |
|
689 void GetCaps(TDes8& aDes) const; |
|
690 TInt Create(DLogicalChannelBase*& aChannel); |
|
691 }; |
|
692 |
|
693 DPciDevice::DPciDevice() |
|
694 { |
|
695 FUNC_LOG(); |
|
696 } |
|
697 |
|
698 DPciDevice::~DPciDevice() |
|
699 { |
|
700 FUNC_LOG(); |
|
701 } |
|
702 |
|
703 TInt DPciDevice::Install() |
|
704 { |
|
705 return SetName(&KPciLddFactory); |
|
706 } |
|
707 |
|
708 void DPciDevice::GetCaps(TDes8&) const |
|
709 { |
|
710 } |
|
711 |
|
712 TInt DPciDevice::Create(DLogicalChannelBase*& aChannel) |
|
713 { |
|
714 aChannel = new DPciTestChannel; |
|
715 return aChannel ? KErrNone : KErrNoMemory; |
|
716 } |
|
717 |
|
718 /**************************************** |
|
719 TUserPciSpace |
|
720 */ |
|
721 |
|
722 /** |
|
723 Decides what action to run based on contents of class |
|
724 */ |
|
725 TUint TUserPciSpace::KRun(TAddrSpace& aAddrSp) |
|
726 { |
|
727 |
|
728 //this could be reworked as a function pointer |
|
729 //table, but this might be clearer |
|
730 switch(iBitWidth) |
|
731 { |
|
732 case 8: |
|
733 { |
|
734 switch(iOperation) |
|
735 { |
|
736 case ERead: |
|
737 { |
|
738 return aAddrSp.Read8(iOffset); |
|
739 } |
|
740 case EWrite: |
|
741 { |
|
742 aAddrSp.Write8(iOffset, iWriteValue); |
|
743 return KErrNone; |
|
744 } |
|
745 case EModify: |
|
746 { |
|
747 aAddrSp.Modify8(iOffset, iClearMask, iSetMask); |
|
748 return KErrNone; |
|
749 } |
|
750 default: |
|
751 { |
|
752 Kern::PanicCurrentThread(KPciTest, KErrNotReady); |
|
753 } |
|
754 } |
|
755 } |
|
756 case 16: |
|
757 { |
|
758 switch(iOperation) |
|
759 { |
|
760 case ERead: |
|
761 { |
|
762 return aAddrSp.Read16(iOffset); |
|
763 } |
|
764 case EWrite: |
|
765 { |
|
766 aAddrSp.Write16(iOffset, iWriteValue); |
|
767 return KErrNone; |
|
768 } |
|
769 case EModify: |
|
770 { |
|
771 aAddrSp.Modify16(iOffset, iClearMask, iSetMask); |
|
772 return KErrNone; |
|
773 } |
|
774 default: |
|
775 { |
|
776 Kern::PanicCurrentThread(KPciTest, KErrNotReady); |
|
777 } |
|
778 } |
|
779 } |
|
780 case 32: |
|
781 { |
|
782 switch(iOperation) |
|
783 { |
|
784 case ERead: |
|
785 { |
|
786 return aAddrSp.Read32(iOffset); |
|
787 } |
|
788 case EWrite: |
|
789 { |
|
790 aAddrSp.Write32(iOffset, iWriteValue); |
|
791 return KErrNone; |
|
792 } |
|
793 case EModify: |
|
794 { |
|
795 aAddrSp.Modify32(iOffset, iClearMask, iSetMask); |
|
796 return KErrNone; |
|
797 } |
|
798 default: |
|
799 { |
|
800 Kern::PanicCurrentThread(KPciTest, KErrNotReady); |
|
801 } |
|
802 } |
|
803 } |
|
804 default: |
|
805 { |
|
806 Kern::PanicCurrentThread(KPciTest, KErrArgument); |
|
807 } |
|
808 |
|
809 } |
|
810 |
|
811 //unreachable return |
|
812 return KMaxTUint; |
|
813 } |
|
814 |
|
815 //stub implementation for kernel side |
|
816 TUint TUserConfigSpace::Call() |
|
817 { |
|
818 FAULT(); |
|
819 return 0; |
|
820 } |
|
821 |
|
822 TUserPciSpace* TUserConfigSpace::Clone() const |
|
823 { |
|
824 FAULT(); |
|
825 return 0; |
|
826 } |
|
827 |
|
828 //stub implementation for kernel side |
|
829 TUint TUserMemorySpace::Call() |
|
830 { |
|
831 FAULT(); |
|
832 return 0; |
|
833 } |
|
834 |
|
835 TUserPciSpace* TUserMemorySpace::Clone() const |
|
836 { |
|
837 FAULT(); |
|
838 return 0; |
|
839 } |
|
840 |
|
841 void TestAllocator() |
|
842 { |
|
843 __KTRACE_OPT(KPCI, Kern::Printf("Testing address allocator")); |
|
844 TAddressAllocator allocator(0x80000000); //2 GB |
|
845 TLinAddr rcvdAddr=NULL; |
|
846 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) ); |
|
847 TEST(0x0 ==rcvdAddr); |
|
848 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x100) ); |
|
849 TEST(0x100 ==rcvdAddr); |
|
850 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) ); |
|
851 TEST(0x10 ==rcvdAddr); |
|
852 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) ); |
|
853 TEST(0x20 ==rcvdAddr); |
|
854 //test deallocating |
|
855 TEST_KERRNONE(allocator.DeAllocate(0x0)); |
|
856 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) ); |
|
857 TEST(0x000 ==rcvdAddr); |
|
858 |
|
859 TEST_KERRNONE(allocator.DeAllocate(0x100)); |
|
860 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x100) ); |
|
861 TEST(0x100 ==rcvdAddr); |
|
862 |
|
863 TEST_KERRNONE(allocator.DeAllocate(0x10)); |
|
864 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) ); |
|
865 TEST(0x10 ==rcvdAddr); |
|
866 |
|
867 TEST_KERRNONE(allocator.DeAllocate(0x20)); |
|
868 TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x20) ); |
|
869 TEST(0x20 ==rcvdAddr); |
|
870 |
|
871 TEST(allocator.DeAllocate(0x40)==KErrNotFound); |
|
872 TEST_KERRNONE(allocator.DeAllocate(0x100)); |
|
873 TEST_KERRNONE(allocator.DeAllocate(0x20)); |
|
874 TEST_KERRNONE(allocator.DeAllocate(0x0)); |
|
875 TEST_KERRNONE(allocator.DeAllocate(0x10)); |
|
876 } |
|
877 |
|
878 |
|
879 DECLARE_STANDARD_LDD() |
|
880 { |
|
881 return new DPciDevice; |
|
882 } |