kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp
branchRCL_3
changeset 28 5b5d147c7838
parent 26 c734af59ce98
child 42 a179b74831c9
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Tue May 11 17:28:22 2010 +0300
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Tue May 25 14:09:55 2010 +0300
@@ -14,6 +14,7 @@
 //
 
 #include <plat_priv.h>
+#include <kernel/cache.h>
 #include "mm.h"
 #include "mmu.h"
 
@@ -25,6 +26,34 @@
 
 
 /**
+Log2 of minimum number of pages to attempt to write at a time.
+
+The value of 2 gives a minimum write size of 16KB.
+*/
+const TUint KMinPreferredWriteShift = 2;
+
+/**
+Log2 of maximum number of pages to attempt to write at a time.
+
+The value of 4 gives a maximum write size of 64KB.
+*/
+const TUint KMaxPreferredWriteShift = 4;
+
+__ASSERT_COMPILE((1 << KMaxPreferredWriteShift) <= KMaxPagesToClean);
+
+
+/**
+Whether the CPU has the page colouring restriction, where pages must be mapped in sequential colour
+order.
+*/
+#ifdef __CPU_CACHE_HAS_COLOUR	
+const TBool KPageColouringRestriction = ETrue;
+#else
+const TBool KPageColouringRestriction = EFalse;
+#endif
+
+
+/**
 Manages the swap via the data paging device.
 */
 class DSwapManager
@@ -57,23 +86,24 @@
 	TInt UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount);
 	TBool IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount);
 
-	TInt ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageReadRequest* aRequest, TPhysAddr* aPhysAddrs);
-	TInt WriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TBool aBackground);
+	TInt ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs);
+	TInt WriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs, TBool aBackground);
 
 	void GetSwapInfo(SVMSwapInfo& aInfoOut);
 	TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds);
+	void SetSwapAlign(TUint aSwapAlign);
 
 private:
 	inline TSwapState SwapState(TUint aSwapData);
 	inline TInt SwapIndex(TUint aSwapData);
 	inline TUint SwapData(TSwapState aSwapState, TInt aSwapIndex);
 	
-	TInt AllocSwapIndex(TInt aCount);
+	TInt AllocSwapIndex(TUint aCount);
 	void FreeSwapIndex(TInt aSwapIndex);
 	void CheckSwapThresholdsAndUnlock(TUint aInitial);
 	
 	void DoDeleteNotify(TUint aSwapIndex);
-	TInt DoWriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TInt aSwapIndex, TBool aBackground);
+	TInt DoWriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TInt aPageIndex, TPhysAddr* aPhysAddrs, TInt aSwapIndex, TBool aBackground);
 	
 private:
 	DPagingDevice* iDevice;			///< Paging device used to read and write swap pages
@@ -81,6 +111,7 @@
 	NFastMutex iSwapLock;			///< Fast mutex protecting access to all members below
 	TUint iFreePageCount;			///< Number of swap pages that have not been reserved
 	TBitMapAllocator* iBitMap;		///< Bitmap of swap pages that have been allocated
+	TUint iSwapAlign;				///< Log2 number of pages to align swap writes to
 	TUint iAllocOffset;				///< Next offset to try when allocating a swap page
  	TUint iSwapThesholdLow;
  	TUint iSwapThesholdGood;
@@ -88,11 +119,11 @@
 
 
 /**
-Manager for demand paged memory objects which contain writeable data.
-The contents of the memory are written to a backing store whenever its
-pages are 'paged out'.
+   Manager for demand paged memory objects which contain writeable data.
+   The contents of the memory are written to a backing store whenever its
+   pages are 'paged out'.
 
-@see DSwapManager
+   @see DSwapManager
 */
 class DDataPagedMemoryManager : public DPagedMemoryManager
 	{
@@ -114,25 +145,38 @@
 public:
 	void GetSwapInfo(SVMSwapInfo& aInfoOut);
 	TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds);
