浏览代码

qcacmn: Add WLAN IPA RX exception packet to pm queue

Below signature is seen in driver logs.
Target is suspended (via send_process_dhcp_ind_cmd_tlv:244)
cds_trigger_recovery_handler: critical host timeout trigger
fw recovery for reason code 34

Suspend/Resume test is run with SAP started and a ref-client
is associated with the SAP. One DHCP-Req packet is received
from ref-client before driver completes the resume process.
With SAP_DHCP_FW_IND feature enabled, driver will send one
WMI cmd to target for such DHCP packets received.

With IPA_OFFLOAD enabled, such DHCP packets are received from
the RX exception callback from IPA driver. Hence add support
to queue these DHCP packets onto pm_queue_head skb queue when
WLAN IPA component is still in suspended state. When IPA component
is resumed from suspend state, pm_queue_head skb queue will be
drained to pass up queued RX exception packets to stack.

For QCA_IPA_LL_TX_FLOW_CONTROL enabled platforms, such as WIN
chipsets, suspend/resume is not supported. Hence wrap fixes
only for !QCA_IPA_LL_TX_FLOW_CONTROL.

Change-Id: I823005d9b58d1d62eec2c044621e1c1423aa3537
CRs-Fixed: 3457254
Jia Ding 2 年之前
父节点
当前提交
e5050154f1
共有 2 个文件被更改,包括 123 次插入4 次删除
  1. 2 0
      ipa/core/inc/wlan_ipa_priv.h
  2. 121 4
      ipa/core/src/wlan_ipa_core.c

+ 2 - 0
ipa/core/inc/wlan_ipa_priv.h

