Преглед изворни кода

qcacld-3.0: Implement htc runtime suspend/resume

Provide the apis to suspend & resume the htc layer
for runtime suspend.

Change-Id: Ia4c4f00fa62b250c5097e6bc14137b0114c5c90f
CRs-Fixed: 935300
Houston Hoffman пре 9 година
родитељ
комит
47e387baf7
7 измењених фајлова са 121 додато и 7 уклоњено
  1. 3 1
      core/dp/htt/htt.c
  2. 2 1
      core/dp/htt/htt_internal.h
  3. 19 1
      core/dp/htt/htt_tx.c
  4. 57 2
      core/htc/htc.c
  5. 7 1
      core/htc/htc_api.h
  6. 4 1
      core/htc/htc_internal.h
  7. 29 0
      core/htc/htc_send.c

+ 3 - 1
core/dp/htt/htt.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -43,6 +43,7 @@
 #include <ol_htt_api.h>
 
 #include <htt_internal.h>
+#include <ol_htt_tx_api.h>
 #include "hif.h"
 
 #define HTT_HTC_PKT_POOL_INIT_SIZE 100  /* enough for a large A-MPDU */
@@ -405,6 +406,7 @@ int htt_htc_attach(struct htt_pdev_t *pdev)
 	connect.EpCallbacks.EpTxComplete = htt_h2t_send_complete;
 	connect.EpCallbacks.EpTxCompleteMultiple = NULL;
 	connect.EpCallbacks.EpRecv = htt_t2h_msg_handler;
+	connect.EpCallbacks.ep_resume_tx_queue = htt_tx_resume_handler;
 
 	/* rx buffers currently are provided by HIF, not by EpRecvRefill */
 	connect.EpCallbacks.EpRecvRefill = NULL;

+ 2 - 1
core/dp/htt/htt_internal.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -413,6 +413,7 @@ static inline void htt_print_rx_desc(struct htt_host_rx_desc_base *rx_desc)
 
 #endif
 
+void htt_tx_resume_handler(void *);
 #ifdef ATH_11AC_TXCOMPACT
 #define HTT_TX_SCHED htt_tx_sched
 #else

+ 19 - 1
core/dp/htt/htt_tx.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -625,6 +625,24 @@ int htt_tx_send_std(htt_pdev_handle pdev, cdf_nbuf_t msdu, uint16_t msdu_id)
 
 }
 
+#ifdef FEATURE_RUNTIME_PM
+/**
+ * htt_tx_resume_handler() - resume callback for the htt endpoint
+ * @context: a pointer to the htt context
+ *
+ * runs htt_tx_sched.
+ */
+void htt_tx_resume_handler(void *context)
+{
+	struct htt_pdev_t *pdev =  (struct htt_pdev_t *) context;
+
+	htt_tx_sched(pdev);
+}
+#else
+void
+htt_tx_resume_handler(void *context) { }
+#endif
+
 cdf_nbuf_t
 htt_tx_send_batch(htt_pdev_handle pdev, cdf_nbuf_t head_msdu, int num_msdus)
 {

+ 57 - 2
core/htc/htc.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015 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.
  *
@@ -34,6 +34,7 @@
 #include "epping_main.h"
 #include "hif_io32.h"
 #include "cds_concurrency.h"
+#include <cds_api.h>
 
 #ifdef DEBUG
 static ATH_DEBUG_MASK_DESCRIPTION g_htc_debug_description[] = {
@@ -214,6 +215,7 @@ HTC_HANDLE htc_create(void *ol_sc, HTC_INIT_INFO *pInfo, cdf_device_t osdev)
 
 	A_MEMZERO(target, sizeof(HTC_TARGET));
 
+	htc_runtime_pm_init(target);
 	cdf_spinlock_init(&target->HTCLock);
 	cdf_spinlock_init(&target->HTCRxLock);
 	cdf_spinlock_init(&target->HTCTxLock);
@@ -681,7 +683,60 @@ void htc_stop(HTC_HANDLE HTCHandle)
 
 	reset_endpoint_states(target);
 
-	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop \n"));
+	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop\n"));
+}
+
+/**
+ * htc_runtime_pm_init(): runtime pm related intialization
+ *
+ * need to initialize a work item.
+ */
+void htc_runtime_pm_init(HTC_TARGET *target)
+{
+	cdf_create_work(&target->queue_kicker, htc_kick_queues, target);
+}
+
+/**
+ * htc_runtime_suspend(): ensure htc is ready to suspend
+ *
+ * htc is ready to suspend if there are no pending pactets
+ * in the txrx queues.
+ *
+ * Return: 0 on success or -EBUSY if there are queued packets.
+ */
+int htc_runtime_suspend(void)
+{
+	ol_txrx_pdev_handle txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX);
+
+	if (txrx_pdev == NULL) {
+		HTC_ERROR("%s: txrx context null", __func__);
+		return CDF_STATUS_E_FAULT;
+	}
+
+	if (ol_txrx_get_tx_pending(txrx_pdev))
+		return -EBUSY;
+	else
+		return 0;
+}
+
+/**
+ * htc_runtime_resume(): resume htc
+ *
+ * The htc message queue needs to be kicked off after
+ * a runtime resume.  Otherwise messages would get stuck.
+ *
+ * Return: 0 for success;
+ */
+int htc_runtime_resume(void)
+{
+	HTC_HANDLE htc_ctx = cds_get_context(CDF_MODULE_ID_HTC);
+	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_ctx);
+
+	if (target == NULL)
+		return 0;
+
+	cdf_schedule_work(&target->queue_kicker);
+	return 0;
 }
 
 void htc_dump_credit_states(HTC_HANDLE HTCHandle)

