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