navienginebsp/naviengine_assp/pci/pci.cpp
changeset 0 5de814552237
equal deleted inserted replaced
-1:000000000000 0:5de814552237
       
     1 /*
       
     2 * Copyright (c) 2008-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 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include <pci.h>
       
    21 #include <naviengine.h>
       
    22 #include <naviengine_priv.h>
       
    23 
       
    24 #include "pci_priv.h"
       
    25 
       
    26 //
       
    27 // TAddrSpace class
       
    28 //
       
    29 
       
    30 TAddrSpace::TAddrSpace(TUint aSize, const TDesC& aName)
       
    31 	:iSize(aSize), iName(aName)
       
    32 	{
       
    33 	}
       
    34 
       
    35 EXPORT_C TUint TAddrSpace::Size()
       
    36 	{
       
    37 	return iSize;
       
    38 	}
       
    39 
       
    40 /**
       
    41 Check access is aligned and in range
       
    42 */
       
    43 void TAddrSpace::CheckAccess(TNumberOfBytes aNumberOfBytes, TUint aByteOffset)
       
    44 	{
       
    45 	if(aByteOffset > iSize-aNumberOfBytes)
       
    46 		{
       
    47 		Kern::Printf("PCI %S: Access out of range", &iName);
       
    48 		FAULT();
       
    49 		}
       
    50 	if(aByteOffset%aNumberOfBytes)
       
    51 		{
       
    52 		Kern::Printf("PCI %S: Access missaligned", &iName);
       
    53 		FAULT();
       
    54 		}
       
    55 	}
       
    56 
       
    57 //
       
    58 // DPciBridge class
       
    59 //
       
    60 DPciBridge::DPciBridge()
       
    61 	{
       
    62 	}
       
    63 
       
    64 DPciBridge::~DPciBridge()
       
    65 	{
       
    66 	}
       
    67 
       
    68 
       
    69 /**
       
    70 Register this bridge with the system wide Pci manager.
       
    71 */
       
    72 TInt DPciBridge::Register()
       
    73 	{
       
    74 	return Pci::AddBridge(this);
       
    75 	}
       
    76 
       
    77 
       
    78 //
       
    79 // Pci class
       
    80 //
       
    81 
       
    82 TBool Pci::iEnumerated = EFalse;
       
    83 
       
    84 RPointerArray<DPciBridge> Pci::iPciBridges(2);
       
    85 
       
    86 /**
       
    87 Search all PCI busses for PCI functions matching the specified vendor and
       
    88 device ids.
       
    89 
       
    90 @param aVid Vendor Id
       
    91 @param aDid Device Id
       
    92 @param aListOfFunctions On KErrNone will be filled with indices of matching PCI functions
       
    93 @return
       
    94 	- KErrNone - Matching functions were found
       
    95 	- KErrNotFound - No matches were found.
       
    96 	- KErrArgument - aListOfFunctions was not empty at start.
       
    97 */
       
    98 EXPORT_C TInt Pci::Probe(RArray<TInt>& aListOfFunctions, TPciVendorId aVid, TDeviceId aDid)
       
    99 	{
       
   100 	if(aListOfFunctions.Count()>0)
       
   101 		return KErrArgument;
       
   102 
       
   103 	const TInt functionCount=iFunctions.Count();
       
   104 	TInt r=KErrNotFound;
       
   105 	for(TInt i=0; i<functionCount;++i)
       
   106 		{
       
   107 		TPciFunction* func=iFunctions[i];
       
   108 		if(func->VendorId()==aVid && func->DeviceId()==aDid)
       
   109 			{
       
   110 			r = aListOfFunctions.Append(i);
       
   111 			if(r!=KErrNone)
       
   112 				return r; //some error when appending
       
   113 			}
       
   114 		}
       
   115 
       
   116 	if(aListOfFunctions.Count()>0)
       
   117 		r=KErrNone;
       
   118 
       
   119 	return r;
       
   120 	}
       
   121 
       
   122 /**
       
   123 Gets a pointer to one of the specified function's memory
       
   124 spaces. A function may have a memory space for each of its
       
   125 6 BARS. If either of the supplied indices are invalid NULL
       
   126 will be returned.
       
   127 
       
   128 @return NULL if error, otherwise a pointer the requested memory space.
       
   129 @param aFunction Index of the PCI function.
       
   130 @param aBarIndex Index from 0 to 5
       
   131 */
       
   132 EXPORT_C TAddrSpace* Pci::GetMemorySpace(TInt aFunction, TInt aBarIndex)
       
   133 	{
       
   134 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   135 		return NULL;
       
   136 	return iFunctions[aFunction]->GetMemorySpace(aBarIndex);
       
   137 	}
       
   138 
       
   139 /**
       
   140 Get a pointer to the specified function's configuration space.
       
   141 
       
   142 @return NULL if aFunction is invalid or some other error
       
   143 @param aFunction Index of the PCI function.
       
   144 */
       
   145 EXPORT_C TAddrSpace* Pci::GetConfigSpace(TInt aFunction)
       
   146 	{
       
   147 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   148 		return NULL;
       
   149 
       
   150 	return iFunctions[aFunction]->GetConfigSpace();
       
   151 	}
       
   152 
       
   153 /**
       
   154 Create a DMA'able DPlatChunkHw chunk with memory allocated which will be accessable by the PCI function aFunction (and other PCI devices
       
   155 on the same bridge). The allocated chunk must only be destroyed with Pci::RemoveChunk. For simplicity
       
   156 it is recommended to use the alternate CreateChunk to create a DChunk, since this will be a able to clean itself up automatically on
       
   157 closure.
       
   158 @return
       
   159 	- KErrNone on success
       
   160 	- KErrInUse - aChunk was not NULL
       
   161 	- KErrNotFound - All of Bridge's BARS have been used up. Free one with RemoveChunk
       
   162 	- KErrArgument - aSize was less than 1.
       
   163 @param aFunction Index of the PCI function.
       
   164 @param aChunk Must be NULL, on success will point to the created chunk.
       
   165 @param aSize of chunk required.
       
   166 This will be rounded up to the next power of 2 in kilobytes
       
   167 .eg 1K, 2K, 4K etc. So requesting a 600Kb buffer will result in 1Mb being allocated.
       
   168 @param aAttributes Attribute mask made up of OR'd values in TMappingAttributes
       
   169 @param aPciAddress On success will be set to the PCI address with which devices may access the allocated memory.
       
   170 */
       
   171 EXPORT_C TInt Pci::CreateChunk(TInt aFunction, DPlatChunkHw*& aChunk, TInt aSize, TUint aAttributes, TUint32& aPciAddress)
       
   172 	{
       
   173 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   174 		return KErrArgument;
       
   175 
       
   176 	return iFunctions[aFunction]->GetBridge().CreateChunk(aChunk, aSize, aAttributes, aPciAddress);
       
   177 	}
       
   178 
       
   179 /**
       
   180 Create a DMA'able chunk with memory allocated which will be accessable by the PCI function aFunction (and other PCI devices
       
   181 on the same bridge). When the final reference to the chunk is closed it will be unmapped from PCI memory and free its physical ram.
       
   182 @return
       
   183 	- KErrNone on success
       
   184 	- KErrInUse - aChunk was not NULL
       
   185 	- KErrNotFound - All of Bridge's BARS have been used up. Free one by calling RemoveMapping, RemoveChunk or closing all
       
   186 	  references to a DChunk previously allocated with this function.
       
   187 	- KErrArgument - aSize was less than 1.
       
   188 @param aFunction Index of the PCI function.
       
   189 @param aChunk Must be NULL, on success will point to the created chunk.
       
   190 @param aAttributes Contains creation parameters for DChunk. These may be adjusted by the driver and can be viewed on return
       
   191 @param aOffset The number of bytes into the chunk's virtual address range at which memory should be commited.
       
   192 @param aSize of chunk required.
       
   193 This will be rounded up to the next power of 2 in kilobytes
       
   194 .eg 1K, 2K, 4K etc. So requesting a 600Kb buffer will result in 1Mb being allocated. 
       
   195 @param aPciAddress On success will be set to the PCI address with which devices may access the allocated memory.
       
   196 */
       
   197 EXPORT_C TInt Pci::CreateChunk(TInt aFunction, DChunk*& aChunk, TChunkCreateInfo &aAttributes, TUint aOffset, TUint aSize, TUint32& aPciAddress)
       
   198 	{
       
   199 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   200 		return KErrArgument;
       
   201 
       
   202 	return iFunctions[aFunction]->GetBridge().CreateChunk(aChunk, aAttributes, aOffset, aSize, aPciAddress);
       
   203 	}
       
   204 
       
   205 RPointerArray<TPciFunction> Pci::iFunctions;
       
   206 
       
   207 
       
   208 /**
       
   209 Remove mapping from PCI memory space to chunk.
       
   210 Free the memory chunk's memory and chunk object itself.
       
   211 
       
   212 @param aFunction The PCI function wth which the chunk was associated.
       
   213 @param aChunk Pointer to the chunk to be deleted
       
   214 @return
       
   215 	- KErrNone on success
       
   216 	- KErrArgument aFunction was invalid
       
   217 	- KErrNotFound aChunk was not found
       
   218 */
       
   219 EXPORT_C TInt Pci::RemoveChunk(TInt aFunction, DPlatChunkHw* aChunk)
       
   220 	{
       
   221 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   222 		return KErrArgument;
       
   223 
       
   224 	return iFunctions[aFunction]->GetBridge().RemoveChunk(aChunk);
       
   225 	}
       
   226 
       
   227 EXPORT_C void Pci::ChunkCleanupCallback(TChunkCleanup* aCleanup)
       
   228 	{
       
   229 	__KTRACE_OPT(KPCI, Kern::Printf("Pci::ChunkCleanupCallback aCleanup = 0x%08x", aCleanup));
       
   230 	aCleanup->Destroy();
       
   231 	delete aCleanup;	
       
   232 	}
       
   233 
       
   234 EXPORT_C TInt Pci::CreateMapping(TInt aFunction, TUint32 aPhysicalAddress, TInt aSize, TUint32& aPciAddress)
       
   235 	{
       
   236 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   237 		return KErrArgument;
       
   238 	__KTRACE_OPT(KPCI, Kern::Printf("Pci::CreateMapping() requested 0x%X bytes", aSize));
       
   239 	return iFunctions[aFunction]->GetBridge().CreateMapping(aPhysicalAddress, aSize, aPciAddress);
       
   240 	}
       
   241 
       
   242 EXPORT_C TInt Pci::RemoveMapping(TInt aFunction, TUint32 aPhysicalAddress)
       
   243 	{
       
   244 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   245 		return KErrArgument;
       
   246 
       
   247 	return iFunctions[aFunction]->GetBridge().RemoveMapping(aPhysicalAddress);
       
   248 	}
       
   249 
       
   250 /**
       
   251 Returns the PCI address corresponding to a given physical address.
       
   252 @param aFunction
       
   253 @param aAddress The physical address, on success, will have been converted to the
       
   254 equivilant PCI address.
       
   255 @return
       
   256 	- KErrNone
       
   257 	- KErrNotFound The physical address has no corresponding PCI address
       
   258 */
       
   259 EXPORT_C TInt Pci::GetPciAddress(TInt aFunction, TUint32& aAddress)
       
   260 	{
       
   261 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   262 		return KErrArgument;
       
   263 
       
   264 	return iFunctions[aFunction]->GetBridge().GetPciAddress(aAddress, aAddress);
       
   265 	}
       
   266 
       
   267 /**
       
   268 Returns the physical address corresponding to a given PCI address.
       
   269 @param aFunction
       
   270 @param aAddress The PCI address, on success, will have been converted to the
       
   271 equivilant physical address.
       
   272 @return
       
   273 	- KErrNone
       
   274 	- KErrNotFound The PCI address has no corresponding physical address
       
   275 */
       
   276 EXPORT_C TInt Pci::GetPhysicalAddress(TInt aFunction, TUint32& aAddress)
       
   277 	{
       
   278 	if(!Rng(0, aFunction, iFunctions.Count()-1 ))
       
   279 		return KErrArgument;
       
   280 
       
   281 	return iFunctions[aFunction]->GetBridge().GetPhysicalAddress(aAddress,aAddress);
       
   282 	}
       
   283 
       
   284 
       
   285 /**
       
   286 Add bridges before calling Enumerate.
       
   287 
       
   288 @param aBridge A constructed bridge object.
       
   289 @return An error value
       
   290 */
       
   291 TInt Pci::AddBridge(DPciBridge* aBridge)
       
   292 	{
       
   293 	return iPciBridges.Append(aBridge);
       
   294 	}
       
   295 
       
   296 /**
       
   297 Query all host bridges on the system for their PCI functions and
       
   298 populate global function list.
       
   299 
       
   300 @return
       
   301 	- KErrNone - Success
       
   302 	- KErrNotSupported - No bridges have been registered
       
   303 	- KErrAccessDenied - Enumerate has already been called
       
   304 */
       
   305 TInt Pci::Enumerate()
       
   306 	{
       
   307 	__KTRACE_OPT(KPCI, Kern::Printf("Pci::Enumerate"));
       
   308 
       
   309 	//only call once, from the extension
       
   310 	if(iEnumerated)
       
   311 		return KErrAccessDenied;
       
   312 	iEnumerated = ETrue;
       
   313 
       
   314 	const TInt numberOfPciBridges= iPciBridges.Count();
       
   315 	if(0 == numberOfPciBridges)
       
   316 		return KErrNotSupported;
       
   317 
       
   318 	TInt r=KErrNone;
       
   319 	for(TInt bridge=0; bridge<numberOfPciBridges; ++bridge)
       
   320 		{
       
   321 		for(TInt bus=0; bus<KPciMaxBusses; ++bus)
       
   322 			{
       
   323 			for(TInt device=0; device<KPciMaxDevices; ++device)
       
   324 				{
       
   325 				for(TInt function=0; function<KPciMaxFunctions; ++function)
       
   326 					{
       
   327 					TPciFunction* func = iPciBridges[bridge]->Function(bus, device, function);
       
   328 					if(func==NULL)
       
   329 						continue;
       
   330 					if(func->IsBridge())
       
   331 						{
       
   332 						//will call bridge fix up code here when supported.
       
   333 						//don't add a bridge into global list as we do not want to
       
   334 						//grant access to it to the client programmer.
       
   335 						__KTRACE_OPT(KPCI, Kern::Printf(  "PCI-PCI bridge unsupported"));
       
   336 						delete func;
       
   337 						func = NULL;
       
   338 						continue;
       
   339 						}
       
   340 					else
       
   341 						{
       
   342 						r=iFunctions.Append(func);
       
   343 						__KTRACE_OPT(KPCI, Kern::Printf("  Adding function %d:%d:%d:%d, vid=0x%04x, did=0x%04x"
       
   344 									, bridge, bus, device, function, func->VendorId(), func->DeviceId()));
       
   345 						}
       
   346 					if(r!=KErrNone)
       
   347 						return r;
       
   348 
       
   349 					//a multifunction device can indicate the last function
       
   350 					//implemented by setting its multi function bit to 0
       
   351 					//so this is checked for all function numbers
       
   352 					if(!func->IsMultiFunc())
       
   353 						{
       
   354 						break;
       
   355 						}
       
   356 					}
       
   357 				}
       
   358 			}
       
   359 		iPciBridges[bridge]->ConfigurationComplete();
       
   360 		}
       
   361 	return r;
       
   362 	}
       
   363 
       
   364 TPciFunction::TPciFunction(TInt aBus, TInt aDevice, TInt aFunction,
       
   365 		TPciVendorId aVid, TDeviceId aDid, DPciBridge& aBridge)
       
   366 	:iBus(aBus), iDevice(aDevice), iFunction(aFunction), iVid(aVid), iDid(aDid),
       
   367 		iBridge(aBridge), iConfigSpace(NULL), iMemorySpaces(KPciNumberOfBars),
       
   368 		iIsBridge(EFalse), iIsMultiFunc(EFalse)
       
   369 	{
       
   370 	__ASSERT_DEBUG(iBus<256, Kern::Printf("TConfigSpace: Bus id too big"));
       
   371 	__ASSERT_DEBUG(iDevice<32, Kern::Printf("TConfigSpace: Device id too big"));
       
   372 	__ASSERT_DEBUG(iFunction<8, Kern::Printf("TConfigSpace: Function id too big"));
       
   373 
       
   374 	//Array has an element for each of this PCI function's BARs
       
   375 	//but an unused one will be NULL
       
   376 	for(TInt i=0; i<KPciNumberOfBars;++i)
       
   377 		{
       
   378 		TInt r=iMemorySpaces.Append(NULL);
       
   379 		__NK_ASSERT_ALWAYS(KErrNone==r);
       
   380 		}
       
   381 
       
   382 	iConfigSpace = new TConfigSpace(*this, iBridge);
       
   383 	__NK_ASSERT_ALWAYS(iConfigSpace!=NULL);
       
   384 
       
   385 	const TUint8 headerTypeByte = iConfigSpace->Read8(KPciHeaderType);
       
   386 	iIsMultiFunc = (headerTypeByte & HeaderType::KHtMultiFunction);
       
   387 
       
   388 	const TInt headerType = headerTypeByte & (~HeaderType::KHtMultiFunction);
       
   389 	_LIT(KHeaderError, "Unknown PCI header type");
       
   390 	switch(headerType)
       
   391 		{
       
   392 	case 0:
       
   393 		iIsBridge=EFalse; break;
       
   394 	case 1:
       
   395 		iIsBridge=ETrue; break;
       
   396 	default:
       
   397 		Kern::PanicCurrentThread(KHeaderError, 0);
       
   398 		}
       
   399 	}
       
   400 
       
   401 TPciFunction::~TPciFunction()
       
   402 	{
       
   403 	iMemorySpaces.ResetAndDestroy();
       
   404 
       
   405 	delete iConfigSpace;
       
   406 	}
       
   407 
       
   408 /**
       
   409 @param aBarIndex The Bar which this memory space is asssociated with
       
   410 */
       
   411 TInt TPciFunction::AddMemorySpace(TUint32 aSize, TUint32 aAddress, TInt aBarIndex)
       
   412 	{
       
   413 	TMemorySpace* space=new TMemorySpace(aAddress, aSize);
       
   414 	if(NULL==space)
       
   415 		{
       
   416 		return KErrNoMemory;
       
   417 		}
       
   418 	else
       
   419 		{
       
   420 		iMemorySpaces[aBarIndex]=space;
       
   421 		return KErrNone;
       
   422 		}
       
   423 	}
       
   424 
       
   425 EXPORT_C TAddrSpace* TPciFunction::GetConfigSpace()
       
   426 	{
       
   427 	return iConfigSpace;
       
   428 	}
       
   429 
       
   430 EXPORT_C TAddrSpace* TPciFunction::GetMemorySpace(TInt aBar)
       
   431 	{
       
   432 	if(!Rng(0,aBar, iMemorySpaces.Count()-1))
       
   433 		return NULL;
       
   434 
       
   435 	return iMemorySpaces[aBar];
       
   436 	}
       
   437 //
       
   438 // TMemory Space
       
   439 //
       
   440 
       
   441 #define READ_TRACE(N) __KTRACE_OPT(KPCI, Kern::Printf( "TMemorySpace::READ" #N " Offset=0x%x, Absolute=0x%x (Base=0x%x), Value=0x%x",\
       
   442 			aOffset, iBaseAddress+aOffset, iBaseAddress, value ))
       
   443 
       
   444 #define WRITE_TRACE(N) __KTRACE_OPT(KPCI, Kern::Printf( "TMemorySpace::Write" #N " Offset=0x%x, Absolute=0x%x (Base=0x%x), Value=0x%x",\
       
   445 			aOffset, iBaseAddress+aOffset, iBaseAddress, aValue ))
       
   446 
       
   447 #define MOD_TRACE(N) __KTRACE_OPT(KPCI, Kern::Printf( "TMemorySpace::Modify" #N " Offset=0x%x, Absolute=0x%x (Base=0x%x), ClearMask=0x%x, SetMask=0x%x",\
       
   448 			aOffset, iBaseAddress+aOffset, iBaseAddress, aClearMask, aSetMask ))
       
   449 
       
   450 _LIT(KTMemorySpace, "TMemorySpace");
       
   451 TMemorySpace::TMemorySpace(TUint32 aBaseAddress, TUint aSize)
       
   452 	:TAddrSpace(aSize, KTMemorySpace), iBaseAddress(aBaseAddress)
       
   453 	{
       
   454 	}
       
   455 
       
   456 TUint32 TMemorySpace::Read32(TUint32 aOffset)
       
   457 	{
       
   458 	CheckAccess(E4Byte, aOffset);
       
   459 	return AsspRegister::Read32(iBaseAddress+aOffset);
       
   460 	}
       
   461 
       
   462 void TMemorySpace::Write32(TUint32 aOffset, TUint32 aValue)
       
   463 	{
       
   464 	WRITE_TRACE(32);
       
   465 	CheckAccess(E4Byte, aOffset);
       
   466 	AsspRegister::Write32(iBaseAddress+aOffset, aValue);
       
   467 	}
       
   468 
       
   469 void TMemorySpace::Modify32(TUint32 aOffset, TUint32 aClearMask, TUint32 aSetMask)
       
   470 	{
       
   471 	MOD_TRACE(32);
       
   472 	CheckAccess(E4Byte, aOffset);
       
   473 	AsspRegister::Modify32(iBaseAddress+aOffset, aClearMask, aSetMask);
       
   474 	}
       
   475 
       
   476 TUint16 TMemorySpace::Read16(TUint32 aOffset)
       
   477 	{
       
   478 	CheckAccess(E2Byte, aOffset);
       
   479 	return AsspRegister::Read16(iBaseAddress+aOffset);
       
   480 	}
       
   481 
       
   482 void TMemorySpace::Write16(TUint32 aOffset, TUint16 aValue)
       
   483 	{
       
   484 	WRITE_TRACE(16);
       
   485 	CheckAccess(E2Byte, aOffset);
       
   486 	AsspRegister::Write16(iBaseAddress+aOffset, aValue);
       
   487 	}
       
   488 
       
   489 void TMemorySpace::Modify16(TUint32 aOffset, TUint16 aClearMask, TUint16 aSetMask)
       
   490 	{
       
   491 	MOD_TRACE(16);
       
   492 	CheckAccess(E2Byte, aOffset);
       
   493 	AsspRegister::Modify16(iBaseAddress+aOffset, aClearMask, aSetMask);
       
   494 	}
       
   495 
       
   496 TUint8 TMemorySpace::Read8(TUint32 aOffset)
       
   497 	{
       
   498 	CheckAccess(E1Byte, aOffset);
       
   499 	return AsspRegister::Read8(iBaseAddress+aOffset);
       
   500 	}
       
   501 
       
   502 void TMemorySpace::Write8(TUint32 aOffset, TUint8 aValue)
       
   503 	{
       
   504 	WRITE_TRACE(8);
       
   505 	CheckAccess(E1Byte, aOffset);
       
   506 	AsspRegister::Write8(iBaseAddress+aOffset, aValue);
       
   507 	}
       
   508 
       
   509 void TMemorySpace::Modify8(TUint32 aOffset, TUint8 aClearMask, TUint8 aSetMask)
       
   510 	{
       
   511 	MOD_TRACE(8);
       
   512 	CheckAccess(E1Byte, aOffset);
       
   513 	AsspRegister::Modify8(iBaseAddress+aOffset, aClearMask, aSetMask);
       
   514 	}
       
   515 
       
   516 //
       
   517 // TChunkCleanup
       
   518 //
       
   519