Bläddra i källkod

qcacmn: Add support for vlan tagged traffic in IPA offload

In IPA offload, both tagged and untagged traffic cannot be handled with
a single rx pipe. Hence, add support for 2nd RX pipe for tagged and
untagged traffic respectively.

Change-Id: I77ff633327696f66df42fb592492321c1591646b
CRs-Fixed: 3226021
Himanshu Batra 3 år sedan
förälder
incheckning
7be2cf3775
7 ändrade filer med 802 tillägg och 38 borttagningar
  1. 7 0
      dp/wifi3.0/dp_htt.c
  2. 531 5
      dp/wifi3.0/dp_ipa.c
  3. 13 0
      dp/wifi3.0/dp_ipa.h
  4. 216 18
      dp/wifi3.0/dp_main.c
  5. 28 15
      dp/wifi3.0/dp_types.h
  6. 3 0
      hal/wifi3.0/hal_internal.h
  7. 4 0
      hal/wifi3.0/qcn9000/hal_9000.c

+ 7 - 0
dp/wifi3.0/dp_htt.c

@@ -549,6 +549,13 @@ int htt_srng_setup(struct htt_soc *soc, int mac_id,
 		    (lmac_id * HAL_MAX_RINGS_PER_LMAC))) {
 			htt_ring_id = HTT_HOST2_TO_FW_RXBUF_RING;
 			htt_ring_type = HTT_SW_TO_SW_RING;
+#ifdef IPA_WDI3_RX_TWO_PIPES
+		} else if (srng_params.ring_id ==
+		    (HAL_SRNG_WMAC1_SW2RXDMA0_BUF3 +
+		    (lmac_id * HAL_MAX_RINGS_PER_LMAC))) {
+			htt_ring_id = HTT_HOST3_TO_FW_RXBUF_RING;
+			htt_ring_type = HTT_SW_TO_SW_RING;
+#endif
 #endif
 #else
 		if (srng_params.ring_id ==

+ 531 - 5
dp/wifi3.0/dp_ipa.c

@@ -1165,6 +1165,33 @@ static void dp_rx_ipa_uc_detach(struct dp_soc *soc, struct dp_pdev *pdev)
 	qdf_mem_free_sgtable(&ipa_res->rx_refill_ring.sgtable);
 }
 
+/*
+ * dp_rx_alt_ipa_uc_detach - free autonomy RX resources
+ * @soc: data path instance
+ * @pdev: core txrx pdev context
+ *
+ * This function will detach DP RX into main device context
+ * will free DP Rx resources.
+ *
+ * Return: none
+ */
+#ifdef IPA_WDI3_RX_TWO_PIPES
+static void dp_rx_alt_ipa_uc_detach(struct dp_soc *soc, struct dp_pdev *pdev)
+{
+	struct dp_ipa_resources *ipa_res = &pdev->ipa_resource;
+
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	qdf_mem_free_sgtable(&ipa_res->rx_alt_rdy_ring.sgtable);
+	qdf_mem_free_sgtable(&ipa_res->rx_alt_refill_ring.sgtable);
+}
+#else
+static inline
+void dp_rx_alt_ipa_uc_detach(struct dp_soc *soc, struct dp_pdev *pdev)
+{ }
+#endif
+
 int dp_ipa_uc_detach(struct dp_soc *soc, struct dp_pdev *pdev)
 {
 	if (!wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx))
@@ -1179,6 +1206,9 @@ int dp_ipa_uc_detach(struct dp_soc *soc, struct dp_pdev *pdev)
 	/* RX resource detach */
 	dp_rx_ipa_uc_detach(soc, pdev);
 
+	/* Cleanup 2nd RX pipe resources */
+	dp_rx_alt_ipa_uc_detach(soc, pdev);
+
 	return QDF_STATUS_SUCCESS;	/* success */
 }
 
@@ -1356,6 +1386,85 @@ int dp_ipa_uc_attach(struct dp_soc *soc, struct dp_pdev *pdev)
 	return QDF_STATUS_SUCCESS;	/* success */
 }
 
