Kaynağa Gözat

qcacmn: Trigger sys wakeup for WMI command when WOW is enabled

DHCP packet is received in the IPA exception path when
system is suspending. As part of DHCP packet processing,
WMI_PEER_SET_PARAM_CMDID is sent to FW after WOW is
enabled resulting in self recovery getting triggered by
host.

Fix is to do an explicit system wakeup if a WMI command
has to be sent post WOW enablement.

Change-Id: If1904a4fe5c861deed1b35071be10cb8cc8d6407
CRs-Fixed: 2890913
Yeshwanth Sriram Guntuka 4 yıl önce
ebeveyn
işleme
6611374cf4
7 değiştirilmiş dosya ile 327 ekleme ve 4 silme
  1. 130 0
      hif/inc/hif.h
  2. 39 0
      hif/src/hif_main.c
  3. 3 0
      hif/src/hif_main.h
  4. 16 1
      htc/htc_api.h
  5. 4 1
      htc/htc_packet.h
  6. 91 1
      htc/htc_send.c
  7. 44 1
      wmi/src/wmi_unified.c

+ 130 - 0
hif/inc/hif.h

@@ -333,6 +333,22 @@ enum hif_event_type {
 	/* Do check hif_hist_skip_event_record when adding new events */
 };
 
+/**
+ * enum hif_system_pm_state - System PM state
+ * HIF_SYSTEM_PM_STATE_ON: System in active state
+ * HIF_SYSTEM_PM_STATE_BUS_RESUMING: bus resume in progress as part of
+ *  system resume
+ * HIF_SYSTEM_PM_STATE_BUS_SUSPENDING: bus suspend in progress as part of
+ *  system suspend
+ * HIF_SYSTEM_PM_STATE_BUS_SUSPENDED: bus suspended as part of system suspend
+ */
+enum hif_system_pm_state {
+	HIF_SYSTEM_PM_STATE_ON,
+	HIF_SYSTEM_PM_STATE_BUS_RESUMING,
+	HIF_SYSTEM_PM_STATE_BUS_SUSPENDING,
+	HIF_SYSTEM_PM_STATE_BUS_SUSPENDED,
+};
+
 #ifdef WLAN_FEATURE_DP_EVENT_HISTORY
 
 #if defined(HIF_CONFIG_SLUB_DEBUG_ON) || defined(HIF_CE_DEBUG_DATA_BUF)
@@ -1778,4 +1794,118 @@ static inline
 void hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value)
 {}
 #endif
+
+#ifdef SYSTEM_PM_CHECK
+/**
+ * __hif_system_pm_set_state() - Set system pm state
+ * @hif: hif opaque handle
+ * @state: system state
+ *
+ * Return:  None
+ */
+void __hif_system_pm_set_state(struct hif_opaque_softc *hif,
+			       enum hif_system_pm_state state);
+
+/**
+ * hif_system_pm_set_state_on() - Set system pm state to ON
+ * @hif: hif opaque handle
+ *
+ * Return:  None
+ */
+static inline
+void hif_system_pm_set_state_on(struct hif_opaque_softc *hif)
+{
+	__hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_ON);
+}
+
+/**
+ * hif_system_pm_set_state_resuming() - Set system pm state to resuming
+ * @hif: hif opaque handle
+ *
+ * Return:  None
+ */
+static inline
+void hif_system_pm_set_state_resuming(struct hif_opaque_softc *hif)
+{
+	__hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_BUS_RESUMING);
+}
+
+/**
+ * hif_system_pm_set_state_suspending() - Set system pm state to suspending
+ * @hif: hif opaque handle
+ *
+ * Return:  None
+ */
+static inline
+void hif_system_pm_set_state_suspending(struct hif_opaque_softc *hif)
+{
+	__hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_BUS_SUSPENDING);
+}
+
+/**
+ * hif_system_pm_set_state_suspended() - Set system pm state to suspended
+ * @hif: hif opaque handle
+ *
+ * Return:  None
+ */
+static inline
+void hif_system_pm_set_state_suspended(struct hif_opaque_softc *hif)
+{
+	__hif_system_pm_set_state(hif, HIF_SYSTEM_PM_STATE_BUS_SUSPENDED);
+}
+
+/**
+ * hif_system_pm_get_state() - Get system pm state
+ * @hif: hif opaque handle
+ *
+ * Return:  system state
+ */
+int32_t hif_system_pm_get_state(struct hif_opaque_softc *hif);
+
+/**
+ * hif_system_pm_state_check() - Check system state and trigger resume
+ *  if required
+ * @hif: hif opaque handle
+ *
+ * Return: 0 if system is in on state else error code
+ */
+int hif_system_pm_state_check(struct hif_opaque_softc *hif);
+#else
+static inline
+void __hif_system_pm_set_state(struct hif_opaque_softc *hif,
+			       enum hif_system_pm_state state)
+{
+}
+
+static inline
+void hif_system_pm_set_state_on(struct hif_opaque_softc *hif)
+{
+}
+
+static inline
+void hif_system_pm_set_state_resuming(struct hif_opaque_softc *hif)
+{
+}
+
+static inline
+void hif_system_pm_set_state_suspending(struct hif_opaque_softc *hif)
+{
+}
+
+static inline
+void hif_system_pm_set_state_suspended(struct hif_opaque_softc *hif)
+{
+}
+
+static inline
+int32_t hif_system_pm_get_state(struct hif_opaque_softc *hif)
+{
+	return 0;
+}
+
+static inline int hif_system_pm_state_check(struct hif_opaque_softc *hif)
+{
+	return 0;
+}
+#endif
 #endif /* _HIF_H_ */

