qcacld-3.0: Runtime PM handling for htc messages

Check runtime pm status while sending messages.
Update runtime pm when sending messages to hif.
Update runtime pm when messages are tx completed.

Change-Id: I27840f57ff87d6d27b1e3611e7fe1f2cd933ddd0
CRs-Fixed: 935300
This commit is contained in:
Houston Hoffman 2015-11-18 02:36:30 -08:00 • committed by Akash Patel
commit 1460fa326f
7 changed files with 226 additions and 22 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
* Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -504,6 +504,7 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
tx_desc->status = status;
netbuf = tx_desc->netbuf;
cdf_runtime_pm_put();
cdf_nbuf_trace_update(netbuf, trace_str);
/* Per SDU update of byte count */
byte_cnt += cdf_nbuf_len(netbuf);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -61,10 +61,19 @@ typedef struct _HTC_TX_PACKET_INFO {
A_UINT32 Flags; /* internal use */
} HTC_TX_PACKET_INFO;
#define HTC_TX_PACKET_TAG_ALL 0 /* a tag of zero is reserved and used to flush ALL packets */
#define HTC_TX_PACKET_TAG_INTERNAL 1 /* internal tags start here */
#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9) /* user-defined tags start here */
#define HTC_TX_PACKET_TAG_BUNDLED HTC_TX_PACKET_TAG_USER_DEFINED + 1 /* indicate this is bundled TX packet */
/**
* HTC_TX_PACKET_TAG_XXX - #defines for tagging packets for special handling
* HTC_TX_PACKET_TAG_ALL: zero is reserved and used to flush ALL packets
* HTC_TX_PACKET_TAG_INTERNAL: internal tags start here
* HTC_TX_PACKET_TAG_USER_DEFINED: user-defined tags start here
* HTC_TX_PACKET_TAG_BUNDLED: indicate this is a bundled tx packet
* HTC_TX_PACKET_TAG_AUTO_PM: indicate a power management wmi command
*/
#define HTC_TX_PACKET_TAG_ALL 0
#define HTC_TX_PACKET_TAG_INTERNAL 1
#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9)
#define HTC_TX_PACKET_TAG_BUNDLED (HTC_TX_PACKET_TAG_USER_DEFINED + 1)
#define HTC_TX_PACKET_TAG_AUTO_PM (HTC_TX_PACKET_TAG_USER_DEFINED + 2)
#define HTC_TX_PACKET_FLAG_FIXUP_NETBUF (1 << 0)

View file

