/*
* 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 DataFrameMemMngr class.
*
*/
/*
* %version: 18 %
*/
#include "WlLddWlanLddConfig.h"
#include "DataFrameMemMngr.h"
#include "osachunk.h"
#include <kernel.h>
#include <kern_priv.h>
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt DataFrameMemMngr::DoOpenHandle(
DThread& aThread,
TSharedChunkInfo& aSharedChunkInfo,
DChunk* aSharedMemoryChunk )
{
TInt ret ( KErrGeneral );
if ( aSharedMemoryChunk )
{
// Need to be in critical section while creating handles
NKern::ThreadEnterCS();
// Make handle to shared memory chunk for client thread
TInt r = Kern::MakeHandleAndOpen( &aThread, aSharedMemoryChunk );
// Leave critical section
NKern::ThreadLeaveCS();
// r: positive value is a handle, negative value is an error code
if( r >= 0 )
{
// mapping success
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: Handle create & open ok: handle: %d"),
r ) );
// store the handle & chunk size
aSharedChunkInfo.iChunkHandle = r;
aSharedChunkInfo.iSize = aSharedMemoryChunk->Size();
iClientChunkHandle = r;
// store the kernel addresses
TLinAddr start_of_mem_linear( 0 );
aSharedMemoryChunk->Address( 0, aSharedChunkInfo.iSize, start_of_mem_linear );
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: chunk kernel mode start addr: 0x%08x"),
start_of_mem_linear ) );
TUint8* start_of_mem = reinterpret_cast<TUint8*>(start_of_mem_linear );
const TUint KRxDataChunkSize(
aSharedChunkInfo.iSize
- ( sizeof( TDataBuffer )
+ KMgmtSideTxBufferLength
+ KProtocolStackSideTxDataChunkSize
+ sizeof( RFrameXferBlock )
+ sizeof( RFrameXferBlockProtocolStack ) ) );
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: KRxDataChunkSize: %d"),
KRxDataChunkSize ) );
iRxDataChunk = start_of_mem;
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: iRxDataChunk start addr: 0x%08x"),
reinterpret_cast<TUint32>(iRxDataChunk) ) );
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: iRxDataChunk end addr: 0x%08x"),
reinterpret_cast<TUint32>(iRxDataChunk + KRxDataChunkSize) ) );
iTxDataChunk =
start_of_mem
+ KRxDataChunkSize
+ sizeof( TDataBuffer )
+ KMgmtSideTxBufferLength;
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: iTxDataChunk start addr: 0x%08x"),
reinterpret_cast<TUint32>(iTxDataChunk) ) );
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: iTxDataChunk end addr: 0x%08x"),
reinterpret_cast<TUint32>(
iTxDataChunk + KProtocolStackSideTxDataChunkSize) ) );
// create the Tx frame memory pool manager to manage the Tx Data
// chunk
iTxFrameMemoryPool = new WlanChunk(
iTxDataChunk,
iTxDataChunk + KProtocolStackSideTxDataChunkSize,
iTxFrameBufAllocationUnit );
if ( iTxFrameMemoryPool && iTxFrameMemoryPool->IsValid() )
{
TraceDump(MEMORY, (("WLANLDD: new WlanChunk: 0x%08x"),
reinterpret_cast<TUint32>(iTxFrameMemoryPool)));
iFrameXferBlock = reinterpret_cast<RFrameXferBlock*>(
start_of_mem
+ KRxDataChunkSize
+ sizeof( TDataBuffer )
+ KMgmtSideTxBufferLength
+ KProtocolStackSideTxDataChunkSize
+ sizeof( RFrameXferBlock ) );
iFrameXferBlockProtoStack =
static_cast<RFrameXferBlockProtocolStack*>(iFrameXferBlock);
TraceDump( INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::DoOpenHandle: Nif RFrameXferBlock addr: 0x%08x"),
reinterpret_cast<TUint32>(iFrameXferBlockProtoStack) ) );
// initiliase xfer block
iFrameXferBlockProtoStack->Initialise();
iRxBufAlignmentPadding = iParent.RxBufAlignmentPadding();
ret = KErrNone;
}
else
{
// create failed
delete iTxFrameMemoryPool;
iTxFrameMemoryPool = NULL;
// error is returned
}
}
else
{
// handle creation & open failed. Error is returned
TraceDump( INIT_LEVEL | ERROR_LEVEL,
(("WLANLDD: DataFrameMemMngr::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: DataFrameMemMngr::OnInitialiseMemory: Error aSharedMemoryChunk is NULL") );
}
return ret;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void DataFrameMemMngr::DoFreeRxBuffers()
{
for ( TUint i = 0; i < iCountCompleted; ++i )
{
TDataBuffer* metaHdr ( reinterpret_cast<TDataBuffer*>(
iRxDataChunk + iCompletedBuffers[i]) );
// first free the actual Rx frame buffer if relevant
if ( metaHdr->KeFlags() & TDataBuffer::KDontReleaseBuffer )
{
// this buffer shall not be freed yet, so no action here
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::DoFreeRxBuffers: don't free yet Rx buf at addr: 0x%08x"),
reinterpret_cast<TUint32>(metaHdr->KeGetBufferStart()) ) );
}
else
{
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::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: DataFrameMemMngr::DoFreeRxBuffers: free Rx meta header at addr: 0x%08x"),
reinterpret_cast<TUint32>(metaHdr)) );
iRxFrameMemoryPool->Free( metaHdr );
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TBool DataFrameMemMngr::DoEthernetFrameRxComplete(
const TDataBuffer*& aBufferStart,
TUint32 aNumOfBuffers )
{
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::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: DataFrameMemMngr::DoEthernetFrameRxComplete: supplied Rx buf addr: 0x%08x"),
iCompletedBuffers[i]) );
iCompletedBuffers[i]
-= reinterpret_cast<TUint32>(iRxDataChunk);
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::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: DataFrameMemMngr::DoEthernetFrameRxComplete: supplied Rx buf addr: 0x%08x"),
iTobeCompletedBuffers[iCountTobeCompleted + i]) );
iTobeCompletedBuffers[iCountTobeCompleted + i]
-= reinterpret_cast<TUint32>(iRxDataChunk);
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::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: DataFrameMemMngr::DoEthernetFrameRxComplete: supplied Rx buf addr: 0x%08x"),
iTobeCompletedBuffers[iCountTobeCompleted + i]) );
iTobeCompletedBuffers[iCountTobeCompleted + i]
-= reinterpret_cast<TUint32>(iRxDataChunk);
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::DoEthernetFrameRxComplete: Rx buf offset addr: 0x%08x"),
iTobeCompletedBuffers[iCountTobeCompleted + i]) );
}
iCountTobeCompleted += aNumOfBuffers;
}
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::DoEthernetFrameRxComplete: end: iCountCompleted: %d"),
iCountCompleted) );
TraceDump( RX_FRAME,
(("WLANLDD: DataFrameMemMngr::DoEthernetFrameRxComplete: end: iCountTobeCompleted: %d"),
iCountTobeCompleted) );
return ret;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TUint32* DataFrameMemMngr::DoGetTobeCompletedBuffersStart()
{
return iTobeCompletedBuffers;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TUint32* DataFrameMemMngr::DoGetCompletedBuffersStart()
{
return iCompletedBuffers;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TDataBuffer* DataFrameMemMngr::AllocTxBuffer( TUint aLength )
{
TraceDump( NWSA_TX_DETAILS,
(("WLANLDD: DataFrameMemMngr::AllocTxBuffer: aLength: %d"),
aLength) );
TDataBuffer* metaHdr ( NULL );
if ( ( !IsMemInUse() ) || ( aLength > KMaxEthernetFrameLength ) )
{
#ifndef NDEBUG
TraceDump( NWSA_TX_DETAILS,
("WLANLDD: DataFrameMemMngr::AllocTxBuffer: WARNING: either "
"memory not in use OR max size exceeded. Req. denied") );
os_assert(
(TUint8*)("WLANLDD: panic"),
(TUint8*)(WLAN_FILE),
__LINE__ );
#endif
return metaHdr;
}
const TUint bufLen ( Align4(
iVendorTxHdrLen +
KHtQoSMacHeaderLength +
KMaxDot11SecurityEncapsulationLength +
sizeof( SSnapHeader ) +
aLength +
KSpaceForAlignment +
iVendorTxTrailerLen ) );
TUint8* buf = reinterpret_cast<TUint8*>(
iTxFrameMemoryPool->Alloc( bufLen, EFalse ));
if ( buf )
{
TraceDump( NWSA_TX_DETAILS,
(("WLANLDD: DataFrameMemMngr::AllocTxBuffer: tx buf kern addr: 0x%08x"),
reinterpret_cast<TUint32>(buf) ) );
metaHdr = iFrameXferBlockProtoStack->AllocTxBuffer(
buf,
static_cast<TUint16>(aLength) );
if ( !metaHdr )
{
iTxFrameMemoryPool->Free( buf );
}
}
return metaHdr;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void DataFrameMemMngr::FreeTxPacket( TDataBuffer*& aPacket )
{
if ( IsMemInUse() )
{
// free the actual Tx buffer
iTxFrameMemoryPool->Free( aPacket->KeGetBufferStart() );
// free the meta header
iFrameXferBlockProtoStack->FreeTxPacket( aPacket );
}
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void DataFrameMemMngr::OnReleaseMemory( DThread& aThread )
{
TraceDump(INIT_LEVEL, ("WLANLDD: DataFrameMemMngr::OnReleaseMemory"));
if ( iTxFrameMemoryPool )
{
TraceDump(MEMORY, (("WLANLDD: delete WlanChunk: 0x%08x"),
reinterpret_cast<TUint32>(iTxFrameMemoryPool)));
delete iTxFrameMemoryPool;
iTxFrameMemoryPool = NULL;
iTxDataChunk = NULL;
MarkMemFree();
}
if ( iClientChunkHandle >= 0 )
{
TraceDump(INIT_LEVEL,
(("WLANLDD: DataFrameMemMngr::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;
}
}