+ 39 - 0
hif/src/hif_main.c

@@ -898,6 +898,7 @@ struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx,
 	qdf_atomic_init(&scn->active_grp_tasklet_cnt);
 	qdf_atomic_init(&scn->link_suspended);
 	qdf_atomic_init(&scn->tasklet_from_intr);
+	hif_system_pm_set_state_on(GET_HIF_OPAQUE_HDL(scn));
 	qdf_mem_copy(&scn->callbacks, cbk,
 		     sizeof(struct hif_driver_state_callbacks));
 	scn->bus_type  = bus_type;
@@ -2035,3 +2036,41 @@ void hif_set_ce_service_max_rx_ind_flush(struct hif_opaque_softc *hif,
 		hif_ctx->ce_service_max_rx_ind_flush =
 						ce_service_max_rx_ind_flush;
 }
+
+#ifdef SYSTEM_PM_CHECK
+void __hif_system_pm_set_state(struct hif_opaque_softc *hif,
+			       enum hif_system_pm_state state)
+{
+	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
+
+	qdf_atomic_set(&hif_ctx->sys_pm_state, state);
+}
+
+int32_t hif_system_pm_get_state(struct hif_opaque_softc *hif)
+{
+	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
+
+	return qdf_atomic_read(&hif_ctx->sys_pm_state);
+}
+
+int hif_system_pm_state_check(struct hif_opaque_softc *hif)
+{
+	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
+	int32_t sys_pm_state;
+
+	if (!hif_ctx) {
+		hif_err("hif context is null");
+		return -EFAULT;
+	}
+
+	sys_pm_state = qdf_atomic_read(&hif_ctx->sys_pm_state);
+	if (sys_pm_state == HIF_SYSTEM_PM_STATE_BUS_SUSPENDING ||
+	    sys_pm_state == HIF_SYSTEM_PM_STATE_BUS_SUSPENDED) {
+		hif_info("Triggering system wakeup");
+		qdf_pm_system_wakeup();
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+#endif

+ 3 - 0
hif/src/hif_main.h

@@ -292,6 +292,9 @@ struct hif_softc {
 #ifdef HIF_DETECTION_LATENCY_ENABLE
 	struct hif_latency_detect latency_detect;
 #endif
+#ifdef SYSTEM_PM_CHECK
+	qdf_atomic_t sys_pm_state;
+#endif
 };
 
 static inline

+ 16 - 1
htc/htc_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, 2016-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -860,4 +860,19 @@ void htc_print_credit_history(HTC_HANDLE htc, uint32_t count,
 	print(print_priv, "HTC Credit History Feature is disabled");
 }
 #endif
+
+#ifdef SYSTEM_PM_CHECK
+/**
+ * htc_system_resume() - Send out any pending WMI/HTT
+ *  messages pending in htc queues on system resume.
+ * @htc: HTC handle
+ *
+ * Return: None
+ */
+void htc_system_resume(HTC_HANDLE htc);
+#else
+static inline void htc_system_resume(HTC_HANDLE htc)
+{
+}
+#endif
 #endif /* _HTC_API_H_ */

+ 4 - 1
htc/htc_packet.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, 2016-2017, 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016-2017, 2019-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -79,6 +79,9 @@ struct htc_tx_packet_info {
 /*Tag packet for runtime put in response or cleanup */
 #define HTC_TX_PACKET_TAG_RTPM_PUT_RC  (HTC_TX_PACKET_TAG_USER_DEFINED + 4)
 
+#define HTC_TX_PACKET_SYSTEM_SUSPEND   (HTC_TX_PACKET_TAG_USER_DEFINED + 5)
+#define HTC_TX_PACKET_SYSTEM_RESUME    (HTC_TX_PACKET_TAG_USER_DEFINED + 6)
+
 #define HTC_TX_PACKET_FLAG_FIXUP_NETBUF (1 << 0)
 #define HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA (1 << 1)
 

+ 91 - 1
htc/htc_send.c

@@ -736,6 +736,7 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
 	int (*update_ep_padding_credit)(void *, int);
 	void *ctx = NULL;
 	bool rt_put_in_resp;
+	int32_t sys_state = HIF_SYSTEM_PM_STATE_ON;
 
 	update_ep_padding_credit =
 			pEndpoint->EpCallBacks.ep_padding_credit_update;
@@ -851,6 +852,11 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
 					pEndpoint->UL_PipeID, false);
 		}
 
+		if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_SUSPEND) {
+			sys_state = hif_system_pm_get_state(target->hif_dev);
+			hif_system_pm_set_state_suspending(target->hif_dev);
+		}
+
 		htc_packet_set_magic_cookie(pPacket, HTC_PACKET_MAGIC_COOKIE);
 		/*
 		 * For HTT messages without a response from fw,
@@ -885,6 +891,12 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
 		if (status != QDF_STATUS_SUCCESS) {
 			if (rt_put_in_resp)
 				htc_dec_return_runtime_cnt((void *)target);
+
+			if (pPacket->PktInfo.AsTx.Tag ==
+			    HTC_TX_PACKET_SYSTEM_SUSPEND)
+				__hif_system_pm_set_state(target->hif_dev,
+							  sys_state);
+
 			if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
 				if (used_extra_tx_credit) {
 					ctx = pEndpoint->EpCallBacks.pContext;
@@ -1057,6 +1069,41 @@ htc_send_pkts_rtpm_dbgid_get(HTC_SERVICE_ID service_id)
 	return rtpm_dbgid;
 }
 
+#ifdef SYSTEM_PM_CHECK
+/**
+ * extract_htc_system_resume_pkts(): Move system pm resume 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 and enqueue
+ * them into a queue
+ */
+static void extract_htc_system_resume_pkts(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_SYSTEM_RESUME) {
+			HTC_PACKET_REMOVE(&endpoint->TxQueue, packet);
+			HTC_PACKET_ENQUEUE(queue, packet);
+		}
+	} ITERATE_END
+}
+#else
+static inline
+void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint,
+				    HTC_PACKET_QUEUE *queue)
+{
+}
+#endif
+
 /**
  * get_htc_send_packets_credit_based() - get packets based on available credits
  * @target: HTC target on which packets need to be sent
@@ -1082,6 +1129,8 @@ static void get_htc_send_packets_credit_based(HTC_TARGET *target,
 	bool do_pm_get = false;
 	wlan_rtpm_dbgid rtpm_dbgid = 0;
 	int ret;
+	HTC_PACKET_QUEUE sys_pm_queue;
+	bool sys_pm_check = false;
 
 	/*** NOTE : the TX lock is held when this function is called ***/
 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
