From e5050154f150f9a5187ebe48d5cb823703863da2 Mon Sep 17 00:00:00 2001 From: Jia Ding Date: Wed, 5 Apr 2023 22:42:00 +0800 Subject: [PATCH] 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 --- ipa/core/inc/wlan_ipa_priv.h | 2 + ipa/core/src/wlan_ipa_core.c | 125 +++++++++++++++++++++++++++++++++-- 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/ipa/core/inc/wlan_ipa_priv.h b/ipa/core/inc/wlan_ipa_priv.h index 88b0ea0cf0..3f03e19c6f 100644 --- a/ipa/core/inc/wlan_ipa_priv.h +++ b/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; }; /** diff --git a/ipa/core/src/wlan_ipa_core.c b/ipa/core/src/wlan_ipa_core.c index 8f396c097a..338afda2e7 100644 --- a/ipa/core/src/wlan_ipa_core.c +++ b/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)