--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/naviengine/navienginebsp/ne1_tb/test/pci/d_pci.cpp Wed Sep 15 13:26:16 2010 +0300
@@ -0,0 +1,882 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This material, including documentation and any related computer
+* programs, is protected by copyright controlled by Nokia. All
+* rights are reserved. Copying, including reproducing, storing
+* adapting or translating, any or all of this material requires the
+* prior written consent of Nokia. This material also contains
+* confidential information which may not be disclosed to others
+* without the prior written consent of Nokia.
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Device-driver for naviEngine PCI testing
+*
+*/
+
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <pci.h>
+#include <naviengine.h>
+#include <kernel/cache.h>
+#include "allocator.h"
+#include "pci-ne.h"
+#include "pci_priv.h"
+#include <platform.h>
+#include "t_pci.h"
+#include "../../naviengine_assp/naviengine_pci.h"
+
+#define TEST(X) __NK_ASSERT_ALWAYS(X)
+#define TEST_KERRNONE(X) if((X) !=KErrNone) {\
+ Kern::Printf("Assertion Failed X=%d", (X)); FAULT();}
+
+#define FUNC_LOG() __KTRACE_OPT(KPCI, Kern::Printf(__PRETTY_FUNCTION__))
+
+
+void TestAllocator();
+
+/**
+So that the test app can get notification
+when PCI DChunks' cleanup operation has run
+we will replace their cleanup object with this
+one, which will call the original object's destroy
+function as well completing a notification
+*/
+class TPciCleanupWrapper : public TChunkCleanup
+ {
+public:
+
+ ~TPciCleanupWrapper()
+ {
+ delete iOriginal;
+ Kern::DestroyClientRequest(iClientRequest);
+ iClient->Close(NULL);
+ }
+
+ static TPciCleanupWrapper* Create(TRequestStatus* aRequestStatus)
+ {
+ __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create aRequestStatus=0x%08x", aRequestStatus));
+ TClientRequest* request = NULL;
+ TInt r = Kern::CreateClientRequest(request);
+ if(r != KErrNone)
+ {
+ __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create Failed to create client request r=%d", r));
+ return NULL;
+ }
+
+ r = request->SetStatus(aRequestStatus);
+ if(r != KErrNone)
+ {
+ __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create Failed to set status r=%d", r));
+ Kern::DestroyClientRequest(request);
+ return NULL;
+ }
+
+ return new TPciCleanupWrapper(request);
+ }
+
+ /**
+ Insert the cleanup object into aChunk, remembering
+ the original one
+
+ @param aChunk a chunk known to have TChunkCleanup derived cleanup object
+ */
+ void Insert(DChunk* aChunk)
+ {
+ __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Insert aChunk=0x%08x", aChunk));
+ __NK_ASSERT_DEBUG(aChunk);
+ __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper replace 0x%08x with 0x%08x", aChunk->iDestroyedDfc, this));
+ iOriginal = static_cast<TChunkCleanup*>(aChunk->iDestroyedDfc);
+
+ __NK_ASSERT_DEBUG(iOriginal);
+ aChunk->iDestroyedDfc = this;
+ }
+
+ /**
+ Run the original object's destroy method
+ then notify client
+ */
+ void Destroy()
+ {
+ __KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Destroy\n"));
+ iOriginal->Destroy();
+
+ __NK_ASSERT_ALWAYS(iClientRequest->IsReady());
+ Kern::QueueRequestComplete(iClient, iClientRequest, KErrNone);
+ }
+
+private:
+ TPciCleanupWrapper(TClientRequest* aRequest)
+ :TChunkCleanup(), iOriginal(NULL), iClientRequest(aRequest), iClient(&Kern::CurrentThread())
+ {
+ __ASSERT_CRITICAL;
+ iClient->Open(); //don't allow thread object to be destroyed before we signal
+ }
+
+
+ TChunkCleanup* iOriginal;
+ TClientRequest* iClientRequest;
+ DThread* const iClient;
+ };
+
+
+
+
+//This information will come from the pci driver
+//if this code is ever made generic
+TPciTestInfo KTestInfo =
+ {
+ TPciDevice(0x1033, 0x35, 0),
+ TPciTestInfo::TAddrSpaceTest(0, 0x00351033, 0),
+ TPciTestInfo::TAddrSpaceTest(KPciBar0, 0, 0xFFF),
+ 0,
+ TPciTestInfo::TAddrSpaceTest(0x34, 0x2EDF, 0),
+ TPciTestInfo::TAddrSpaceTest(0x20, 0, 0xF),
+ KNeBridgeNumberOfBars
+ };
+
+/**
+Class for a DChunk to remove a DPlatHwChunk chunk
+*/
+class TPciPlatChunkCleanup : public TChunkCleanup
+ {
+public:
+ TPciPlatChunkCleanup(TInt aPciFunction, DPlatChunkHw* aPciPlatChunk);
+ virtual void Destroy();
+public:
+ TInt iPciFunction;
+ DPlatChunkHw* iPciChunk;
+ };
+
+TPciPlatChunkCleanup::TPciPlatChunkCleanup(TInt aPciFunction, DPlatChunkHw* aPciPlatChunk)
+ : TChunkCleanup(), iPciFunction(aPciFunction), iPciChunk(aPciPlatChunk)
+ {
+ }
+
+void TPciPlatChunkCleanup::Destroy()
+ {
+ __KTRACE_OPT(KPCI, Kern::Printf("SHAREDCHUNK ChunkDestroyed DFC\n"));
+ TInt r = Pci::RemoveChunk(iPciFunction, iPciChunk);
+ __NK_ASSERT_ALWAYS(r==KErrNone);
+ }
+
+/**
+Cleanup class to remove the mapping for an externally
+mapped chunk
+*/
+class TPciMappedChunkCleanup : public TChunkCleanup
+ {
+public:
+ TPciMappedChunkCleanup (TInt aPciFunction,TUint32 aPhysicalAddress);
+ virtual void Destroy();
+public:
+ TInt iPciFunction;
+ TUint32 iPhysicalAddress;
+ };
+
+TPciMappedChunkCleanup::TPciMappedChunkCleanup(TInt aPciFunction,TUint32 aPhysicalAddress)
+ : TChunkCleanup(), iPciFunction(aPciFunction),iPhysicalAddress(aPhysicalAddress)
+ {
+ }
+
+void TPciMappedChunkCleanup::Destroy()
+ {
+ //remove mapping
+ TInt r = Pci::RemoveMapping(iPciFunction, iPhysicalAddress);
+ __NK_ASSERT_ALWAYS(r==KErrNone);
+ __KTRACE_OPT(KPCI, Kern::Printf("MAPPING REMOVED ChunkDestroyed DFC\n"));
+ }
+
+class DPciTestChannel : public DLogicalChannelBase
+ {
+public:
+ DPciTestChannel();
+ virtual ~DPciTestChannel();
+ TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
+ virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+
+private:
+ TInt OpenPciDChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus);
+ TInt OpenPciPlatHwChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus);
+ TInt OpenPciMappedChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus);
+ TInt CreateSharedChunk(TInt aPciChunkSize, TUint32 aAttributes, DChunk*& aChunk, TLinAddr& aVirt, TPhysAddr& aPhysicalAddress);
+ TInt OpenPciWindowChunk();
+ void RunUnitTests();
+
+private:
+ const TPciTestInfo& iTestInfo;
+ TInt iFunction; ///< PCI function number this channel is associated with
+ };
+
+DPciTestChannel::DPciTestChannel()
+ : iTestInfo(KTestInfo), iFunction(-1)
+ {
+ FUNC_LOG();
+ }
+
+DPciTestChannel::~DPciTestChannel()
+ {
+ FUNC_LOG();
+ }
+
+TInt DPciTestChannel::DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
+ {
+ if(aInfo == NULL)
+ return KErrNone; //Not a device specific channel
+
+ TPciDevice dev;
+ TPckg<TPciDevice> devPckg(dev);
+ TInt r = Kern::ThreadDesRead(&Kern::CurrentThread(), aInfo, devPckg, 0, KChunkShiftBy0);
+ if(r != KErrNone)
+ return r;
+
+ NKern::ThreadEnterCS();
+ RArray<TInt> indicies;
+ r = Pci::Probe(indicies, dev.iVendorId, dev.iDeviceId);
+
+ if((KErrNone == r) && (dev.iInstance < indicies.Count()))
+ {
+ iFunction = indicies[dev.iInstance];
+ }
+ else
+ {
+ r = KErrNotFound;
+ }
+
+ indicies.Close();
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+
+TInt DPciTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
+ {
+ switch (aFunction)
+ {
+ case EGetTestInfo:
+ {
+ TDes8& dest(*(TDes8*)a1);
+ TPckgC<TPciTestInfo> info(iTestInfo);
+ Kern::KUDesPut(dest, info);
+ return KErrNone;
+ }
+ case EAccessConfigSpace:
+ {
+ TPckgBuf<TUserConfigSpace> pckg;
+ Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1));
+
+ TAddrSpace* configSpace = Pci::GetConfigSpace(iFunction);
+ if(configSpace == NULL)
+ {
+ Kern::PanicCurrentThread(KPciTest, KErrGeneral);
+ return KErrGeneral;
+ }
+ return pckg().KRun(*configSpace);
+ }
+ case EAccessMemorySpace:
+ {
+ TPckgBuf<TUserMemorySpace> pckg;
+ Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1));
+
+ TAddrSpace* memSpace = Pci::GetMemorySpace(iFunction, pckg().BarIndex());
+ if(memSpace == NULL)
+ {
+ Kern::PanicCurrentThread(KPciTest, KErrGeneral);
+ return KErrGeneral;
+ }
+ return pckg().KRun(*memSpace);
+ }
+ case EOpenPciWindowChunk:
+ {
+ TInt rHandle = 0;
+ rHandle = OpenPciWindowChunk();
+ return rHandle;
+ }
+ case EOpenPciDChunk: //Fall-through
+ case EOpenPciPlatHwChunk:
+ case EOpenPciMappedChunk:
+ {
+ TPckgBuf<TPciChunkCreateInfo> pckg;
+ Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1));
+
+ TUint32 pciAddr;
+ TInt rHandle = 0;
+ switch (aFunction)
+ {
+ case EOpenPciDChunk:
+ {
+ rHandle = OpenPciDChunk(pciAddr, pckg().iSize, pckg().iStatus);
+ break;
+ }
+ case EOpenPciPlatHwChunk:
+ {
+ rHandle = OpenPciPlatHwChunk(pciAddr, pckg().iSize, pckg().iStatus);
+ break;
+ }
+ case EOpenPciMappedChunk:
+ {
+ rHandle = OpenPciMappedChunk(pciAddr, pckg().iSize, pckg().iStatus);
+ break;
+ }
+ default:
+ {
+ FAULT();
+ }
+ }
+ //write back PCI address to user
+ umemput(pckg().iPciAddress,&pciAddr,sizeof(pciAddr));
+ return rHandle;
+ }
+ case ERunUnitTests:
+ {
+ RunUnitTests();
+ return KErrNone;
+ }
+ default:
+ return KErrNotSupported;
+ }
+ }
+
+/**
+This function runs tests for the address allocator
+*/
+void DPciTestChannel::RunUnitTests()
+{
+ // Enter critical section
+ NKern::ThreadEnterCS();
+
+ TestAllocator();
+
+ // Finished
+ NKern::ThreadLeaveCS();
+}
+
+
+/**
+This function creates and opens a PCI DChunk and returns the PCI addresss
+@param aPciAddr on return contains the pci address
+@param aPciChunkSize contains the size of the PCI DChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciDChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus)
+{
+ //Chunk Attributes
+ TChunkCreateInfo aInfo;
+ aInfo.iType = TChunkCreateInfo::ESharedKernelMultiple;
+ aInfo.iMapAttr = EMapAttrSupRw|EMapAttrFullyBlocking;
+ aInfo.iOwnsMemory = EFalse; // We'll be using our own devices memory
+
+ DChunk* pciChunk;
+ pciChunk=NULL;
+
+ // Enter critical section
+ NKern::ThreadEnterCS();
+
+ //Create DChunk
+ TInt r = Pci::CreateChunk(iFunction, pciChunk, aInfo,0,aPciChunkSize,aPciAddr);
+ if(r!=KErrNone)
+ {
+ // Failed to create DChunk
+ __KTRACE_OPT(KPCI,Kern::Printf("Failed to create DChunk: Error code is=%d", r) );
+ NKern::ThreadLeaveCS(); // Finished
+ return r;
+ }
+ else
+ {
+ TInt rHandle = KErrGeneral;
+ if(aStatus)
+ {
+ TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus);
+ if(wrapper == NULL)
+ {
+ __KTRACE_OPT(KPCI,Kern::Printf("Creation of TPciCleanupWrapper failed"));
+ goto End;
+ }
+ wrapper->Insert(pciChunk);
+ }
+
+ __KTRACE_OPT(KPCI,Kern::Printf("Created DChunk: PCI_ADDRESS=0x%08x",aPciAddr));
+ rHandle = Kern::MakeHandleAndOpen(NULL, pciChunk);//Get DChunk handle
+
+End:
+ pciChunk->Close(NULL); // Close DChunk
+ NKern::ThreadLeaveCS(); // Finished
+ return rHandle;
+ }
+}
+
+/**
+This function creates and opens a PCI DPlatChunk and returns the PCI addresss.
+A DPlatChunk is intially created and then a DChunk is set to point to the same
+memory as the DPlatChunk.This is done so that it can be accessed on the user side.
+@param aPciAddr on return contains the pci address
+@param aPciChunkSize contains the size of the PCI PlatHwChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciPlatHwChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus)
+{
+ TUint32 pciPhysicalAddr;
+ TUint32 pciChunkMapAttr;
+ TLinAddr pciChunkKernelAddr;
+
+ DPlatChunkHw* pciPlatChunk;
+ pciPlatChunk=NULL;
+
+ // Enter critical section
+ NKern::ThreadEnterCS();
+
+ //Create DPlatChunkHw
+ TInt r = Pci::CreateChunk(iFunction,pciPlatChunk,aPciChunkSize,(EMapAttrSupRw|EMapAttrFullyBlocking),aPciAddr);
+ if(r!=KErrNone)
+ {
+ // Failed to create DPlatChunkHw
+ __KTRACE_OPT(KPCI,Kern::Printf("Failed to create DPlatChunkHw chunk: Error code is=%d", r));
+ NKern::ThreadLeaveCS(); // Finished
+ return r;
+ }
+
+ //Get physical addresss
+ pciPhysicalAddr = pciPlatChunk->PhysicalAddress();
+
+ // Create DChunk cleanup object
+ TPciPlatChunkCleanup* cleanup = new TPciPlatChunkCleanup(iFunction, pciPlatChunk);
+ if(!cleanup)
+ {
+ pciPlatChunk->Close(NULL); //close pciPlatChunk
+ NKern::ThreadLeaveCS();
+ return KErrNoMemory;
+ }
+
+ //Chunk Attributes for DChunk
+ TChunkCreateInfo chunkinfo;
+ chunkinfo.iType = TChunkCreateInfo::ESharedKernelMultiple;
+ chunkinfo.iMaxSize = 0x4000;
+ chunkinfo.iMapAttr = EMapAttrSupRw|EMapAttrFullyBlocking; // No caching
+ chunkinfo.iOwnsMemory = EFalse; // Use memory from system's free pool
+ chunkinfo.iDestroyedDfc = cleanup;
+
+ DChunk* pciDChunk;
+
+ //Create DChunk
+ r = Kern::ChunkCreate(chunkinfo, pciDChunk, pciChunkKernelAddr, pciChunkMapAttr);
+ if(r!=KErrNone)
+ {
+ pciPlatChunk->Close(NULL); //close pciPlatChunk
+ delete cleanup;
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+
+ pciPlatChunk=NULL; // pciDChunk now owns chunk
+
+ if(aStatus)
+ {
+ TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus);
+ if(wrapper == NULL)
+ {
+ pciDChunk->Close(NULL); // Close pciDChunk
+ NKern::ThreadLeaveCS(); // Finished
+ return KErrGeneral;
+ }
+ wrapper->Insert(pciDChunk);
+ }
+
+ //Commit memory to a DChunk using DPlatChunkHw physical address
+ r = Kern::ChunkCommitPhysical(pciDChunk,0,aPciChunkSize,pciPhysicalAddr);
+ if(r!=KErrNone)
+ {
+ // Failed to commit memory
+ Kern::Printf("Commit failed: Error code is=%d", r);
+ __KTRACE_OPT(KPCI,Kern::Printf("Commit failed: Error code is=%d", r));
+
+ // Close chunk, which will then get deleted at some point
+ Kern::ChunkClose(pciDChunk);
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+
+ //Close pciPlatChunk using pciDChunk as pciDChunk now owns it
+ const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciDChunk); //Get DChunk handle
+ pciDChunk->Close(NULL); // Close pciDChunk
+ NKern::ThreadLeaveCS(); // Finished
+ return rHandle;
+}
+
+/**
+This function creates and opens a PCI mapped DChunk and returns the PCI addresss
+@param aPciAddr on return contains the pci address
+@param aPciChunkSize contains the size of the PCI DChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciMappedChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus)
+{
+ TLinAddr virt=NULL;
+ TPhysAddr physicalAddress=NULL;
+ DChunk* pciChunk=NULL;
+ TUint32 pciAttributes=EMapAttrSupRw|EMapAttrFullyBlocking;
+
+ // Enter critical section
+ NKern::ThreadEnterCS();
+
+ //create DChunk
+ TInt r = CreateSharedChunk(aPciChunkSize, pciAttributes, pciChunk, virt, physicalAddress);
+ if(r!=KErrNone)
+ {
+ __KTRACE_OPT(KPCI,Kern::Printf("Create shared Chunk failed: Error code is=%d", r));
+ return r;
+ }
+
+ __NK_ASSERT_ALWAYS(pciChunk);
+
+ //create mapping
+ r=Pci::CreateMapping(iFunction, physicalAddress, aPciChunkSize, aPciAddr);
+ if(r!=KErrNone)
+ {
+ pciChunk->Close(NULL);
+ __KTRACE_OPT(KPCI,Kern::Printf("Create mapping failed: Error code is=%d", r));
+ return r;
+ }
+
+
+ // Create DChunk cleanup object
+ TPciMappedChunkCleanup* cleanup = new TPciMappedChunkCleanup(iFunction, physicalAddress);
+ if(!cleanup)
+ {
+ pciChunk->Close(NULL);
+ NKern::ThreadLeaveCS();
+ return KErrNoMemory;
+ }
+
+ //must add the cleanup dfc to the chunk after creation
+ //since the cleanup parameters aren't known
+ //till after creating it and allocating memory to it
+ pciChunk->iDestroyedDfc = cleanup;
+
+ if(aStatus)
+ {
+ TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus);
+ if(wrapper == NULL)
+ {
+ pciChunk->Close(NULL); // Close pciDChunk
+ NKern::ThreadLeaveCS();
+ return KErrGeneral;
+ }
+ wrapper->Insert(pciChunk);
+ }
+
+ //Get DChunk handle
+ const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciChunk);
+
+ // Close DChunk
+ pciChunk->Close(NULL);
+
+ // Finished
+ NKern::ThreadLeaveCS();
+ return rHandle;
+}
+
+/**
+This function creates and opens a PCI Window Chunk and returns the PCI Window addresss
+@param aPciChunkSize contains the size of the PCI Window DChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciWindowChunk()
+{
+ TUint32 pciChunkMapAttr;
+ TLinAddr pciChunkKernelAddr=NULL;
+ DChunk* pciWindowChunk=NULL;
+
+ //Chunk Attributes for DChunk
+ TChunkCreateInfo chunkinfo;
+ chunkinfo.iType = TChunkCreateInfo::ESharedKernelMultiple;
+ chunkinfo.iMaxSize = 0x2000;
+ chunkinfo.iMapAttr = EMapAttrSupRw|EMapAttrFullyBlocking; // No caching
+ chunkinfo.iOwnsMemory = EFalse; // Use memory from system's free pool
+
+ // Enter critical section
+ NKern::ThreadEnterCS();
+
+ //Create shared chunk for PCI window
+ TInt r = Kern::ChunkCreate(chunkinfo, pciWindowChunk, pciChunkKernelAddr, pciChunkMapAttr);
+ if(r!=KErrNone)
+ {
+ // Failed to create DChunk
+ __KTRACE_OPT(KPCI,Kern::Printf("Failed to create DChunk: Error code is=%d", r) );
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+
+ //This address is PSL specific. This will have to be changed
+ //if d_pci.cpp is ever made generic
+ TUint32 pciPhysicalAddr = KHwUSBHPhys; // Internal PCI window address
+
+ //Commit memory to a DChunk using Internal PCI window address
+ r = Kern::ChunkCommitPhysical(pciWindowChunk,0,KHwUSBHInternalPciWindowSize, pciPhysicalAddr);
+ if(r!=KErrNone)
+ {
+ // Failed to commit memory
+ Kern::Printf("Commit failed: Error code is=%d", r);
+ __KTRACE_OPT(KPCI,Kern::Printf("Commit failed: Error code is=%d", r));
+
+ // Close chunk, which will then get deleted at some point
+ Kern::ChunkClose(pciWindowChunk);
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+
+ //Close pciPlatChunk using pciDChunk as pciDChunk now owns it
+ const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciWindowChunk); //Get PCI Window DChunk handle
+ pciWindowChunk->Close(NULL); // Close pci window chunk
+ NKern::ThreadLeaveCS(); // Finished
+ return rHandle;
+}
+
+/**
+This function creates and opens a shared chunk. The chunk is then commited to a contiguous memory
+@param aPciChunkSize contains the size of the PCI DChunk which is to be created
+@param aAttributes on return, this is set to the mmu mapping attributes used for the chunk
+@param aChunk on return, a reference to the shared chunk
+@param aVirt on return, this is set to the virtual address shared chunk
+@param aPhysicalAddress on return, this is set to the physical address of the first page of memory
+ which was committed.
+*/
+TInt DPciTestChannel::CreateSharedChunk(TInt aPciChunkSize, TUint32 aAttributes, DChunk*& aChunk, TLinAddr& aVirt, TPhysAddr& aPhysicalAddress)
+{
+ __NK_ASSERT_DEBUG(aChunk==NULL);
+ aPciChunkSize = Kern::RoundToPageSize(aPciChunkSize);
+ DChunk* pC=NULL;
+
+ // Enter critical section
+ NKern::ThreadEnterCS();
+
+ //Chunk Attributes for DChunk
+ TChunkCreateInfo info;
+ info.iType=TChunkCreateInfo::ESharedKernelSingle;
+ info.iMaxSize=aPciChunkSize;
+ info.iMapAttr=aAttributes;
+ info.iOwnsMemory=ETrue;
+
+ //Create DChunk
+ TInt r=Kern::ChunkCreate(info, pC, aVirt, aAttributes);
+ if(r!=KErrNone)
+ {
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+ //Commit DChunk to Contiguous memory
+ r = Kern::ChunkCommitContiguous(pC, 0, aPciChunkSize, aPhysicalAddress);
+ if(r==KErrNone)
+ {
+ aChunk=pC;
+ }
+ else
+ {
+ Kern::ChunkClose(pC);
+ __KTRACE_OPT(KPCI,Kern::Printf("Commit DChunk to Contiguous memory Failed : Error code is=%d",r));
+ return r;
+ }
+
+ NKern::ThreadLeaveCS(); // Finished
+ __KTRACE_OPT(KPCI, Kern::Printf("Created SC: size=0x%08x, virtual= 0x%08x, phys=0x%08x", aPciChunkSize, aVirt, aPhysicalAddress));
+ return r;
+}
+
+class DPciDevice : public DLogicalDevice
+ {
+public:
+ DPciDevice();
+ ~DPciDevice();
+ TInt Install();
+ void GetCaps(TDes8& aDes) const;
+ TInt Create(DLogicalChannelBase*& aChannel);
+ };
+
+DPciDevice::DPciDevice()
+ {
+ FUNC_LOG();
+ }
+
+DPciDevice::~DPciDevice()
+ {
+ FUNC_LOG();
+ }
+
+TInt DPciDevice::Install()
+ {
+ return SetName(&KPciLddFactory);
+ }
+
+void DPciDevice::GetCaps(TDes8&) const
+ {
+ }
+
+TInt DPciDevice::Create(DLogicalChannelBase*& aChannel)
+ {
+ aChannel = new DPciTestChannel;
+ return aChannel ? KErrNone : KErrNoMemory;
+ }
+
+/****************************************
+TUserPciSpace
+*/
+
+/**
+Decides what action to run based on contents of class
+*/
+TUint TUserPciSpace::KRun(TAddrSpace& aAddrSp)
+ {
+
+ //this could be reworked as a function pointer
+ //table, but this might be clearer
+ switch(iBitWidth)
+ {
+ case 8:
+ {
+ switch(iOperation)
+ {
+ case ERead:
+ {
+ return aAddrSp.Read8(iOffset);
+ }
+ case EWrite:
+ {
+ aAddrSp.Write8(iOffset, iWriteValue);
+ return KErrNone;
+ }
+ case EModify:
+ {
+ aAddrSp.Modify8(iOffset, iClearMask, iSetMask);
+ return KErrNone;
+ }
+ default:
+ {
+ Kern::PanicCurrentThread(KPciTest, KErrNotReady);
+ }
+ }
+ }
+ case 16:
+ {
+ switch(iOperation)
+ {
+ case ERead:
+ {
+ return aAddrSp.Read16(iOffset);
+ }
+ case EWrite:
+ {
+ aAddrSp.Write16(iOffset, iWriteValue);
+ return KErrNone;
+ }
+ case EModify:
+ {
+ aAddrSp.Modify16(iOffset, iClearMask, iSetMask);
+ return KErrNone;
+ }
+ default:
+ {
+ Kern::PanicCurrentThread(KPciTest, KErrNotReady);
+ }
+ }
+ }
+ case 32:
+ {
+ switch(iOperation)
+ {
+ case ERead:
+ {
+ return aAddrSp.Read32(iOffset);
+ }
+ case EWrite:
+ {
+ aAddrSp.Write32(iOffset, iWriteValue);
+ return KErrNone;
+ }
+ case EModify:
+ {
+ aAddrSp.Modify32(iOffset, iClearMask, iSetMask);
+ return KErrNone;
+ }
+ default:
+ {
+ Kern::PanicCurrentThread(KPciTest, KErrNotReady);
+ }
+ }
+ }
+ default:
+ {
+ Kern::PanicCurrentThread(KPciTest, KErrArgument);
+ }
+
+ }
+
+ //unreachable return
+ return KMaxTUint;
+ }
+
+//stub implementation for kernel side
+TUint TUserConfigSpace::Call()
+ {
+ FAULT();
+ return 0;
+ }
+
+TUserPciSpace* TUserConfigSpace::Clone() const
+ {
+ FAULT();
+ return 0;
+ }
+
+//stub implementation for kernel side
+TUint TUserMemorySpace::Call()
+ {
+ FAULT();
+ return 0;
+ }
+
+TUserPciSpace* TUserMemorySpace::Clone() const
+ {
+ FAULT();
+ return 0;
+ }
+
+void TestAllocator()
+ {
+ __KTRACE_OPT(KPCI, Kern::Printf("Testing address allocator"));
+ TAddressAllocator allocator(0x80000000); //2 GB
+ TLinAddr rcvdAddr=NULL;
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+ TEST(0x0 ==rcvdAddr);
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x100) );
+ TEST(0x100 ==rcvdAddr);
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+ TEST(0x10 ==rcvdAddr);
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+ TEST(0x20 ==rcvdAddr);
+ //test deallocating
+ TEST_KERRNONE(allocator.DeAllocate(0x0));
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+ TEST(0x000 ==rcvdAddr);
+
+ TEST_KERRNONE(allocator.DeAllocate(0x100));
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x100) );
+ TEST(0x100 ==rcvdAddr);
+
+ TEST_KERRNONE(allocator.DeAllocate(0x10));
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+ TEST(0x10 ==rcvdAddr);
+
+ TEST_KERRNONE(allocator.DeAllocate(0x20));
+ TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x20) );
+ TEST(0x20 ==rcvdAddr);
+
+ TEST(allocator.DeAllocate(0x40)==KErrNotFound);
+ TEST_KERRNONE(allocator.DeAllocate(0x100));
+ TEST_KERRNONE(allocator.DeAllocate(0x20));
+ TEST_KERRNONE(allocator.DeAllocate(0x0));
+ TEST_KERRNONE(allocator.DeAllocate(0x10));
+ }
+
+
+DECLARE_STANDARD_LDD()
+ {
+ return new DPciDevice;
+ }