+#ifdef IPA_WDI3_RX_TWO_PIPES
+/*
+ * dp_ipa_rx_alt_ring_resource_setup() - setup IPA 2nd RX ring resources
+ * @soc: data path SoC handle
+ * @pdev: data path pdev handle
+ *
+ * Return: none
+ */
+static
+void dp_ipa_rx_alt_ring_resource_setup(struct dp_soc *soc, struct dp_pdev *pdev)
+{
+	struct hal_soc *hal_soc = (struct hal_soc *)soc->hal_soc;
+	struct hal_srng *hal_srng;
+	struct hal_srng_params srng_params;
+	unsigned long addr_offset, dev_base_paddr;
+	qdf_dma_addr_t hp_addr;
+
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	dev_base_paddr =
+		(unsigned long)
+		((struct hif_softc *)(hal_soc->hif_handle))->mem_pa;
+
+	/* IPA REO_DEST Ring - HAL_SRNG_REO2SW3 */
+	hal_srng = (struct hal_srng *)
+			soc->reo_dest_ring[IPA_ALT_REO_DEST_RING_IDX].hal_srng;
+	hal_get_srng_params(hal_soc_to_hal_soc_handle(hal_soc),
+			    hal_srng_to_hal_ring_handle(hal_srng),
+			    &srng_params);
+
+	soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_base_paddr =
+						srng_params.ring_base_paddr;
+	soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_base_vaddr =
+						srng_params.ring_base_vaddr;
+	soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_size =
+		(srng_params.num_entries * srng_params.entry_size) << 2;
+	addr_offset = (unsigned long)(hal_srng->u.dst_ring.tp_addr) -
+		      (unsigned long)(hal_soc->dev_base_addr);
+	soc->ipa_uc_rx_rsc_alt.ipa_reo_tp_paddr =
+				(qdf_dma_addr_t)(addr_offset + dev_base_paddr);
+
+	dp_info("IPA REO_DEST Ring addr_offset=%x, dev_base_paddr=%x, tp_paddr=%x paddr=%pK vaddr=%pK size= %u(%u bytes)",
+		(unsigned int)addr_offset,
+		(unsigned int)dev_base_paddr,
+		(unsigned int)(soc->ipa_uc_rx_rsc_alt.ipa_reo_tp_paddr),
+		(void *)soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_base_paddr,
+		(void *)soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_base_vaddr,
+		srng_params.num_entries,
+		soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_size);
+
+	hal_srng = (struct hal_srng *)
+			pdev->rx_refill_buf_ring3.hal_srng;
+	hal_get_srng_params(hal_soc_to_hal_soc_handle(hal_soc),
+			    hal_srng_to_hal_ring_handle(hal_srng),
+			    &srng_params);
+	soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_base_paddr =
+		srng_params.ring_base_paddr;
+	soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_base_vaddr =
+		srng_params.ring_base_vaddr;
+	soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_size =
+		(srng_params.num_entries * srng_params.entry_size) << 2;
+	hp_addr = hal_srng_get_hp_addr(hal_soc_to_hal_soc_handle(hal_soc),
+				       hal_srng_to_hal_ring_handle(hal_srng));
+	soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_hp_paddr =
+		qdf_mem_paddr_from_dmaaddr(soc->osdev, hp_addr);
+
+	dp_info("IPA REFILL_BUF Ring hp_paddr=%x paddr=%pK vaddr=%pK size= %u(%u bytes)",
+		(unsigned int)(soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_hp_paddr),
+		(void *)soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_base_paddr,
+		(void *)soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_base_vaddr,
+		srng_params.num_entries,
+		soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_size);
+}
+#else
+static inline
+void dp_ipa_rx_alt_ring_resource_setup(struct dp_soc *soc, struct dp_pdev *pdev)
+{ }
+#endif
 /*
  * dp_ipa_ring_resource_setup() - setup IPA ring resources
  * @soc: data path SoC handle
@@ -1510,9 +1619,51 @@ int dp_ipa_ring_resource_setup(struct dp_soc *soc,
 
 	hal_reo_read_write_ctrl_ix(soc->hal_soc, false, &ix0, NULL, NULL, NULL);
 
+	dp_ipa_rx_alt_ring_resource_setup(soc, pdev);
 	return 0;
 }
 
+#ifdef IPA_WDI3_RX_TWO_PIPES
+/*
+ * dp_ipa_rx_alt_ring_get_resource() - get IPA 2nd RX ring resources
+ * @pdev: data path pdev handle
+ *
+ * Return: Success if resourece is found
+ */
+static QDF_STATUS dp_ipa_rx_alt_ring_get_resource(struct dp_pdev *pdev)
+{
+	struct dp_soc *soc = pdev->soc;
+	struct dp_ipa_resources *ipa_res = &pdev->ipa_resource;
+
+	if (!wlan_ipa_is_vlan_enabled())
+		return QDF_STATUS_SUCCESS;
+
+	dp_ipa_get_shared_mem_info(soc->osdev, &ipa_res->rx_alt_rdy_ring,
+				   soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_base_vaddr,
+				   soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_base_paddr,
+				   soc->ipa_uc_rx_rsc_alt.ipa_reo_ring_size);
+
+	dp_ipa_get_shared_mem_info(
+			soc->osdev, &ipa_res->rx_alt_refill_ring,
+			soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_base_vaddr,
+			soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_base_paddr,
+			soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_ring_size);
+
+	if (!qdf_mem_get_dma_addr(soc->osdev,
+				  &ipa_res->rx_alt_rdy_ring.mem_info) ||
+	    !qdf_mem_get_dma_addr(soc->osdev,
+				  &ipa_res->rx_alt_refill_ring.mem_info))
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static inline QDF_STATUS dp_ipa_rx_alt_ring_get_resource(struct dp_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 QDF_STATUS dp_ipa_get_resource(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 {
 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
@@ -1564,6 +1715,9 @@ QDF_STATUS dp_ipa_get_resource(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 	if (dp_ipa_tx_alt_ring_get_resource(pdev))
 		return QDF_STATUS_E_FAILURE;
 
+	if (dp_ipa_rx_alt_ring_get_resource(pdev))
+		return QDF_STATUS_E_FAILURE;
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -1574,6 +1728,70 @@ QDF_STATUS dp_ipa_get_resource(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 		dp_ipa_set_tx_doorbell_paddr(soc, ipa_res)
 #endif
 
+#ifdef IPA_WDI3_RX_TWO_PIPES
+/*
+ * dp_ipa_map_rx_alt_ring_doorbell_paddr() - Map 2nd rx ring doorbell paddr
+ * @pdev: data path pdev handle
+ *
+ * Return: none
+ */
+static void dp_ipa_map_rx_alt_ring_doorbell_paddr(struct dp_pdev *pdev)
+{
+	struct dp_ipa_resources *ipa_res = &pdev->ipa_resource;
+	uint32_t rx_ready_doorbell_dmaaddr;
+	struct dp_soc *soc = pdev->soc;
+	struct hal_srng *reo_srng = (struct hal_srng *)
+			soc->reo_dest_ring[IPA_ALT_REO_DEST_RING_IDX].hal_srng;
+	int ret = 0;
+
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	if (qdf_mem_smmu_s1_enabled(soc->osdev)) {
+		ret = pld_smmu_map(soc->osdev->dev,
+				   ipa_res->rx_alt_ready_doorbell_paddr,
+				   &rx_ready_doorbell_dmaaddr,
+				   sizeof(uint32_t));
+		ipa_res->rx_alt_ready_doorbell_paddr =
+					rx_ready_doorbell_dmaaddr;
+		qdf_assert_always(!ret);
+	}
+
+	hal_srng_dst_set_hp_paddr_confirm(reo_srng,
+					  ipa_res->rx_alt_ready_doorbell_paddr);
+}
+
+/*
+ * dp_ipa_unmap_rx_alt_ring_doorbell_paddr() - Unmap 2nd rx ring doorbell paddr
+ * @pdev: data path pdev handle
+ *
+ * Return: none
+ */
+static void dp_ipa_unmap_rx_alt_ring_doorbell_paddr(struct dp_pdev *pdev)
+{
+	struct dp_ipa_resources *ipa_res = &pdev->ipa_resource;
+	struct dp_soc *soc = pdev->soc;
+	int ret = 0;
+
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	if (!qdf_mem_smmu_s1_enabled(soc->osdev))
+		return;
+
+	ret = pld_smmu_unmap(soc->osdev->dev,
+			     ipa_res->rx_alt_ready_doorbell_paddr,
+			     sizeof(uint32_t));
+	qdf_assert_always(!ret);
+}
+#else
+static inline void dp_ipa_map_rx_alt_ring_doorbell_paddr(struct dp_pdev *pdev)
+{ }
+
+static inline void dp_ipa_unmap_rx_alt_ring_doorbell_paddr(struct dp_pdev *pdev)
+{ }
+#endif
+
 QDF_STATUS dp_ipa_set_doorbell_paddr(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 {
 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
@@ -1593,6 +1811,7 @@ QDF_STATUS dp_ipa_set_doorbell_paddr(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 		return QDF_STATUS_SUCCESS;
 
 	dp_ipa_map_ring_doorbell_paddr(pdev);
+	dp_ipa_map_rx_alt_ring_doorbell_paddr(pdev);
 
 	DP_IPA_SET_TX_DB_PADDR(soc, ipa_res);
 
@@ -1776,7 +1995,10 @@ QDF_STATUS dp_ipa_enable_autonomy(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 	ix_map[0] = REO_REMAP_SW1;
 	ix_map[1] = REO_REMAP_SW4;
 	ix_map[2] = REO_REMAP_SW1;
-	ix_map[3] = REO_REMAP_SW4;
+	if (wlan_ipa_is_vlan_enabled())
+		ix_map[3] = REO_REMAP_SW3;
+	else
+		ix_map[3] = REO_REMAP_SW4;
 	ix_map[4] = REO_REMAP_SW4;
 	ix_map[5] = REO_REMAP_RELEASE;
 	ix_map[6] = REO_REMAP_FW;
@@ -2064,6 +2286,208 @@ dp_ipa_wdi_rx_smmu_params(struct dp_soc *soc,
 		soc->rx_pkt_tlv_size + L3_HEADER_PADDING;
 }
 
+#ifdef IPA_WDI3_RX_TWO_PIPES
+/*
+ * dp_ipa_wdi_rx_alt_pipe_smmu_params() - Setup 2nd rx pipe smmu params
+ * @soc: data path soc handle
+ * @ipa_res: ipa resource pointer
+ * @rx_smmu: smmu pipe info handle
+ * @over_gsi: flag for IPA offload over gsi
+ * @hdl: ipa registered handle
+ *
+ * Return: none
+ */
+static void
+dp_ipa_wdi_rx_alt_pipe_smmu_params(struct dp_soc *soc,
+				   struct dp_ipa_resources *ipa_res,
+				   qdf_ipa_wdi_pipe_setup_info_smmu_t *rx_smmu,
+				   bool over_gsi,
+				   qdf_ipa_wdi_hdl_t hdl)
+{
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	if (over_gsi) {
+		if (hdl == DP_IPA_HDL_FIRST)
+			QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) =
+				IPA_CLIENT_WLAN2_PROD1;
+		else if (hdl == DP_IPA_HDL_SECOND)
+			QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) =
+				IPA_CLIENT_WLAN3_PROD1;
+	} else {
+		QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) =
+					IPA_CLIENT_WLAN1_PROD;
+	}
+
+	qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_BASE(rx_smmu),
+		     &ipa_res->rx_alt_rdy_ring.sgtable,
+		     sizeof(sgtable_t));
+	QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_SIZE(rx_smmu) =
+		qdf_mem_get_dma_size(soc->osdev,
+				     &ipa_res->rx_alt_rdy_ring.mem_info);
+	/* REO Tail Pointer Address */
+	QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_DOORBELL_PA(rx_smmu) =
+		soc->ipa_uc_rx_rsc_alt.ipa_reo_tp_paddr;
+	QDF_IPA_WDI_SETUP_INFO_SMMU_IS_TXR_RN_DB_PCIE_ADDR(rx_smmu) = true;
+
+	qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_BASE(rx_smmu),
+		     &ipa_res->rx_alt_refill_ring.sgtable,
+		     sizeof(sgtable_t));
+	QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_SIZE(rx_smmu) =
+		qdf_mem_get_dma_size(soc->osdev,
+				     &ipa_res->rx_alt_refill_ring.mem_info);
+
+	/* FW Head Pointer Address */
+	QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_DOORBELL_PA(rx_smmu) =
+		soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_hp_paddr;
+	QDF_IPA_WDI_SETUP_INFO_SMMU_IS_EVT_RN_DB_PCIE_ADDR(rx_smmu) = false;
+
+	QDF_IPA_WDI_SETUP_INFO_SMMU_PKT_OFFSET(rx_smmu) =
+		soc->rx_pkt_tlv_size + L3_HEADER_PADDING;
+}
+
+/*
+ * dp_ipa_wdi_rx_alt_pipe_smmu_params() - Setup 2nd rx pipe params
+ * @soc: data path soc handle
+ * @ipa_res: ipa resource pointer
+ * @rx: pipe info handle
+ * @over_gsi: flag for IPA offload over gsi
+ * @hdl: ipa registered handle
+ *
+ * Return: none
+ */
+static void dp_ipa_wdi_rx_alt_pipe_params(struct dp_soc *soc,
+					  struct dp_ipa_resources *ipa_res,
+					  qdf_ipa_wdi_pipe_setup_info_t *rx,
+					  bool over_gsi,
+					  qdf_ipa_wdi_hdl_t hdl)
+{
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	if (over_gsi) {
+		if (hdl == DP_IPA_HDL_FIRST)
+			QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) =
+				IPA_CLIENT_WLAN2_PROD1;
+		else if (hdl == DP_IPA_HDL_SECOND)
+			QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) =
+				IPA_CLIENT_WLAN3_PROD1;
+	} else {
+		QDF_IPA_WDI_SETUP_INFO_CLIENT(rx) =
+					IPA_CLIENT_WLAN1_PROD;
+	}
+
+	QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(rx) =
+		qdf_mem_get_dma_addr(soc->osdev,
+				     &ipa_res->rx_alt_rdy_ring.mem_info);
+	QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_SIZE(rx) =
+		qdf_mem_get_dma_size(soc->osdev,
+				     &ipa_res->rx_alt_rdy_ring.mem_info);
+
+	/* REO Tail Pointer Address */
+	QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_DOORBELL_PA(rx) =
+		soc->ipa_uc_rx_rsc_alt.ipa_reo_tp_paddr;
+	QDF_IPA_WDI_SETUP_INFO_IS_TXR_RN_DB_PCIE_ADDR(rx) = true;
+
+	QDF_IPA_WDI_SETUP_INFO_EVENT_RING_BASE_PA(rx) =
+		qdf_mem_get_dma_addr(soc->osdev,
+				     &ipa_res->rx_alt_refill_ring.mem_info);
+	QDF_IPA_WDI_SETUP_INFO_EVENT_RING_SIZE(rx) =
+		qdf_mem_get_dma_size(soc->osdev,
+				     &ipa_res->rx_alt_refill_ring.mem_info);
+
+	/* FW Head Pointer Address */
+	QDF_IPA_WDI_SETUP_INFO_EVENT_RING_DOORBELL_PA(rx) =
+		soc->ipa_uc_rx_rsc_alt.ipa_rx_refill_buf_hp_paddr;
+	QDF_IPA_WDI_SETUP_INFO_IS_EVT_RN_DB_PCIE_ADDR(rx) = false;
+
+	QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(rx) =
+		soc->rx_pkt_tlv_size + L3_HEADER_PADDING;
+}
+
+/*
+ * dp_ipa_setup_rx_alt_pipe() - Setup 2nd rx pipe for IPA offload
+ * @soc: data path soc handle
+ * @res: ipa resource pointer
+ * @in: pipe in handle
+ * @over_gsi: flag for IPA offload over gsi
+ * @hdl: ipa registered handle
+ *
+ * Return: none
+ */
+static void dp_ipa_setup_rx_alt_pipe(struct dp_soc *soc,
+				     struct dp_ipa_resources *res,
+				     qdf_ipa_wdi_conn_in_params_t *in,
+				     bool over_gsi,
+				     qdf_ipa_wdi_hdl_t hdl)
+{
+	qdf_ipa_wdi_pipe_setup_info_smmu_t *rx_smmu = NULL;
+	qdf_ipa_wdi_pipe_setup_info_t *rx = NULL;
+	qdf_ipa_ep_cfg_t *rx_cfg;
+
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	QDF_IPA_WDI_CONN_IN_PARAMS_IS_RX1_USED(in) = true;
+	if (qdf_mem_smmu_s1_enabled(soc->osdev)) {
+		rx_smmu = &QDF_IPA_WDI_CONN_IN_PARAMS_RX_ALT_SMMU(in);
+		rx_cfg = &QDF_IPA_WDI_SETUP_INFO_SMMU_EP_CFG(rx_smmu);
+		dp_ipa_wdi_rx_alt_pipe_smmu_params(soc, res, rx_smmu,
+						   over_gsi, hdl);
+	} else {
+		rx = &QDF_IPA_WDI_CONN_IN_PARAMS_RX_ALT(in);
+		rx_cfg = &QDF_IPA_WDI_SETUP_INFO_SMMU_EP_CFG(rx);
+		dp_ipa_wdi_rx_alt_pipe_params(soc, res, rx, over_gsi, hdl);
+	}
+
+	QDF_IPA_EP_CFG_NAT_EN(rx_cfg) = IPA_BYPASS_NAT;
+	/* Update with wds len(96) + 4 if wds support is enabled */
+	if (ucfg_ipa_is_wds_enabled())
+		QDF_IPA_EP_CFG_HDR_LEN(rx_cfg) = DP_IPA_UC_WLAN_RX_HDR_LEN_AST_VLAN;
+	else
+		QDF_IPA_EP_CFG_HDR_LEN(rx_cfg) = DP_IPA_UC_WLAN_TX_VLAN_HDR_LEN;
+	QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE_VALID(rx_cfg) = 1;
+	QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE(rx_cfg) = 0;
+	QDF_IPA_EP_CFG_HDR_ADDITIONAL_CONST_LEN(rx_cfg) = 0;
+	QDF_IPA_EP_CFG_HDR_OFST_METADATA_VALID(rx_cfg) = 0;
+	QDF_IPA_EP_CFG_HDR_METADATA_REG_VALID(rx_cfg) = 1;
+	QDF_IPA_EP_CFG_MODE(rx_cfg) = IPA_BASIC;
+	QDF_IPA_EP_CFG_HDR_LITTLE_ENDIAN(rx_cfg) = true;
+}
+
+/*
+ * dp_ipa_set_rx_alt_pipe_db() - Setup 2nd rx pipe doorbell
+ * @res: ipa resource pointer
+ * @out: pipe out handle
+ *
+ * Return: none
+ */
+static void dp_ipa_set_rx_alt_pipe_db(struct dp_ipa_resources *res,
+				      qdf_ipa_wdi_conn_out_params_t *out)
+{
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	res->rx_alt_ready_doorbell_paddr =
+			QDF_IPA_WDI_CONN_OUT_PARAMS_RX_ALT_UC_DB_PA(out);
+	dp_debug("Setting DB 0x%x for RX alt pipe",
+		 res->rx_alt_ready_doorbell_paddr);
+}
+#else
+static inline
+void dp_ipa_setup_rx_alt_pipe(struct dp_soc *soc,
+			      struct dp_ipa_resources *res,
+			      qdf_ipa_wdi_conn_in_params_t *in,
+			      bool over_gsi,
+			      qdf_ipa_wdi_hdl_t hdl)
+{ }
+
+static inline
+void dp_ipa_set_rx_alt_pipe_db(struct dp_ipa_resources *res,
+			       qdf_ipa_wdi_conn_out_params_t *out)
+{ }
+#endif
+
 QDF_STATUS dp_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id,
 			void *ipa_i2w_cb, void *ipa_w2i_cb,
 			void *ipa_wdi_meter_notifier_cb,
@@ -2174,6 +2598,9 @@ QDF_STATUS dp_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id,
 	else
 		dp_ipa_wdi_rx_params(soc, ipa_res, rx, over_gsi);
 
+	/* setup 2nd rx pipe */
+	dp_ipa_setup_rx_alt_pipe(soc, ipa_res, pipe_in, over_gsi, id);
+
 	QDF_IPA_WDI_CONN_IN_PARAMS_NOTIFY(pipe_in) = ipa_w2i_cb;
 	QDF_IPA_WDI_CONN_IN_PARAMS_PRIV(pipe_in) = ipa_priv;
 	QDF_IPA_WDI_CONN_IN_PARAMS_HANDLE(pipe_in) = hdl;
@@ -2196,6 +2623,7 @@ QDF_STATUS dp_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id,
 		(unsigned int)QDF_IPA_WDI_CONN_OUT_PARAMS_RX_UC_DB_PA(&pipe_out));
 
 	dp_ipa_set_pipe_db(ipa_res, &pipe_out);
+	dp_ipa_set_rx_alt_pipe_db(ipa_res, &pipe_out);
 
 	ipa_res->is_db_ddr_mapped =
 		QDF_IPA_WDI_CONN_OUT_PARAMS_IS_DB_DDR_MAPPED(&pipe_out);
@@ -2209,6 +2637,64 @@ QDF_STATUS dp_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef IPA_WDI3_RX_TWO_PIPES
+/*
+ * dp_ipa_set_rx1_used() - Set rx1 used flag for 2nd rx offload ring
+ * @in: pipe in handle
+ *
+ * Return: none
+ */
+static inline
+void dp_ipa_set_rx1_used(qdf_ipa_wdi_reg_intf_in_params_t *in)
+{
+	QDF_IPA_WDI_REG_INTF_IN_PARAMS_IS_RX1_USED(in) = true;
+}
+
+/*
+ * dp_ipa_set_v4_vlan_hdr() - Set v4 vlan hdr
+ * @in: pipe in handle
+ * hdr: pointer to hdr
+ *
+ * Return: none
+ */
+static inline
+void dp_ipa_set_v4_vlan_hdr(qdf_ipa_wdi_reg_intf_in_params_t *in,
+			    qdf_ipa_wdi_hdr_info_t *hdr)
+{
+	qdf_mem_copy(&(QDF_IPA_WDI_REG_INTF_IN_PARAMS_HDR_INFO(in)[IPA_IP_v4_VLAN]),
+		     hdr, sizeof(qdf_ipa_wdi_hdr_info_t));
+}
+
+/*
+ * dp_ipa_set_v6_vlan_hdr() - Set v6 vlan hdr
+ * @in: pipe in handle
+ * hdr: pointer to hdr
+ *
+ * Return: none
+ */
+static inline
+void dp_ipa_set_v6_vlan_hdr(qdf_ipa_wdi_reg_intf_in_params_t *in,
+			    qdf_ipa_wdi_hdr_info_t *hdr)
+{
+	qdf_mem_copy(&(QDF_IPA_WDI_REG_INTF_IN_PARAMS_HDR_INFO(in)[IPA_IP_v6_VLAN]),
+		     hdr, sizeof(qdf_ipa_wdi_hdr_info_t));
+}
+#else
+static inline
+void dp_ipa_set_rx1_used(qdf_ipa_wdi_reg_intf_in_params_t *in)
+{ }
+
+static inline
+void dp_ipa_set_v4_vlan_hdr(qdf_ipa_wdi_reg_intf_in_params_t *in,
+			    qdf_ipa_wdi_hdr_info_t *hdr)
+{ }
+
+static inline
+void dp_ipa_set_v6_vlan_hdr(qdf_ipa_wdi_reg_intf_in_params_t *in,
+			    qdf_ipa_wdi_hdr_info_t *hdr)
+{ }
+#endif
+
 /**
  * dp_ipa_setup_iface() - Setup IPA header and register interface
  * @ifname: Interface name
@@ -2231,6 +2717,8 @@ QDF_STATUS dp_ipa_setup_iface(char *ifname, uint8_t *mac_addr,
 	qdf_ipa_wdi_hdr_info_t hdr_info;
 	struct dp_ipa_uc_tx_hdr uc_tx_hdr;
 	struct dp_ipa_uc_tx_hdr uc_tx_hdr_v6;
+	struct dp_ipa_uc_tx_vlan_hdr uc_tx_vlan_hdr;
+	struct dp_ipa_uc_tx_vlan_hdr uc_tx_vlan_hdr_v6;
 	int ret = -EINVAL;
 
 	qdf_mem_zero(&in, sizeof(qdf_ipa_wdi_reg_intf_in_params_t));
@@ -2258,6 +2746,7 @@ QDF_STATUS dp_ipa_setup_iface(char *ifname, uint8_t *mac_addr,
 	QDF_IPA_WDI_REG_INTF_IN_PARAMS_META_DATA_MASK(&in) = WLAN_IPA_META_DATA_MASK;
 	QDF_IPA_WDI_REG_INTF_IN_PARAMS_HANDLE(&in) = hdl;
 	dp_ipa_setup_iface_session_id(&in, session_id);
+	dp_debug("registering for session_id: %u", session_id);
 
 	/* IPV6 header */
 	if (is_ipv6_enabled) {
@@ -2269,14 +2758,50 @@ QDF_STATUS dp_ipa_setup_iface(char *ifname, uint8_t *mac_addr,
 			     &hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t));
 	}
 
-	dp_debug("registering for session_id: %u", session_id);
+	if (wlan_ipa_is_vlan_enabled()) {
+		/* Add vlan specific headers if vlan supporti is enabled */
+		qdf_mem_zero(&hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t));
+		dp_ipa_set_rx1_used(&in);
+		qdf_ether_addr_copy(uc_tx_vlan_hdr.eth.h_source, mac_addr);
+		/* IPV4 Vlan header */
+		uc_tx_vlan_hdr.eth.h_vlan_proto = qdf_htons(ETH_P_8021Q);
+		uc_tx_vlan_hdr.eth.h_vlan_encapsulated_proto = qdf_htons(ETH_P_IP);
+
+		QDF_IPA_WDI_HDR_INFO_HDR(&hdr_info) =
+				(uint8_t *)&uc_tx_vlan_hdr;
+		QDF_IPA_WDI_HDR_INFO_HDR_LEN(&hdr_info) =
+				DP_IPA_UC_WLAN_TX_VLAN_HDR_LEN;
+		if (ucfg_ipa_is_wds_enabled())
+			QDF_IPA_WDI_HDR_INFO_HDR_TYPE(&hdr_info) =
+					IPA_HDR_L2_802_1Q_AST;
+		else
+			QDF_IPA_WDI_HDR_INFO_HDR_TYPE(&hdr_info) =
+					IPA_HDR_L2_802_1Q;
+
+		QDF_IPA_WDI_HDR_INFO_DST_MAC_ADDR_OFFSET(&hdr_info) =
+			DP_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
+
+		dp_ipa_set_v4_vlan_hdr(&in, &hdr_info);
+
+		/* IPV6 Vlan header */
+		if (is_ipv6_enabled) {
+			qdf_mem_copy(&uc_tx_vlan_hdr_v6, &uc_tx_vlan_hdr,
+				     DP_IPA_UC_WLAN_TX_VLAN_HDR_LEN);
+			uc_tx_vlan_hdr_v6.eth.h_vlan_proto =
+					qdf_htons(ETH_P_8021Q);
+			uc_tx_vlan_hdr_v6.eth.h_vlan_encapsulated_proto =
+					qdf_htons(ETH_P_IPV6);
+			QDF_IPA_WDI_HDR_INFO_HDR(&hdr_info) =
+					(uint8_t *)&uc_tx_vlan_hdr_v6;
+			dp_ipa_set_v6_vlan_hdr(&in, &hdr_info);
+		}
+	}
 
 	ret = qdf_ipa_wdi_reg_intf(&in);
-
 	if (ret) {
 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
-		    "%s: ipa_wdi_reg_intf: register IPA interface falied: ret=%d",
-		    __func__, ret);
+			  "%s: ipa_wdi_reg_intf: register IPA interface falied: ret=%d",
+			  __func__, ret);
 		return QDF_STATUS_E_FAILURE;
 	}
 
@@ -2581,6 +3106,7 @@ QDF_STATUS dp_ipa_cleanup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id,
 	}
 
 	dp_ipa_unmap_ring_doorbell_paddr(pdev);
+	dp_ipa_unmap_rx_alt_ring_doorbell_paddr(pdev);
 exit:
 	return status;
 }

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

@@ -35,6 +35,9 @@
 
 #define IPA_RX_REFILL_BUF_RING_IDX	2
 
+#define IPA_ALT_REO_DEST_RING_IDX	2
+#define IPA_RX_ALT_REFILL_BUF_RING_IDX	3
+
 /* Adding delay before disabling ipa pipes if any Tx Completions are pending */
 #define TX_COMP_DRAIN_WAIT_MS	50
 #define TX_COMP_DRAIN_WAIT_TIMEOUT_MS	100
@@ -64,6 +67,14 @@ struct dp_ipa_uc_tx_hdr {
 	struct ethhdr eth;
 } __packed;
 
