Browse Source

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
Houston Hoffman 9 years ago
parent
commit
1460fa326f

+ 2 - 1
core/dp/txrx/ol_tx_send.c

@@ -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);

+ 14 - 5
core/htc/htc_packet.h

@@ -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)
 

+ 122 - 10
core/htc/htc_send.c

@@ -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 =

+ 5 - 0
core/wma/src/wma_features.c

@@ -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);

+ 58 - 3
core/wmi/wmi_unified.c

@@ -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

+ 19 - 2
core/wmi/wmi_unified_api.h

@@ -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.

+ 6 - 1
core/wmi/wmi_unified_priv.h

@@ -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);
 };