diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c index 9efd6d237e15..71532f8a4126 100644 --- a/components/ipa/core/src/wlan_ipa_core.c +++ b/components/ipa/core/src/wlan_ipa_core.c @@ -275,6 +275,115 @@ static void wlan_ipa_send_pkt_to_tl( iface_context->stats.num_tx++; } +/** + * wlan_ipa_forward() - handle packet forwarding to wlan tx + * @ipa_ctx: pointer to ipa ipa context + * @iface_ctx: interface context + * @skb: data pointer + * + * if exception packet has set forward bit, copied new packet should be + * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should + * put into pm queue and tx procedure will be differed + * + * Return: None + */ +static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_iface_context *iface_ctx, + qdf_nbuf_t skb) +{ + struct wlan_ipa_pm_tx_cb *pm_tx_cb; + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + + /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */ + qdf_nbuf_ipa_owned_set(skb); + + /* WLAN subsystem is in suspend, put in queue */ + if (ipa_ctx->suspended) { + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + ipa_info_rl("Tx in suspend, put in queue"); + qdf_mem_zero(skb->cb, sizeof(skb->cb)); + pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb; + pm_tx_cb->exception = true; + pm_tx_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 { + /* Resume, put packet into WLAN TX */ + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + if (ipa_ctx->softap_xmit) { + if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) { + ipa_err_rl("packet Tx fail"); + ipa_ctx->stats.num_tx_fwd_err++; + } else { + ipa_ctx->stats.num_tx_fwd_ok++; + } + } else { + dev_kfree_skb_any(skb); + } + } +} + +/** + * wlan_ipa_intrabss_forward() - Forward intra bss packets. + * @ipa_ctx: pointer to IPA IPA struct + * @iface_ctx: ipa interface context + * @desc: Firmware descriptor + * @skb: Data buffer + * + * Return: + * WLAN_IPA_FORWARD_PKT_NONE + * WLAN_IPA_FORWARD_PKT_DISCARD + * WLAN_IPA_FORWARD_PKT_LOCAL_STACK + * + */ + +static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward( + struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_iface_context *iface_ctx, + uint8_t desc, + qdf_nbuf_t skb) +{ + int ret = WLAN_IPA_FORWARD_PKT_NONE; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if ((desc & FW_RX_DESC_FORWARD_M)) { + void *vdev = cdp_get_vdev_from_vdev_id(soc, pdev, + iface_ctx->session_id); + if (cdp_tx_desc_thresh_reached(soc, vdev)) { + /* Drop the packet*/ + ipa_ctx->stats.num_tx_fwd_err++; + dev_kfree_skb_any(skb); + ret = WLAN_IPA_FORWARD_PKT_DISCARD; + return ret; + } + ipa_debug_rl("Forward packet to Tx (fw_desc=%d)", desc); + ipa_ctx->ipa_tx_forward++; + + if ((desc & FW_RX_DESC_DISCARD_M)) { + wlan_ipa_forward(ipa_ctx, iface_ctx, skb); + ipa_ctx->ipa_rx_internal_drop_count++; + ipa_ctx->ipa_rx_discard++; + ret = WLAN_IPA_FORWARD_PKT_DISCARD; + } else { + struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC); + + if (cloned_skb) + wlan_ipa_forward(ipa_ctx, iface_ctx, + cloned_skb); + else + ipa_err_rl("tx skb alloc failed"); + ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK; + } + } + + return ret; +} + #ifdef CONFIG_IPA_WDI_UNIFIED_API /* * TODO: Get WDI version through FW capabilities @@ -474,6 +583,40 @@ int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) return qdf_ipa_wdi_release_smmu_mapping(num_buf, buf_arr); } +static enum wlan_ipa_forward_type +wlan_ipa_rx_intrabss_fwd(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_iface_context *iface_ctx, + qdf_nbuf_t nbuf) +{ + uint8_t fw_desc = 0; + bool fwd_success; + int ret; + + /* legacy intra-bss fowarding for WDI 1.0 and 2.0 */ + if (ipa_ctx->wdi_version != IPA_WDI_3) { + fw_desc = (uint8_t)nbuf->cb[1]; + return wlan_ipa_intrabss_forward(ipa_ctx, iface_ctx, fw_desc, + nbuf); + } + + if (cdp_ipa_rx_intrabss_fwd(ipa_ctx->dp_soc, iface_ctx->tl_context, + nbuf, &fwd_success)) { + ipa_ctx->ipa_rx_internal_drop_count++; + ipa_ctx->ipa_rx_discard++; + + ret = WLAN_IPA_FORWARD_PKT_DISCARD; + } else { + ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK; + } + + if (fwd_success) + ipa_ctx->stats.num_tx_fwd_ok++; + else + ipa_ctx->stats.num_tx_fwd_err++; + + return ret; +} + #else /* CONFIG_IPA_WDI_UNIFIED_API */ static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) @@ -608,6 +751,18 @@ int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) return qdf_ipa_release_wdi_mapping(num_buf, buf_arr); } +static enum wlan_ipa_forward_type +wlan_ipa_rx_intrabss_fwd(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_iface_context *iface_ctx, + qdf_nbuf_t nbuf) +{ + uint8_t fw_desc; + + fw_desc = (uint8_t)nbuf->cb[1]; + + return wlan_ipa_intrabss_forward(ipa_ctx, iface_ctx, fw_desc, nbuf); +} + #endif /* CONFIG_IPA_WDI_UNIFIED_API */ /** @@ -641,115 +796,6 @@ wlan_ipa_send_skb_to_network(qdf_nbuf_t skb, ipa_ctx->ipa_rx_net_send_count++; } -/** - * wlan_ipa_forward() - handle packet forwarding to wlan tx - * @ipa_ctx: pointer to ipa ipa context - * @iface_ctx: interface context - * @skb: data pointer - * - * if exception packet has set forward bit, copied new packet should be - * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should - * put into pm queue and tx procedure will be differed - * - * Return: None - */ -static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx, - struct wlan_ipa_iface_context *iface_ctx, - qdf_nbuf_t skb) -{ - struct wlan_ipa_pm_tx_cb *pm_tx_cb; - - qdf_spin_lock_bh(&ipa_ctx->pm_lock); - - /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */ - qdf_nbuf_ipa_owned_set(skb); - - /* WLAN subsystem is in suspend, put in queue */ - if (ipa_ctx->suspended) { - qdf_spin_unlock_bh(&ipa_ctx->pm_lock); - ipa_info_rl("Tx in suspend, put in queue"); - qdf_mem_zero(skb->cb, sizeof(skb->cb)); - pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb; - pm_tx_cb->exception = true; - pm_tx_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 { - /* Resume, put packet into WLAN TX */ - qdf_spin_unlock_bh(&ipa_ctx->pm_lock); - - if (ipa_ctx->softap_xmit) { - if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) { - ipa_err_rl("packet Tx fail"); - ipa_ctx->stats.num_tx_fwd_err++; - } else { - ipa_ctx->stats.num_tx_fwd_ok++; - } - } else { - dev_kfree_skb_any(skb); - } - } -} - -/** - * wlan_ipa_intrabss_forward() - Forward intra bss packets. - * @ipa_ctx: pointer to IPA IPA struct - * @iface_ctx: ipa interface context - * @desc: Firmware descriptor - * @skb: Data buffer - * - * Return: - * WLAN_IPA_FORWARD_PKT_NONE - * WLAN_IPA_FORWARD_PKT_DISCARD - * WLAN_IPA_FORWARD_PKT_LOCAL_STACK - * - */ - -static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward( - struct wlan_ipa_priv *ipa_ctx, - struct wlan_ipa_iface_context *iface_ctx, - uint8_t desc, - qdf_nbuf_t skb) -{ - int ret = WLAN_IPA_FORWARD_PKT_NONE; - void *soc = cds_get_context(QDF_MODULE_ID_SOC); - void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); - - if ((desc & FW_RX_DESC_FORWARD_M)) { - void *vdev = cdp_get_vdev_from_vdev_id(soc, pdev, - iface_ctx->session_id); - if (cdp_tx_desc_thresh_reached(soc, vdev)) { - /* Drop the packet*/ - ipa_ctx->stats.num_tx_fwd_err++; - dev_kfree_skb_any(skb); - ret = WLAN_IPA_FORWARD_PKT_DISCARD; - return ret; - } - ipa_debug_rl("Forward packet to Tx (fw_desc=%d)", desc); - ipa_ctx->ipa_tx_forward++; - - if ((desc & FW_RX_DESC_DISCARD_M)) { - wlan_ipa_forward(ipa_ctx, iface_ctx, skb); - ipa_ctx->ipa_rx_internal_drop_count++; - ipa_ctx->ipa_rx_discard++; - ret = WLAN_IPA_FORWARD_PKT_DISCARD; - } else { - struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC); - - if (cloned_skb) - wlan_ipa_forward(ipa_ctx, iface_ctx, - cloned_skb); - else - ipa_err_rl("tx skb alloc failed"); - ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK; - } - } - - return ret; -} - /** * __wlan_ipa_w2i_cb() - WLAN to IPA callback handler * @priv: pointer to private data registered with IPA (we register a @@ -767,7 +813,6 @@ static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt, uint8_t iface_id; uint8_t session_id = 0xff; struct wlan_ipa_iface_context *iface_context; - uint8_t fw_desc; ipa_ctx = (struct wlan_ipa_priv *)priv; if (!ipa_ctx) { @@ -827,10 +872,9 @@ static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt, * set, and forward to Tx. Then copy to kernel stack * only when DISCARD bit is not set. */ - fw_desc = (uint8_t)skb->cb[1]; if (WLAN_IPA_FORWARD_PKT_DISCARD == - wlan_ipa_intrabss_forward(ipa_ctx, iface_context, - fw_desc, skb)) + wlan_ipa_rx_intrabss_fwd(ipa_ctx, iface_context, + skb)) break; } else { ipa_debug_rl("Intra-BSS forwarding is disabled");