+/**
+ * struct dp_ipa_uc_tx_hdr - full tx header registered to IPA hardware
+ * @eth:     ether II header
+ */
+struct dp_ipa_uc_tx_vlan_hdr {
+	struct vlan_ethhdr eth;
+} __packed;
+
 /**
  * struct dp_ipa_uc_rx_hdr - full rx header registered to IPA hardware
  * @eth:     ether II header
@@ -73,11 +84,13 @@ struct dp_ipa_uc_rx_hdr {
 } __packed;
 
 #define DP_IPA_UC_WLAN_TX_HDR_LEN      sizeof(struct dp_ipa_uc_tx_hdr)
+#define DP_IPA_UC_WLAN_TX_VLAN_HDR_LEN sizeof(struct dp_ipa_uc_tx_vlan_hdr)
 #define DP_IPA_UC_WLAN_RX_HDR_LEN      sizeof(struct dp_ipa_uc_rx_hdr)
 /* 28 <bytes of rx_msdu_end_tlv> + 16 <bytes of attn tlv> +
  * 52 <bytes of rx_mpdu_start_tlv> + <L2 Header>
  */
 #define DP_IPA_UC_WLAN_RX_HDR_LEN_AST  110
+#define DP_IPA_UC_WLAN_RX_HDR_LEN_AST_VLAN 114
 #define DP_IPA_UC_WLAN_HDR_DES_MAC_OFFSET	0
 
 #define DP_IPA_HDL_INVALID	0xFF

