/*
* Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Implementation of the MgmtFrameMemMngr class.
*
*/
/*
* %version: 20 %
*/
#include "WlLddWlanLddConfig.h"
#include "MgmtFrameMemMngr.h"
#include "osachunk.h"
#include <kern_priv.h>
extern TAny* os_alloc( const TUint32 );
extern void os_free( const TAny* );
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt MgmtFrameMemMngr::DoAllocate( DChunk*& aSharedMemoryChunk )
{
TraceDump( INIT_LEVEL,
("WLANLDD: MgmtFrameMemMngr::DoAllocate:") );
// determine if cached memory shall be used
TUint cacheOption = iUseCachedMemory ?
EMapAttrCachedMax :
EMapAttrFullyBlocking;
// Start creating the chunk
TChunkCreateInfo info;
info.iType = TChunkCreateInfo::ESharedKernelMultiple;
info.iMaxSize = iChunkSize;
info.iMapAttr = EMapAttrReadUser |
EMapAttrWriteUser |
EMapAttrShared |
cacheOption;
info.iOwnsMemory = ETrue;
info.iDestroyedDfc = NULL;
DChunk* chunk;
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoAllocate: create chunk of size: %d"),
iChunkSize) );
TUint32 chunkMapAttrNotNeeded ( 0 );
// Enter critical section so we can't die and leak the object we are
// creating, i.e. DChunk (shared memory chunk)
NKern::ThreadEnterCS();
TInt r = Kern::ChunkCreate(
info,
chunk,
iChunkKernelAddr,
chunkMapAttrNotNeeded );
if( r != KErrNone)
{
TraceDump( WARNING_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoAllocate: create chunk failed. Status: %d"),
r ) );
NKern::ThreadLeaveCS();
return r;
}
TraceDump(MEMORY, (("WLANLDD: new DChunk: 0x%08x"),
reinterpret_cast<TUint32>(chunk)));
TraceDump(INIT_LEVEL,
(("MgmtFrameMemMngr::DoAllocate: Platform Hw Chunk create success with cacheOption: 0x%08x"),
cacheOption));
TUint32 physicalAddressNotNeeded ( 0 );
// Map our device's memory into the chunk (at offset 0)
r = Kern::ChunkCommitContiguous(
chunk,
0,
iChunkSize,
physicalAddressNotNeeded );
if ( r != KErrNone)
{
TraceDump( WARNING_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoAllocate: chunk commit failed. Status: %d"),
r ) );
// Commit failed so tidy-up.
// Close chunk, which will then get deleted at some point
Kern::ChunkClose( chunk );
}
else
{
TraceDump( INIT_LEVEL,
("WLANLDD: MgmtFrameMemMngr::DoAllocate: chunk commit success") );
// Commit succeeded so pass back the chunk pointer
aSharedMemoryChunk = chunk;
}
// Can leave critical section now that we have saved pointer to created object
NKern::ThreadLeaveCS();
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoAllocate: chunk map attr: %d"),
chunkMapAttrNotNeeded ) );
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoAllocate: iChunkKernelAddr: 0x%08x"),
static_cast<TUint32>(iChunkKernelAddr) ) );
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoAllocate: chunk physical address: 0x%08x"),
physicalAddressNotNeeded ) );
return r;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt MgmtFrameMemMngr::DoOpenHandle(
DThread& aThread,
TSharedChunkInfo& aSharedChunkInfo,
DChunk* aSharedMemoryChunk )
{
TInt ret ( KErrGeneral );
if ( aSharedMemoryChunk )
{
// Need to be in critical section while creating handles
NKern::ThreadEnterCS();
// Create handle to shared memory chunk for client thread
TInt r = Kern::MakeHandleAndOpen( &aThread, aSharedMemoryChunk );
// Leave critical section
NKern::ThreadLeaveCS();
// positive r value is a handle, negative value is an error code
if( r >= 0 )
{
// mapping success
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::OnInitialiseMemory: Handle create & open ok: handle: %d"),
r ) );
// store the handle & the chunk size
aSharedChunkInfo.iChunkHandle = r;
aSharedChunkInfo.iSize = iChunkSize;
iClientChunkHandle = r;
// store the kernel addresses
TUint8* start_of_mem = reinterpret_cast<TUint8*>(iChunkKernelAddr );
const TUint KRxDataChunkSize(
iChunkSize
- ( sizeof( TDataBuffer )
+ KMgmtSideTxBufferLength
+ KProtocolStackSideTxDataChunkSize
+ sizeof( RFrameXferBlock )
+ sizeof( RFrameXferBlockProtocolStack ) ) );
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoOpenHandle: KRxDataChunkSize: %d"),
KRxDataChunkSize ) );
iRxDataChunk = start_of_mem;
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoOpenHandle: iRxDataChunk start addr: 0x%08x"),
reinterpret_cast<TUint32>(iRxDataChunk) ) );
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoOpenHandle: iRxDataChunk end addr: 0x%08x"),
reinterpret_cast<TUint32>(iRxDataChunk + KRxDataChunkSize) ) );
// create the Rx frame memory pool manager
iRxFrameMemoryPool = new WlanChunk(
iRxDataChunk,
iRxDataChunk + KRxDataChunkSize,
iRxFrameBufAllocationUnit );
if ( iRxFrameMemoryPool && iRxFrameMemoryPool->IsValid() )
{
ret = KErrNone;
TraceDump(MEMORY, (("WLANLDD: new WlanChunk: 0x%08x"),
reinterpret_cast<TUint32>(iRxFrameMemoryPool)));
iTxDataBuffer = reinterpret_cast<TDataBuffer*>(
start_of_mem
+ KRxDataChunkSize );
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoOpenHandle: Engine TxDataBuf start addr: 0x%08x"),
reinterpret_cast<TUint32>(iTxDataBuffer) ) );
// for the single Tx buffer the actual buffer memory immediately
// follows the Tx frame meta header
iTxDataBuffer->KeSetBufferOffset( sizeof( TDataBuffer ) );
iFrameXferBlock = reinterpret_cast<RFrameXferBlock*>(
start_of_mem
+ KRxDataChunkSize
+ sizeof( TDataBuffer )
+ KMgmtSideTxBufferLength
+ KProtocolStackSideTxDataChunkSize );
TraceDump( INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::DoOpenHandle: Engine RFrameXferBlock addr: 0x%08x"),
reinterpret_cast<TUint32>(iFrameXferBlock) ) );
// initiliase xfer block
iFrameXferBlock->Initialize( KMgmtSideTxBufferLength );
iRxBufAlignmentPadding = RxBufAlignmentPadding();
iParent.SetRxBufAlignmentPadding( iRxBufAlignmentPadding );
}
else
{
// create failed
delete iRxFrameMemoryPool;
iRxFrameMemoryPool = NULL;
// error is returned
}
}
else
{
// handle creation & open failed. Error is returned
TraceDump( INIT_LEVEL | ERROR_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::OnInitialiseMemory: Handle create & open error: %d"),
r ) );
}
}
else
{
// at this point the shared memory chunk should always exist. However,
// as it doesn't exist in this case, we return an error
TraceDump( INIT_LEVEL | ERROR_LEVEL,
("WLANLDD: MgmtFrameMemMngr::OnInitialiseMemory: Error aSharedMemoryChunk is NULL") );
}
return ret;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TUint8* MgmtFrameMemMngr::DoGetNextFreeRxBuffer( TUint aLengthinBytes )
{
TraceDump( RX_FRAME,
("WLANLDD: MgmtFrameMemMngr::DoGetNextFreeRxBuffer") );
// if there are any Rx buffers which have been handled and
// can already be re-used, free them first
const TUint32* rxHandledBuffersArray ( NULL );
TUint32 numOfHandled ( 0 );
iFrameXferBlock->KeGetHandledRxBuffers(
rxHandledBuffersArray,
numOfHandled );
if ( numOfHandled )
{
// there are buffers which can be freed, so free them
for ( TUint i = 0; i < numOfHandled; ++i )
{
// first free the actual Rx frame buffer
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoGetNextFreeRxBuffer: free Rx buf at addr: 0x%08x"),
reinterpret_cast<TUint32>(reinterpret_cast<TDataBuffer*>(
iRxDataChunk
+ rxHandledBuffersArray[i])->KeGetBufferStart()) ) );
iRxFrameMemoryPool->Free(
reinterpret_cast<TDataBuffer*>(
iRxDataChunk + rxHandledBuffersArray[i])->KeGetBufferStart()
// take into account the alignment padding
- iRxBufAlignmentPadding );
// then free the Rx frame meta header
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoGetNextFreeRxBuffer: free Rx meta header at addr: 0x%08x"),
reinterpret_cast<TUint32>( iRxDataChunk + rxHandledBuffersArray[i])) );
iRxFrameMemoryPool->Free( iRxDataChunk + rxHandledBuffersArray[i] );
}
// remove the buffers we freed above from the completed buffers of this
// object so that they are not tried to be freed again once the Mgmt
// Client issues the next Rx request
iCountCompleted -= numOfHandled;
assign(
iCompletedBuffers + numOfHandled,
iCompletedBuffers,
iCountCompleted );
}
// reserve a new Rx buffer.
TUint8* buffer ( NULL );
if ( iRxFrameMemoryPool )
{
buffer = reinterpret_cast<TUint8*>(iRxFrameMemoryPool->Alloc(
aLengthinBytes
+ iRxBufAlignmentPadding,
EFalse ) ); // no need to zero stamp the buffer content
if ( buffer )
{
// allocation succeeded
// the alignment padding is before the Rx buffer
buffer += iRxBufAlignmentPadding;
TraceDump(RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoGetNextFreeRxBuffer: addr of allocated Rx buf: 0x%08x"),
reinterpret_cast<TUint32>(buffer)) );
}
else
{
TraceDump(RX_FRAME | WARNING_LEVEL,
("WLANLDD: MgmtFrameMemMngr::DoGetNextFreeRxBuffer: WARNING: not enough free memory => failed"));
}
}
else
{
TraceDump(RX_FRAME | WARNING_LEVEL,
("WLANLDD: MgmtFrameMemMngr::DoGetNextFreeRxBuffer: WARNING: no Rx mem pool mgr => failed"));
}
return buffer;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TBool MgmtFrameMemMngr::DoEthernetFrameRxComplete(
const TDataBuffer*& aBufferStart,
TUint32 aNumOfBuffers )
{
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: aNumOfBuffers: %d"),
aNumOfBuffers) );
if ( aNumOfBuffers + iCountTobeCompleted > KMaxToBeCompletedRxBufs )
{
// too little space reserved for Rx buffer handles
os_assert( (TUint8*)("WLANLDD: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
}
TBool ret( EFalse );
if ( iReadStatus == EPending )
{
// read pending
if ( !iCountTobeCompleted )
{
// no existing Rx buffers to complete in queue
// we may complete these ones on the fly
// note the completed Rx buffers first so that we can change
// their addresses to offsets
assign(
reinterpret_cast<TUint32*>(&aBufferStart),
iCompletedBuffers,
aNumOfBuffers );
// update the new Rx buffer start addresses added above to be
// offsets from the Rx memory pool beginning
for( TUint i = 0; i < aNumOfBuffers; ++i )
{
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: supplied Rx buf addr: 0x%08x"),
iCompletedBuffers[i]) );
iCompletedBuffers[i]
-= reinterpret_cast<TUint32>(iRxDataChunk);
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: Rx buf offset addr: 0x%08x"),
iCompletedBuffers[i]) );
}
iCountCompleted = aNumOfBuffers;
iFrameXferBlock->KeRxComplete( iCompletedBuffers, iCountCompleted);
}
else
{
// existing rx buffers to complete in queue.
// We must append these at the rear and after that
// complete the existing read request
assign(
reinterpret_cast<TUint32*>(&aBufferStart),
iTobeCompletedBuffers + iCountTobeCompleted,
aNumOfBuffers );
// update the new Rx buffer start addresses added above to be
// offsets from the Rx memory pool beginning
for( TUint i = 0; i < aNumOfBuffers; ++i )
{
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: supplied Rx buf addr: 0x%08x"),
iTobeCompletedBuffers[iCountTobeCompleted + i]) );
iTobeCompletedBuffers[iCountTobeCompleted + i]
-= reinterpret_cast<TUint32>(iRxDataChunk);
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: Rx buf offset addr: 0x%08x"),
iTobeCompletedBuffers[iCountTobeCompleted + i]) );
}
iCountCompleted = iCountTobeCompleted + aNumOfBuffers;
iFrameXferBlock->KeRxComplete(
iTobeCompletedBuffers,
iCountCompleted );
// note the completed Rx buffers
assign( iTobeCompletedBuffers, iCompletedBuffers, iCountCompleted );
iCountTobeCompleted = 0;
}
ret = ETrue;
}
else
{
// no read pending
// append at the rear
assign(
reinterpret_cast<TUint32*>(&aBufferStart),
iTobeCompletedBuffers + iCountTobeCompleted,
aNumOfBuffers );
// update the new Rx buffer start addresses added above to be
// offsets from the Rx memory pool beginning
for( TUint i = 0; i < aNumOfBuffers; ++i )
{
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: supplied Rx buf addr: 0x%08x"),
iTobeCompletedBuffers[iCountTobeCompleted + i]) );
iTobeCompletedBuffers[iCountTobeCompleted + i]
-= reinterpret_cast<TUint32>(iRxDataChunk);
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: Rx buf offset addr: 0x%08x"),
iTobeCompletedBuffers[iCountTobeCompleted + i]) );
}
iCountTobeCompleted += aNumOfBuffers;
}
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: end: iCountCompleted: %d"),
iCountCompleted) );
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoEthernetFrameRxComplete: end: iCountTobeCompleted: %d"),
iCountTobeCompleted) );
return ret;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TUint32* MgmtFrameMemMngr::DoGetTobeCompletedBuffersStart()
{
return iTobeCompletedBuffers;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TUint32* MgmtFrameMemMngr::DoGetCompletedBuffersStart()
{
return iCompletedBuffers;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void MgmtFrameMemMngr::DoFreeRxBuffers()
{
if ( IsMemInUse() )
{
for ( TUint i = 0; i < iCountCompleted; ++i )
{
TDataBuffer* metaHdr ( reinterpret_cast<TDataBuffer*>(
iRxDataChunk + iCompletedBuffers[i]) );
// first free the actual Rx frame buffer
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoFreeRxBuffers: free Rx buf at addr: 0x%08x"),
reinterpret_cast<TUint32>(metaHdr->KeGetBufferStart()) ) );
iRxFrameMemoryPool->Free(
metaHdr->KeGetBufferStart()
// take into account the alignment padding
- iRxBufAlignmentPadding );
// free the Rx frame meta header
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoFreeRxBuffers: free Rx meta header at addr: 0x%08x"),
reinterpret_cast<TUint32>(metaHdr)) );
iRxFrameMemoryPool->Free( metaHdr );
}
}
else
{
// the whole Rx memory pool has already been deallocated, so nothing
// is done in this case
TraceDump( RX_FRAME,
("WLANLDD: MgmtFrameMemMngr::DoFreeRxBuffers: Rx memory pool already deallocated; no action needed") );
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void MgmtFrameMemMngr::DoMarkRxBufFree( TUint8* aBufferToFree )
{
TraceDump( RX_FRAME,
(("WLANLDD: MgmtFrameMemMngr::DoMarkRxBufFree: free Rx buf at addr: 0x%08x"),
reinterpret_cast<TUint32>(aBufferToFree) ) );
if ( IsMemInUse() )
{
iRxFrameMemoryPool->Free(
aBufferToFree
// take into account the alignment padding
- iRxBufAlignmentPadding );
}
else
{
// the whole Rx memory pool - including aBufferToFree - has already
// been deallocated, so nothing is done in this case
TraceDump( RX_FRAME,
("WLANLDD: MgmtFrameMemMngr::DoMarkRxBufFree: Rx memory pool already deallocated; no action needed") );
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt MgmtFrameMemMngr::RxBufAlignmentPadding() const
{
const TInt KMemMgrHdrLen = iRxFrameMemoryPool->HeaderSize();
const TInt KRemainder ( KMemMgrHdrLen % iRxFrameBufAllocationUnit );
TInt padding = KRemainder ?
( iRxFrameBufAllocationUnit - KRemainder ) : KRemainder;
TraceDump(INIT_LEVEL, (("WLANLDD: MgmtFrameMemMngr::RxBufAlignmentPadding: %d"),
padding));
return padding;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void MgmtFrameMemMngr::OnReleaseMemory( DThread& aThread )
{
TraceDump(INIT_LEVEL, ("WLANLDD: MgmtFrameMemMngr::OnReleaseMemory"));
if ( iRxFrameMemoryPool )
{
TraceDump(MEMORY, (("WLANLDD: delete WlanChunk: 0x%08x"),
reinterpret_cast<TUint32>(iRxFrameMemoryPool)));
delete iRxFrameMemoryPool;
iRxFrameMemoryPool = NULL;
}
if ( iParent.SharedMemoryChunk() )
{
TraceDump(MEMORY, (("WLANLDD: delete DChunk: 0x%08x"),
reinterpret_cast<TUint32>(iParent.SharedMemoryChunk())));
if ( iClientChunkHandle >= 0 )
{
TraceDump(INIT_LEVEL,
(("WLANLDD: MgmtFrameMemMngr::OnReleaseMemory: close shared "
"chunk handle: %d"),
iClientChunkHandle));
// We have a valid client handle to the shared chunk, so close it
Kern::CloseHandle( &aThread, iClientChunkHandle );
iClientChunkHandle = -1;
}
// schedule the shared memory chunk for destruction
Kern::ChunkClose( iParent.SharedMemoryChunk() );
iParent.SharedMemoryChunk() = NULL;
MarkMemFree();
}
}