blob: c11fa6d98cc785aaf0531f05fbee60dc4a373901 [file] [log] [blame]
/*
* Copyright (c) 2012-2016 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include <wlan_qct_sys.h>
#include <cds_api.h>
#include <sir_types.h> /* needed for tSirRetStatus */
#include <sir_params.h> /* needed for tSirMbMsg */
#include <sir_api.h> /* needed for SIR_... message types */
#include <wni_api.h> /* needed for WNI_... message types */
#include "ani_global.h"
#include "wma_types.h"
#include "sme_api.h"
#include "mac_init_api.h"
#include "qdf_trace.h"
/* SYS stop timeout 30 seconds */
#define SYS_STOP_TIMEOUT (30000)
static qdf_event_t g_stop_evt;
/**
* sys_build_message_header() - to build the sys message header
* @sysMsgId: message id
* @pMsg: pointer to message context
*
* This API is used to build the sys message header.
*
* Return: QDF_STATUS
*/
QDF_STATUS sys_build_message_header(SYS_MSG_ID sysMsgId, cds_msg_t *pMsg)
{
pMsg->type = sysMsgId;
pMsg->reserved = SYS_MSG_COOKIE;
return QDF_STATUS_SUCCESS;
}
/**
* sys_stop_complete_cb() - a callback when system stop completes
* @pUserData: pointer to user provided data context
*
* this callback is used once system stop is completed.
*
* Return: none
*/
#ifdef QDF_ENABLE_TRACING
static void sys_stop_complete_cb(void *pUserData)
{
qdf_event_t *pStopEvt = (qdf_event_t *) pUserData;
QDF_STATUS qdf_status = qdf_event_set(pStopEvt);
QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
}
#else
static void sys_stop_complete_cb(void *pUserData)
{
return;
}
#endif
/**
* sys_stop() - To post stop message to system module
* @p_cds_context: pointer to cds context
*
* This API is used post a stop message to system module
*
* Return: QDF_STATUS
*/
QDF_STATUS sys_stop(v_CONTEXT_t p_cds_context)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
cds_msg_t sysMsg;
/* Initialize the stop event */
qdf_status = qdf_event_create(&g_stop_evt);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
return qdf_status;
/* post a message to SYS module in MC to stop SME and MAC */
sys_build_message_header(SYS_MSG_ID_MC_STOP, &sysMsg);
/* Save the user callback and user data */
sysMsg.callback = sys_stop_complete_cb;
sysMsg.bodyptr = (void *)&g_stop_evt;
/* post the message.. */
qdf_status = cds_mq_post_message(CDS_MQ_ID_SYS, &sysMsg);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_status = QDF_STATUS_E_BADMSG;
qdf_status = qdf_wait_single_event(&g_stop_evt, SYS_STOP_TIMEOUT);
QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
qdf_status = qdf_event_destroy(&g_stop_evt);
QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
return qdf_status;
}
/**
* sys_mc_process_msg() - to process system mc thread messages
* @p_cds_context: pointer to cds context
* @pMsg: message pointer
*
* This API is used to process the message
*
* Return: QDF_STATUS
*/
QDF_STATUS sys_mc_process_msg(v_CONTEXT_t p_cds_context, cds_msg_t *pMsg)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpAniSirGlobal mac_ctx;
void *hHal;
if (NULL == pMsg) {
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"%s: NULL pointer to cds_msg_t", __func__);
QDF_ASSERT(0);
return QDF_STATUS_E_INVAL;
}
/*
* All 'new' SYS messages are identified by a cookie in the reserved
* field of the message as well as the message type. This prevents
* the possibility of overlap in the message types defined for new
* SYS messages with the 'legacy' message types. The legacy messages
* will not have this cookie in the reserved field
*/
if (SYS_MSG_COOKIE == pMsg->reserved) {
/* Process all the new SYS messages.. */
switch (pMsg->type) {
case SYS_MSG_ID_MC_START:
/*
* Handling for this message is not needed now so adding
* debug print and QDF_ASSERT
*/
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"Rx SYS_MSG_ID_MC_START msgType= %d [0x%08x]",
pMsg->type, pMsg->type);
QDF_ASSERT(0);
break;
case SYS_MSG_ID_MC_STOP:
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO,
"Processing SYS MC STOP");
/* get the HAL context... */
hHal = cds_get_context(QDF_MODULE_ID_PE);
if (NULL == hHal) {
QDF_TRACE(QDF_MODULE_ID_SYS,
QDF_TRACE_LEVEL_ERROR,
"%s: Invalid hHal", __func__);
} else {
qdf_status = sme_stop(hHal,
HAL_STOP_TYPE_SYS_DEEP_SLEEP);
QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
qdf_status = mac_stop(hHal,
HAL_STOP_TYPE_SYS_DEEP_SLEEP);
QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
((sysResponseCback) pMsg->callback)(
(void *)pMsg->bodyptr);
qdf_status = QDF_STATUS_SUCCESS;
}
break;
case SYS_MSG_ID_MC_THR_PROBE:
/*
* Process MC thread probe. Just callback to the
* function that is in the message.
*/
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"Rx SYS_MSG_ID_MC_THR_PROBE msgType=%d[0x%08x]",
pMsg->type, pMsg->type);
break;
case SYS_MSG_ID_FTM_RSP:
hHal = cds_get_context(QDF_MODULE_ID_PE);
if (NULL == hHal) {
QDF_TRACE(QDF_MODULE_ID_SYS,
QDF_TRACE_LEVEL_ERROR,
FL("Invalid hal"));
qdf_mem_free(pMsg->bodyptr);
break;
}
mac_ctx = PMAC_STRUCT(hHal);
if (NULL == mac_ctx) {
QDF_TRACE(QDF_MODULE_ID_SYS,
QDF_TRACE_LEVEL_ERROR,
FL("Invalid mac context"));
qdf_mem_free(pMsg->bodyptr);
break;
}
if (NULL == mac_ctx->ftm_msg_processor_callback) {
QDF_TRACE(QDF_MODULE_ID_SYS,
QDF_TRACE_LEVEL_ERROR,
FL("callback pointer is NULL"));
qdf_mem_free(pMsg->bodyptr);
break;
}
mac_ctx->ftm_msg_processor_callback(
(void *)pMsg->bodyptr);
qdf_mem_free(pMsg->bodyptr);
break;
default:
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"Unknown message type msgType= %d [0x%08x]",
pMsg->type, pMsg->type);
break;
}
} else {
QDF_TRACE(QDF_MODULE_ID_SYS,
QDF_TRACE_LEVEL_ERROR,
"Rx SYS unknown MC msgtype= %d [0x%08X]",
pMsg->type, pMsg->type);
QDF_ASSERT(0);
qdf_status = QDF_STATUS_E_BADMSG;
if (pMsg->bodyptr)
qdf_mem_free(pMsg->bodyptr);
}
return qdf_status;
}
#ifdef NAPIER_CODE
QDF_STATUS sys_mc_process_handler(struct scheduler_msg *msg)
{
void *cds_ctx = cds_get_global_context();
if (cds_ctx == NULL) {
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"CDS context is NULL");
return QDF_STATUS_E_FAILURE;
}
return sys_mc_process_msg(cds_ctx, (cds_msg_t *)msg);
}
#endif
/**
* sys_process_mmh_msg() - this api to process mmh message
* @pMac: pointer to mac context
* @pMsg: pointer to message
*
* This API is used to process mmh message
*
* Return: none
*/
void sys_process_mmh_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg)
{
CDS_MQ_ID targetMQ = CDS_MQ_ID_SYS;
/*
* The body of this pMsg is a tSirMbMsg
* Contrary to previous generation, we cannot free it here!
* It is up to the callee to free it
*/
if (NULL == pMsg) {
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"NULL Message Pointer");
QDF_ASSERT(0);
return;
}
switch (pMsg->type) {
/*
* Following messages are routed to SYS
*/
case WNI_CFG_DNLD_REQ:
case WNI_CFG_DNLD_CNF:
/* Forward this message to the SYS module */
targetMQ = CDS_MQ_ID_SYS;
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"Handling for the Message ID %d is removed in SYS",
pMsg->type);
QDF_ASSERT(0);
break;
/*
* Following messages are routed to HAL
*/
case WNI_CFG_DNLD_RSP:
/* Forward this message to the HAL module */
targetMQ = CDS_MQ_ID_WMA;
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"Handling for the Message ID %d is removed as no HAL",
pMsg->type);
QDF_ASSERT(0);
break;
case WNI_CFG_GET_REQ:
case WNI_CFG_SET_REQ:
case WNI_CFG_SET_REQ_NO_RSP:
case eWNI_SME_SYS_READY_IND:
/* Forward this message to the PE module */
targetMQ = CDS_MQ_ID_PE;
break;
case WNI_CFG_GET_RSP:
case WNI_CFG_SET_CNF:
/* Forward this message to the SME module */
targetMQ = CDS_MQ_ID_SME;
break;
default:
if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN)
&& (pMsg->type <= eWNI_SME_MSG_TYPES_END)) {
targetMQ = CDS_MQ_ID_SME;
break;
}
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
"Message of ID %d is not yet handled by SYS",
pMsg->type);
QDF_ASSERT(0);
}
/*
* Post now the message to the appropriate module for handling
*/
if (QDF_STATUS_SUCCESS != cds_mq_post_message(targetMQ,
(cds_msg_t *) pMsg)) {
/*
* Caller doesn't allocate memory for the pMsg.
* It allocate memory for bodyptr free the mem and return
*/
if (pMsg->bodyptr)
qdf_mem_free(pMsg->bodyptr);
}
}
/**
* wlan_sys_probe() - API to post MC thread probe
*
* This API will be used send probe message
*
* Return: none
*/
void wlan_sys_probe(void)
{
cds_msg_t cds_message;
cds_message.reserved = SYS_MSG_COOKIE;
cds_message.type = SYS_MSG_ID_MC_THR_PROBE;
cds_message.bodyptr = NULL;
cds_mq_post_message(CDS_MQ_ID_SYS, &cds_message);
}