@@ -1090,8 +1139,16 @@ static void get_htc_send_packets_credit_based(HTC_TARGET *target,
 	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;
+
+		INIT_HTC_PACKET_QUEUE(&sys_pm_queue);
+		extract_htc_system_resume_pkts(pEndpoint, &sys_pm_queue);
+		if (HTC_QUEUE_EMPTY(&sys_pm_queue)) {
+			tx_queue = &pEndpoint->TxQueue;
+			sys_pm_check = true;
+		} else {
+			tx_queue = &sys_pm_queue;
+		}
 	} else {
 		tx_queue = &pm_queue;
 	}
@@ -1127,6 +1184,13 @@ static void get_htc_send_packets_credit_based(HTC_TARGET *target,
 			break;
 		}
 
+		if (sys_pm_check &&
+		    hif_system_pm_state_check(target->hif_dev)) {
+			if (do_pm_get)
+				hif_pm_runtime_put(target->hif_dev, rtpm_dbgid);
+			break;
+		}
+
 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
 				(" Got head packet:%pK , Queue Depth: %d\n",
 				 pPacket,
@@ -1275,6 +1339,11 @@ static void get_htc_send_packets(HTC_TARGET *target,
 				hif_pm_runtime_put(target->hif_dev, rtpm_dbgid);
 			break;
 		}
+
+		ret = hif_system_pm_state_check(target->hif_dev);
+		if (ret)
+			break;
+
 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
 				(" Got packet:%pK , New Queue Depth: %d\n",
 				 pPacket,
@@ -2722,3 +2791,24 @@ struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle)
 
 	return &(target->htc_pkt_stats);
 }