+ 7 - 1
core/htc/htc_api.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.
  *
@@ -66,6 +66,9 @@ struct ol_ath_htc_stats {
 	int htc_send_q_empty_count;
 };
 
+/* To resume HTT Tx queue during runtime resume */
+typedef void (*HTC_EP_RESUME_TX_QUEUE)(void *);
+
 /* per service connection send completion */
 typedef void (*HTC_EP_SEND_PKT_COMPLETE)(void *, HTC_PACKET *);
 /* per service connection callback when a plurality of packets have been sent
@@ -151,6 +154,7 @@ typedef struct _HTC_EP_CALLBACKS {
 	                                                                   indications (EpTxComplete must be NULL) */
 	HTC_EP_RECV_PKT_MULTIPLE EpRecvPktMultiple;             /* OPTIONAL completion handler for multiple
 	                                                           recv packet indications (EpRecv must be NULL) */
+	HTC_EP_RESUME_TX_QUEUE ep_resume_tx_queue;
 	int RecvAllocThreshold;         /* if EpRecvAllocThresh is non-NULL, HTC will compare the
 	                                   threshold value to the current recv packet length and invoke
 	                                   the EpRecvAllocThresh callback to acquire a packet buffer */
@@ -694,6 +698,8 @@ void htc_dump_counter_info(HTC_HANDLE HTCHandle);
 void *htc_get_targetdef(HTC_HANDLE htc_handle);
 void htc_set_target_to_sleep(void *context);
 void htc_cancel_deferred_target_sleep(void *context);
+int htc_runtime_suspend(void);
+int htc_runtime_resume(void);
 
 /* Disable ASPM : Disable PCIe low power */
 void htc_disable_aspm(void);

+ 4 - 1
core/htc/htc_internal.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015 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.
  *
@@ -184,6 +184,7 @@ typedef struct _HTC_TARGET {
 	A_UINT32 ce_send_cnt;
 	A_UINT32 TX_comp_cnt;
 	A_UINT8 MaxMsgsPerHTCBundle;
+	cdf_work_t queue_kicker;
 } HTC_TARGET;
 
 #define HTC_ENABLE_BUNDLE(target) (target->MaxMsgsPerHTCBundle > 1)
@@ -245,6 +246,8 @@ void htc_process_credit_rpt(HTC_TARGET *target,
 			    int NumEntries, HTC_ENDPOINT_ID FromEndpoint);
 void htc_fw_event_handler(void *context, CDF_STATUS status);
 void htc_send_complete_check_cleanup(void *context);
+void htc_runtime_pm_init(HTC_TARGET *target);
+void htc_kick_queues(void *context);
 
 void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit,
 		       uint32_t htc_tx_queue_depth);

+ 29 - 0
core/htc/htc_send.c

@@ -1669,6 +1669,35 @@ void htc_tx_resource_avail_handler(void *context, A_UINT8 pipeID)
 	htc_try_send(target, pEndpoint, NULL);
 }
 
+/**
+ * htc_kick_queues(): resumes tx transactions of suspended endpoints
+ * @context: pointer to the htc target context
+ *
+ * Iterates throught the enpoints and provides a context to empty queues
+ * int the hif layer when they are stalled due to runtime suspend.
+ *
+ * Return: none
+ */
+void htc_kick_queues(void *context)
+{
+	int i;
+	HTC_TARGET *target = (HTC_TARGET *)context;
+	HTC_ENDPOINT *endpoint = NULL;
+
+	for (i = 0; i < ENDPOINT_MAX; i++) {
+		endpoint = &target->endpoint[i];
+
+		if (endpoint->service_id == 0)
+			continue;
+
+		if (endpoint->EpCallBacks.ep_resume_tx_queue)
+			endpoint->EpCallBacks.ep_resume_tx_queue(
+					endpoint->EpCallBacks.pContext);
+
+		htc_try_send(target, endpoint, NULL);
+	}
+}
+
 /* flush endpoint TX queue */
 void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint,
 			   HTC_TX_TAG Tag)