+ 216 - 18
dp/wifi3.0/dp_main.c

@@ -17,6 +17,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <wlan_ipa_obj_mgmt_api.h>
 #include <qdf_types.h>
 #include <qdf_lock.h>
 #include <qdf_net_types.h>
@@ -4093,6 +4094,53 @@ static void dp_soc_disable_unused_mac_intr_mask(struct dp_soc *soc,
 					      group_number, 0x0);
 }
 
+#ifdef IPA_OFFLOAD
+#ifdef IPA_WDI3_RX_TWO_PIPES
+/*
+ * dp_soc_reset_ipa_vlan_intr_mask() - reset interrupt mask for IPA offloaded
+ * ring for vlan tagged traffic
+ * @dp_soc - DP Soc handle
+ *
+ * Return: Return void
+ */
+static void dp_soc_reset_ipa_vlan_intr_mask(struct dp_soc *soc)
+{
+	uint8_t *grp_mask = NULL;
+	int group_number, mask;
+
+	if (!wlan_ipa_is_vlan_enabled())
+		return;
+
+	grp_mask = &soc->wlan_cfg_ctx->int_rx_ring_mask[0];
+
+	group_number = dp_srng_find_ring_in_mask(IPA_ALT_REO_DEST_RING_IDX, grp_mask);
+	if (group_number < 0) {
+		dp_init_debug("%pK: ring not part of any group; ring_type: %d,ring_num %d",
+			      soc, REO_DST, IPA_ALT_REO_DEST_RING_IDX);
+		return;
+	}
+
+	mask =  wlan_cfg_get_rx_ring_mask(soc->wlan_cfg_ctx, group_number);
+
+	/* reset the interrupt mask for offloaded ring */
+	mask &= (~(1 << IPA_ALT_REO_DEST_RING_IDX));
+
+	/*
+	 * set the interrupt mask to zero for rx offloaded radio.
+	 */
+	wlan_cfg_set_rx_ring_mask(soc->wlan_cfg_ctx, group_number, mask);
+}
+#else
+static inline
+void dp_soc_reset_ipa_vlan_intr_mask(struct dp_soc *soc)
+{ }
+#endif /* IPA_WDI3_RX_TWO_PIPES */
+#else
+static inline
+void dp_soc_reset_ipa_vlan_intr_mask(struct dp_soc *soc)
+{ }
+#endif /* IPA_OFFLOAD */
+
 /*
  * dp_soc_reset_intr_mask() - reset interrupt mask
  * @dp_soc - DP Soc handle
@@ -4249,10 +4297,21 @@ bool dp_reo_remap_config(struct dp_soc *soc, uint32_t *remap0,
 		break;
 
 	case CDP_ARCH_TYPE_LI:
-		hal_compute_reo_remap_ix2_ix3(soc->hal_soc, ring,
-					      soc->num_reo_dest_rings -
-					      USE_1_IPA_RX_REO_RING, remap1,
-					      remap2);
+		if (wlan_ipa_is_vlan_enabled()) {
+			hal_compute_reo_remap_ix2_ix3(
+					soc->hal_soc, ring,
+					soc->num_reo_dest_rings -
+					USE_2_IPA_RX_REO_RINGS, remap1,
+					remap2);
+
+		} else {
+			hal_compute_reo_remap_ix2_ix3(
+					soc->hal_soc, ring,
+					soc->num_reo_dest_rings -
+					USE_1_IPA_RX_REO_RING, remap1,
+					remap2);
+		}
+
 		hal_compute_reo_remap_ix0(soc->hal_soc, remap0);
 		break;
 	default:
@@ -5043,6 +5102,101 @@ static int dp_setup_ipa_rx_refill_buf_ring(struct dp_soc *soc,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef IPA_WDI3_RX_TWO_PIPES
+static int dp_setup_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					       struct dp_pdev *pdev)
+{
+	struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx;
+	int entries;
+
+	if (wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx) &&
+	    wlan_ipa_is_vlan_enabled()) {
+		soc_cfg_ctx = soc->wlan_cfg_ctx;
+		entries =
+			wlan_cfg_get_dp_soc_rxdma_refill_ring_size(soc_cfg_ctx);
+
+		/* Setup second Rx refill buffer ring */
+		if (dp_srng_alloc(soc, &pdev->rx_refill_buf_ring3, RXDMA_BUF,
+				  entries, 0)) {
+			dp_init_err("%pK: alloc failed for 3rd rx refill ring",
+				    soc);
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static int dp_init_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					      struct dp_pdev *pdev)
+{
+	if (wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx) &&
+	    wlan_ipa_is_vlan_enabled()) {
+		if (dp_srng_init(soc, &pdev->rx_refill_buf_ring3, RXDMA_BUF,
+				 IPA_RX_ALT_REFILL_BUF_RING_IDX,
+				 pdev->pdev_id)) {
+			dp_init_err("%pK: init failed for 3rd rx refill ring",
+				    soc);
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void dp_deinit_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+						 struct dp_pdev *pdev)
+{
+	if (wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx) &&
+	    wlan_ipa_is_vlan_enabled())
+		dp_srng_deinit(soc, &pdev->rx_refill_buf_ring3, RXDMA_BUF, 0);
+}
+
+static void dp_free_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					       struct dp_pdev *pdev)
+{
+	if (wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx) &&
+	    wlan_ipa_is_vlan_enabled())
+		dp_srng_free(soc, &pdev->rx_refill_buf_ring3);
+}
+#else
+static int dp_setup_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					       struct dp_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static int dp_init_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					      struct dp_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static void dp_deinit_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+						 struct dp_pdev *pdev)
+{
+}
+
+static void dp_free_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					       struct dp_pdev *pdev)
+{
+}
+#endif
+
+/**
+ * dp_deinit_ipa_rx_refill_buf_ring - deinit second Rx refill buffer ring
+ * @soc: data path instance
+ * @pdev: core txrx pdev context
+ *
+ * Return: void
+ */
+static void dp_deinit_ipa_rx_refill_buf_ring(struct dp_soc *soc,
+					     struct dp_pdev *pdev)
+{
+	if (wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx))
+		dp_srng_deinit(soc, &pdev->rx_refill_buf_ring2, RXDMA_BUF, 0);
+}
+
 /**
  * dp_init_ipa_rx_refill_buf_ring - Init second Rx refill buffer ring
  * @soc: data path instance
@@ -5062,21 +5216,13 @@ static int dp_init_ipa_rx_refill_buf_ring(struct dp_soc *soc,
 			return QDF_STATUS_E_FAILURE;
 		}
 	}
-	return QDF_STATUS_SUCCESS;
-}
 
-/**
- * dp_deinit_ipa_rx_refill_buf_ring - deinit second Rx refill buffer ring
- * @soc: data path instance
- * @pdev: core txrx pdev context
- *
- * Return: void
- */
-static void dp_deinit_ipa_rx_refill_buf_ring(struct dp_soc *soc,
-					     struct dp_pdev *pdev)
-{
-	if (wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx))
-		dp_srng_deinit(soc, &pdev->rx_refill_buf_ring2, RXDMA_BUF, 0);
+	if (dp_init_ipa_rx_alt_refill_buf_ring(soc, pdev)) {
+		dp_deinit_ipa_rx_refill_buf_ring(soc, pdev);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
 }
 
 /**
@@ -5114,6 +5260,22 @@ static void dp_free_ipa_rx_refill_buf_ring(struct dp_soc *soc,
 					   struct dp_pdev *pdev)
 {
 }
+
+static int dp_setup_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					       struct dp_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static void dp_deinit_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+						 struct dp_pdev *pdev)
+{
+}
+
+static void dp_free_ipa_rx_alt_refill_buf_ring(struct dp_soc *soc,
+					       struct dp_pdev *pdev)
+{
+}
 #endif
 
 #ifdef DP_TX_HW_DESC_HISTORY
@@ -5439,7 +5601,17 @@ QDF_STATUS dp_pdev_attach_wifi3(struct cdp_soc_t *txrx_soc,
 
 	soc->arch_ops.txrx_pdev_attach(pdev, params);
 
+	/* Setup third Rx refill buffer ring */
+	if (dp_setup_ipa_rx_alt_refill_buf_ring(soc, pdev)) {
+		dp_init_err("%pK: dp_srng_alloc failed rxrefill3 ring",
+			    soc);
+		goto fail6;
+	}
+
 	return QDF_STATUS_SUCCESS;