+
+#ifdef SYSTEM_PM_CHECK
+void htc_system_resume(HTC_HANDLE htc)
+{
+	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc);
+	HTC_ENDPOINT *endpoint = NULL;
+	int i;
+
+	if (!target)
+		return;
+
+	for (i = 0; i < ENDPOINT_MAX; i++) {
+		endpoint = &target->endpoint[i];
+
+		if (endpoint->service_id == 0)
+			continue;
+
+		htc_try_send(target, endpoint, NULL);
+	}
+}
+#endif

+ 44 - 1
wmi/src/wmi_unified.c

@@ -1942,14 +1942,54 @@ static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle)
 						"WMI_NON_TLV_TARGET"));
 }
 
+#ifdef SYSTEM_PM_CHECK
+/**
+ * wmi_set_system_pm_pkt_tag() - API to set tag for system pm packets
+ * @htc_tag: HTC tag
+ * @buf: wmi cmd buffer
+ * @cmd_id: cmd id
+ *
+ * Return: None
+ */
+static void wmi_set_system_pm_pkt_tag(uint16_t *htc_tag, wmi_buf_t buf,
+				      uint32_t cmd_id)
+{
+	switch (cmd_id) {
+	case WMI_WOW_ENABLE_CMDID:
+	case WMI_PDEV_SUSPEND_CMDID:
+		*htc_tag = HTC_TX_PACKET_SYSTEM_SUSPEND;
+		break;
+	case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID:
+	case WMI_PDEV_RESUME_CMDID:
+		*htc_tag = HTC_TX_PACKET_SYSTEM_RESUME;
+		break;
+	case WMI_D0_WOW_ENABLE_DISABLE_CMDID:
+		if (wmi_is_legacy_d0wow_disable_cmd(buf, cmd_id))
+			*htc_tag = HTC_TX_PACKET_SYSTEM_RESUME;
+		else
+			*htc_tag = HTC_TX_PACKET_SYSTEM_SUSPEND;
+		break;
+	default:
+		break;
+	}
+}
+#else
+static inline void wmi_set_system_pm_pkt_tag(uint16_t *htc_tag, wmi_buf_t buf,
+					     uint32_t cmd_id)
+{
+}
+#endif
+
 QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf,
 				   uint32_t len, uint32_t cmd_id,
 				   const char *func, uint32_t line)
 {
 	HTC_PACKET *pkt;
 	uint16_t htc_tag = 0;
+	bool rtpm_inprogress;
 
-	if (wmi_get_runtime_pm_inprogress(wmi_handle)) {
+	rtpm_inprogress = wmi_get_runtime_pm_inprogress(wmi_handle);
+	if (rtpm_inprogress) {
 		htc_tag = wmi_handle->ops->wmi_set_htc_tx_tag(wmi_handle, buf,
 							      cmd_id);
 	} else if (qdf_atomic_read(&wmi_handle->is_target_suspended) &&
@@ -2011,6 +2051,9 @@ QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf,
 		return QDF_STATUS_E_NOMEM;
 	}
 
+	if (!rtpm_inprogress)
+		wmi_set_system_pm_pkt_tag(&htc_tag, buf, cmd_id);
+
 	SET_HTC_PACKET_INFO_TX(pkt,
 			       NULL,
 			       qdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR),