Forráskód Böngészése

qcacmn: 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: Ibc2246620490905fd992a2df31cc6f241cc63592
CRs-Fixed: 2432831
jiad 6 éve
szülő
commit
5a4530f824
5 módosított fájl, 171 hozzáadás és 1 törlés
  1. 32 0
      dp/inc/cdp_txrx_ipa.h
  2. 2 0
      dp/inc/cdp_txrx_ops.h
  3. 120 0
      dp/wifi3.0/dp_ipa.c
  4. 15 0
      dp/wifi3.0/dp_ipa.h
  5. 2 1
      dp/wifi3.0/dp_main.c

+ 32 - 0
dp/inc/cdp_txrx_ipa.h

@@ -574,6 +574,38 @@ cdp_ipa_set_perf_level(ol_txrx_soc_handle soc, int client,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+/**
+ * cdp_ipa_rx_intrabss_fwd() - Perform intra-bss fwd for IPA RX path
+ *
+ * @soc: data path soc handle
+ * @vdev: vdev handle
+ * @nbuf: pointer to skb of ethernet packet received from IPA RX path
+ * @fwd_success: pointer to indicate if skb succeeded in intra-bss TX
+ *
+ * This function performs intra-bss forwarding for WDI 3.0 IPA RX path.
+ *
+ * Return: true if packet is intra-bss fwd-ed and no need to pass to
+ *	   network stack. false if packet needs to be passed to network stack.
+ */
+static inline bool
+cdp_ipa_rx_intrabss_fwd(ol_txrx_soc_handle soc, struct cdp_vdev *vdev,
+			qdf_nbuf_t nbuf, bool *fwd_success)
+{
+	if (!soc || !soc->ops || !soc->ops->ipa_ops || !vdev || !fwd_success) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL,
+			  "%s invalid instance", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (soc->ops->ipa_ops->ipa_rx_intrabss_fwd)
+		return soc->ops->ipa_ops->ipa_rx_intrabss_fwd(vdev, nbuf,
+							      fwd_success);
+
+	/* Fall back to pass up to stack */
+	return false;
+}
+
 #endif /* IPA_OFFLOAD */
 
 #endif /* _CDP_TXRX_IPA_H_ */

+ 2 - 0
dp/inc/cdp_txrx_ops.h

@@ -1210,6 +1210,8 @@ struct cdp_ipa_ops {
 	QDF_STATUS (*ipa_disable_pipes)(struct cdp_pdev *pdev);
 	QDF_STATUS (*ipa_set_perf_level)(int client,
 		uint32_t max_supported_bw_mbps);
+	bool (*ipa_rx_intrabss_fwd)(struct cdp_vdev *vdev, qdf_nbuf_t nbuf,
+				    bool *fwd_success);
 };
 #endif
 

+ 120 - 0
dp/wifi3.0/dp_ipa.c

@@ -1547,4 +1547,124 @@ QDF_STATUS dp_ipa_set_perf_level(int client, uint32_t max_supported_bw_mbps)
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * dp_ipa_intrabss_send - send IPA RX intra-bss frames
+ * @pdev: pdev
+ * @vdev: vdev
+ * @nbuf: skb
+ *
+ * Return: nbuf if TX fails and NULL if TX succeeds
+ */
+static qdf_nbuf_t dp_ipa_intrabss_send(struct dp_pdev *pdev,
+				       struct dp_vdev *vdev,
+				       qdf_nbuf_t nbuf)
+{
+	struct cdp_tid_rx_stats *tid_stats;
+	struct dp_peer *vdev_peer;
+	uint16_t len;
+	uint8_t tid;
+
+	vdev_peer = vdev->vap_bss_peer;
+	if (qdf_unlikely(!vdev_peer))
+		return nbuf;
+
+	tid = qdf_nbuf_get_priority(nbuf);
+	tid_stats = &pdev->stats.tid_stats.tid_rx_stats[tid];
+
+	qdf_mem_zero(nbuf->cb, sizeof(nbuf->cb));
+	len = qdf_nbuf_len(nbuf);
+
+	if (dp_tx_send(vdev, nbuf)) {
+		DP_STATS_INC_PKT(vdev_peer, rx.intra_bss.fail, 1, len);
+		tid_stats->fail_cnt[INTRABSS_DROP]++;
+		return nbuf;
+	}
+
+	DP_STATS_INC_PKT(vdev_peer, rx.intra_bss.pkts, 1, len);
+	tid_stats->intrabss_cnt++;
+	return NULL;
+}
+
+bool dp_ipa_rx_intrabss_fwd(struct cdp_vdev *pvdev, qdf_nbuf_t nbuf,
+			    bool *fwd_success)
+{
+	struct dp_vdev *vdev = (struct dp_vdev *)pvdev;
+	struct dp_pdev *pdev;
+	struct dp_peer *da_peer;
+	struct dp_peer *sa_peer;
+	qdf_nbuf_t nbuf_copy;
+	uint8_t da_is_bcmc;
+	struct ethhdr *eh;
+	uint8_t local_id;
+
+	*fwd_success = false; /* set default as failure */
+
+	/*
+	 * WDI 3.0 skb->cb[] info from IPA driver
+	 * skb->cb[0] = vdev_id
+	 * skb->cb[1].bit#1 = da_is_bcmc
+	 */
+	da_is_bcmc = ((uint8_t)nbuf->cb[1]) & 0x2;
+
+	if (qdf_unlikely(!vdev))
+		return false;
+
+	pdev = vdev->pdev;
+	if (qdf_unlikely(!pdev))
+		return false;
+
+	/* no fwd for station mode and just pass up to stack */
+	if (vdev->opmode == wlan_op_mode_sta)
+		return false;
+
+	if (da_is_bcmc) {
+		nbuf_copy = qdf_nbuf_copy(nbuf);
+		if (!nbuf_copy)
+			return false;
+
+		if (dp_ipa_intrabss_send(pdev, vdev, nbuf_copy))
+			qdf_nbuf_free(nbuf_copy);
+		else
+			*fwd_success = true;
+
+		/* return false to pass original pkt up to stack */
+		return false;
+	}
+
+	eh = (struct ethhdr *)qdf_nbuf_data(nbuf);
+
+	if (!qdf_mem_cmp(eh->h_dest, vdev->mac_addr.raw, QDF_MAC_ADDR_SIZE))
+		return false;
+
+	da_peer = dp_find_peer_by_addr((struct cdp_pdev *)pdev, eh->h_dest,
+				       &local_id);
+	if (!da_peer)
+		return false;
+
+	if (da_peer->vdev != vdev)
+		return false;
+
+	sa_peer = dp_find_peer_by_addr((struct cdp_pdev *)pdev, eh->h_source,
+				       &local_id);
+	if (!sa_peer)
+		return false;
+
+	if (sa_peer->vdev != vdev)
+		return false;
+
+	/*
+	 * In intra-bss forwarding scenario, skb is allocated by IPA driver.
+	 * Need to add skb to internal tracking table to avoid nbuf memory
+	 * leak check for unallocated skb.
+	 */
+	qdf_net_buf_debug_acquire_skb(nbuf, __FILE__, __LINE__);
+
+	if (dp_ipa_intrabss_send(pdev, vdev, nbuf))
+		qdf_nbuf_free(nbuf);
+	else
+		*fwd_success = true;
+
+	return true;
+}
+
 #endif

+ 15 - 0
dp/wifi3.0/dp_ipa.h

@@ -86,6 +86,21 @@ QDF_STATUS dp_ipa_enable_pipes(struct cdp_pdev *pdev);
 QDF_STATUS dp_ipa_disable_pipes(struct cdp_pdev *pdev);
 QDF_STATUS dp_ipa_set_perf_level(int client,
 		uint32_t max_supported_bw_mbps);
+
+/**
+ * dp_ipa_rx_intrabss_fwd() - Perform intra-bss fwd for IPA RX path
+ *
+ * @pvdev: pointer to dp_vdev structure
+ * @nbuf: pointer to skb of ethernet packet received from IPA RX path
+ * @fwd_success: pointer to indicate if skb succeeded in intra-bss TX
+ *
+ * This function performs intra-bss forwarding for WDI 3.0 IPA RX path.
+ *
+ * Return: true if packet is intra-bss fwd-ed and no need to pass to
+ *	   network stack. false if packet needs to be passed to network stack.
+ */
+bool dp_ipa_rx_intrabss_fwd(struct cdp_vdev *pvdev, qdf_nbuf_t nbuf,
+			    bool *fwd_success);
 int dp_ipa_uc_detach(struct dp_soc *soc, struct dp_pdev *pdev);
 int dp_ipa_uc_attach(struct dp_soc *soc, struct dp_pdev *pdev);
 int dp_ipa_ring_resource_setup(struct dp_soc *soc,

+ 2 - 1
dp/wifi3.0/dp_main.c

@@ -10100,7 +10100,8 @@ static struct cdp_ipa_ops dp_ops_ipa = {
 	.ipa_cleanup_iface = dp_ipa_cleanup_iface,
 	.ipa_enable_pipes = dp_ipa_enable_pipes,
 	.ipa_disable_pipes = dp_ipa_disable_pipes,
-	.ipa_set_perf_level = dp_ipa_set_perf_level
+	.ipa_set_perf_level = dp_ipa_set_perf_level,
+	.ipa_rx_intrabss_fwd = dp_ipa_rx_intrabss_fwd
 };
 #endif