+	TBool PhysicalAccessSupported();
+	TBool UsePhysicalAccess();
+	void SetUsePhysicalAccess(TBool aUsePhysicalAccess);
+	TUint PreferredWriteSize();
+	TUint PreferredSwapAlignment();
+	TInt SetWriteSize(TUint aWriteShift);
 
 private:
 	TInt WritePages(DMemoryObject** aMemory, TUint* aIndex, TPhysAddr* aPages, TUint aCount, DPageWriteRequest *aRequest, TBool aAnyExecutable, TBool aBackground);
 
 private:
 	/**
-	The paging device used for accessing the backing store.
-	This is set by #InstallPagingDevice.
+	   The paging device used for accessing the backing store.
+	   This is set by #InstallPagingDevice.
 	*/
 	DPagingDevice* iDevice;
 
 	/**
-	The instance of #DSwapManager being used by this manager.
+	   The instance of #DSwapManager being used by this manager.
 	*/
 	DSwapManager* iSwapManager;
 
+	/**
+	   Whether to read and write pages by physical address without mapping them first.
+
+	   Set if the paging media driver supports it.
+	*/
+	TBool iUsePhysicalAccess;
+
 public:
 	/**
-	The single instance of this manager class.
+	   The single instance of this manager class.
 	*/
 	static DDataPagedMemoryManager TheManager;
 	};
@@ -143,9 +187,9 @@
 
 
 /**
-Create a swap manager.
+   Create a swap manager.
 
-@param	aDevice	The demand paging device for access to the swap.
+   @param	aDevice	The demand paging device for access to the swap.
 */
 TInt DSwapManager::Create(DPagingDevice* aDevice)
 	{
@@ -175,6 +219,15 @@
 	}
 
 
