navienginebsp/ne1_tb/test/pci/t_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: 
       
    15 *	memory space.
       
    16 *	- RPciChunk which is derived from and RChunk and corresponds to
       
    17 *	a kernel-side DChunk, which in turn corresponds to a PCI chunk or
       
    18 *	buffer. The test driver uses these for all PCI chunk types (a
       
    19 *	"wrapper" DChunk is used to map the memory of a PCI DPlatHwChunk
       
    20 *	to user side).
       
    21 *
       
    22 */
       
    23 
       
    24 
       
    25 #include <e32std.h>
       
    26 #define __E32TEST_EXTENSION__
       
    27 #include <e32test.h>
       
    28 #include "t_pci.h"
       
    29 #include <assp/naviengine/pci.h>
       
    30 
       
    31 class RPci;
       
    32 /**
       
    33 Extends RChunk to hold the PCI address
       
    34 associated with a chunk.
       
    35 */
       
    36 class RPciChunk: public RChunk
       
    37 	{
       
    38 public:
       
    39 	TUint PciBase()
       
    40 		{
       
    41 		return iPciBaseAddr;
       
    42 		}
       
    43 
       
    44 	/**
       
    45 	Return the PCI accessible size
       
    46 	*/
       
    47 	TInt Size() const
       
    48 		{
       
    49 		return iPciSize;
       
    50 		}
       
    51 
       
    52 private:
       
    53 	friend class RPci;
       
    54 	TUint iPciBaseAddr;
       
    55 	TInt iPciSize; //size of the region mapped into PCI
       
    56 	};
       
    57 
       
    58 typedef TInt (RPci::*ChunkOpenFn)(RPciChunk&, TInt, TRequestStatus*);
       
    59 
       
    60 class RPci : public RBusLogicalChannel
       
    61 	{
       
    62 public:
       
    63 	TInt Open();
       
    64 	TInt GetTestInfo(TPciTestInfo& aTestInfo);
       
    65 
       
    66 	TInt Open(const TPciDevice&);
       
    67 
       
    68 	TUint AccessConfigSpace(const TUserConfigSpace& aCs);
       
    69 	TUint AccessMemorySpace(const TUserMemorySpace& aMs);
       
    70 	TInt  OpenPciDChunk(RPciChunk& aPciChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);
       
    71 	TInt  OpenPciPlatHwChunk(RPciChunk& aPciHwChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);
       
    72 	TInt  OpenPciMappedChunk(RPciChunk& aPciMappedChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);	
       
    73 	TInt  OpenPciWindowChunk(RChunk& aPciWindowChunk);
       
    74 	TInt  RunUnitTests();
       
    75 private:	
       
    76 	TInt DoOpenPciChunk(RPciChunk& aPciChunk, TInt aPciChunkSize, TPciTestCmd aCmd, TRequestStatus* aStatus);
       
    77 	};
       
    78 
       
    79 inline TInt RPci::Open()
       
    80 	{
       
    81 	return DoCreate(KPciLddFactory, TVersion(), KNullUnit, NULL, NULL);
       
    82 	}
       
    83 
       
    84 inline TInt RPci::Open(const TPciDevice& aDevice) 
       
    85 	{
       
    86 	TPckgC<TPciDevice> devicePkg(aDevice);
       
    87 	return DoCreate(KPciLddFactory, TVersion(), KNullUnit, NULL, &devicePkg);
       
    88 	}
       
    89 
       
    90 inline TInt RPci::GetTestInfo(TPciTestInfo& aTestInfo)
       
    91 	{
       
    92 	TPckg<TPciTestInfo> info(aTestInfo);
       
    93 	return DoControl(EGetTestInfo, &info);
       
    94 	}
       
    95 
       
    96 inline TInt RPci::RunUnitTests()
       
    97 	{
       
    98 	return DoControl(ERunUnitTests);
       
    99 	}
       
   100 
       
   101 TUint RPci::AccessConfigSpace(const TUserConfigSpace& aCs)
       
   102 	{
       
   103 	TPckgC<TUserConfigSpace> pkg(aCs);
       
   104 	return DoControl(EAccessConfigSpace, &pkg);
       
   105 	}
       
   106 
       
   107 TUint RPci::AccessMemorySpace(const TUserMemorySpace& aMs)
       
   108 	{
       
   109 	TPckgC<TUserMemorySpace> pkg(aMs);
       
   110 	return DoControl(EAccessMemorySpace, &pkg);
       
   111 	}
       
   112 
       
   113 TInt RPci::OpenPciDChunk(RPciChunk& aPciChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
       
   114 	{	
       
   115 	return DoOpenPciChunk(aPciChunk, aPciChunkSize, EOpenPciDChunk, aStatus);
       
   116 	}
       
   117 
       
   118 TInt RPci::OpenPciPlatHwChunk(RPciChunk& aPciHwChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
       
   119 	{
       
   120 	return DoOpenPciChunk(aPciHwChunk, aPciChunkSize, EOpenPciPlatHwChunk, aStatus);
       
   121 	}
       
   122 
       
   123 TInt RPci::OpenPciMappedChunk(RPciChunk& aPciMappedChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
       
   124 	{
       
   125 	return DoOpenPciChunk(aPciMappedChunk, aPciChunkSize, EOpenPciMappedChunk, aStatus);
       
   126 	}
       
   127 
       
   128 TInt RPci::OpenPciWindowChunk(RChunk& aPciWindowChunk)
       
   129 	{	
       
   130 	TUint chunkHandle = DoControl(EOpenPciWindowChunk);			
       
   131 	return aPciWindowChunk.SetReturnedHandle(chunkHandle);
       
   132 	}
       
   133 
       
   134 TInt RPci::DoOpenPciChunk(RPciChunk& aPciChunk, TInt aPciChunkSize, TPciTestCmd aCmd, TRequestStatus* aStatus)
       
   135 	{
       
   136 	const TInt constPciChunkSize = aPciChunkSize;
       
   137 	TPciChunkCreateInfo info(constPciChunkSize, aPciChunk.iPciBaseAddr, aStatus);
       
   138 	TPckgC<TPciChunkCreateInfo> pkg(info);
       
   139 
       
   140 	TUint chunkHandle = DoControl(aCmd, &pkg);	
       
   141 	
       
   142 	const TInt r = aPciChunk.SetReturnedHandle(chunkHandle);
       
   143 	if(r == KErrNone)
       
   144 		{		
       
   145 		aPciChunk.iPciSize = constPciChunkSize;					
       
   146 		}
       
   147 	return r;
       
   148 	}
       
   149 
       
   150 TUserPciSpace::TUserPciSpace(RPci& aPci)
       
   151 	:iPci(&aPci)
       
   152 	{}
       
   153 
       
   154 TUserConfigSpace::TUserConfigSpace(RPci& aPci)
       
   155 	:TUserPciSpace(aPci)
       
   156 	{}
       
   157 
       
   158 TUint TUserConfigSpace::Call()
       
   159 	{
       
   160 	return iPci->AccessConfigSpace(*this);
       
   161 	}
       
   162 
       
   163 TUserPciSpace* TUserConfigSpace::Clone() const
       
   164 	{
       
   165 	return new TUserConfigSpace(*this);
       
   166 	}
       
   167 
       
   168 TUserMemorySpace::TUserMemorySpace(RPci& aPci, TInt aBarIndex)
       
   169 	:TUserPciSpace(aPci), iBarIndex(aBarIndex)
       
   170 	{}
       
   171 
       
   172 TUint TUserMemorySpace::Call()
       
   173 	{
       
   174 	return iPci->AccessMemorySpace(*this);
       
   175 	}
       
   176 
       
   177 TUserPciSpace* TUserMemorySpace::Clone() const
       
   178 	{
       
   179 	return new TUserMemorySpace(*this);
       
   180 	}
       
   181 
       
   182 /**
       
   183 Test address allocator
       
   184 */
       
   185 TInt TestRunPciUnitTest(RPci& pci)
       
   186 	{		
       
   187 	return pci.RunUnitTests();
       
   188 	}
       
   189 
       
   190 
       
   191 /**
       
   192 Read from a defined address in memory or config space, compare against expected values.
       
   193 8,16, and 32 bit accesses performed.
       
   194 
       
   195 @param aSpace Object gving access to either the config or memory space of a PCI device
       
   196 @param aInfo Contains the address and expected value of a dword
       
   197 */
       
   198 void TestReadAddressSpace(TUserPciSpace& aSpace, const TPciTestInfo::TAddrSpaceTest& aInfo, RTest& test, TBool aVerbose=EFalse)
       
   199 	{
       
   200 	const TUint os = aInfo.iOffset;
       
   201 	//Iterate over different widths, and possible
       
   202 	//subfields of 32 bit word
       
   203 	for(TInt bitWidth=32; bitWidth>=8; bitWidth>>=1)
       
   204 		{
       
   205 		const TInt numberOfFields = (32/bitWidth);
       
   206 		for(TInt i=0; i< numberOfFields; i++)
       
   207 			{
       
   208 			const TInt extraByteOffset = i * (bitWidth >> 3);
       
   209 			const TInt byteOffset = os + extraByteOffset;
       
   210 			if(aVerbose)
       
   211 				test.Printf(_L("Access bitWidth=%d byte offset=%d\n"), bitWidth, byteOffset);
       
   212 
       
   213 			const TUint expected = aInfo.Expected(bitWidth, byteOffset);
       
   214 			const TUint read = aSpace.Read(bitWidth, byteOffset);
       
   215 			if(aVerbose)
       
   216 				test.Printf(_L("expect 0x%08x, read 0x%08x\n"), expected, read);
       
   217 			test_Equal(expected, read);
       
   218 			}
       
   219 		}
       
   220 	}
       
   221 
       
   222 /**
       
   223 Verify writes and modifications to a defined address in memory or config space. 8,16, and 32 bit
       
   224 accesses performed.
       
   225 
       
   226 @param aSpace Object gving access to either the config or memory space of a PCI device
       
   227 @param aInfo Contains the address of a (at least partially) writable dword
       
   228 */
       
   229 void TestWriteAddressSpace(TUserPciSpace& aSpace, TPciTestInfo::TAddrSpaceTest& aInfo, RTest& test, TBool aVerbose=EFalse)
       
   230 	{
       
   231 	const TUint original = aSpace.Read(32, aInfo.iOffset);
       
   232 	const TUint os = aInfo.iOffset;
       
   233 	TUint mask = ~aInfo.iReadOnlyMask;
       
   234 
       
   235 	//The pattern will be truncated when used with bit widths
       
   236 	//less than 32.
       
   237 	const TUint initPattern = 0xFFFFFFFF;
       
   238 
       
   239 	for(TInt bitWidth=32; bitWidth>=8; bitWidth>>=1)
       
   240 		{
       
   241 		const TUint pattern = initPattern >> (32-bitWidth);
       
   242 		const TInt numberOfFields = (32/bitWidth);
       
   243 		for(TInt i=0; i< numberOfFields; i++)
       
   244 			{
       
   245 			const TInt extraByteOffset = i * (bitWidth >> 3);
       
   246 			const TInt byteOffset = os + extraByteOffset;
       
   247 			if(aVerbose)
       
   248 				test.Printf(_L("Access bitWidth=%d byte offset=%d\n"), bitWidth, byteOffset);
       
   249 			//the full dword we expect
       
   250 			//currently assume that the unwritable bits will be 0
       
   251 			const TUint writeExpect = (pattern << (bitWidth * i) ) & mask; 
       
   252 			const TUint clearExpect = 0;
       
   253 						
       
   254 			//do write followed by clear
       
   255 			const TUint expect[] = {writeExpect, clearExpect};
       
   256 			const TUint write[] = {pattern, 0};
       
   257 			for(TInt n = 0; n < 2; n++)
       
   258 				{
       
   259 				aSpace.Write(bitWidth, byteOffset, write[n]);
       
   260 				TUint result = aSpace.Read(32, os);
       
   261 							
       
   262 				if(aVerbose)
       
   263 					test.Printf(_L("wrote 0x%08x, expect 0x%08x, read 0x%08x\n"),
       
   264 						write[n], expect[n], result);
       
   265 				test_Equal(expect[n], result);
       
   266 				}
       
   267 
       
   268 			//test Modify calls. Set then clear pattern
       
   269 			TUint set[] = {pattern, 0};
       
   270 			TUint clear[] = {0, pattern};
       
   271 
       
   272 			for(TInt m = 0; m < 2; m++)
       
   273 				{	
       
   274 				aSpace.Modify(bitWidth, byteOffset, clear[m], set[m]);
       
   275 				TUint result = aSpace.Read(32, os);
       
   276 						
       
   277 				if(aVerbose)
       
   278 					test.Printf(_L("clear 0x%08x, set 0x%08x,  expect 0x%08x, read 0x%08x\n"), clear[m], set[m], expect[m], result);
       
   279 				test_Equal(expect[m], result);
       
   280 				}
       
   281 			}
       
   282 		}
       
   283 
       
   284 	//restore orginal value or we will not be able to access device
       
   285 	aSpace.Write(32, os, original);
       
   286 	}
       
   287 
       
   288 
       
   289 /**
       
   290 Verify that a PCI DChunk can be opened and closed from user side
       
   291 
       
   292 @param pci  The RPci object to use
       
   293 @param test The RTest object to use
       
   294 @param aPciChunkSize The size of the DChunk which would be created
       
   295 */
       
   296 void TestOpenAndCloseDChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
       
   297 	{
       
   298 	RPciChunk testPciDChunk;
       
   299 
       
   300 	// Create and open Chunk
       
   301 	TRequestStatus status;
       
   302 	TInt r = pci.OpenPciDChunk(testPciDChunk,aPciChunkSize, &status);	
       
   303 	test_KErrNone(r);
       
   304 	
       
   305 	test(testPciDChunk.IsWritable());
       
   306 	test(testPciDChunk.IsReadable());
       
   307 
       
   308 	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciDChunk.Base());
       
   309 	test.Printf(_L("PCI Chunk size = %d\n"), testPciDChunk.Size());
       
   310 	test.Printf(_L("PCI Address = 0x%08x\n"), testPciDChunk.PciBase());	
       
   311 
       
   312 	//Close Chunk
       
   313 	test.Next(_L("Close PCI Chunk handle"));	
       
   314 
       
   315 	RTest::CloseHandleAndWaitForDestruction(testPciDChunk);
       
   316 	User::WaitForRequest(status);
       
   317 	}
       
   318 
       
   319 /**
       
   320 Verify that a PCI PlatHwChunk can be opened and closed from user side
       
   321 
       
   322 
       
   323 @param pci  The RPci object to use
       
   324 @param test The RTest object to use
       
   325 @param aPciChunkSize The size of the PlatHwChunk which would be created
       
   326 */
       
   327 void TestOpenAndClosePciPlatHwChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
       
   328 	{
       
   329 	RPciChunk testPciPlatHwChunk;
       
   330 
       
   331 	// Create and open Chunk
       
   332 	TRequestStatus status;
       
   333 	TInt r = pci.OpenPciPlatHwChunk(testPciPlatHwChunk,aPciChunkSize, &status);	
       
   334 	test_KErrNone(r);
       
   335 	
       
   336 	test(testPciPlatHwChunk.IsWritable());
       
   337 	test(testPciPlatHwChunk.IsReadable());
       
   338 
       
   339 	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciPlatHwChunk.Base());
       
   340 	test.Printf(_L("PCI Chunk size = %d\n"), testPciPlatHwChunk.Size());
       
   341 	test.Printf(_L("PCI Address = 0x%08x\n"), testPciPlatHwChunk.PciBase());	
       
   342 
       
   343 	//Close Chunk	
       
   344 	testPciPlatHwChunk.Close();
       
   345 	User::WaitForRequest(status);
       
   346 	test.Next(_L("Closed PCI PlatHwChunk handle"));	
       
   347 	}
       
   348 
       
   349 /**
       
   350 Verify that pci-mapped DChunk can be opended and closed form user side 
       
   351 
       
   352 @param pci  The RPci object to use
       
   353 @param test The RTest object to use
       
   354 @param aPciChunkSize The size of the pci-mapped DChunk which would be created
       
   355 */
       
   356 void TestPciMapppedChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
       
   357 	{
       
   358 	RPciChunk testPciMappedChunk;
       
   359 
       
   360 	// Create and open Chunk
       
   361 	TRequestStatus status;
       
   362 	TInt r = pci.OpenPciMappedChunk(testPciMappedChunk,aPciChunkSize, &status);	
       
   363 	test_KErrNone(r);
       
   364 	
       
   365 	test(testPciMappedChunk.IsWritable());
       
   366 	test(testPciMappedChunk.IsReadable());
       
   367 
       
   368 	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciMappedChunk.Base());
       
   369 	test.Printf(_L("PCI Chunk size = %d\n"), testPciMappedChunk.Size());
       
   370 	test.Printf(_L("PCI Address = 0x%08x\n"), testPciMappedChunk.PciBase());	
       
   371 
       
   372 	//Close Chunk
       
   373 	testPciMappedChunk.Close();
       
   374 	User::WaitForRequest(status);
       
   375 	test.Next(_L("Closed PCI Mapped Chunk handle"));	
       
   376 	}
       
   377 
       
   378 /**
       
   379 Verify that an RChunk can be open to grant access to the internal PCI window from the user side
       
   380 
       
   381 @param pci  The RPci object to use
       
   382 @param test The RTest object to use
       
   383 */
       
   384 void TestPciWindowChunk(RPci& pci,RTest& test)
       
   385 	{
       
   386 	RChunk testPciWindowChunk;
       
   387 
       
   388 	// Create and open DChunk
       
   389 	TInt r = pci.OpenPciWindowChunk(testPciWindowChunk);	
       
   390 	test_KErrNone(r);
       
   391 	
       
   392 	test(testPciWindowChunk.IsWritable());
       
   393 	test(testPciWindowChunk.IsReadable());
       
   394 
       
   395 	test.Printf(_L("PCI Window Chunk base = 0x%08x\n"), testPciWindowChunk.Base());
       
   396 	test.Printf(_L("PCI Window Chunk size = %d\n"), testPciWindowChunk.Size());
       
   397 	
       
   398 	//Close Chunk
       
   399 	testPciWindowChunk.Close();
       
   400 	test.Next(_L("Closed PCI Window Chunk handle"));	
       
   401 	}
       
   402 
       
   403 
       
   404 class CPciTest : public CTest
       
   405 	{
       
   406 protected:
       
   407 	CPciTest(const TDesC& aName, TInt aIterations, RPci& aDevice)
       
   408 		: CTest(aName, aIterations), iDevice(aDevice)
       
   409 		{}
       
   410 
       
   411 	RPci iDevice;
       
   412 	};
       
   413 
       
   414 /**
       
   415 Each instance of test will open a chunk, using the function specified in
       
   416 the template argument, FUNC.
       
   417 
       
   418 The total number of chunks that can be opened by all instances is limited
       
   419 by iMaxCount.
       
   420 
       
   421 All intances of the test will hold their chunk open until iMaxCount has
       
   422 been reached.
       
   423 */
       
   424 template<ChunkOpenFn FUNC>
       
   425 class CPciOpenChunkTest : public CPciTest
       
   426 	{
       
   427 public:
       
   428 	CPciOpenChunkTest(const TDesC& aName, TInt aIterations, RPci& aDevice,
       
   429 			RSemaphore aSemOpen, RSemaphore aSemClose, RFastLock aLock, TInt aMaxCount)
       
   430 		:CPciTest(aName, aIterations, aDevice),
       
   431 			iSemOpen(aSemOpen), iSemClose(aSemClose), iLock(aLock), iMaxCount(aMaxCount)
       
   432 		{
       
   433 		}
       
   434 
       
   435 	virtual void RunTest()
       
   436 		{
       
   437 		RTest test(iName);
       
   438 		RPciChunk chunk;
       
   439 
       
   440 		iSemOpen.Wait();
       
   441 		TRequestStatus status;
       
   442 		const TInt chunkSize = 0x400;
       
   443 		//open chunk by calling FUNC
       
   444 		TInt r = ((iDevice).*(FUNC))(chunk, chunkSize, &status);
       
   445 		test_KErrNone(r);
       
   446 
       
   447 		iLock.Wait();
       
   448 		iOpenCount++;
       
   449 		test.Printf(_L("Opened chunk %d\n"), iOpenCount);
       
   450 		if(iOpenCount == iMaxCount)
       
   451 			{
       
   452 			test.Printf(_L("Opened=%d, max=%d: Allow chunks to close\n"), iOpenCount, iMaxCount);
       
   453 			//release all waiting threads
       
   454 			//plus 1 preincrement so this
       
   455 			//thread also passes
       
   456 			iSemClose.Signal(iOpenCount);			
       
   457 			iOpenCount = 0;
       
   458 			}	
       
   459 		iLock.Signal();
       
   460 
       
   461 
       
   462 		iSemClose.Wait();
       
   463 		chunk.Close();
       
   464 		User::WaitForRequest(status);
       
   465 
       
   466 		// permit another chunk to be opened  
       
   467 		iSemOpen.Signal();
       
   468 		test.Close();
       
   469 		}
       
   470 
       
   471 	virtual CTest* Clone() const
       
   472 		{
       
   473 		//make shallow copy
       
   474 		return new CPciOpenChunkTest(*this);
       
   475 		}
       
   476 
       
   477 
       
   478 private:
       
   479 	RSemaphore& iSemOpen; //!< Represents the number of available PCI mappings
       
   480 	RSemaphore& iSemClose; //!< Represents the number of threads waiting to close their chunk
       
   481 	RFastLock& iLock;
       
   482 	static TInt iOpenCount;
       
   483 	const TInt iMaxCount;
       
   484 	};
       
   485 
       
   486 template<ChunkOpenFn FUNC>
       
   487 TInt CPciOpenChunkTest<FUNC>::iOpenCount = 0;
       
   488 
       
   489 
       
   490 /**
       
   491 Test which will perform various reads from a PCI address
       
   492 space (config or memory) and confirm that values are read
       
   493 as expected
       
   494 */
       
   495 class CPciAddressSpaceRead : public CPciTest
       
   496 	{
       
   497 public:
       
   498 	CPciAddressSpaceRead(const TDesC& aName, TInt aIterations, RPci& aDevice,
       
   499 		const TUserPciSpace& aSpace, const TPciTestInfo::TAddrSpaceTest& aInfo)
       
   500 		:CPciTest(aName, aIterations, aDevice),
       
   501 			iAddressSpace(aSpace.Clone()), iSpaceTestInfo(aInfo)
       
   502 	{
       
   503 	}
       
   504 
       
   505 	CPciAddressSpaceRead(const CPciAddressSpaceRead& aOther)
       
   506 		:CPciTest(aOther)/* TODO-REVIEW have object-sliced aOther - is this ok?*/,
       
   507 			iAddressSpace(aOther.iAddressSpace->Clone()), iSpaceTestInfo(aOther.iSpaceTestInfo)
       
   508 	{
       
   509 	}
       
   510 
       
   511 	virtual ~CPciAddressSpaceRead()
       
   512 		{
       
   513 		delete iAddressSpace;
       
   514 		}
       
   515 
       
   516 	virtual void RunTest()
       
   517 		{
       
   518 		__UHEAP_MARK;
       
   519 		RTest test(iName);
       
   520 		TestReadAddressSpace(*iAddressSpace, iSpaceTestInfo, test);
       
   521 		test.Close();
       
   522 		__UHEAP_MARKEND;
       
   523 		}
       
   524 
       
   525 	virtual CTest* Clone() const
       
   526 		{
       
   527 		//make shallow copy
       
   528 		return new CPciAddressSpaceRead(*this);
       
   529 		}
       
   530 
       
   531 private:
       
   532 	TUserPciSpace* iAddressSpace;
       
   533 	const TPciTestInfo::TAddrSpaceTest& iSpaceTestInfo;
       
   534 	};
       
   535 
       
   536 /**
       
   537 For aBuffer, test writing to it then reading back from aWindow
       
   538 then write via window and read back from chunk
       
   539 
       
   540 @param test The RTest object to use
       
   541 @param aBuffer RChunk corresponding to a PCI accessible buffer
       
   542 @param aWindow RChunk coressponding an appropriate System-to-PCI memory window
       
   543 It is presumed to start at PCI address 0
       
   544 */
       
   545 void DoLoopBackTest(RTest& test, RPciChunk aBuffer, RChunk aWindow)
       
   546 	{
       
   547 	test.Start(_L("Test accessing memory via PCI"));
       
   548 
       
   549 	TUint8* const bufferBase = aBuffer.Base();
       
   550 	const TUint bufferSize = aBuffer.Size();
       
   551 	const TUint bufferPciBase = aBuffer.PciBase();
       
   552 
       
   553 	TUint8* const windowBase = aWindow.Base();
       
   554 	const TUint windowSize = aWindow.Size();
       
   555 
       
   556 #define PRINT(N) RDebug::Printf("%s = 0x%08x (%d)", #N, (N), (N)) 
       
   557 	PRINT(bufferBase);
       
   558 	PRINT(bufferSize);
       
   559 	PRINT(bufferPciBase);
       
   560 
       
   561 	PRINT(windowBase);
       
   562 	PRINT(windowSize);
       
   563 
       
   564 #undef PRINT
       
   565 
       
   566 	//need to check that the end of the buffer
       
   567 	//is within the windowed region
       
   568 	test(bufferPciBase + bufferSize <= windowSize);
       
   569 	TUint8* const bufferBaseWithinWindow = windowBase + bufferPciBase;
       
   570 
       
   571 	test.Next(_L("write chunk"));
       
   572 	for(TUint i = 0; i < bufferSize; ++i)
       
   573 		{
       
   574 		//each byte will hold its own offset modulo 256
       
   575 		bufferBase[i] = (TUint8)i;
       
   576 		}
       
   577 
       
   578 	test.Next(_L("read back via window"));
       
   579 	for(TUint j=0; j < bufferSize; ++j)
       
   580 		{
       
   581 		const TUint8 result = bufferBaseWithinWindow[j];
       
   582 		test_Equal(j%256, result);
       
   583 		}
       
   584 
       
   585 	//clear chunk
       
   586 	memclr(bufferBase, bufferSize);
       
   587 	test.Next(_L("write via window"));
       
   588 	for(TUint k=0; k < bufferSize; ++k)
       
   589 		{
       
   590 		//each byte will hold its own offset modulo 256
       
   591 		bufferBaseWithinWindow[k] = (TUint8)k;
       
   592 		}
       
   593 
       
   594 	test.Next(_L("read back from chunk"));
       
   595 	for(TUint l=0; l < bufferSize; ++l)
       
   596 		{
       
   597 		const TUint8 result = bufferBase[l];
       
   598 		test_Equal(l%256, result);
       
   599 		}
       
   600 
       
   601 	test.End();
       
   602 	}
       
   603 
       
   604 /**
       
   605 Take care of opening a chunk, running the test and closing
       
   606 */
       
   607 template<ChunkOpenFn OPEN_FUNC>
       
   608 inline void LoopBackTest(RPci& aPci, RTest& test, RChunk& aWindow)
       
   609 	{
       
   610 	RPciChunk pciChunk;
       
   611 	const TInt chunkSize = 0x400; //1k
       
   612 
       
   613 	//call the specified chunk opening function
       
   614 	TRequestStatus status;
       
   615 	TInt r = ((aPci).*(OPEN_FUNC))(pciChunk, chunkSize, &status);	
       
   616 	test_KErrNone(r);
       
   617 	DoLoopBackTest(test, pciChunk, aWindow);
       
   618 	pciChunk.Close();
       
   619 	User::WaitForRequest(status);
       
   620 	}
       
   621 
       
   622 /**
       
   623 Run the loopback test for the 3 types of buffer supported by the PCI driver.
       
   624 DChunk
       
   625 DPlatChunk
       
   626 Mapped In external memory
       
   627 */
       
   628 void TestLoopBack(RPci& aPci, RTest& test)
       
   629 	{
       
   630 	test.Next(_L("Open PCI window"));
       
   631 	RChunk window;
       
   632 	
       
   633 	TInt r = aPci.OpenPciWindowChunk(window);	
       
   634 	test_KErrNone(r);
       
   635 
       
   636 	test.Next(_L("DChunk"));
       
   637 	LoopBackTest<&RPci::OpenPciDChunk>(aPci, test, window);
       
   638 
       
   639 	test.Next(_L("DPlatHwChunk"));
       
   640 	LoopBackTest<&RPci::OpenPciPlatHwChunk>(aPci, test, window);
       
   641 
       
   642 	test.Next(_L("DChunk (mapped in)"));
       
   643 	LoopBackTest<&RPci::OpenPciMappedChunk>(aPci, test, window);
       
   644 
       
   645 	window.Close();
       
   646 	}
       
   647 #ifndef __VC32__ //visual studio 6 doesn't approve of pointer to member function template parameters
       
   648 /**
       
   649 Run the CPciOpenChunkTest for each type of chunk. This function also creates (and destroys) the
       
   650 necessary semaphores and locks.
       
   651 CPciOpenChunkTest objects are run in multiple threads using MultipleTestRun().
       
   652 
       
   653 @param aDevice Handle to the test driver
       
   654 @param test RTest to use.
       
   655 @param aBufferLimit The maximum number of buffers which can be opened simultaneously
       
   656 */
       
   657 void TestBufferOpenConcurrency(RPci& aDevice, RTest& test, TInt aBufferLimit)
       
   658 	{
       
   659 	RSemaphore semaphoreOpen;
       
   660 	RSemaphore semaphoreClose;
       
   661 	RFastLock lock;
       
   662 
       
   663 	TInt r = semaphoreOpen.CreateLocal(aBufferLimit);
       
   664 	test_KErrNone(r);
       
   665 
       
   666 	r = semaphoreClose.CreateLocal(0);
       
   667 	test_KErrNone(r);
       
   668 
       
   669 	r = lock.CreateLocal();
       
   670 	test_KErrNone(r);
       
   671 
       
   672 	const TInt iterations = 3;
       
   673 	{
       
   674 	test.Printf(_L("Opening %d PCI DChunks in %d threads\n"), aBufferLimit, aBufferLimit);
       
   675 	CPciOpenChunkTest<&RPci::OpenPciDChunk>
       
   676 		dChunkTest(_L("Concurrent-DChunk"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
       
   677 
       
   678 	MultipleTestRun(test, dChunkTest, aBufferLimit);
       
   679 	}
       
   680 
       
   681 	{
       
   682 	test.Printf(_L("Opening %d PCI DPlatHwChunks in %d threads\n"), aBufferLimit, aBufferLimit);
       
   683 	CPciOpenChunkTest<&RPci::OpenPciPlatHwChunk>
       
   684 		platChunkTest(_L("Concurrent-DPlatHwChunk"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
       
   685 
       
   686 	MultipleTestRun(test, platChunkTest, aBufferLimit);
       
   687 	}
       
   688 
       
   689 	{
       
   690 	test.Printf(_L("Opening %d PCI Mapped chunks in %d threads\n"), aBufferLimit, aBufferLimit);
       
   691 	CPciOpenChunkTest<&RPci::OpenPciMappedChunk>
       
   692 		mappedChunkTest(_L("Concurrent-DChunk(mapped)"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
       
   693 
       
   694 	MultipleTestRun(test, mappedChunkTest, aBufferLimit);
       
   695 	}
       
   696 
       
   697 	semaphoreOpen.Close();
       
   698 	semaphoreClose.Close();
       
   699 	lock.Close();
       
   700 	}
       
   701 #endif
       
   702 
       
   703 TInt E32Main()
       
   704 	{
       
   705 	__UHEAP_MARK;
       
   706 
       
   707 	_LIT(KPci, "PCI");
       
   708 	RTest test(KPci);
       
   709 	test.Start(_L("Running PCI tests\n"));
       
   710 
       
   711 	TInt r = User::LoadLogicalDevice(KPciLdd);
       
   712 
       
   713 	__KHEAP_MARK;
       
   714 	
       
   715 	if(r==KErrNotFound)
       
   716 		{
       
   717 		test.Printf(_L("No PCI system present - skipping test\n"));
       
   718 		return KErrNone;
       
   719 		}
       
   720 	if(r!=KErrNone && r!=KErrAlreadyExists)
       
   721 		{
       
   722 		test_KErrNone(r);
       
   723 		}
       
   724 	
       
   725 	test.Next(_L("Open non-existant device\n"));
       
   726 	RPci device;
       
   727 	TPciDevice unavailable;
       
   728 	r = device.Open(unavailable);
       
   729 	test_Equal(KErrNotFound, r);
       
   730 
       
   731 	RPci pciInfo;
       
   732 	r = pciInfo.Open();
       
   733 	test_KErrNone(r);
       
   734 
       
   735 	test.Next(_L("Get test info from driver\n"));
       
   736 	TPciTestInfo info;
       
   737 	r = pciInfo.GetTestInfo(info);
       
   738 	test_KErrNone(r);
       
   739 	pciInfo.Close();
       
   740 
       
   741 	test.Next(_L("Open test device\n"));
       
   742 	r = device.Open(info.iDevice);
       
   743 	test_KErrNone(r);
       
   744 
       
   745 	test.Next(_L("Run Device Unit Test\n"));
       
   746 	r=TestRunPciUnitTest(device);	
       
   747 	test_KErrNone(r);
       
   748 
       
   749 	test.Next(_L("Read config space\n"));
       
   750 	TUserConfigSpace cs(device);
       
   751 	TestReadAddressSpace(cs, info.iCfgSpaceRead, test);
       
   752 
       
   753 	test.Next(_L("Write config space\n"));
       
   754 	TestWriteAddressSpace(cs, info.iCfgSpaceWrite, test);
       
   755 	
       
   756 	test.Next(_L("Read memory space\n"));
       
   757 	TUserMemorySpace ms(device, info.iMemSpaceIndex);
       
   758 	TestReadAddressSpace(ms, info.iMemSpaceRead, test);
       
   759 
       
   760 	test.Next(_L("Modify memory space\n"));
       
   761 	TestWriteAddressSpace(ms, info.iMemSpaceWrite, test);
       
   762 
       
   763 	{
       
   764 	const TInt addrSpaceThreadCount = 4;
       
   765 	const TInt iterations = 100;
       
   766 	test.Next(_L("Concurrent config space reads")); 
       
   767 	CPciAddressSpaceRead cfgSpaceRead(_L("Cfg Space Read"), iterations, device, cs, info.iCfgSpaceRead);
       
   768 	MultipleTestRun(test, cfgSpaceRead, addrSpaceThreadCount);
       
   769 
       
   770 	test.Next(_L("Concurrent memory space reads")); 
       
   771 	CPciAddressSpaceRead memSpaceRead(_L("Memory Space Read"), iterations, device, ms, info.iMemSpaceRead);
       
   772 	MultipleTestRun(test, memSpaceRead, addrSpaceThreadCount);
       
   773 	}
       
   774 
       
   775 	TInt testDChunkSize = 0x4000;
       
   776 	test.Next(_L("Open and Close DChunks\n"));	
       
   777 	TestOpenAndCloseDChunk(device,test,testDChunkSize);
       
   778 	
       
   779 	TInt testDPlatChunkSize = 0x2000;
       
   780 	test.Next(_L("Open and Close PlatHwChunks\n"));	
       
   781 	TestOpenAndClosePciPlatHwChunk(device,test,testDPlatChunkSize);
       
   782 
       
   783 	//TestPciMapppedChunk() fails for sizes greater than 4K.
       
   784 	//The issue is that a block of externally mapped memory must be
       
   785 	//naturally alligned in order to be accessible to the PCI bus (ie
       
   786 	//an 8k buffer would have to start at an address which is a
       
   787 	//multiple of 8k.
       
   788 	//
       
   789 	//Now we could fix this for sure on the kernel side, by making
       
   790 	//sure we only commit correctly aligned memory into the chunk (as
       
   791 	//the pci driver itself does),
       
   792 	//However, by using a 4k chunk, we know this will be on a page
       
   793 	//boundary so the alignment is correct (assuming the page size
       
   794 	//isn't changed). 	
       
   795 	TInt testMapppedChunkSize = 0x1000; 
       
   796 	test.Next(_L("Open and Close Pci Mappped Chunk\n"));	
       
   797 	TestPciMapppedChunk(device,test,testMapppedChunkSize);
       
   798 
       
   799 	test.Next(_L("Open and Close Pci Window Chunk\n"));	
       
   800 	TestPciWindowChunk(device,test);
       
   801 
       
   802 	const TInt numberOfThreads = info.iNumberOfBars;
       
   803 	test.Printf(_L("Open buffers concurrently, max supported = %d\n"), numberOfThreads);
       
   804 #ifndef __VC32__
       
   805 	TestBufferOpenConcurrency(device, test, numberOfThreads);
       
   806 #else
       
   807 	test.Printf(_L("TestBufferOpenConcurrency not implemented for WINS"), numberOfThreads);
       
   808 #endif
       
   809 
       
   810 	test.Next(_L("Test loop back"));	
       
   811 	TestLoopBack(device, test);
       
   812 
       
   813 	device.Close();
       
   814 	__KHEAP_MARKEND;
       
   815 
       
   816 	r = User::FreeLogicalDevice(KPciLdd);
       
   817 	test_KErrNone(r);
       
   818 
       
   819 	test.End();
       
   820 	test.Close();
       
   821 
       
   822 	__UHEAP_MARKEND;
       
   823 	return KErrNone;
       
   824 	}	
       
   825