naviengine/navienginebsp/ne1_tb/test/pci/t_pci.cpp
branchRCL_3
changeset 49 a4ff6126ec76
equal deleted inserted replaced
45:be079f63985a 49:a4ff6126ec76
       
     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 <e32std.h>
       
    66 #define __E32TEST_EXTENSION__
       
    67 #include <e32test.h>
       
    68 #include "t_pci.h"
       
    69 #include <assp/naviengine/pci.h>
       
    70 
       
    71 #define __E32TEST_EXTENSION__
       
    72 #include <e32test.h>
       
    73 #include <e32svr.h>
       
    74 #include <e32des8.h>
       
    75 #include <e32des8_private.h>
       
    76 #include <e32cmn.h>
       
    77 #include <e32cmn_private.h>
       
    78 #include <e32std.h>
       
    79 #include <e32std_private.h>
       
    80     
       
    81 
       
    82 _LIT(KPciPanicCat, "test_thread.h");
       
    83 
       
    84 static const TInt KPciHeapSize=0x2000;
       
    85 
       
    86 enum TPciPanicCode
       
    87 	{
       
    88 	EThreadCreateFailed
       
    89 	};
       
    90 
       
    91 /**
       
    92 A utility class for running functions in other threads/processes
       
    93 */
       
    94 class TTestRemote
       
    95 	{
       
    96 public:
       
    97 	virtual TInt WaitForExitL() = 0;
       
    98 	virtual ~TTestRemote()
       
    99 		{}
       
   100 
       
   101 	virtual void Rendezvous(TRequestStatus& aStatus) = 0;
       
   102 
       
   103 protected:
       
   104 	TTestRemote()
       
   105 		{}
       
   106 
       
   107 	static TInt RunFunctor(TAny* aFunctor)
       
   108 		{
       
   109 		TFunctor& functor = *(TFunctor*)aFunctor;
       
   110 		functor();
       
   111 		return KErrNone;
       
   112 		}
       
   113 
       
   114 	TRequestStatus iLogonStatus;
       
   115 	static TInt iCount;
       
   116 	};
       
   117 TInt TTestRemote::iCount=0;
       
   118 
       
   119 class TTestThread : public TTestRemote
       
   120 	{
       
   121 public:
       
   122 	TTestThread(const TDesC& aName, TThreadFunction aFn, TAny* aData, TBool aAutoResume=ETrue)
       
   123 		{
       
   124 		Init(aName, aFn, aData, aAutoResume);
       
   125 		}
       
   126 
       
   127 	/**
       
   128 	Run aFunctor in another thread
       
   129 	*/
       
   130 	TTestThread(const TDesC& aName, TFunctor& aFunctor, TBool aAutoResume=ETrue)
       
   131 		{
       
   132 		Init(aName, RunFunctor, &aFunctor, aAutoResume);
       
   133 		}
       
   134 
       
   135 	~TTestThread()
       
   136 		{
       
   137 		//RTest::CloseHandleAndWaitForDestruction(iThread);
       
   138 		iThread.Close();
       
   139 		}
       
   140 
       
   141 	void Resume()
       
   142 		{
       
   143 		iThread.Resume();
       
   144 		}
       
   145 
       
   146 	/**
       
   147 	If thread exited normally, return its return code
       
   148 	Otherwise, leave with exit reason
       
   149 	*/
       
   150 	virtual TInt WaitForExitL()
       
   151 		{
       
   152 		User::WaitForRequest(iLogonStatus);
       
   153 		const TInt exitType = iThread.ExitType();
       
   154 		const TInt exitReason = iThread.ExitReason();
       
   155 
       
   156 		__ASSERT_ALWAYS(exitType != EExitPending, User::Panic(_L("TTestThread"),0));
       
   157 
       
   158 		if(exitType != EExitKill)
       
   159 			User::Leave(exitReason);
       
   160 
       
   161 		return exitReason;
       
   162 		}
       
   163 
       
   164 	virtual void Rendezvous(TRequestStatus& aStatus)
       
   165 		{
       
   166 		iThread.Rendezvous(aStatus);
       
   167 		}
       
   168 
       
   169 private:
       
   170 	void Init(const TDesC& aName, TThreadFunction aFn, TAny* aData, TBool aAutoResume)
       
   171 		{
       
   172 		TKName name(aName);
       
   173 		name.AppendFormat(_L("-%d"), iCount++);	
       
   174 		TInt r=iThread.Create(name, aFn, KDefaultStackSize, KPciHeapSize, KPciHeapSize, aData);
       
   175 		if(r!=KErrNone)
       
   176 			{
       
   177 			RDebug::Printf("RThread::Create failed, code=%d", r);
       
   178 			User::Panic(KPciPanicCat, EThreadCreateFailed);
       
   179 			}
       
   180 		
       
   181 		iThread.Logon(iLogonStatus);
       
   182 		__ASSERT_ALWAYS(iLogonStatus == KRequestPending, User::Panic(_L("TTestThread"),0));
       
   183 
       
   184 		if(aAutoResume)
       
   185 			iThread.Resume();
       
   186 		}
       
   187 
       
   188 	RThread iThread;
       
   189 	};
       
   190 
       
   191 class CTest : public CBase, public TFunctor
       
   192 	{
       
   193 public:
       
   194 	~CTest()
       
   195 		{
       
   196 		iName.Close();
       
   197 		}
       
   198 
       
   199 	virtual void operator()()
       
   200 		{
       
   201 		RTest test(iName);
       
   202 		test.Start(iName);
       
   203 		for(TInt i=0; i<iIterations; i++)
       
   204 			{
       
   205 			test.Next(iName);
       
   206 			RunTest();
       
   207 			}
       
   208 		test.End();
       
   209 		}
       
   210 
       
   211 	virtual void RunTest() = 0; 
       
   212 
       
   213 	virtual CTest* Clone() const = 0;
       
   214 
       
   215 	const TDesC& Name() const
       
   216 		{
       
   217 		return iName;
       
   218 		}
       
   219 
       
   220 protected:
       
   221 	CTest(const TDesC& aName, TInt aIterations)
       
   222 		:iIterations(aIterations)
       
   223 		{
       
   224 		iName.CreateL(aName);
       
   225 		}
       
   226 
       
   227 
       
   228 	
       
   229 	CTest(const CTest& aOther)
       
   230 		:iIterations(aOther.iIterations)
       
   231 		{
       
   232 		iName.CreateL(aOther.iName);
       
   233 		}
       
   234 
       
   235 	//It would be useful to have an RTest member, but this can't be
       
   236 	//initialised untill the new thread is running as it will refer to
       
   237 	//the creating thread
       
   238 	RBuf iName;
       
   239 	const TInt iIterations; 
       
   240 	};
       
   241 
       
   242 /**
       
   243 Make aNumberOfThreads copies of aTest and run
       
   244 each in its own thread
       
   245 
       
   246 @param test Reference to test object
       
   247 @param aTest Referance
       
   248 */
       
   249 void MultipleTestRun(RTest& test, const CTest& aTest, TInt aNumberOfThreads)
       
   250 	{
       
   251 	RPointerArray<CTest> testArray;
       
   252 	RPointerArray<TTestThread> threadArray;
       
   253 
       
   254 	for(TInt i=0; i<aNumberOfThreads; i++)
       
   255 		{		
       
   256 		test.Printf(_L("Create test thread"));
       
   257 		CTest* newTest = aTest.Clone();
       
   258 		test_NotNull(newTest);
       
   259 
       
   260 		TTestThread* thread = new TTestThread(aTest.Name(), *newTest);
       
   261 		test_NotNull(thread);
       
   262 
       
   263 		threadArray.AppendL(thread);
       
   264 		testArray.AppendL(newTest);
       
   265 		}
       
   266 
       
   267 	const TInt count = threadArray.Count();
       
   268 	for(TInt j=0; j<count; j++)
       
   269 		{
       
   270 		TTestThread* thread = threadArray[j];
       
   271 		
       
   272 		TInt r = KErrNone;
       
   273 		TRAPD(leaveCode, r = thread->WaitForExitL());
       
   274 		if(leaveCode != KErrNone)
       
   275 			{
       
   276 			test.Printf(_L("Thread %d: Panic code:%d\n"), j, leaveCode);
       
   277 			test_KErrNone(leaveCode);
       
   278 			}
       
   279 
       
   280 		if(r!=KErrNone)
       
   281 			{
       
   282 			test.Printf(_L("Thread Number %d\n"), j);
       
   283 			test_KErrNone(r);
       
   284 			}
       
   285 		}
       
   286 	
       
   287 	threadArray.ResetAndDestroy();
       
   288 	threadArray.Close();
       
   289 
       
   290 	testArray.ResetAndDestroy();
       
   291 	testArray.Close();
       
   292 	}
       
   293 
       
   294 class RPci;
       
   295 /**
       
   296 Extends RChunk to hold the PCI address
       
   297 associated with a chunk.
       
   298 */
       
   299 class RPciChunk: public RChunk
       
   300 	{
       
   301 public:
       
   302 	TUint PciBase()
       
   303 		{
       
   304 		return iPciBaseAddr;
       
   305 		}
       
   306 
       
   307 	/**
       
   308 	Return the PCI accessible size
       
   309 	*/
       
   310 	TInt Size() const
       
   311 		{
       
   312 		return iPciSize;
       
   313 		}
       
   314 
       
   315 private:
       
   316 	friend class RPci;
       
   317 	TUint iPciBaseAddr;
       
   318 	TInt iPciSize; //size of the region mapped into PCI
       
   319 	};
       
   320 
       
   321 typedef TInt (RPci::*ChunkOpenFn)(RPciChunk&, TInt, TRequestStatus*);
       
   322 
       
   323 class RPci : public RBusLogicalChannel
       
   324 	{
       
   325 public:
       
   326 	TInt Open();
       
   327 	TInt GetTestInfo(TPciTestInfo& aTestInfo);
       
   328 
       
   329 	TInt Open(const TPciDevice&);
       
   330 
       
   331 	TUint AccessConfigSpace(const TUserConfigSpace& aCs);
       
   332 	TUint AccessMemorySpace(const TUserMemorySpace& aMs);
       
   333 	TInt  OpenPciDChunk(RPciChunk& aPciChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);
       
   334 	TInt  OpenPciPlatHwChunk(RPciChunk& aPciHwChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);
       
   335 	TInt  OpenPciMappedChunk(RPciChunk& aPciMappedChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);	
       
   336 	TInt  OpenPciWindowChunk(RChunk& aPciWindowChunk);
       
   337 	TInt  RunUnitTests();
       
   338 private:	
       
   339 	TInt DoOpenPciChunk(RPciChunk& aPciChunk, TInt aPciChunkSize, TPciTestCmd aCmd, TRequestStatus* aStatus);
       
   340 	};
       
   341 
       
   342 inline TInt RPci::Open()
       
   343 	{
       
   344 	return DoCreate(KPciLddFactory, TVersion(), KNullUnit, NULL, NULL);
       
   345 	}
       
   346 
       
   347 inline TInt RPci::Open(const TPciDevice& aDevice) 
       
   348 	{
       
   349 	TPckgC<TPciDevice> devicePkg(aDevice);
       
   350 	return DoCreate(KPciLddFactory, TVersion(), KNullUnit, NULL, &devicePkg);
       
   351 	}
       
   352 
       
   353 inline TInt RPci::GetTestInfo(TPciTestInfo& aTestInfo)
       
   354 	{
       
   355 	TPckg<TPciTestInfo> info(aTestInfo);
       
   356 	return DoControl(EGetTestInfo, &info);
       
   357 	}
       
   358 
       
   359 inline TInt RPci::RunUnitTests()
       
   360 	{
       
   361 	return DoControl(ERunUnitTests);
       
   362 	}
       
   363 
       
   364 TUint RPci::AccessConfigSpace(const TUserConfigSpace& aCs)
       
   365 	{
       
   366 	TPckgC<TUserConfigSpace> pkg(aCs);
       
   367 	return DoControl(EAccessConfigSpace, &pkg);
       
   368 	}
       
   369 
       
   370 TUint RPci::AccessMemorySpace(const TUserMemorySpace& aMs)
       
   371 	{
       
   372 	TPckgC<TUserMemorySpace> pkg(aMs);
       
   373 	return DoControl(EAccessMemorySpace, &pkg);
       
   374 	}
       
   375 
       
   376 TInt RPci::OpenPciDChunk(RPciChunk& aPciChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
       
   377 	{	
       
   378 	return DoOpenPciChunk(aPciChunk, aPciChunkSize, EOpenPciDChunk, aStatus);
       
   379 	}
       
   380 
       
   381 TInt RPci::OpenPciPlatHwChunk(RPciChunk& aPciHwChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
       
   382 	{
       
   383 	return DoOpenPciChunk(aPciHwChunk, aPciChunkSize, EOpenPciPlatHwChunk, aStatus);
       
   384 	}
       
   385 
       
   386 TInt RPci::OpenPciMappedChunk(RPciChunk& aPciMappedChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
       
   387 	{
       
   388 	return DoOpenPciChunk(aPciMappedChunk, aPciChunkSize, EOpenPciMappedChunk, aStatus);
       
   389 	}
       
   390 
       
   391 TInt RPci::OpenPciWindowChunk(RChunk& aPciWindowChunk)
       
   392 	{	
       
   393 	TUint chunkHandle = DoControl(EOpenPciWindowChunk);			
       
   394 	return aPciWindowChunk.SetReturnedHandle(chunkHandle);
       
   395 	}
       
   396 
       
   397 TInt RPci::DoOpenPciChunk(RPciChunk& aPciChunk, TInt aPciChunkSize, TPciTestCmd aCmd, TRequestStatus* aStatus)
       
   398 	{
       
   399 	const TInt constPciChunkSize = aPciChunkSize;
       
   400 	TPciChunkCreateInfo info(constPciChunkSize, aPciChunk.iPciBaseAddr, aStatus);
       
   401 	TPckgC<TPciChunkCreateInfo> pkg(info);
       
   402 
       
   403 	TUint chunkHandle = DoControl(aCmd, &pkg);	
       
   404 	
       
   405 	const TInt r = aPciChunk.SetReturnedHandle(chunkHandle);
       
   406 	if(r == KErrNone)
       
   407 		{		
       
   408 		aPciChunk.iPciSize = constPciChunkSize;					
       
   409 		}
       
   410 	return r;
       
   411 	}
       
   412 
       
   413 TUserPciSpace::TUserPciSpace(RPci& aPci)
       
   414 	:iPci(&aPci)
       
   415 	{}
       
   416 
       
   417 TUserConfigSpace::TUserConfigSpace(RPci& aPci)
       
   418 	:TUserPciSpace(aPci)
       
   419 	{}
       
   420 
       
   421 TUint TUserConfigSpace::Call()
       
   422 	{
       
   423 	return iPci->AccessConfigSpace(*this);
       
   424 	}
       
   425 
       
   426 TUserPciSpace* TUserConfigSpace::Clone() const
       
   427 	{
       
   428 	return new TUserConfigSpace(*this);
       
   429 	}
       
   430 
       
   431 TUserMemorySpace::TUserMemorySpace(RPci& aPci, TInt aBarIndex)
       
   432 	:TUserPciSpace(aPci), iBarIndex(aBarIndex)
       
   433 	{}
       
   434 
       
   435 TUint TUserMemorySpace::Call()
       
   436 	{
       
   437 	return iPci->AccessMemorySpace(*this);
       
   438 	}
       
   439 
       
   440 TUserPciSpace* TUserMemorySpace::Clone() const
       
   441 	{
       
   442 	return new TUserMemorySpace(*this);
       
   443 	}
       
   444 
       
   445 /**
       
   446 Test address allocator
       
   447 */
       
   448 TInt TestRunPciUnitTest(RPci& pci)
       
   449 	{		
       
   450 	return pci.RunUnitTests();
       
   451 	}
       
   452 
       
   453 
       
   454 /**
       
   455 Read from a defined address in memory or config space, compare against expected values.
       
   456 8,16, and 32 bit accesses performed.
       
   457 
       
   458 @param aSpace Object gving access to either the config or memory space of a PCI device
       
   459 @param aInfo Contains the address and expected value of a dword
       
   460 */
       
   461 void TestReadAddressSpace(TUserPciSpace& aSpace, const TPciTestInfo::TAddrSpaceTest& aInfo, RTest& test, TBool aVerbose=EFalse)
       
   462 	{
       
   463 	const TUint os = aInfo.iOffset;
       
   464 	//Iterate over different widths, and possible
       
   465 	//subfields of 32 bit word
       
   466 	for(TInt bitWidth=32; bitWidth>=8; bitWidth>>=1)
       
   467 		{
       
   468 		const TInt numberOfFields = (32/bitWidth);
       
   469 		for(TInt i=0; i< numberOfFields; i++)
       
   470 			{
       
   471 			const TInt extraByteOffset = i * (bitWidth >> 3);
       
   472 			const TInt byteOffset = os + extraByteOffset;
       
   473 			if(aVerbose)
       
   474 				test.Printf(_L("Access bitWidth=%d byte offset=%d\n"), bitWidth, byteOffset);
       
   475 
       
   476 			const TUint expected = aInfo.Expected(bitWidth, byteOffset);
       
   477 			const TUint read = aSpace.Read(bitWidth, byteOffset);
       
   478 			if(aVerbose)
       
   479 				test.Printf(_L("expect 0x%08x, read 0x%08x\n"), expected, read);
       
   480 			test_Equal(expected, read);
       
   481 			}
       
   482 		}
       
   483 	}
       
   484 
       
   485 /**
       
   486 Verify writes and modifications to a defined address in memory or config space. 8,16, and 32 bit
       
   487 accesses performed.
       
   488 
       
   489 @param aSpace Object gving access to either the config or memory space of a PCI device
       
   490 @param aInfo Contains the address of a (at least partially) writable dword
       
   491 */
       
   492 void TestWriteAddressSpace(TUserPciSpace& aSpace, TPciTestInfo::TAddrSpaceTest& aInfo, RTest& test, TBool aVerbose=EFalse)
       
   493 	{
       
   494 	const TUint original = aSpace.Read(32, aInfo.iOffset);
       
   495 	const TUint os = aInfo.iOffset;
       
   496 	TUint mask = ~aInfo.iReadOnlyMask;
       
   497 
       
   498 	//The pattern will be truncated when used with bit widths
       
   499 	//less than 32.
       
   500 	const TUint initPattern = 0xFFFFFFFF;
       
   501 
       
   502 	for(TInt bitWidth=32; bitWidth>=8; bitWidth>>=1)
       
   503 		{
       
   504 		const TUint pattern = initPattern >> (32-bitWidth);
       
   505 		const TInt numberOfFields = (32/bitWidth);
       
   506 		for(TInt i=0; i< numberOfFields; i++)
       
   507 			{
       
   508 			const TInt extraByteOffset = i * (bitWidth >> 3);
       
   509 			const TInt byteOffset = os + extraByteOffset;
       
   510 			if(aVerbose)
       
   511 				test.Printf(_L("Access bitWidth=%d byte offset=%d\n"), bitWidth, byteOffset);
       
   512 			//the full dword we expect
       
   513 			//currently assume that the unwritable bits will be 0
       
   514 			const TUint writeExpect = (pattern << (bitWidth * i) ) & mask; 
       
   515 			const TUint clearExpect = 0;
       
   516 						
       
   517 			//do write followed by clear
       
   518 			const TUint expect[] = {writeExpect, clearExpect};
       
   519 			const TUint write[] = {pattern, 0};
       
   520 			for(TInt n = 0; n < 2; n++)
       
   521 				{
       
   522 				aSpace.Write(bitWidth, byteOffset, write[n]);
       
   523 				TUint result = aSpace.Read(32, os);
       
   524 							
       
   525 				if(aVerbose)
       
   526 					test.Printf(_L("wrote 0x%08x, expect 0x%08x, read 0x%08x\n"),
       
   527 						write[n], expect[n], result);
       
   528 				test_Equal(expect[n], result);
       
   529 				}
       
   530 
       
   531 			//test Modify calls. Set then clear pattern
       
   532 			TUint set[] = {pattern, 0};
       
   533 			TUint clear[] = {0, pattern};
       
   534 
       
   535 			for(TInt m = 0; m < 2; m++)
       
   536 				{	
       
   537 				aSpace.Modify(bitWidth, byteOffset, clear[m], set[m]);
       
   538 				TUint result = aSpace.Read(32, os);
       
   539 						
       
   540 				if(aVerbose)
       
   541 					test.Printf(_L("clear 0x%08x, set 0x%08x,  expect 0x%08x, read 0x%08x\n"), clear[m], set[m], expect[m], result);
       
   542 				test_Equal(expect[m], result);
       
   543 				}
       
   544 			}
       
   545 		}
       
   546 
       
   547 	//restore orginal value or we will not be able to access device
       
   548 	aSpace.Write(32, os, original);
       
   549 	}
       
   550 
       
   551 
       
   552 /**
       
   553 Verify that a PCI DChunk can be opened and closed from user side
       
   554 
       
   555 @param pci  The RPci object to use
       
   556 @param test The RTest object to use
       
   557 @param aPciChunkSize The size of the DChunk which would be created
       
   558 */
       
   559 void TestOpenAndCloseDChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
       
   560 	{
       
   561 	RPciChunk testPciDChunk;
       
   562 
       
   563 	// Create and open Chunk
       
   564 	TRequestStatus status;
       
   565 	TInt r = pci.OpenPciDChunk(testPciDChunk,aPciChunkSize, &status);	
       
   566 	test_KErrNone(r);
       
   567 	
       
   568 	test(testPciDChunk.IsWritable());
       
   569 	test(testPciDChunk.IsReadable());
       
   570 
       
   571 	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciDChunk.Base());
       
   572 	test.Printf(_L("PCI Chunk size = %d\n"), testPciDChunk.Size());
       
   573 	test.Printf(_L("PCI Address = 0x%08x\n"), testPciDChunk.PciBase());	
       
   574 
       
   575 	//Close Chunk
       
   576 	test.Next(_L("Close PCI Chunk handle"));	
       
   577 
       
   578 	RTest::CloseHandleAndWaitForDestruction(testPciDChunk);
       
   579 	User::WaitForRequest(status);
       
   580 	}
       
   581 
       
   582 /**
       
   583 Verify that a PCI PlatHwChunk can be opened and closed from user side
       
   584 
       
   585 
       
   586 @param pci  The RPci object to use
       
   587 @param test The RTest object to use
       
   588 @param aPciChunkSize The size of the PlatHwChunk which would be created
       
   589 */
       
   590 void TestOpenAndClosePciPlatHwChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
       
   591 	{
       
   592 	RPciChunk testPciPlatHwChunk;
       
   593 
       
   594 	// Create and open Chunk
       
   595 	TRequestStatus status;
       
   596 	TInt r = pci.OpenPciPlatHwChunk(testPciPlatHwChunk,aPciChunkSize, &status);	
       
   597 	test_KErrNone(r);
       
   598 	
       
   599 	test(testPciPlatHwChunk.IsWritable());
       
   600 	test(testPciPlatHwChunk.IsReadable());
       
   601 
       
   602 	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciPlatHwChunk.Base());
       
   603 	test.Printf(_L("PCI Chunk size = %d\n"), testPciPlatHwChunk.Size());
       
   604 	test.Printf(_L("PCI Address = 0x%08x\n"), testPciPlatHwChunk.PciBase());	
       
   605 
       
   606 	//Close Chunk	
       
   607 	testPciPlatHwChunk.Close();
       
   608 	User::WaitForRequest(status);
       
   609 	test.Next(_L("Closed PCI PlatHwChunk handle"));	
       
   610 	}
       
   611 
       
   612 /**
       
   613 Verify that pci-mapped DChunk can be opended and closed form user side 
       
   614 
       
   615 @param pci  The RPci object to use
       
   616 @param test The RTest object to use
       
   617 @param aPciChunkSize The size of the pci-mapped DChunk which would be created
       
   618 */
       
   619 void TestPciMapppedChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
       
   620 	{
       
   621 	RPciChunk testPciMappedChunk;
       
   622 
       
   623 	// Create and open Chunk
       
   624 	TRequestStatus status;
       
   625 	TInt r = pci.OpenPciMappedChunk(testPciMappedChunk,aPciChunkSize, &status);	
       
   626 	test_KErrNone(r);
       
   627 	
       
   628 	test(testPciMappedChunk.IsWritable());
       
   629 	test(testPciMappedChunk.IsReadable());
       
   630 
       
   631 	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciMappedChunk.Base());
       
   632 	test.Printf(_L("PCI Chunk size = %d\n"), testPciMappedChunk.Size());
       
   633 	test.Printf(_L("PCI Address = 0x%08x\n"), testPciMappedChunk.PciBase());	
       
   634 
       
   635 	//Close Chunk
       
   636 	testPciMappedChunk.Close();
       
   637 	User::WaitForRequest(status);
       
   638 	test.Next(_L("Closed PCI Mapped Chunk handle"));	
       
   639 	}
       
   640 
       
   641 /**
       
   642 Verify that an RChunk can be open to grant access to the internal PCI window from the user side
       
   643 
       
   644 @param pci  The RPci object to use
       
   645 @param test The RTest object to use
       
   646 */
       
   647 void TestPciWindowChunk(RPci& pci,RTest& test)
       
   648 	{
       
   649 	RChunk testPciWindowChunk;
       
   650 
       
   651 	// Create and open DChunk
       
   652 	TInt r = pci.OpenPciWindowChunk(testPciWindowChunk);	
       
   653 	test_KErrNone(r);
       
   654 	
       
   655 	test(testPciWindowChunk.IsWritable());
       
   656 	test(testPciWindowChunk.IsReadable());
       
   657 
       
   658 	test.Printf(_L("PCI Window Chunk base = 0x%08x\n"), testPciWindowChunk.Base());
       
   659 	test.Printf(_L("PCI Window Chunk size = %d\n"), testPciWindowChunk.Size());
       
   660 	
       
   661 	//Close Chunk
       
   662 	testPciWindowChunk.Close();
       
   663 	test.Next(_L("Closed PCI Window Chunk handle"));	
       
   664 	}
       
   665 
       
   666 
       
   667 class CPciTest : public CTest
       
   668 	{
       
   669 protected:
       
   670 	CPciTest(const TDesC& aName, TInt aIterations, RPci& aDevice)
       
   671 		: CTest(aName, aIterations), iDevice(aDevice)
       
   672 		{}
       
   673 
       
   674 	RPci iDevice;
       
   675 	};
       
   676 
       
   677 /**
       
   678 Each instance of test will open a chunk, using the function specified in
       
   679 the template argument, FUNC.
       
   680 
       
   681 The total number of chunks that can be opened by all instances is limited
       
   682 by iMaxCount.
       
   683 
       
   684 All intances of the test will hold their chunk open until iMaxCount has
       
   685 been reached.
       
   686 */
       
   687 template<ChunkOpenFn FUNC>
       
   688 class CPciOpenChunkTest : public CPciTest
       
   689 	{
       
   690 public:
       
   691 	CPciOpenChunkTest(const TDesC& aName, TInt aIterations, RPci& aDevice,
       
   692 			RSemaphore aSemOpen, RSemaphore aSemClose, RFastLock aLock, TInt aMaxCount)
       
   693 		:CPciTest(aName, aIterations, aDevice),
       
   694 			iSemOpen(aSemOpen), iSemClose(aSemClose), iLock(aLock), iMaxCount(aMaxCount)
       
   695 		{
       
   696 		}
       
   697 
       
   698 	virtual void RunTest()
       
   699 		{
       
   700 		RTest test(iName);
       
   701 		RPciChunk chunk;
       
   702 
       
   703 		iSemOpen.Wait();
       
   704 		TRequestStatus status;
       
   705 		const TInt chunkSize = 0x400;
       
   706 		//open chunk by calling FUNC
       
   707 		TInt r = ((iDevice).*(FUNC))(chunk, chunkSize, &status);
       
   708 		test_KErrNone(r);
       
   709 
       
   710 		iLock.Wait();
       
   711 		iOpenCount++;
       
   712 		test.Printf(_L("Opened chunk %d\n"), iOpenCount);
       
   713 		if(iOpenCount == iMaxCount)
       
   714 			{
       
   715 			test.Printf(_L("Opened=%d, max=%d: Allow chunks to close\n"), iOpenCount, iMaxCount);
       
   716 			//release all waiting threads
       
   717 			//plus 1 preincrement so this
       
   718 			//thread also passes
       
   719 			iSemClose.Signal(iOpenCount);			
       
   720 			iOpenCount = 0;
       
   721 			}	
       
   722 		iLock.Signal();
       
   723 
       
   724 
       
   725 		iSemClose.Wait();
       
   726 		chunk.Close();
       
   727 		User::WaitForRequest(status);
       
   728 
       
   729 		// permit another chunk to be opened  
       
   730 		iSemOpen.Signal();
       
   731 		test.Close();
       
   732 		}
       
   733 
       
   734 	virtual CTest* Clone() const
       
   735 		{
       
   736 		//make shallow copy
       
   737 		return new CPciOpenChunkTest(*this);
       
   738 		}
       
   739 
       
   740 
       
   741 private:
       
   742 	RSemaphore& iSemOpen; ///!< Represents the number of available PCI mappings
       
   743 	RSemaphore& iSemClose; ///!< Represents the number of threads waiting to close their chunk
       
   744 	RFastLock& iLock;
       
   745 	static TInt iOpenCount;
       
   746 	const TInt iMaxCount;
       
   747 	};
       
   748 
       
   749 template<ChunkOpenFn FUNC>
       
   750 TInt CPciOpenChunkTest<FUNC>::iOpenCount = 0;
       
   751 
       
   752 
       
   753 /**
       
   754 Test which will perform various reads from a PCI address
       
   755 space (config or memory) and confirm that values are read
       
   756 as expected
       
   757 */
       
   758 class CPciAddressSpaceRead : public CPciTest
       
   759 	{
       
   760 public:
       
   761 	CPciAddressSpaceRead(const TDesC& aName, TInt aIterations, RPci& aDevice,
       
   762 		const TUserPciSpace& aSpace, const TPciTestInfo::TAddrSpaceTest& aInfo)
       
   763 		:CPciTest(aName, aIterations, aDevice),
       
   764 			iAddressSpace(aSpace.Clone()), iSpaceTestInfo(aInfo)
       
   765 	{
       
   766 	}
       
   767 
       
   768 	CPciAddressSpaceRead(const CPciAddressSpaceRead& aOther)
       
   769 		:CPciTest(aOther)/* TODO-REVIEW have object-sliced aOther - is this ok?*/,
       
   770 			iAddressSpace(aOther.iAddressSpace->Clone()), iSpaceTestInfo(aOther.iSpaceTestInfo)
       
   771 	{
       
   772 	}
       
   773 
       
   774 	virtual ~CPciAddressSpaceRead()
       
   775 		{
       
   776 		delete iAddressSpace;
       
   777 		}
       
   778 
       
   779 	virtual void RunTest()
       
   780 		{
       
   781 		__UHEAP_MARK;
       
   782 		RTest test(iName);
       
   783 		TestReadAddressSpace(*iAddressSpace, iSpaceTestInfo, test);
       
   784 		test.Close();
       
   785 		__UHEAP_MARKEND;
       
   786 		}
       
   787 
       
   788 	virtual CTest* Clone() const
       
   789 		{
       
   790 		//make shallow copy
       
   791 		return new CPciAddressSpaceRead(*this);
       
   792 		}
       
   793 
       
   794 private:
       
   795 	TUserPciSpace* iAddressSpace;
       
   796 	const TPciTestInfo::TAddrSpaceTest& iSpaceTestInfo;
       
   797 	};
       
   798 
       
   799 /**
       
   800 For aBuffer, test writing to it then reading back from aWindow
       
   801 then write via window and read back from chunk
       
   802 
       
   803 @param test The RTest object to use
       
   804 @param aBuffer RChunk corresponding to a PCI accessible buffer
       
   805 @param aWindow RChunk coressponding an appropriate System-to-PCI memory window
       
   806 It is presumed to start at PCI address 0
       
   807 */
       
   808 void DoLoopBackTest(RTest& test, RPciChunk aBuffer, RChunk aWindow)
       
   809 	{
       
   810 	test.Start(_L("Test accessing memory via PCI"));
       
   811 
       
   812 	TUint8* const bufferBase = aBuffer.Base();
       
   813 	const TUint bufferSize = aBuffer.Size();
       
   814 	const TUint bufferPciBase = aBuffer.PciBase();
       
   815 
       
   816 	TUint8* const windowBase = aWindow.Base();
       
   817 	const TUint windowSize = aWindow.Size();
       
   818 
       
   819 #define PRINT(N) RDebug::Printf("%s = 0x%08x (%d)", #N, (N), (N)) 
       
   820 	PRINT(bufferBase);
       
   821 	PRINT(bufferSize);
       
   822 	PRINT(bufferPciBase);
       
   823 
       
   824 	PRINT(windowBase);
       
   825 	PRINT(windowSize);
       
   826 
       
   827 #undef PRINT
       
   828 
       
   829 	//need to check that the end of the buffer
       
   830 	//is within the windowed region
       
   831 	test(bufferPciBase + bufferSize <= windowSize);
       
   832 	TUint8* const bufferBaseWithinWindow = windowBase + bufferPciBase;
       
   833 
       
   834 	test.Next(_L("write chunk"));
       
   835 	for(TUint i = 0; i < bufferSize; ++i)
       
   836 		{
       
   837 		//each byte will hold its own offset modulo 256
       
   838 		bufferBase[i] = (TUint8)i;
       
   839 		}
       
   840 
       
   841 	test.Next(_L("read back via window"));
       
   842 	for(TUint j=0; j < bufferSize; ++j)
       
   843 		{
       
   844 		const TUint8 result = bufferBaseWithinWindow[j];
       
   845 		test_Equal(j%256, result);
       
   846 		}
       
   847 
       
   848 	//clear chunk
       
   849 	memclr(bufferBase, bufferSize);
       
   850 	test.Next(_L("write via window"));
       
   851 	for(TUint k=0; k < bufferSize; ++k)
       
   852 		{
       
   853 		//each byte will hold its own offset modulo 256
       
   854 		bufferBaseWithinWindow[k] = (TUint8)k;
       
   855 		}
       
   856 
       
   857 	test.Next(_L("read back from chunk"));
       
   858 	for(TUint l=0; l < bufferSize; ++l)
       
   859 		{
       
   860 		const TUint8 result = bufferBase[l];
       
   861 		test_Equal(l%256, result);
       
   862 		}
       
   863 
       
   864 	test.End();
       
   865 	}
       
   866 
       
   867 /**
       
   868 Take care of opening a chunk, running the test and closing
       
   869 */
       
   870 template<ChunkOpenFn OPEN_FUNC>
       
   871 inline void LoopBackTest(RPci& aPci, RTest& test, RChunk& aWindow)
       
   872 	{
       
   873 	RPciChunk pciChunk;
       
   874 	const TInt chunkSize = 0x400; //1k
       
   875 
       
   876 	//call the specified chunk opening function
       
   877 	TRequestStatus status;
       
   878 	TInt r = ((aPci).*(OPEN_FUNC))(pciChunk, chunkSize, &status);	
       
   879 	test_KErrNone(r);
       
   880 	DoLoopBackTest(test, pciChunk, aWindow);
       
   881 	pciChunk.Close();
       
   882 	User::WaitForRequest(status);
       
   883 	}
       
   884 
       
   885 /**
       
   886 Run the loopback test for the 3 types of buffer supported by the PCI driver.
       
   887 DChunk
       
   888 DPlatChunk
       
   889 Mapped In external memory
       
   890 */
       
   891 void TestLoopBack(RPci& aPci, RTest& test)
       
   892 	{
       
   893 	test.Next(_L("Open PCI window"));
       
   894 	RChunk window;
       
   895 	
       
   896 	TInt r = aPci.OpenPciWindowChunk(window);	
       
   897 	test_KErrNone(r);
       
   898 
       
   899 	test.Next(_L("DChunk"));
       
   900 	LoopBackTest<&RPci::OpenPciDChunk>(aPci, test, window);
       
   901 
       
   902 	test.Next(_L("DPlatHwChunk"));
       
   903 	LoopBackTest<&RPci::OpenPciPlatHwChunk>(aPci, test, window);
       
   904 
       
   905 	test.Next(_L("DChunk (mapped in)"));
       
   906 	LoopBackTest<&RPci::OpenPciMappedChunk>(aPci, test, window);
       
   907 
       
   908 	window.Close();
       
   909 	}
       
   910 #ifndef __VC32__ //visual studio 6 doesn't approve of pointer to member function template parameters
       
   911 /**
       
   912 Run the CPciOpenChunkTest for each type of chunk. This function also creates (and destroys) the
       
   913 necessary semaphores and locks.
       
   914 CPciOpenChunkTest objects are run in multiple threads using MultipleTestRun().
       
   915 
       
   916 @param aDevice Handle to the test driver
       
   917 @param test RTest to use.
       
   918 @param aBufferLimit The maximum number of buffers which can be opened simultaneously
       
   919 */
       
   920 void TestBufferOpenConcurrency(RPci& aDevice, RTest& test, TInt aBufferLimit)
       
   921 	{
       
   922 	RSemaphore semaphoreOpen;
       
   923 	RSemaphore semaphoreClose;
       
   924 	RFastLock lock;
       
   925 
       
   926 	TInt r = semaphoreOpen.CreateLocal(aBufferLimit);
       
   927 	test_KErrNone(r);
       
   928 
       
   929 	r = semaphoreClose.CreateLocal(0);
       
   930 	test_KErrNone(r);
       
   931 
       
   932 	r = lock.CreateLocal();
       
   933 	test_KErrNone(r);
       
   934 
       
   935 	const TInt iterations = 3;
       
   936 	{
       
   937 	test.Printf(_L("Opening %d PCI DChunks in %d threads\n"), aBufferLimit, aBufferLimit);
       
   938 	CPciOpenChunkTest<&RPci::OpenPciDChunk>
       
   939 		dChunkTest(_L("Concurrent-DChunk"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
       
   940 
       
   941 	MultipleTestRun(test, dChunkTest, aBufferLimit);
       
   942 	}
       
   943 
       
   944 	{
       
   945 	test.Printf(_L("Opening %d PCI DPlatHwChunks in %d threads\n"), aBufferLimit, aBufferLimit);
       
   946 	CPciOpenChunkTest<&RPci::OpenPciPlatHwChunk>
       
   947 		platChunkTest(_L("Concurrent-DPlatHwChunk"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
       
   948 
       
   949 	MultipleTestRun(test, platChunkTest, aBufferLimit);
       
   950 	}
       
   951 
       
   952 	{
       
   953 	test.Printf(_L("Opening %d PCI Mapped chunks in %d threads\n"), aBufferLimit, aBufferLimit);
       
   954 	CPciOpenChunkTest<&RPci::OpenPciMappedChunk>
       
   955 		mappedChunkTest(_L("Concurrent-DChunk(mapped)"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
       
   956 
       
   957 	MultipleTestRun(test, mappedChunkTest, aBufferLimit);
       
   958 	}
       
   959 
       
   960 	semaphoreOpen.Close();
       
   961 	semaphoreClose.Close();
       
   962 	lock.Close();
       
   963 	}
       
   964 #endif
       
   965 
       
   966 TInt E32Main()
       
   967 	{
       
   968 	__UHEAP_MARK;
       
   969 
       
   970 	_LIT(KPci, "PCI");
       
   971 	RTest test(KPci);
       
   972 	test.Start(_L("Running PCI tests\n"));
       
   973 
       
   974 	TInt r = User::LoadLogicalDevice(KPciLdd);
       
   975 
       
   976 	__KHEAP_MARK;
       
   977 	
       
   978 	if(r==KErrNotFound)
       
   979 		{
       
   980 		test.Printf(_L("No PCI system present - skipping test\n"));
       
   981 		return KErrNone;
       
   982 		}
       
   983 	if(r!=KErrNone && r!=KErrAlreadyExists)
       
   984 		{
       
   985 		test_KErrNone(r);
       
   986 		}
       
   987 	
       
   988 	test.Next(_L("Open non-existant device\n"));
       
   989 	RPci device;
       
   990 	TPciDevice unavailable;
       
   991 	r = device.Open(unavailable);
       
   992 	test_Equal(KErrNotFound, r);
       
   993 
       
   994 	RPci pciInfo;
       
   995 	r = pciInfo.Open();
       
   996 	test_KErrNone(r);
       
   997 
       
   998 	test.Next(_L("Get test info from driver\n"));
       
   999 	TPciTestInfo info;
       
  1000 	r = pciInfo.GetTestInfo(info);
       
  1001 	test_KErrNone(r);
       
  1002 	pciInfo.Close();
       
  1003 
       
  1004 	test.Next(_L("Open test device\n"));
       
  1005 	r = device.Open(info.iDevice);
       
  1006 	test_KErrNone(r);
       
  1007 
       
  1008 	test.Next(_L("Run Device Unit Test\n"));
       
  1009 	r=TestRunPciUnitTest(device);	
       
  1010 	test_KErrNone(r);
       
  1011 
       
  1012 	test.Next(_L("Read config space\n"));
       
  1013 	TUserConfigSpace cs(device);
       
  1014 	TestReadAddressSpace(cs, info.iCfgSpaceRead, test);
       
  1015 
       
  1016 	test.Next(_L("Write config space\n"));
       
  1017 	TestWriteAddressSpace(cs, info.iCfgSpaceWrite, test);
       
  1018 	
       
  1019 	test.Next(_L("Read memory space\n"));
       
  1020 	TUserMemorySpace ms(device, info.iMemSpaceIndex);
       
  1021 	TestReadAddressSpace(ms, info.iMemSpaceRead, test);
       
  1022 
       
  1023 	test.Next(_L("Modify memory space\n"));
       
  1024 	TestWriteAddressSpace(ms, info.iMemSpaceWrite, test);
       
  1025 
       
  1026 	{
       
  1027 	const TInt addrSpaceThreadCount = 4;
       
  1028 	const TInt iterations = 100;
       
  1029 	test.Next(_L("Concurrent config space reads")); 
       
  1030 	CPciAddressSpaceRead cfgSpaceRead(_L("Cfg Space Read"), iterations, device, cs, info.iCfgSpaceRead);
       
  1031 	MultipleTestRun(test, cfgSpaceRead, addrSpaceThreadCount);
       
  1032 
       
  1033 	test.Next(_L("Concurrent memory space reads")); 
       
  1034 	CPciAddressSpaceRead memSpaceRead(_L("Memory Space Read"), iterations, device, ms, info.iMemSpaceRead);
       
  1035 	MultipleTestRun(test, memSpaceRead, addrSpaceThreadCount);
       
  1036 	}
       
  1037 
       
  1038 	TInt testDChunkSize = 0x4000;
       
  1039 	test.Next(_L("Open and Close DChunks\n"));	
       
  1040 	TestOpenAndCloseDChunk(device,test,testDChunkSize);
       
  1041 	
       
  1042 	TInt testDPlatChunkSize = 0x2000;
       
  1043 	test.Next(_L("Open and Close PlatHwChunks\n"));	
       
  1044 	TestOpenAndClosePciPlatHwChunk(device,test,testDPlatChunkSize);
       
  1045 
       
  1046 	//TestPciMapppedChunk() fails for sizes greater than 4K.
       
  1047 	//The issue is that a block of externally mapped memory must be
       
  1048 	//naturally alligned in order to be accessible to the PCI bus (ie
       
  1049 	//an 8k buffer would have to start at an address which is a
       
  1050 	//multiple of 8k.
       
  1051 	//
       
  1052 	//Now we could fix this for sure on the kernel side, by making
       
  1053 	//sure we only commit correctly aligned memory into the chunk (as
       
  1054 	//the pci driver itself does),
       
  1055 	//However, by using a 4k chunk, we know this will be on a page
       
  1056 	//boundary so the alignment is correct (assuming the page size
       
  1057 	//isn't changed). 	
       
  1058 	TInt testMapppedChunkSize = 0x1000; 
       
  1059 	test.Next(_L("Open and Close Pci Mappped Chunk\n"));	
       
  1060 	TestPciMapppedChunk(device,test,testMapppedChunkSize);
       
  1061 
       
  1062 	test.Next(_L("Open and Close Pci Window Chunk\n"));	
       
  1063 	TestPciWindowChunk(device,test);
       
  1064 
       
  1065 	const TInt numberOfThreads = info.iNumberOfBars;
       
  1066 	test.Printf(_L("Open buffers concurrently, max supported = %d\n"), numberOfThreads);
       
  1067 #ifndef __VC32__
       
  1068 	TestBufferOpenConcurrency(device, test, numberOfThreads);
       
  1069 #else
       
  1070 	test.Printf(_L("TestBufferOpenConcurrency not implemented for WINS"), numberOfThreads);
       
  1071 #endif
       
  1072 
       
  1073 	test.Next(_L("Test loop back"));	
       
  1074 	TestLoopBack(device, test);
       
  1075 
       
  1076 	device.Close();
       
  1077 	__KHEAP_MARKEND;
       
  1078 
       
  1079 	r = User::FreeLogicalDevice(KPciLdd);
       
  1080 	test_KErrNone(r);
       
  1081 
       
  1082 	test.End();
       
  1083 	test.Close();
       
  1084 
       
  1085 	__UHEAP_MARKEND;
       
  1086 	return KErrNone;
       
  1087 	}