@@ -303,11 +303,13 @@ struct wlan_ipa_rx_hdr {
  * @exception: Exception packet
  * @iface_context: Interface context
  * @ipa_tx_desc: IPA TX descriptor
+ * @send_to_nw: RX exception packet that needs to be passed up to stack
  */
 struct wlan_ipa_pm_tx_cb {
 	bool exception;
 	struct wlan_ipa_iface_context *iface_context;
 	qdf_ipa_rx_data_t *ipa_tx_desc;
+	bool send_to_nw;
 };
 
 /**

+ 121 - 4
ipa/core/src/wlan_ipa_core.c

@@ -818,6 +818,7 @@ static void wlan_ipa_pm_flush(void *data)
 	struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
 	qdf_nbuf_t skb;
 	uint32_t dequeued = 0;
+	qdf_netdev_t ndev;
 
 	qdf_spin_lock_bh(&ipa_ctx->pm_lock);
 	while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) !=
@@ -836,6 +837,15 @@ static void wlan_ipa_pm_flush(void *data)
 			} else {
 				dev_kfree_skb_any(skb);
 			}
+		} else if (pm_tx_cb->send_to_nw) {
+			ndev = pm_tx_cb->iface_context->dev;
+
+			if (ipa_ctx->send_to_nw && ndev) {
+				ipa_ctx->send_to_nw(skb, ndev);
+				ipa_ctx->ipa_rx_net_send_count++;
+			} else {
+				dev_kfree_skb_any(skb);
+			}
 		} else {
 			wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context,
 						pm_tx_cb->ipa_tx_desc);
@@ -1184,6 +1194,109 @@ static int wlan_ipa_send_sta_eapol_to_nw(qdf_nbuf_t skb,
 	return 0;
 }
 
+#ifndef QCA_IPA_LL_TX_FLOW_CONTROL
+
+#ifdef SAP_DHCP_FW_IND
+/**
+ * wlan_ipa_send_to_nw_sap_dhcp - Check if SAP mode and skb is a DHCP packet
+ * @iface_ctx: IPA per-interface ctx
+ * @skb: socket buffer
+ *
+ * Check if @iface_ctx is SAP and @skb is a DHCP packet.
+ *
+ * When SAP_DHCP_FW_IND feature is enabled, DHCP packets received will be
+ * notified to target via WMI cmd. However if system is suspended, WMI
+ * cmd is not allowed from Host to Target.
+ *
+ * Return: true if iface is SAP mode and skb is a DHCP packet. Otherwise false
+ */
+static bool
+wlan_ipa_send_to_nw_sap_dhcp(struct wlan_ipa_iface_context *iface_ctx,
+			     qdf_nbuf_t skb)
+{
+	if (iface_ctx->device_mode == QDF_SAP_MODE &&
+	    qdf_nbuf_is_ipv4_dhcp_pkt(skb) == true)
+		return true;
+
+	return false;
+}
+#else /* !SAP_DHCP_FW_IND */
+static inline bool
+wlan_ipa_send_to_nw_sap_dhcp(struct wlan_ipa_iface_context *iface_ctx,
+			     qdf_nbuf_t skb)
+{
+	return false;
+}
+#endif /* SAP_DHCP_FW_IND */
+
+/**
+ * wlan_ipa_send_to_nw_defer - Check if skb needs to deferred to network stack
+ * @iface_ctx: IPA per-interface ctx
+ * @skb: socket buffer
+ *
+ * Check if @skb received on @iface_ctx needs to be deferred to be passed
+ * up to network stack.
+ *
+ * Return: true if needs to be deferred, otherwise false
+ */
+static bool wlan_ipa_send_to_nw_defer(struct wlan_ipa_iface_context *iface_ctx,
+				      qdf_nbuf_t skb)
+{
+	struct wlan_ipa_priv *ipa_ctx = iface_ctx->ipa_ctx;
+
+	qdf_spin_lock_bh(&ipa_ctx->pm_lock);
+	if (!ipa_ctx->suspended) {
+		qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
+		return false;
+	}
+	qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
+
+	return wlan_ipa_send_to_nw_sap_dhcp(iface_ctx, skb);
+}
+
+/**
+ * wlan_ipa_send_to_nw_queue - Add skb to pm_queue_head if deferred
+ * @iface_ctx: IPA per-interface ctx
+ * @skb: socket buffer
+ *
+ * Add @skb to pm_queue_head to defer passing up to network stack due to
+ * system suspended.
+ *
+ * Return: None
+ */
+static void wlan_ipa_send_to_nw_queue(struct wlan_ipa_iface_context *iface_ctx,
+				      qdf_nbuf_t skb)
+{
+	struct wlan_ipa_priv *ipa_ctx = iface_ctx->ipa_ctx;
+	struct wlan_ipa_pm_tx_cb *pm_cb;
+
+	qdf_mem_zero(skb->cb, sizeof(skb->cb));
+	pm_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
+
+	pm_cb->send_to_nw = true;
+	pm_cb->iface_context = iface_ctx;
+
+	qdf_spin_lock_bh(&ipa_ctx->pm_lock);
+	qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb);
+	qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
+
+	ipa_ctx->stats.num_tx_queued++;
+}
+#else /* QCA_IPA_LL_TX_FLOW_CONTROL */
+static inline bool
+wlan_ipa_send_to_nw_defer(struct wlan_ipa_iface_context *iface_ctx,
+			  qdf_nbuf_t skb)
+{
+	return false;
+}
+
+static inline void
+wlan_ipa_send_to_nw_queue(struct wlan_ipa_iface_context *iface_ctx,
+			  qdf_nbuf_t skb)
+{
+}
+#endif /* QCA_IPA_LL_TX_FLOW_CONTROL */
+
 /**
  * wlan_ipa_send_skb_to_network() - Send skb to kernel
  * @skb: network buffer
@@ -1211,10 +1324,14 @@ wlan_ipa_send_skb_to_network(qdf_nbuf_t skb,
 
 	skb->destructor = wlan_ipa_uc_rt_debug_destructor;
 
-	if (ipa_ctx->send_to_nw)
-		ipa_ctx->send_to_nw(skb, iface_ctx->dev);
+	if (wlan_ipa_send_to_nw_defer(iface_ctx, skb)) {
+		wlan_ipa_send_to_nw_queue(iface_ctx, skb);
+	} else {
+		if (ipa_ctx->send_to_nw)
+			ipa_ctx->send_to_nw(skb, iface_ctx->dev);
 
-	ipa_ctx->ipa_rx_net_send_count++;
+		ipa_ctx->ipa_rx_net_send_count++;
+	}
 }
 
 /**
@@ -4199,7 +4316,7 @@ void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx)
 
 		pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb;
 
-		if (pm_tx_cb->exception) {
+		if (pm_tx_cb->exception || pm_tx_cb->send_to_nw) {
 			dev_kfree_skb_any(skb);
 		} else {
 			if (pm_tx_cb->ipa_tx_desc)