+
+fail6:
+	dp_monitor_pdev_detach(pdev);
 fail5:
 	dp_rx_pdev_desc_pool_free(pdev);
 fail4:
@@ -5591,6 +5763,7 @@ static void dp_pdev_deinit(struct cdp_pdev *txrx_pdev, int force)
 	dp_pdev_srng_deinit(pdev);
 
 	dp_ipa_uc_detach(pdev->soc, pdev);
+	dp_deinit_ipa_rx_alt_refill_buf_ring(pdev->soc, pdev);
 	dp_deinit_ipa_rx_refill_buf_ring(pdev->soc, pdev);
 	dp_rxdma_ring_cleanup(pdev->soc, pdev);
 
@@ -5691,6 +5864,7 @@ static void dp_pdev_detach(struct cdp_pdev *txrx_pdev, int force)
 	dp_monitor_pdev_detach(pdev);
 	dp_rxdma_ring_free(pdev);
 	dp_free_ipa_rx_refill_buf_ring(soc, pdev);
+	dp_free_ipa_rx_alt_refill_buf_ring(soc, pdev);
 	dp_pdev_srng_free(pdev);
 
 	soc->pdev_count--;
@@ -6016,6 +6190,25 @@ dp_htt_setup_rxdma_err_dst_ring(struct dp_soc *soc, int mac_id,
 			       RXDMA_DST);
 }
 
