qcacld-3.0: Support WDI 3.0 SW path intra-bss forwarding

Support WDI 3.0 SW path intra-bss forwarding. Major
difference for WDI 3.0 is the metadata info passed
from ipa driver in skb->cb[].

Previously intra-bss fwd decision is done by FW and
it passes fw_desc to IPA where IPA driver passes onto
WLAN driver. Now for WDI 3.0, FW is not involved in RX
path and SW path intra-bss fwd decision has to be done
in wlan driver.

Change-Id: I0b4b9bbf16440dd47b6f97460f8931ea3a79303c
CRs-Fixed: 2426857
diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c
index 9efd6d2..71532f8 100644
--- a/components/ipa/core/src/wlan_ipa_core.c
+++ b/components/ipa/core/src/wlan_ipa_core.c
@@ -275,6 +275,115 @@
 	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 @@
 		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 @@
 		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 */
 
 /**
@@ -642,115 +797,6 @@
 }
 
 /**
- * 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
  *	pointer to the global IPA context)
@@ -767,7 +813,6 @@
 	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 @@
 			 * 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");