@ -597,6 +597,60 @@ static A_STATUS htc_issue_packets(HTC_TARGET *target,
return status;
}
#ifdef FEATURE_RUNTIME_PM
/**
* extract_htc_pm_packtes(): move pm packets from endpoint into queue
* @endpoint: which enpoint to extract packets from
* @queue: a queue to store extracted packets in.
*
* remove pm packets from the endpoint's tx queue.
* queue them into a queue
*/
static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
HTC_PACKET_QUEUE *queue)
{
HTC_PACKET *packet;
/* only WMI endpoint has power management packets */
if (endpoint->service_id != WMI_CONTROL_SVC)
return;
ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet,
HTC_PACKET, ListLink) {
if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_AUTO_PM) {
HTC_PACKET_REMOVE(&endpoint->TxQueue, packet);
HTC_PACKET_ENQUEUE(queue, packet);
}
} ITERATE_END
}
/**
* queue_htc_pm_packets(): queue pm packets with priority
* @endpoint: enpoint to queue packets to
* @queue: queue of pm packets to enque
*
* suspend resume packets get special treatment & priority.
* need to queue them at the front of the queue.
*/
static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
HTC_PACKET_QUEUE *queue)
{
if (endpoint->service_id != WMI_CONTROL_SVC)
return;
HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&endpoint->TxQueue, queue);
}
#else
static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
HTC_PACKET_QUEUE *queue)
{}
static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
HTC_PACKET_QUEUE *queue)
{}
#endif
/* get HTC send packets from the TX queue on an endpoint, based on available credits */
void get_htc_send_packets_credit_based(HTC_TARGET *target,
HTC_ENDPOINT *pEndpoint,
@ -607,24 +661,43 @@ void get_htc_send_packets_credit_based(HTC_TARGET *target,
A_UINT8 sendFlags;
HTC_PACKET *pPacket;
unsigned int transferLength;
HTC_PACKET_QUEUE *tx_queue;
HTC_PACKET_QUEUE pm_queue;
bool do_pm_get = false;
/****** NOTE : the TX lock is held when this function is called *****************/
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+get_htc_send_packets_credit_based \n"));
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+get_htc_send_packets_credit_based\n"));
INIT_HTC_PACKET_QUEUE(&pm_queue);
extract_htc_pm_packets(pEndpoint, &pm_queue);
if (HTC_QUEUE_EMPTY(&pm_queue)) {
tx_queue = &pEndpoint->TxQueue;
do_pm_get = true;
} else {
tx_queue = &pm_queue;
}
/* loop until we can grab as many packets out of the queue as we can */
while (true) {
if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) {
/* bus suspended, runtime resume issued */
CDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0);
break;
}
sendFlags = 0;
/* get packet at head, but don't remove it */
pPacket = htc_get_pkt_at_head(&pEndpoint->TxQueue);
pPacket = htc_get_pkt_at_head(tx_queue);
if (pPacket == NULL) {
if (do_pm_get)
hif_pm_runtime_put(target->hif_dev);
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
(" Got head packet:%p , Queue Depth: %d\n",
pPacket,
HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
HTC_PACKET_QUEUE_DEPTH(tx_queue)));
transferLength = pPacket->ActualLength + HTC_HDR_LENGTH;
@ -676,6 +749,8 @@ void get_htc_send_packets_credit_based(HTC_TARGET *target,
pEndpoint->TxCredits,
creditsRequired));
#endif
if (do_pm_get)
hif_pm_runtime_put(target->hif_dev);
break;
}
@ -694,8 +769,7 @@ void get_htc_send_packets_credit_based(HTC_TARGET *target,
htc_credit_record(HTC_REQUEST_CREDIT,
pEndpoint->TxCredits,
HTC_PACKET_QUEUE_DEPTH
(&pEndpoint->
TxQueue));
(tx_queue));
UNLOCK_HTC_CREDIT(target);
}
@ -710,7 +784,7 @@ void get_htc_send_packets_credit_based(HTC_TARGET *target,
}
/* now we can fully dequeue */
pPacket = htc_packet_dequeue(&pEndpoint->TxQueue);
pPacket = htc_packet_dequeue(tx_queue);
if (pPacket) {
/* save the number of credits this packet consumed */
pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired;
@ -722,7 +796,11 @@ void get_htc_send_packets_credit_based(HTC_TARGET *target,
}
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets_credit_based \n"));
if (!HTC_QUEUE_EMPTY(&pm_queue))
queue_htc_pm_packets(pEndpoint, &pm_queue);
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
("-get_htc_send_packets_credit_based\n"));
}
@ -732,23 +810,43 @@ void get_htc_send_packets(HTC_TARGET *target,
{
HTC_PACKET *pPacket;
HTC_PACKET_QUEUE *tx_queue;
HTC_PACKET_QUEUE pm_queue;
bool do_pm_get;
/****** NOTE : the TX lock is held when this function is called *****************/
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
("+get_htc_send_packets %d resources\n", Resources));
INIT_HTC_PACKET_QUEUE(&pm_queue);
extract_htc_pm_packets(pEndpoint, &pm_queue);
if (HTC_QUEUE_EMPTY(&pm_queue)) {
tx_queue = &pEndpoint->TxQueue;
do_pm_get = true;
} else {
tx_queue = &pm_queue;
}
/* loop until we can grab as many packets out of the queue as we can */
while (Resources > 0) {
int num_frags;
pPacket = htc_packet_dequeue(&pEndpoint->TxQueue);
if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) {
/* bus suspended, runtime resume issued */
CDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0);
break;
}
pPacket = htc_packet_dequeue(tx_queue);
if (pPacket == NULL) {
if (do_pm_get)
hif_pm_runtime_put(target->hif_dev);
break;
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
(" Got packet:%p , New Queue Depth: %d\n",
pPacket,
HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
HTC_PACKET_QUEUE_DEPTH(tx_queue)));
/* For non-credit path the sequence number is already embedded
* in the constructed HTC header
*/
@ -779,7 +877,10 @@ void get_htc_send_packets(HTC_TARGET *target,
Resources -= num_frags;
}
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets \n"));
if (!HTC_QUEUE_EMPTY(&pm_queue))
queue_htc_pm_packets(pEndpoint, &pm_queue);
AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n"));
}
@ -991,9 +1092,14 @@ static HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target,
/* send what we can */
result = htc_issue_packets(target, pEndpoint, &sendQueue);
if (result) {
int i;
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
("htc_issue_packets, failed status:%d put it back to head of callersSendQueue",
result));
for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--)
hif_pm_runtime_put(target->hif_dev);
HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
&sendQueue);
LOCK_HTC_TX(target);
@ -1264,6 +1370,9 @@ A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, cdf_nbuf_t netbuf, int Epid,
}
}
if (hif_pm_runtime_get(target->hif_dev))
return A_ERROR;
pHtcHdr = (HTC_FRAME_HDR *) cdf_nbuf_get_frag_vaddr(netbuf, 0);
AR_DEBUG_ASSERT(pHtcHdr);
@ -1609,6 +1718,9 @@ CDF_STATUS htc_tx_completion_handler(void *Context,
netbuf = NULL;
break;
}
if (pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_AUTO_PM)
hif_pm_runtime_put(target->hif_dev);
if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) {
HTC_PACKET *pPacketTemp;
HTC_PACKET_QUEUE *pQueueSave =

View file

@ -3654,6 +3654,8 @@ CDF_STATUS wma_resume_req(tp_wma_handle wma, enum cdf_suspend_type type)
/* unpause the vdev if left paused and hif_pci_suspend fails */
wma_unpause_vdev(wma);
wmi_set_runtime_pm_inprogress(wma->wmi_handle, false);
return CDF_STATUS_SUCCESS;
}
@ -4172,6 +4174,9 @@ static void wma_notify_suspend_req_procesed(tp_wma_handle wma,
*/
CDF_STATUS wma_suspend_req(tp_wma_handle wma, enum cdf_suspend_type type)
{
if (type == CDF_RUNTIME_SUSPEND)
wmi_set_runtime_pm_inprogress(wma->wmi_handle, true);
if (wma_is_wow_applicable(wma)) {
WMA_LOGE("WOW Suspend");
wma_apply_lphb(wma);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -766,6 +766,30 @@ static inline void wma_log_cmd_id(WMI_CMD_ID cmd_id)
}
#endif
/**
* wmi_is_runtime_pm_cmd() - check if a cmd is part of the suspend resume sequence
* @cmd: command to check
*
* Return: true if the command is part of the suspend resume sequence.
*/
bool wmi_is_runtime_pm_cmd(WMI_CMD_ID cmd_id)
{
switch (cmd_id) {
case WMI_WOW_ENABLE_CMDID:
case WMI_PDEV_SUSPEND_CMDID:
case WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID:
case WMI_WOW_ADD_WAKE_PATTERN_CMDID:
case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID:
case WMI_PDEV_RESUME_CMDID:
case WMI_WOW_DEL_WAKE_PATTERN_CMDID:
case WMI_D0_WOW_ENABLE_DISABLE_CMDID:
return true;
default:
return false;
}
}
/* WMI command API */
int wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf, int len,
WMI_CMD_ID cmd_id)
@ -773,8 +797,12 @@ int wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf, int len,
HTC_PACKET *pkt;
A_STATUS status;
struct ol_softc *scn;
uint16_t htc_tag = 0;
if (cdf_atomic_read(&wmi_handle->is_target_suspended) &&
if (wmi_get_runtime_pm_inprogress(wmi_handle)) {
if (wmi_is_runtime_pm_cmd(cmd_id))
htc_tag = HTC_TX_PACKET_TAG_AUTO_PM;
} else if (cdf_atomic_read(&wmi_handle->is_target_suspended) &&
((WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID != cmd_id) &&
(WMI_PDEV_RESUME_CMDID != cmd_id))) {
pr_err("%s: Target is suspended could not send WMI command\n",
@ -830,7 +858,7 @@ int wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf, int len,
NULL,
cdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR),
/* htt_host_data_dl_len(buf)+20 */
wmi_handle->wmi_endpoint_id, 0 /*htc_tag */ );
wmi_handle->wmi_endpoint_id, htc_tag);
SET_HTC_PACKET_NET_BUF_CONTEXT(pkt, buf);
@ -1160,6 +1188,21 @@ void wmi_rx_event_work(struct work_struct *work)
/* WMI Initialization functions */
#ifdef FEATURE_RUNTIME_PM
/**
* wmi_runtime_pm_init() - initialize runtime pm wmi variables
* @wmi_handle: wmi context
*/
void wmi_runtime_pm_init(struct wmi_unified *wmi_handle)
{
cdf_atomic_init(&wmi_handle->runtime_pm_inprogress);
}
#else
void wmi_runtime_pm_init(struct wmi_unified *wmi_handle)
{
}
#endif
void *wmi_unified_attach(ol_scn_t scn_handle,
wma_process_fw_event_handler_cbk func)
{
@ -1176,6 +1219,7 @@ void *wmi_unified_attach(ol_scn_t scn_handle,
wmi_handle->scn_handle = scn_handle;
cdf_atomic_init(&wmi_handle->pending_cmds);
cdf_atomic_init(&wmi_handle->is_target_suspended);
wmi_runtime_pm_init(wmi_handle);
cdf_spinlock_init(&wmi_handle->eventq_lock);
cdf_nbuf_queue_init(&wmi_handle->event_queue);
#ifdef CONFIG_CNSS
@ -1335,3 +1379,14 @@ void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val)
cdf_atomic_set(&wmi_handle->is_target_suspended, val);
}
#ifdef FEATURE_RUNTIME_PM
void wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, A_BOOL val)
{
cdf_atomic_set(&wmi_handle->runtime_pm_inprogress, val);
}
inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle)
{
return cdf_atomic_read(&wmi_handle->runtime_pm_inprogress);
}
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -150,7 +150,24 @@ int wmi_get_pending_cmds(wmi_unified_t wmi_handle);
WMI API to set target suspend state
*/
void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val);
void wmi_set_target_suspend(wmi_unified_t wmi_handle, bool val);
#ifdef FEATURE_RUNTIME_PM
void
wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, bool val);
bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle);
#else
static inline void
wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, bool val)
{
return;
}
static inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle)
{
return false;
}
#endif
/**
* WMA Callback to process fw event.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -89,6 +89,11 @@ struct wmi_unified {
#endif /*WMI_INTERFACE_EVENT_LOGGING */
cdf_atomic_t is_target_suspended;
#ifdef FEATURE_RUNTIME_PM
cdf_atomic_t runtime_pm_inprogress;
#endif
int (*wma_process_fw_event_handler_cbk)(struct wmi_unified *wmi_handle,
wmi_buf_t evt_buf);
};