+#ifdef IPA_WDI3_RX_TWO_PIPES
+static inline
+void dp_rxdma_setup_refill_ring3(struct dp_soc *soc,
+				 struct dp_pdev *pdev,
+				 uint8_t idx)
+{
+	if (pdev->rx_refill_buf_ring3.hal_srng)
+		htt_srng_setup(soc->htt_handle, idx,
+			       pdev->rx_refill_buf_ring3.hal_srng,
+			       RXDMA_BUF);
+}
+#else
+static inline
+void dp_rxdma_setup_refill_ring3(struct dp_soc *soc,
+				 struct dp_pdev *pdev,
+				 uint8_t idx)
+{ }
+#endif
+
 static QDF_STATUS dp_rxdma_ring_config(struct dp_soc *soc)
 {
 	int i;
@@ -6042,6 +6235,8 @@ static QDF_STATUS dp_rxdma_ring_config(struct dp_soc *soc)
 					       .hal_srng,
 					       RXDMA_BUF);
 
+			dp_rxdma_setup_refill_ring3(soc, pdev, i);
+
 			dp_update_num_mac_rings_for_dbs(soc, &max_mac_rings);
 			dp_err("pdev_id %d max_mac_rings %d",
 			       pdev->pdev_id, max_mac_rings);
@@ -15665,6 +15860,9 @@ static QDF_STATUS dp_pdev_init(struct cdp_soc_t *txrx_soc,
 		dp_soc_reset_intr_mask(soc);
 	}
 
