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