blob: 0c10de9d00056a9df802c94d44953975ec51cf8b [file] [log] [blame]
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "palTypes.h"
#include "wniApi.h" /* WNI_CFG_SET_REQ */
#include "sirParams.h" /* tSirMbMsg */
#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
#include "halHddApis.h" /* palAllocateMemory */
#endif
#include "smsDebug.h" /* smsLog */
#include "cfgApi.h"
#include "ccmApi.h"
#include "logDump.h"
//#define CCM_DEBUG
#undef CCM_DEBUG
#define CCM_DEBUG2
//#undef CCM_DEBUG2
#define CFGOBJ_ALIGNTO 4
#define CFGOBJ_ALIGN(len) ( ((len)+CFGOBJ_ALIGNTO-1) & ~(CFGOBJ_ALIGNTO-1) )
#define CFGOBJ_ID_SIZE 4 /* 4 bytes for cfgId */
#define CFGOBJ_LEN_SIZE 4 /* 4 bytes for length */
#define CFGOBJ_INTEGER_VALUE_SIZE 4 /* 4 bytes for integer value */
#define CFG_UPDATE_MAGIC_DWORD 0xabab
#define halHandle2HddHandle(hHal) ( (NULL == (hHal)) ? 0 : ((tpAniSirGlobal)(hHal))->hHdd )
static void ccmComplete(tHddHandle hHdd, void *done)
{
if (done)
{
(void)palSemaphoreGive(hHdd, done);
}
}
static void ccmWaitForCompletion(tHddHandle hHdd, void *done)
{
if (done)
{
(void)palSemaphoreTake(hHdd, done);
}
}
static tANI_U32 * encodeCfgReq(tHddHandle hHdd, tANI_U32 *pl, tANI_U32 cfgId, tANI_S32 length, void *pBuf, tANI_U32 value, tANI_U32 type)
{
*pl++ = pal_cpu_to_be32(cfgId) ;
*pl++ = pal_cpu_to_be32(length) ;
if (type == CCM_INTEGER_TYPE)
{
*pl++ = pal_cpu_to_be32(value) ;
}
else
{
palCopyMemory(hHdd, (void *)pl, (void *)pBuf, length);
pl += (CFGOBJ_ALIGN(length) / CFGOBJ_ALIGNTO);
}
return pl ;
}
/*
* CCM_STRING_TYPE CCM_INTEGER_TYPE
* |<-------- 4 ----->| |<-------- 4 ----->|
* +----------+ <-- msg --> +----------+
* |type | |type |
* +----------+ +----------+
* |msgLen=24 | |msgLen=16 |
* +----------+----------+ +----------+----------+
* | cfgId | | cfgId |
* +---------------------+ +---------------------+
* | length=11 | | length=4 |
* +---------------------+ +---------------------+
* | | | value |
* | | +---------------------+
* | |
* | +----+
* | |////| <- padding to 4-byte boundary
* +----------------+----+
*/
static eHalStatus sendCfg(tpAniSirGlobal pMac, tHddHandle hHdd, tCfgReq *req, tANI_BOOLEAN fRsp)
{
tSirMbMsg *msg;
eHalStatus status;
tANI_S16 msgLen = (tANI_U16)(4 + /* 4 bytes for msg header */
CFGOBJ_ID_SIZE +
CFGOBJ_LEN_SIZE +
CFGOBJ_ALIGN(req->length)) ;
status = palAllocateMemory(hHdd, (void **)&msg, msgLen);
if (status == eHAL_STATUS_SUCCESS)
{
if( fRsp )
{
msg->type = pal_cpu_to_be16(WNI_CFG_SET_REQ);
}
else
{
msg->type = pal_cpu_to_be16(WNI_CFG_SET_REQ_NO_RSP);
}
msg->msgLen = pal_cpu_to_be16(msgLen);
(void)encodeCfgReq(hHdd, msg->data, req->cfgId, req->length, req->ccmPtr, req->ccmValue, req->type) ;
status = palSendMBMessage(hHdd, msg) ;
if (status != eHAL_STATUS_SUCCESS)
{
smsLog( pMac, LOGW, FL("palSendMBMessage() failed\n"));
//No need to free msg. palSendMBMessage frees it.
status = eHAL_STATUS_FAILURE ;
}
}
else
{
smsLog( pMac, LOGW, FL("palAllocateMemory(len=%d)\n"), msgLen );
}
return status ;
}
static tCfgReq * allocateCfgReq(tHddHandle hHdd, tANI_U32 type, tANI_S32 length)
{
tCfgReq *req ;
tANI_S32 alloc_len = sizeof(tCfgReq) ;
if (type == CCM_STRING_TYPE)
{
alloc_len += length ;
}
if (palAllocateMemory(hHdd, (void **)&req, alloc_len) != eHAL_STATUS_SUCCESS)
{
return NULL ;
}
req->ccmPtr = (req+1);
return req ;
}
static void freeCfgReq(tHddHandle hHdd, tCfgReq *req)
{
palFreeMemory(hHdd, (void*)req) ;
}
static void add_req_tail(tCfgReq *req, struct ccmlink *q)
{
if (q->tail)
{
q->tail->next = req;
q->tail = req ;
}
else
{
q->head = q->tail = req ;
}
}
static void del_req(tCfgReq *req, struct ccmlink *q)
{
q->head = req->next ;
req->next = NULL ;
if (q->head == NULL)
{
q->tail = NULL ;
}
}
static void purgeReqQ(tHalHandle hHal)
{
tHddHandle hHdd = halHandle2HddHandle(hHal);
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
tCfgReq *req, *tmp ;
for (req = pMac->ccm.reqQ.head; req; req = tmp)
{
/* loop thru reqQ and invoke callback to return failure */
smsLog(pMac, LOGW, FL("deleting cfgReq, cfgid=%d\n"), (int)req->cfgId);
tmp = req->next ;
if (req->callback)
{
req->callback(hHal, eHAL_STATUS_FAILURE);
}
palSpinLockTake(hHdd, pMac->ccm.lock);
del_req(req, &pMac->ccm.reqQ);
palSpinLockGive(hHdd, pMac->ccm.lock);
freeCfgReq(hHdd, req);
}
return ;
}
static void sendQueuedReqToMacSw(tpAniSirGlobal pMac, tHddHandle hHdd)
{
tCfgReq *req ;
/* Send the head req */
req = pMac->ccm.reqQ.head ;
if (req)
{
if (req->state == eCCM_REQ_QUEUED)
{
/* Send WNI_CFG_SET_REQ */
req->state = eCCM_REQ_SENT;
if (sendCfg(pMac, hHdd, req, eANI_BOOLEAN_TRUE) != eHAL_STATUS_SUCCESS)
{
smsLog( pMac, LOGW, FL("sendCfg() failed\n"));
palSpinLockTake(hHdd, pMac->ccm.lock);
del_req(req, &pMac->ccm.reqQ) ;
palSpinLockGive(hHdd, pMac->ccm.lock);
if (req->callback)
{
req->callback((tHalHandle)pMac, WNI_CFG_OTHER_ERROR) ;
}
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("ccmComplete(%p)\n"), req->done);
#endif
ccmComplete(hHdd, req->done);
freeCfgReq(hHdd, req);
}
}
else
{
smsLog( pMac, LOGW, FL("reqState is not eCCM_REQ_QUEUED, is %d\n"), req->state );
}
}
return ;
}
static eHalStatus cfgSetSub(tpAniSirGlobal pMac, tHddHandle hHdd, tANI_U32 cfgId, tANI_U32 type,
tANI_S32 length, void *ccmPtr, tANI_U32 ccmValue,
tCcmCfgSetCallback callback, eAniBoolean toBeSaved, void *sem, tCfgReq **r)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tCfgReq *req ;
do
{
*r = NULL ;
if (pMac->ccm.state == eCCM_STOPPED)
{
status = eHAL_STATUS_FAILURE ;
break ;
}
req = allocateCfgReq(hHdd, type, length);
if (req == NULL)
{
status = eHAL_STATUS_FAILED_ALLOC ;
break ;
}
req->next = NULL ;
req->cfgId = (tANI_U16)cfgId ;
req->type = (tANI_U8)type ;
req->state = eCCM_REQ_QUEUED ;
req->toBeSaved = !!toBeSaved ;
req->length = length ;
req->done = sem ;
req->callback = callback ;
if (type == CCM_INTEGER_TYPE)
{
req->ccmValue = ccmValue ;
}
else
{
palCopyMemory(hHdd, (void*)req->ccmPtr, (void*)ccmPtr, length);
}
palSpinLockTake(hHdd, pMac->ccm.lock);
add_req_tail(req, &pMac->ccm.reqQ);
/* If this is the first req on the queue, send it to MAC SW */
if ((pMac->ccm.replay.started == 0) && (pMac->ccm.reqQ.head == req))
{
/* Send WNI_CFG_SET_REQ */
req->state = eCCM_REQ_SENT;
palSpinLockGive(hHdd, pMac->ccm.lock);
status = sendCfg(pMac, hHdd, req, eANI_BOOLEAN_TRUE) ;
if (status != eHAL_STATUS_SUCCESS)
{
smsLog( pMac, LOGW, FL("sendCfg() failed\n"));
palSpinLockTake(hHdd, pMac->ccm.lock);
del_req(req, &pMac->ccm.reqQ);
palSpinLockGive(hHdd, pMac->ccm.lock);
freeCfgReq(hHdd, req);
break ;
}
else
{
palSpinLockTake(hHdd, pMac->ccm.lock);
if(req != pMac->ccm.reqQ.head)
{
//We send the request and it must be done already
req = NULL;
}
palSpinLockGive(hHdd, pMac->ccm.lock);
}
}
else
{
palSpinLockGive(hHdd, pMac->ccm.lock);
}
*r = req ;
} while(0) ;
return status;
}
static eHalStatus cfgSet(tHalHandle hHal, tANI_U32 cfgId, tANI_U32 type, tANI_S32 length, void * ccmPtr, tANI_U32 ccmValue, tCcmCfgSetCallback callback, eAniBoolean toBeSaved)
{
tHddHandle hHdd = halHandle2HddHandle(hHal);
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
eHalStatus status;
tCfgReq *req ;
if (pal_in_interrupt())
{
#ifdef CCM_DEBUG2
smsLog(pMac, LOG1, FL("WNI_CFG_%s (%d 0x%x), in_interrupt()=TRUE"), gCfgParamName[cfgId], (int)cfgId, (int)cfgId);
#endif
status = cfgSetSub(pMac, hHdd, cfgId, type, length, ccmPtr, ccmValue, callback, toBeSaved, NULL, &req);
}
else
{
void *sem ;
#ifdef CCM_DEBUG2
smsLog(pMac, LOG1, FL("WNI_CFG_%s (%d 0x%x), in_interrupt()=FALSE"), gCfgParamName[cfgId], (int)cfgId, (int)cfgId);
#endif
pal_local_bh_disable() ;
status = palMutexAllocLocked( hHdd, &sem ) ;
if (status != eHAL_STATUS_SUCCESS)
{
smsLog(pMac, LOGE, FL("mutex alloc failed\n"));
sem = NULL;
}
else
{
status = cfgSetSub(pMac, hHdd, cfgId, type, length, ccmPtr, ccmValue, callback, toBeSaved, sem, &req);
if ((status != eHAL_STATUS_SUCCESS) || (req == NULL))
{
//Either it fails to send or the req is finished already
palSemaphoreFree( hHdd, sem );
sem = NULL;
}
}
pal_local_bh_enable() ;
if ((status == eHAL_STATUS_SUCCESS) && (sem != NULL))
{
#ifdef CCM_DEBUG
smsLog(pMac, LOG1, FL("ccmWaitForCompletion(%p)"), req->done);
#endif
ccmWaitForCompletion(hHdd, sem);
#ifdef CCM_DEBUG
smsLog(pMac, LOG1, FL("free(%p)"), req->done);
#endif
palSemaphoreFree( hHdd, sem ) ;
}
}
return status ;
}
eHalStatus ccmOpen(tHalHandle hHal)
{
tHddHandle hHdd = halHandle2HddHandle(hHal);
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
(void)palZeroMemory(hHdd, &pMac->ccm, sizeof(tCcm)) ;
return palSpinLockAlloc(hHdd, &pMac->ccm.lock);
}
eHalStatus ccmClose(tHalHandle hHal)
{
tHddHandle hHdd = halHandle2HddHandle(hHal);
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
tANI_U32 i ;
tCfgReq *req ;
ccmStop(hHal);
/* Go thru comp[] to free all saved requests */
for (i = 0 ; i < CFG_PARAM_MAX_NUM ; ++i)
{
if ((req = pMac->ccm.comp[i]) != NULL)
{
freeCfgReq(hHdd, req);
}
}
return palSpinLockFree(hHdd, pMac->ccm.lock);
}
/* This function executes in (Linux) softirq context */
void ccmCfgCnfMsgHandler(tHalHandle hHal, void *m)
{
tHddHandle hHdd = halHandle2HddHandle(hHal);
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
tSirMbMsg *msg = (tSirMbMsg *)m ;
tANI_U32 result, cfgId ;
tCfgReq *req, *old ;
#if 0
if (pMac->ccm.state != eCCM_STARTED)
{
return ;
}
#endif
result = pal_be32_to_cpu(msg->data[0]);
cfgId = pal_be32_to_cpu(msg->data[1]);
if (pMac->ccm.replay.started && cfgId == CFG_UPDATE_MAGIC_DWORD)
{
pMac->ccm.replay.in_progress = 1 ;
return ;
}
if (pMac->ccm.replay.in_progress)
{
/* save error code */
if (!CCM_IS_RESULT_SUCCESS(result))
{
pMac->ccm.replay.result = result ;
}
if (--pMac->ccm.replay.nr_param == 0)
{
pMac->ccm.replay.in_progress = 0 ;
if (pMac->ccm.replay.callback)
{
pMac->ccm.replay.callback(hHal, pMac->ccm.replay.result);
}
pMac->ccm.replay.started = 0 ;
/* Wake up the sleeping process */
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("ccmComplete(%p)\n"), pMac->ccm.replay.done);
#endif
ccmComplete(hHdd, pMac->ccm.replay.done);
//Let go with the rest of the set CFGs waiting.
sendQueuedReqToMacSw(pMac, hHdd);
}
}
else
{
/*
* Try to match this response with the request.
* What if i could not find the req entry ???
*/
req = pMac->ccm.reqQ.head ;
if (req)
{
if (req->cfgId == cfgId && req->state == eCCM_REQ_SENT)
{
palSpinLockTake(hHdd, pMac->ccm.lock);
del_req(req, &pMac->ccm.reqQ);
palSpinLockGive(hHdd, pMac->ccm.lock);
req->state = eCCM_REQ_DONE ;
if (result == WNI_CFG_NEED_RESTART ||
result == WNI_CFG_NEED_RELOAD)
{
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("need restart/reload, cfgId=%d\n"), req->cfgId) ;
#endif
//purgeReqQ(hHal);
}
/* invoke callback */
if (req->callback)
{
#ifdef CCM_DEBUG
req->callback(hHal, cfgId) ;
#else
req->callback(hHal, result) ;
#endif
}
/* Wake up the sleeping process */
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("cfgId=%ld, calling ccmComplete(%p)\n"), cfgId, req->done);
#endif
ccmComplete(hHdd, req->done);
/* move the completed req from reqQ to comp[] */
if (req->toBeSaved && (CCM_IS_RESULT_SUCCESS(result)))
{
if ((old = pMac->ccm.comp[cfgId]) != NULL)
{
freeCfgReq(hHdd, old) ;
}
pMac->ccm.comp[cfgId] = req ;
}
else
{
freeCfgReq(hHdd, req) ;
}
sendQueuedReqToMacSw(pMac, hHdd);
}
else
{
smsLog( pMac, LOGW, FL("can not match RSP with REQ, rspcfgid=%d result=%d reqcfgid=%d reqstate=%d\n"),
(int)cfgId, (int)result, req->cfgId, req->state);
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("ccmComplete(%p)\n"), req->done);
#endif
}
}
}
return ;
}
void ccmStart(tHalHandle hHal)
{
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
pMac->ccm.state = eCCM_STARTED ;
#if defined(ANI_LOGDUMP)
ccmDumpInit(hHal);
#endif //#if defined(ANI_LOGDUMP)
return ;
}
void ccmStop(tHalHandle hHal)
{
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
pMac->ccm.state = eCCM_STOPPED ;
pal_local_bh_disable() ;
purgeReqQ(hHal);
pal_local_bh_enable() ;
return ;
}
eHalStatus ccmCfgSetInt(tHalHandle hHal, tANI_U32 cfgId, tANI_U32 ccmValue, tCcmCfgSetCallback callback, eAniBoolean toBeSaved)
{
if( callback || toBeSaved)
{
//we need to sychronous this one
return cfgSet(hHal, cfgId, CCM_INTEGER_TYPE, sizeof(tANI_U32), NULL, ccmValue, callback, toBeSaved);
}
else
{
//Simply push to CFG and not waiting for the response
tCfgReq req;
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
req.callback = NULL;
req.next = NULL;
req.cfgId = ( tANI_U16 )cfgId;
req.length = sizeof( tANI_U32 );
req.type = CCM_INTEGER_TYPE;
req.ccmPtr = NULL;
req.ccmValue = ccmValue;
req.toBeSaved = toBeSaved;
req.state = eCCM_REQ_SENT;
return ( sendCfg( pMac, pMac->hHdd, &req, eANI_BOOLEAN_FALSE ) );
}
}
eHalStatus ccmCfgSetStr(tHalHandle hHal, tANI_U32 cfgId, tANI_U8 *pStr, tANI_U32 length, tCcmCfgSetCallback callback, eAniBoolean toBeSaved)
{
if( callback || toBeSaved )
{
//we need to sychronous this one
return cfgSet(hHal, cfgId, CCM_STRING_TYPE, length, pStr, 0, callback, toBeSaved);
}
else
{
//Simply push to CFG and not waiting for the response
tCfgReq req;
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
req.callback = NULL;
req.next = NULL;
req.cfgId = ( tANI_U16 )cfgId;
req.length = length;
req.type = CCM_STRING_TYPE;
req.ccmPtr = pStr;
req.ccmValue = 0;
req.toBeSaved = toBeSaved;
req.state = eCCM_REQ_SENT;
return ( sendCfg( pMac, pMac->hHdd, &req, eANI_BOOLEAN_FALSE ) );
}
}
eHalStatus ccmCfgGetInt(tHalHandle hHal, tANI_U32 cfgId, tANI_U32 *pValue)
{
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
eHalStatus status = eHAL_STATUS_SUCCESS ;
tCfgReq *req = pMac->ccm.comp[cfgId] ;
if (req && req->state == eCCM_REQ_DONE)
{
*pValue = req->ccmValue ;
}
else
{
if (wlan_cfgGetInt(pMac, (tANI_U16)cfgId, pValue) != eSIR_SUCCESS)
status = eHAL_STATUS_FAILURE;
}
return status ;
}
eHalStatus ccmCfgGetStr(tHalHandle hHal, tANI_U32 cfgId, tANI_U8 *pBuf, tANI_U32 *pLength)
{
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
tHddHandle hHdd = halHandle2HddHandle(hHal);
eHalStatus status = eHAL_STATUS_SUCCESS ;
tCfgReq *req = pMac->ccm.comp[cfgId] ;
if (req && req->state == eCCM_REQ_DONE && (tANI_U32)req->length <= *pLength)
{
*pLength = req->length ;
palCopyMemory(hHdd, (void*)pBuf, (void*)req->ccmPtr, req->length);
}
else
{
if (wlan_cfgGetStr(pMac, (tANI_U16)cfgId, pBuf, pLength) != eSIR_SUCCESS)
status = eHAL_STATUS_FAILURE;
}
return status ;
}
/*
* Loop thru comp[] and form an ANI message which contains all completed cfgIds.
* The message begins with an INTEGER parameter (cfgId=CFG_UPDATE_MAGIC_DWORD)
* to mark the start of the message.
*/
static eHalStatus cfgUpdate(tpAniSirGlobal pMac, tHddHandle hHdd, tCcmCfgSetCallback callback)
{
tANI_U32 i, *pl ;
tCfgReq *req ;
tSirMbMsg *msg ;
eHalStatus status ;
tANI_S16 msgLen = 4 + /* 4 bytes for msg header */
/* for CFG_UPDATE_MAGIC_DWORD */
CFGOBJ_ID_SIZE +
CFGOBJ_LEN_SIZE +
CFGOBJ_INTEGER_VALUE_SIZE ;
if (pMac->ccm.state == eCCM_STOPPED || pMac->ccm.replay.started)
{
status = eHAL_STATUS_FAILURE ;
goto end ;
}
palSpinLockTake(hHdd, pMac->ccm.lock);
pMac->ccm.replay.started = 1 ;
pMac->ccm.replay.nr_param = 0 ;
palSpinLockGive(hHdd, pMac->ccm.lock);
/* Calculate message length */
for (i = 0 ; i < CFG_PARAM_MAX_NUM ; ++i)
{
if ((req = pMac->ccm.comp[i]) != NULL)
{
msgLen += (tANI_S16)(CFGOBJ_ID_SIZE + CFGOBJ_LEN_SIZE + CFGOBJ_ALIGN(req->length)) ;
pMac->ccm.replay.nr_param += 1 ;
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("cfgId=%d\n"), req->cfgId);
#endif
}
}
if (pMac->ccm.replay.nr_param == 0)
{
if (callback)
{
callback((tHalHandle)pMac, WNI_CFG_SUCCESS) ;
}
status = eHAL_STATUS_SUCCESS ;
goto end ;
}
pMac->ccm.replay.in_progress = 0 ;
pMac->ccm.replay.result = WNI_CFG_SUCCESS ;
pMac->ccm.replay.callback = callback ;
pMac->ccm.replay.done = NULL ;
status = palAllocateMemory(hHdd, (void **)&msg, msgLen) ;
if (status != eHAL_STATUS_SUCCESS)
{
pMac->ccm.replay.started = 0 ;
goto end ;
}
msg->type = pal_cpu_to_be16(WNI_CFG_SET_REQ);
msg->msgLen = pal_cpu_to_be16(msgLen);
/* Encode the starting cfgId */
pl = encodeCfgReq(hHdd, msg->data, CFG_UPDATE_MAGIC_DWORD, 4, NULL, 0, CCM_INTEGER_TYPE) ;
/* Encode the saved cfg requests */
for (i = 0 ; i < CFG_PARAM_MAX_NUM ; ++i)
{
if ((req = pMac->ccm.comp[i]) != NULL)
{
pl = encodeCfgReq(hHdd, pl, req->cfgId, req->length, req->ccmPtr, req->ccmValue, req->type) ;
}
}
status = palSendMBMessage(hHdd, msg) ;
if (status != eHAL_STATUS_SUCCESS)
{
smsLog(pMac, LOGW, FL("palSendMBMessage() failed. status=%d\n"), status);
pMac->ccm.replay.started = 0 ;
//No need to free msg. palSendMBMessage frees it.
goto end ;
}
end:
return status ;
}
eHalStatus ccmCfgUpdate(tHalHandle hHal, tCcmCfgSetCallback callback)
{
tHddHandle hHdd = halHandle2HddHandle(hHal);
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
eHalStatus status ;
pal_local_bh_disable() ;
status = cfgUpdate(pMac, hHdd, callback) ;
if (status == eHAL_STATUS_SUCCESS)
{
if (pMac->ccm.replay.nr_param == 0)
{
/* there is nothing saved at comp[], so we are done! */
pMac->ccm.replay.started = 0 ;
}
else
{
/* we have sent update message to MAC SW */
void *sem ;
status = palMutexAllocLocked( hHdd, &sem ) ;
if (status != eHAL_STATUS_SUCCESS)
{
smsLog(pMac, LOGE, FL("mutex alloc failed\n"));
pMac->ccm.replay.started = 0 ;
}
else
{
pMac->ccm.replay.done = sem ;
}
}
}
pal_local_bh_enable() ;
/* Waiting here ... */
if (status == eHAL_STATUS_SUCCESS && pMac->ccm.replay.done)
{
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("ccmWaitForCompletion(%p)\n"), pMac->ccm.replay.done);
#endif
ccmWaitForCompletion(hHdd, pMac->ccm.replay.done);
#ifdef CCM_DEBUG
smsLog(pMac, LOGW, FL("free(%p)\n"), pMac->ccm.replay.done);
#endif
palSemaphoreFree( hHdd, pMac->ccm.replay.done) ;
}
return status ;
}
#if 0
///////////////////////////////////////////////////////////////////
#include <linux/netdevice.h>
#include <linux/delay.h>
extern struct net_device * hdd_dev[];
typedef struct pal_netdev_priv_s
{
// pointer to the PCI device structure for this device
struct pci_dev *pci_dev;
// TAURUS has three BAR registers
// BAR0 is a fixed window for the PIF registers
volatile void *win0_addr;
tANI_U32 win0_size;
// BAR1 is a movable window for all other registers
volatile void *win1_addr;
tANI_U32 win1_size;
tANI_U32 win1_current;
// BAR2 is a movable window for all other memory
volatile void *win2_addr;
tANI_U32 win2_size;
tANI_U32 win2_current;
} pal_netdev_priv_t;
typedef struct hdd_stats_s {
/* Stats on the MAC SW messages sent to applications */
ulong stats_mac_rx_mbx_tot_cnt;
ulong stats_mac_rx_mbx_success_cnt;
ulong stats_mac_rx_mbx_drop_cnt;
/* Stats on messages sent to the MAC SW messages from applications */
ulong stats_mac_tx_mbx_tot_cnt;
ulong stats_mac_tx_mbx_success_cnt;
ulong stats_mac_tx_mbx_drop_cnt;
} hdd_stats_t;
/* HDD Driver Private Data structure */
typedef struct hdd_netdev_priv_s
{
tANI_U32 magic_head;
// chipset-specific private data
pal_netdev_priv_t ANI_CHIPSET;
tHalHandle halHandle;
#ifdef ANI_BUS_TYPE_PCI
struct pci_dev *pci_dev;
struct pci_device_id * pPciDevId;
#endif // ANI_BUS_TYPE_PCI
// Queued EAPOL frame destination.
tANI_U32 eapol_pid;
unsigned int num_xmit;
/*
* Various frequently used variables that pertain to this
* instance of the driver
*/
tANI_U32 rx_buf_sz; /* Based on MTU+extra headroom needed.*/
tANI_U32 td_enqueue_nested;
/*
* Flag set by MAC SW to indicate a TD ring is desired
*/
int td_flush;
int selectiveFlush;
spinlock_t lock;
/* Stats */
struct net_device_stats stats;
int curr_acc_cat;
#ifdef LX5280
unsigned short rtl_pvid; //VLAN id this Interface belongs to
int rtl_extPortNum; //ext port used in RTL865x driver
int rtl_linkId[16];//link ID of each interface for RTL865x driver
int rtl_wdsActive;
#endif
tANI_U16 lport; /* switch logical port */
/* management and control */
tANI_U32 status;
tANI_U32 msg_enable;
tANI_U32 radio_id; /* Unit # of this device */
int ap_flag; /*
* indicates if the Radio is in AP
* or BP mode.
*/
/* NAPI Polling suport */
struct timer_list oom_timer; /* Out of memory timer. */
struct timer_list reset_req_timer;/*
* Timer started when a Reset
* request is sent to WSM. Cleared
* when a subsequent Radio Disable
* Request is received.
*/
struct tasklet_struct *rx_tasklet;
struct tasklet_struct *tx_tasklet;
tANI_U32 learn_mode_frame_cnt; /*
* Data Frames forwarded to MAC SW
* when Polaris is in learn mode
*/
tANI_U32 mgmt_ctl_frames; /* MGMT/CTL Frames forwarded to MAC SW */
tANI_U32 nir; /* total number of times the ISR has
* been invoked.*/
tANI_U32 stats_dummy_pkt_requeue_cnt;
tANI_U32 stats_rx_td_dummy_pkt_cnt;/* TD Dummy pkts that were after HIF loopback */
tANI_U32 stats_rx_tm_dummy_pkt_cnt;/* TM Dummy pkts that were after HIF loopback */
tANI_U32 stats_td_dummy_pkt_cnt; /* Dummy pkts that were succesfully
* put on the TD ring and that
* were picked up by the HIF
*/
tANI_U32 stats_mac_dummy_pkt_drop_cnt;/* Number of dummy pkts dropped by the HDD
* due to any reason
*/
tANI_U32 stats_wns_l2update_cnt;
tANI_U32 stats_app_hif_wr_pkt_cnt;
hdd_stats_t hdd_stats;
tANI_U32 stats_reset_req_timer_cnt; /*
* Number of times the
* Reset Req Timer expired
*/
#ifdef TCP_PROFILE
unsigned int pv_current_ip_proto;
unsigned int pv_current_ip_byte;
unsigned int pv_current_ack_seq;
unsigned int pv_current_seq;
unsigned int pv_rtt;
unsigned int pv_sent_seq;
unsigned int pv_p_ts;
unsigned int pv_tfpl_ts;
#endif
tANI_U32 stats_mac_reset_cnt; /* MAC SW Reset Requests */
tANI_U32 stats_mac_reset_eof_sof;
tANI_U32 stats_mac_reset_bmu;
tANI_U32 stats_mac_reset_pdu_low;
tANI_U32 stats_mac_reset_user;
tANI_U32 stats_mac_reset_wd_timeout;
tANI_U32 stats_mac_reset_unspecified;
tANI_U32 stats_wd_timeout_cnt;
tANI_U32 stats_radio_enable_cnt;
tANI_U32 stats_radio_disable_cnt;
#ifdef PLM_EXTRA_STATS
tANI_U32 stats_tx_xmit_refilled; /* Pkts xmit-filled */
tANI_U32 stats_tx_queue_stop;
tANI_U32 stats_tx_queue_start;
tANI_U32 stats_alloc_fail;
tANI_U32 stats_poll_starts;
tANI_U32 stats_poll_pkts;
tANI_U32 stats_poll_exit_done;
tANI_U32 stats_poll_exit_not_done;
tANI_U32 stats_poll_exit_oom;
tANI_U32 stats_poll_exit_done_rx_pending;
tANI_U32 stats_poll_zero_rx;
#ifdef CONFIG_PROC_FS
#ifdef ANI_USE_TASKLET
struct proc_dir_entry *proc_driver_dir; // for /proc/net/drivers
#endif
struct proc_dir_entry *proc_ent_dir; // for the directory itself
struct proc_dir_entry *proc_ent_stats;
struct proc_dir_entry *proc_ent_np_dump;
struct proc_dir_entry *proc_ent_ring;
char proc_fname_stats[32];
char proc_fname_np_dump[32];
char proc_fname_ring[32];
/* Setting Debug levels */
struct proc_dir_entry * proc_ent_dbg;
char proc_fname_dbg[32];
/* For bypass flags */
struct proc_dir_entry * proc_ent_bypass;
char proc_fname_bypass[32];
int sir_dump_cmd; // Dump SIR command
int sir_dump_arg1; // Dump SIR argument 1
int sir_dump_arg2; // Dump SIR argument 2
int sir_dump_arg3; // Dump SIR argument 3
int sir_dump_arg4; // Dump SIR argument 4
struct proc_dir_entry * proc_ent_sir_dump;
char proc_fname_sir_dump[32];
eHalStatus status ;
struct proc_dir_entry * proc_ent_eeprom_info;
char proc_fname_eeprom_info[32];
#endif /* ifdef CONFIG_PROC_FS */
tANI_U32 rx_small_skb_failure;
unsigned long open_time; /* jiffies for last open */
#endif /* PLM_EXTRA_STATS */
int mac_down;
tANI_U32 rx_mac_msg_cnt;
tANI_U32 tx_mac_msg_cnt;
int mbx_sent;
tANI_U32 bypass; // Used to various types of bypasses
// in the driver
/*
* this table is initialized once for all by poldrv and so is not in
* mac_param struct
*/
t_mac_block_table * mac_block_table;
struct sk_buff_head mac_list;
#if defined(ASICDXE_PROFILE) && defined(LX5280)
tANI_U32 num_of_reg_switches;
#endif
tANI_U32 magic_tail;
} hdd_netdev_priv_t;
static void ccm_callback(tHalHandle hHal, tANI_S32 cfgId)
{
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
smsLog(pMac, LOGW, FL("cfgId = %d\n"), cfgId);
}
static void ccm_callback2(tHalHandle hHal, tANI_S32 result)
{
tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
smsLog(pMac, LOGW, FL("result = %d\n"), result);
}
void ccm_test(void)
{
tHalHandle hHal ;
tpAniSirGlobal pMac;
eHalStatus status ;
struct net_device *dev;
hdd_netdev_priv_t *np;
char str[80] = {1} ;
dev = hdd_dev[0];
np = (hdd_netdev_priv_t *)dev->priv;
hHal = np->halHandle ;
pMac = PMAC_STRUCT( hHal );
smsLog(pMac, LOGW, "ccmStart()\n");
ccmStart(hHal) ;
status = ccmCfgUpdate(hHal, ccm_callback2) ;
smsLog(pMac, LOGW, "ccmCfgUpdate(): status=%d\n", status);
status = ccmCfgSetInt(hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, 100, ccm_callback, 1) ;
smsLog(pMac, LOGW, "ccmCfgSetInt(WNI_CFG_FRAGMENTATION_THRESHOLD = %d): status=%d\n",
WNI_CFG_FRAGMENTATION_THRESHOLD, status);
status = ccmCfgSetInt(hHal, WNI_CFG_RTS_THRESHOLD, 100, ccm_callback, 1) ;
smsLog(pMac, LOGW, "ccmCfgSetInt(WNI_CFG_RTS_THRESHOLD = %d): status=%d\n",
WNI_CFG_RTS_THRESHOLD, status);
/* this cfgid causes reload */
status = ccmCfgSetInt(hHal, WNI_CFG_MIMO_ENABLED, 1, ccm_callback, 1) ;
smsLog(pMac, LOGW, "ccmCfgSetInt(WNI_CFG_MIMO_ENABLED = %d): status=%d\n",
WNI_CFG_MIMO_ENABLED, status);
status = ccmCfgSetInt(hHal, WNI_CFG_SHORT_RETRY_LIMIT, 100, ccm_callback, 1) ;
smsLog(pMac, LOGW, "ccmCfgSetInt(WNI_CFG_SHORT_RETRY_LIMIT = %d): status=%d\n",
WNI_CFG_SHORT_RETRY_LIMIT, status);
status = ccmCfgSetInt(hHal, WNI_CFG_LONG_RETRY_LIMIT, 100, ccm_callback, 1) ;
smsLog(pMac, LOGW, "ccmCfgSetInt(WNI_CFG_LONG_RETRY_LIMIT = %d): status=%d\n",
WNI_CFG_LONG_RETRY_LIMIT, status);
/* this cfgid causes restart */
status = ccmCfgSetStr(hHal, WNI_CFG_EDCA_WME_ACVI, str, sizeof(str), ccm_callback, 1) ;
smsLog(pMac, LOGW, "ccmCfgSetStr(WNI_CFG_EDCA_WME_ACVI = %d): status=%d\n",
WNI_CFG_EDCA_WME_ACVI, status);
mdelay(100);
smsLog(pMac, LOGW, "ccmStop()\n");
ccmStop(hHal);
status = ccmCfgUpdate(hHal, ccm_callback2) ;
smsLog(pMac, LOGW, "ccmCfgUpdate(): status=%d\n", status);
smsLog(pMac, LOGW, "ccmStart()\n");
ccmStart(hHal) ;
status = ccmCfgUpdate(hHal, ccm_callback2) ;
smsLog(pMac, LOGW, "ccmCfgUpdate(): status=%d\n", status);
}
#endif