+	/* Reset the cpu ring map if radio is NSS offloaded */
+	dp_soc_reset_ipa_vlan_intr_mask(soc);
+
 	TAILQ_INIT(&pdev->vdev_list);
 	qdf_spinlock_create(&pdev->vdev_list_lock);
 	pdev->vdev_count = 0;

+ 28 - 15
dp/wifi3.0/dp_types.h

@@ -1722,6 +1722,21 @@ struct ipa_dp_tx_rsc {
 	void **tx_buf_pool_vaddr_unaligned;
 	qdf_dma_addr_t *tx_buf_pool_paddr_unaligned;
 };
+
+/* IPA uC datapath offload Wlan Rx resources */
+struct ipa_dp_rx_rsc {
+	/* Resource info to be passed to IPA */
+	qdf_dma_addr_t ipa_reo_ring_base_paddr;
+	void *ipa_reo_ring_base_vaddr;
+	uint32_t ipa_reo_ring_size;
+	qdf_dma_addr_t ipa_reo_tp_paddr;
+
+	/* Resource info to be passed to firmware and IPA */
+	qdf_dma_addr_t ipa_rx_refill_buf_ring_base_paddr;
+	void *ipa_rx_refill_buf_ring_base_vaddr;
+	uint32_t ipa_rx_refill_buf_ring_size;
+	qdf_dma_addr_t ipa_rx_refill_buf_hp_paddr;
+};
 #endif
 
 struct dp_tx_msdu_info_s;
@@ -2252,21 +2267,10 @@ struct dp_soc {
 	struct ipa_dp_tx_rsc ipa_uc_tx_rsc_alt;
 #endif
 
-	/* IPA uC datapath offload Wlan Rx resources */
-	struct {
-		/* Resource info to be passed to IPA */
-		qdf_dma_addr_t ipa_reo_ring_base_paddr;
-		void *ipa_reo_ring_base_vaddr;
-		uint32_t ipa_reo_ring_size;
-		qdf_dma_addr_t ipa_reo_tp_paddr;
-
-		/* Resource info to be passed to firmware and IPA */
-		qdf_dma_addr_t ipa_rx_refill_buf_ring_base_paddr;
-		void *ipa_rx_refill_buf_ring_base_vaddr;
-		uint32_t ipa_rx_refill_buf_ring_size;
-		qdf_dma_addr_t ipa_rx_refill_buf_hp_paddr;
-	} ipa_uc_rx_rsc;
-
+	struct ipa_dp_rx_rsc ipa_uc_rx_rsc;
+#ifdef IPA_WDI3_RX_TWO_PIPES
+	struct ipa_dp_rx_rsc ipa_uc_rx_rsc_alt;
+#endif
 	qdf_atomic_t ipa_pipes_enabled;
 	bool ipa_first_tx_db_access;
 	qdf_spinlock_t ipa_rx_buf_map_lock;
@@ -2493,6 +2497,11 @@ struct dp_ipa_resources {
 	qdf_dma_addr_t tx_alt_comp_doorbell_paddr;
 	uint32_t *tx_alt_comp_doorbell_vaddr;
 #endif
+#ifdef IPA_WDI3_RX_TWO_PIPES
+	qdf_shared_mem_t rx_alt_rdy_ring;
+	qdf_shared_mem_t rx_alt_refill_ring;
+	qdf_dma_addr_t rx_alt_ready_doorbell_paddr;
+#endif
 };
 #endif
 
@@ -2795,6 +2804,10 @@ struct dp_pdev {
 
 	/* Second ring used to replenish rx buffers */
 	struct dp_srng rx_refill_buf_ring2;
+#ifdef IPA_WDI3_RX_TWO_PIPES
+	/* Third ring used to replenish rx buffers */
+	struct dp_srng rx_refill_buf_ring3;
+#endif
 
 	/* Empty ring used by firmware to post rx buffers to the MAC */
 	struct dp_srng rx_mac_buf_ring[MAX_RX_MAC_RINGS];

+ 3 - 0
hal/wifi3.0/hal_internal.h

@@ -260,6 +260,9 @@ enum hal_srng_ring_id {
 #ifdef IPA_OFFLOAD
 	HAL_SRNG_WMAC1_SW2RXDMA0_BUF1,
 	HAL_SRNG_WMAC1_SW2RXDMA0_BUF2,
+#ifdef IPA_WDI3_RX_TWO_PIPES
+	HAL_SRNG_WMAC1_SW2RXDMA0_BUF3,
+#endif
 	HAL_SRNG_WMAC1_SW2RXDMA1_BUF,
 #else
 	HAL_SRNG_WMAC1_SW2RXDMA1_BUF,

+ 4 - 0
hal/wifi3.0/qcn9000/hal_9000.c

@@ -2273,7 +2273,11 @@ struct hal_hw_srng_config hw_srng_table_9000[] = {
 	{ /* RXDMA_BUF */
 		.start_ring_id = HAL_SRNG_WMAC1_SW2RXDMA0_BUF0,
 #ifdef IPA_OFFLOAD
+#ifdef IPA_WDI3_RX_TWO_PIPES
+		.max_rings = 4,
+#else
 		.max_rings = 3,
+#endif
 #else
 		.max_rings = 2,
 #endif