+void DSwapManager::SetSwapAlign(TUint aSwapAlign)
+	{
+	TRACE(("WDP: Set swap alignment to %d (%d KB)", aSwapAlign, 4 << aSwapAlign));
+	NKern::FMWait(&iSwapLock);
+	iSwapAlign = aSwapAlign;
+	NKern::FMSignal(&iSwapLock);
+	}
+
+
 inline DSwapManager::TSwapState DSwapManager::SwapState(TUint aSwapData)
 	{
 	TSwapState state = (TSwapState)(aSwapData & ESwapStateMask);
@@ -196,50 +249,73 @@
 
 
 /**
-Allocate one or more page's worth of space within the swap area.
+   Allocate one or more page's worth of space within the swap area.
 
-The location is represented by a page-based index into the swap area.
+   The location is represented by a page-based index into the swap area.
 
-@param aCount The number of page's worth of space to allocate.
+   @param aCount The number of page's worth of space to allocate.
 
-@return The swap index of the first location allocated.
+   @return The swap index of the first location allocated.
 */
-TInt DSwapManager::AllocSwapIndex(TInt aCount)
+TInt DSwapManager::AllocSwapIndex(TUint aCount)
 	{
-	__NK_ASSERT_DEBUG(aCount > 0 && aCount <= KMaxPagesToClean);
+	TRACE2(("DSwapManager::AllocSwapIndex %d", aCount));
+		
+	__NK_ASSERT_DEBUG(aCount <= KMaxPagesToClean);
 	NKern::FMWait(&iSwapLock);
 
-	// search for run of aCount from iAllocOffset to end
-	TInt carry = 0;
+	TInt carry;
 	TInt l = KMaxTInt;
-	TInt swapIndex = iBitMap->AllocAligned(aCount, 0, 0, EFalse, carry, l, iAllocOffset);
+	TInt swapIndex = -1;
 
-	// if search failed, retry from beginning
+	// if size suitable for alignment, search for aligned run of aCount from iAllocOffset to end,
+	// then from beginning
+	// 
+	// note that this aligns writes that at least as large as the alignment size - an alternative
+	// policy might be to align writes that are an exact multiple of the alignment size
+	if (iSwapAlign && aCount >= (1u << iSwapAlign))
+		{
+		carry = 0;
+		swapIndex = iBitMap->AllocAligned(aCount, iSwapAlign, 0, EFalse, carry, l, iAllocOffset);
+		if (swapIndex < 0)
+			{
+			carry = 0;
+			swapIndex = iBitMap->AllocAligned(aCount, iSwapAlign, 0, EFalse, carry, l, 0);
+			}
+		}
+	
+	// if not doing aligned search, or aligned search failed, retry without alignment
 	if (swapIndex < 0)
 		{
-		iAllocOffset = 0;
 		carry = 0;
 		swapIndex = iBitMap->AllocAligned(aCount, 0, 0, EFalse, carry, l, iAllocOffset);
+		if (swapIndex < 0)
+			{
+			carry = 0;
+			swapIndex = iBitMap->AllocAligned(aCount, 0, 0, EFalse, carry, l, 0);
+			}
 		}
 
 	// if we found one then mark it as allocated and update iAllocOffset
 	if (swapIndex >= 0)
 		{
-		__NK_ASSERT_DEBUG(swapIndex <= (iBitMap->iSize - aCount));
+		__NK_ASSERT_DEBUG(swapIndex <= (TInt)(iBitMap->iSize - aCount));
 		iBitMap->Alloc(swapIndex, aCount);
 		iAllocOffset = (swapIndex + aCount) % iBitMap->iSize;
 		}
 	
 	NKern::FMSignal(&iSwapLock);
 	__NK_ASSERT_DEBUG(swapIndex >= 0 || aCount > 1); // can't fail to allocate single page
+
+	TRACE2(("DSwapManager::AllocSwapIndex returns %d", swapIndex));	
 	return swapIndex;
 	}
 
 
 /**
-Free one page's worth of space within the swap area.
+   Free one page's worth of space within the swap area.
 
-The index must have been previously allocated with AllocSwapIndex().
+   The index must have been previously allocated with AllocSwapIndex().
 */
 void DSwapManager::FreeSwapIndex(TInt aSwapIndex)
 	{
@@ -252,15 +328,15 @@
 
 
 /**
-Reserve some swap pages for the requested region of the memory object
+   Reserve some swap pages for the requested region of the memory object
 
-@param aMemory		The memory object to reserve pages for.
-@param aStartIndex	The page index in the memory object of the start of the region.
-@param aPageCount	The number of pages to reserve.
+   @param aMemory		The memory object to reserve pages for.
+   @param aStartIndex	The page index in the memory object of the start of the region.
+   @param aPageCount	The number of pages to reserve.
 
-@return KErrNone on success, KErrNoMemory if not enough swap space available.
-@pre aMemory's lock is held.
-@post aMemory's lock is held.
+   @return KErrNone on success, KErrNoMemory if not enough swap space available.
+   @pre aMemory's lock is held.
+   @post aMemory's lock is held.
 */
 TInt DSwapManager::ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
 	{
@@ -293,15 +369,15 @@
 
 
 /**
-Unreserve swap pages for the requested region of the memory object.
+   Unreserve swap pages for the requested region of the memory object.
 
-@param aMemory		The memory object to unreserve pages for.
-@param aStartIndex	The page index in the memory object of the start of the region.
-@param aPageCount	The number of pages to unreserve.
+   @param aMemory		The memory object to unreserve pages for.
+   @param aStartIndex	The page index in the memory object of the start of the region.
+   @param aPageCount	The number of pages to unreserve.
 
-@return The number of pages freed.
-@pre aMemory's lock is held.
-@post aMemory's lock is held.
+   @return The number of pages freed.
+   @pre aMemory's lock is held.
+   @post aMemory's lock is held.
 */
 TInt DSwapManager::UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
 	{
@@ -348,13 +424,13 @@
 
 
 /**
-Determine whether the specified pages in the memory object have swap reserved for them.
+   Determine whether the specified pages in the memory object have swap reserved for them.
 
-@param aMemory		The memory object that owns the pages.
-@param aStartIndex	The first index of the pages to check.
-@param aPageCount	The number of pages to check.
+   @param aMemory		The memory object that owns the pages.
+   @param aStartIndex	The first index of the pages to check.
+   @param aPageCount	The number of pages to check.
 
-@return ETrue if swap is reserved for all the pages, EFalse otherwise.
+   @return ETrue if swap is reserved for all the pages, EFalse otherwise.
 */
 TBool DSwapManager::IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
 	{// MmuLock required to protect manager data.
@@ -375,16 +451,16 @@
 
 
 /**
-Read from the swap the specified pages associated with the memory object.
+   Read from the swap the specified pages associated with the memory object.
 
-@param aMemory 	The memory object to read the pages for
-@param aIndex	The index of the first page within the memory object.
-@param aCount	The number of pages to read.
-@param aLinAddr	The address to copy the pages to.
-@param aRequest	The request to use for the read.
-@param aPhysAddrs	An array of the physical addresses for each page to read in.
+   @param aMemory 	The memory object to read the pages for
+   @param aIndex	The index of the first page within the memory object.
+   @param aCount	The number of pages to read.
+   @param aLinAddr	The address to copy the pages to.
+   @param aRequest	The request to use for the read.
+   @param aPhysAddrs	An array of the physical addresses for each page to read in.
 */
-TInt DSwapManager::ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageReadRequest* aRequest, TPhysAddr* aPhysAddrs)
+TInt DSwapManager::ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs)
 	{
 	__ASSERT_CRITICAL;
 	
@@ -447,19 +523,21 @@
 
 
 /**
-Write the specified memory object's pages from the RAM into the swap.
+   Write the specified memory object's pages from the RAM into the swap.
 
-@param	aMemory		The memory object who owns the pages.
-@param	aIndex		The index within the memory object.
-@param 	aCount		The number of pages to write out.
-@param	aLinAddr	The location of the pages to write out.
-@param  aBackground Whether this is being called in the background by the page cleaning thread
-                    as opposed to on demand when a free page is required.
+   @param	aMemory		The memory object who owns the pages.
+   @param	aIndex		The index within the memory object.
+   @param 	aCount		The number of pages to write out.
+   @param	aLinAddr	The location of the pages to write out.
+   @param  aBackground Whether this is being called in the background by the page cleaning thread
+   as opposed to on demand when a free page is required.
 
-@pre Called with page cleaning lock held
+   @pre Called with page cleaning lock held
 */
-TInt DSwapManager::WriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TBool aBackground)
+TInt DSwapManager::WriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs, TBool aBackground)
 	{
+	TRACE(("DSwapManager::WriteSwapPages %d pages", aCount));
+	
 	__ASSERT_CRITICAL;  // so we can pass the paging device a stack-allocated TThreadMessage
 	__NK_ASSERT_DEBUG(PageCleaningLock::IsHeld());
 
@@ -503,13 +581,13 @@
 			if (startIndex != -1)
 				{
 				// write pages from startIndex to i exclusive
-				TInt count = i - startIndex;
+				TUint count = i - startIndex;
 				__NK_ASSERT_DEBUG(count > 0 && count <= KMaxPagesToClean);
 
 				// Get a new swap location for these pages, writing them all together if possible
 				TInt swapIndex = AllocSwapIndex(count);
 				if (swapIndex >= 0)
-					r = DoWriteSwapPages(&aMemory[startIndex], &aIndex[startIndex], count, aLinAddr + (startIndex << KPageShift), swapIndex, aBackground);
+					r = DoWriteSwapPages(&aMemory[startIndex], &aIndex[startIndex], count, aLinAddr, startIndex, aPhysAddrs, swapIndex, aBackground);
 				else
 					{
 					// Otherwise, write them individually
@@ -517,7 +595,7 @@
 						{
 						swapIndex = AllocSwapIndex(1);
 						__NK_ASSERT_DEBUG(swapIndex >= 0);
-						r = DoWriteSwapPages(&aMemory[j], &aIndex[j], 1, aLinAddr + (j << KPageShift), swapIndex, aBackground);
+						r = DoWriteSwapPages(&aMemory[j], &aIndex[j], 1, aLinAddr, j, &aPhysAddrs[j], swapIndex, aBackground);
 						if (r != KErrNone)
 							break;
 						}
@@ -533,16 +611,22 @@
 	return r;
 	}
 
-TInt DSwapManager::DoWriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TInt aSwapIndex, TBool aBackground)
+TInt DSwapManager::DoWriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TInt aPageIndex, TPhysAddr* aPhysAddrs, TInt aSwapIndex, TBool aBackground)
 	{	
+	TRACE2(("DSwapManager::DoWriteSwapPages %d pages to %d", aCount, aSwapIndex));
 		
 	const TUint readUnitShift = iDevice->iReadUnitShift;
 	const TUint writeSize = aCount << (KPageShift - readUnitShift);
 	const TUint writeOffset = aSwapIndex << (KPageShift - readUnitShift);
-		
+
 	TThreadMessage msg;
 	START_PAGING_BENCHMARK;
-	TInt r = iDevice->Write(&msg, aLinAddr, writeOffset, writeSize, aBackground);
+	TInt r;
+	if (aLinAddr == 0)
+		r = iDevice->WritePhysical(&msg, aPhysAddrs, aCount, writeOffset, aBackground);
+	else
+		r = iDevice->Write(&msg, aLinAddr + (aPageIndex << KPageShift), writeOffset, writeSize, aBackground);
+		
 	if (r != KErrNone)
 		{
 		__KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::WriteSwapPages: error writing media from %08x to %08x + %x: %d", aLinAddr, writeOffset << readUnitShift, writeSize << readUnitShift, r));
@@ -643,6 +727,63 @@
 	}
 
 
+TBool DDataPagedMemoryManager::PhysicalAccessSupported()
+	{
+	return (iDevice->iFlags & DPagingDevice::ESupportsPhysicalAccess) != 0;
+	}
+
+
+TBool DDataPagedMemoryManager::UsePhysicalAccess()
+	{
+	return iUsePhysicalAccess;
+	}
+
+
+void DDataPagedMemoryManager::SetUsePhysicalAccess(TBool aUsePhysicalAccess)
+	{
+	TRACE(("WDP: Use physical access set to %d", aUsePhysicalAccess));
+	NKern::ThreadEnterCS();
+	PageCleaningLock::Lock();
+	iUsePhysicalAccess = aUsePhysicalAccess;
+	ThePager.SetCleanInSequence(!iUsePhysicalAccess && KPageColouringRestriction);
+	PageCleaningLock::Unlock();
+	NKern::ThreadLeaveCS();
+	}
+
+
+TUint DDataPagedMemoryManager::PreferredWriteSize()
+	{
+	return MaxU(iDevice->iPreferredWriteShift, KMinPreferredWriteShift + KPageShift) - KPageShift;
+	}
+
+
+TUint DDataPagedMemoryManager::PreferredSwapAlignment()
+	{
+	return MaxU(iDevice->iPreferredWriteShift, KPageShift) - KPageShift;
+	}
+
+
+TInt DDataPagedMemoryManager::SetWriteSize(TUint aWriteShift)
+	{
+	TRACE(("WDP: Set write size to %d (%d KB)", aWriteShift, 4 << aWriteShift));
+	// Check value is sensible
+	if (aWriteShift > 31)
+		return KErrArgument;
+	if (aWriteShift > KMaxPreferredWriteShift)
+		{
+		aWriteShift = KMaxPreferredWriteShift;
+		TRACE(("WDP: Reduced write size to %d (%d KB)",
+			   aWriteShift, 4 << aWriteShift));
+
+		}
+	NKern::ThreadEnterCS();
+	PageCleaningLock::Lock();
+	ThePager.SetPagesToClean(1 << aWriteShift);
+	PageCleaningLock::Unlock();
+	NKern::ThreadLeaveCS();
+	return KErrNone;
+	}
+
 
 TInt DDataPagedMemoryManager::InstallPagingDevice(DPagingDevice* aDevice)
 	{
@@ -664,9 +805,11 @@
 
 	// Now we can determine the size of the swap, create the swap manager.
 	iSwapManager = new DSwapManager;
-	__NK_ASSERT_ALWAYS(iSwapManager);
+	if (!iSwapManager)
+		return KErrNoMemory;
 
-	TInt r = iSwapManager->Create(iDevice);
+	// Create swap manager object
+	TInt r = iSwapManager->Create(aDevice);
 	if (r != KErrNone)
 		{// Couldn't create the swap manager.
 		delete iSwapManager;
@@ -674,6 +817,25 @@
 		NKern::SafeSwap(NULL, (TAny*&)iDevice);
 		return r;
 		}
+
+	// Enable physical access where supported
+	SetUsePhysicalAccess(PhysicalAccessSupported());
+	
+	// Determine swap alignment and number of pages to clean at once from device's preferred write
+	// size, if set
+	TRACE(("WDP: Preferred write shift is %d", iDevice->iPreferredWriteShift));
+	r = SetWriteSize(PreferredWriteSize());
+	if (r != KErrNone)
+		{
+		delete iSwapManager;
+		iSwapManager = NULL;
+		NKern::SafeSwap(NULL, (TAny*&)iDevice);
+		return r;
+		}
+
+	// Set swap alignment
+	iSwapManager->SetSwapAlign(PreferredSwapAlignment());
+	
  	NKern::LockedSetClear(K::MemModelAttributes, 0, EMemModelAttrDataPaging);
 
 	return r;
@@ -746,10 +908,15 @@
 	{
 	__NK_ASSERT_DEBUG(aRequest->CheckUseContiguous(aMemory,aIndex,aCount));
 
+	// todo: Possible to read using physical addresses here, but not sure it's worth it because it's
+	// not much saving and we may need to map the page anyway if it's blank to clear it
+	// 
+	// todo: Could move clearing pages up to here maybe?
+
 	// Map pages temporarily so that we can copy into them.
 	const TLinAddr linAddr = aRequest->MapPages(aIndex, aCount, aPages);
 
-	TInt r = iSwapManager->ReadSwapPages(aMemory, aIndex, aCount, linAddr, aRequest, aPages);
+	TInt r = iSwapManager->ReadSwapPages(aMemory, aIndex, aCount, linAddr, aPages);
 
 	// The memory object allows executable mappings then need IMB.
 	aRequest->UnmapPages(aMemory->IsExecutable());
@@ -760,13 +927,28 @@
 
 TInt DDataPagedMemoryManager::WritePages(DMemoryObject** aMemory, TUint* aIndex, TPhysAddr* aPages, TUint aCount, DPageWriteRequest* aRequest, TBool aAnyExecutable, TBool aBackground)
 	{
-	// Map pages temporarily so that we can copy into them.
-	const TLinAddr linAddr = aRequest->MapPages(aIndex[0], aCount, aPages);
+	// Note: this method used to do an IMB for executable pages (like ReadPages) but it was thought
+	// that this was uncessessary and so was removed
+
+	TLinAddr linAddr = 0;
 
-	TInt r = iSwapManager->WriteSwapPages(aMemory, aIndex, aCount, linAddr, aBackground);
+	if (iUsePhysicalAccess)
+		{
+		// must maps pages to perform cache maintenance but can map each page individually
+		for (TUint i = 0 ; i < aCount ; ++i)
+			{
+			TLinAddr addr = aRequest->MapPages(aIndex[i], 1, &aPages[i]);
+			Cache::SyncMemoryBeforeDmaWrite(addr, KPageSize);
+			aRequest->UnmapPages(EFalse);
+			}
+		}
+	else
+		linAddr = aRequest->MapPages(aIndex[0], aCount, aPages);
+	
+	TInt r = iSwapManager->WriteSwapPages(aMemory, aIndex, aCount, linAddr, aPages, aBackground);
 
-	// The memory object allows executable mappings then need IMB.
-	aRequest->UnmapPages(aAnyExecutable);
+	if (linAddr != 0)
+		aRequest->UnmapPages(EFalse);
 
 	return r;
 	}
@@ -774,6 +956,8 @@
 
 void DDataPagedMemoryManager::CleanPages(TUint aPageCount, SPageInfo** aPageInfos, TBool aBackground)
 	{
+	TRACE(("DDataPagedMemoryManager::CleanPages %d", aPageCount));
+	
 	__NK_ASSERT_DEBUG(PageCleaningLock::IsHeld());
 	__NK_ASSERT_DEBUG(MmuLock::IsHeld());
 	__NK_ASSERT_DEBUG(aPageCount <= (TUint)KMaxPagesToClean);
@@ -783,7 +967,7 @@
 	TUint index[KMaxPagesToClean];
 	TPhysAddr physAddr[KMaxPagesToClean];
 	TBool anyExecutable = EFalse;
-	
+
 	for (i = 0 ; i < aPageCount ; ++i)
 		{
 		SPageInfo* pi = aPageInfos[i];
@@ -819,7 +1003,8 @@
 		{
 		SPageInfo* pi = aPageInfos[i];
 		// check if page is clean...
-		if(pi->CheckModified(&memory[0]) || pi->IsWritable())
+		if(pi->CheckModified(&memory[0]) ||
+		   pi->IsWritable())
 			{
 			// someone else modified the page, or it became writable, so mark as not cleaned
 			aPageInfos[i] = NULL;
@@ -866,4 +1051,34 @@
 	{
 	return ((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->SetSwapThresholds(aThresholds);
 	}
-  
+
+
+TBool GetPhysicalAccessSupported()
+	{
+	return ((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->PhysicalAccessSupported();
+	}
+
+
+TBool GetUsePhysicalAccess()
+	{
+	return ((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->UsePhysicalAccess();
+	}
+
+
+void SetUsePhysicalAccess(TBool aUsePhysicalAccess)
+	{
+	((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->SetUsePhysicalAccess(aUsePhysicalAccess);
+	}
+
+
+TUint GetPreferredDataWriteSize()
+	{
+	return ((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->PreferredWriteSize();
+	}
+
+
+TInt SetDataWriteSize(TUint aWriteShift)
+	{
+	return	((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->SetWriteSize(aWriteShift);
+	}
+