Prechádzať zdrojové kódy

Merge "qcacmn: Add a configure interface to get max_peers from OL_IF to DP"

Linux Build Service Account 7 rokov pred
rodič
commit
a6f86837f6
56 zmenil súbory, kde vykonal 1379 pridanie a 478 odobranie
  1. 5 0
      dp/inc/cdp_txrx_cfg.h
  2. 9 0
      dp/inc/cdp_txrx_cmn_struct.h
  3. 1 0
      dp/inc/cdp_txrx_ops.h
  4. 5 0
      dp/inc/cdp_txrx_stats_struct.h
  5. 1 1
      dp/wifi3.0/dp_htt.c
  6. 1 0
      dp/wifi3.0/dp_internal.h
  7. 58 13
      dp/wifi3.0/dp_main.c
  8. 91 0
      dp/wifi3.0/dp_peer.c
  9. 21 3
      dp/wifi3.0/dp_rx.c
  10. 7 2
      dp/wifi3.0/dp_rx.h
  11. 0 2
      dp/wifi3.0/dp_rx_desc.c
  12. 61 22
      dp/wifi3.0/dp_rx_err.c
  13. 52 70
      dp/wifi3.0/dp_rx_mon_dest.c
  14. 11 16
      dp/wifi3.0/dp_rx_mon_status.c
  15. 42 0
      dp/wifi3.0/dp_tx.c
  16. 11 1
      dp/wifi3.0/dp_types.h
  17. 41 4
      dp/wifi3.0/hal_rx.h
  18. 234 61
      hal/wifi3.0/hal_api_mon.h
  19. 11 0
      hal/wifi3.0/hal_internal.h
  20. 2 1
      hal/wifi3.0/hal_reo.h
  21. 1 7
      hif/inc/hif.h
  22. 59 0
      hif/inc/hif_unit_test_suspend.h
  23. 8 9
      hif/src/ce/ce_assignment.h
  24. 28 11
      hif/src/ce/ce_main.c
  25. 16 10
      hif/src/ce/ce_service.c
  26. 11 91
      hif/src/ce/ce_tasklet.c
  27. 3 0
      hif/src/hif_main.c
  28. 2 17
      hif/src/hif_main.h
  29. 114 0
      hif/src/hif_unit_test_suspend.c
  30. 84 0
      hif/src/hif_unit_test_suspend_i.h
  31. 2 1
      hif/src/snoc/if_ahb.c
  32. 2 0
      os_if/linux/scan/inc/wlan_cfg80211_scan.h
  33. 40 4
      os_if/linux/scan/src/wlan_cfg80211_scan.c
  34. 75 73
      pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c
  35. 12 0
      qdf/inc/qdf_nbuf.h
  36. 1 1
      qdf/linux/src/i_qdf_lock.h
  37. 3 15
      qdf/linux/src/i_qdf_nbuf.h
  38. 1 1
      qdf/linux/src/qdf_nbuf.c
  39. 5 7
      qdf/linux/src/qdf_trace.c
  40. 11 0
      umac/cmn_services/obj_mgr/src/wlan_objmgr_pdev_obj.c
  41. 18 0
      umac/cmn_services/obj_mgr/src/wlan_objmgr_peer_obj.c
  42. 11 0
      umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c
  43. 11 0
      umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c
  44. 19 3
      umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
  45. 1 27
      umac/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c
  46. 42 2
      umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  47. 6 1
      umac/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c
  48. 2 0
      umac/scan/dispatcher/inc/wlan_scan_public_structs.h
  49. 2 0
      utils/host_diag_log/inc/host_diag_core_event.h
  50. 8 2
      wlan_cfg/wlan_cfg.c
  51. 3 0
      wlan_cfg/wlan_cfg.h
  52. 2 0
      wmi/inc/wmi_unified_api.h
  53. 18 0
      wmi/inc/wmi_unified_param.h
  54. 3 0
      wmi/inc/wmi_unified_priv.h
  55. 20 0
      wmi/src/wmi_unified_api.c
  56. 71 0
      wmi/src/wmi_unified_tlv.c

+ 5 - 0
dp/inc/cdp_txrx_cfg.h

@@ -254,4 +254,9 @@ static inline void cdp_cfg_set_flow_steering(ol_txrx_soc_handle soc,
 
 	return;
 }
+
+static inline void cdp_cfg_get_max_peer_id(ol_txrx_soc_handle soc,
+		struct cdp_cfg *cfg_pdev)
+{
+}
 #endif /* _CDP_TXRX_CFG_H_ */

+ 9 - 0
dp/inc/cdp_txrx_cmn_struct.h

@@ -89,6 +89,15 @@
 		WME_AC_VO)
 
 #define CDP_MAX_RX_RINGS 4
+
+/*
+ * DP configuration parameters
+ */
+enum cdp_cfg_param_type {
+	CDP_CFG_MAX_PEER_ID,
+	CDP_CFG_NUM_PARAMS
+};
+
 /*
  * htt_dbg_stats_type -
  * bit positions for each stats type within a stats type bitmask

+ 1 - 0
dp/inc/cdp_txrx_ops.h

@@ -615,6 +615,7 @@ struct ol_if_ops {
 			uint8_t vdev_id, uint8_t *peer_mac_addr);
 	int (*peer_unmap_event)(void *ol_soc_handle, uint16_t peer_id);
 
+	int (*get_dp_cfg_param)(void *ol_soc_handle, enum cdp_cfg_param_type param_num);
 
 	/* TODO: Add any other control path calls required to OL_IF/WMA layer */
 };

+ 5 - 0
dp/inc/cdp_txrx_stats_struct.h

@@ -213,6 +213,11 @@ struct ol_ath_radiostats {
 	A_INT16     chan_nf;
 	A_UINT32    rx_last_msdu_unset_cnt;
 	A_INT16     chan_nf_sec80;
+	A_UINT64    wmi_tx_mgmt;
+	A_UINT64    wmi_tx_mgmt_completions;
+	A_UINT32    wmi_tx_mgmt_completion_err;
+	A_UINT32    peer_delete_req;
+	A_UINT32    peer_delete_resp;
 };
 
 #ifndef CONFIG_WIN

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

@@ -815,7 +815,7 @@ int htt_h2t_rx_ring_cfg(void *htt_soc, int pdev_id, void *hal_srng,
 	htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PACKET_HEADER,
 		htt_tlv_filter->packet_header);
 	htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, ATTENTION,
-		htt_tlv_filter->ppdu_end_status_done);
+		htt_tlv_filter->attention);
 	htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PPDU_START,
 		htt_tlv_filter->ppdu_start);
 	htt_rx_ring_tlv_filter_in_enable_set(tlv_filter, PPDU_END,

+ 1 - 0
dp/wifi3.0/dp_internal.h

@@ -284,4 +284,5 @@ QDF_STATUS dp_h2t_ext_stats_msg_send(struct dp_pdev *pdev,
 		uint32_t config_param_1, uint32_t config_param_2,
 		uint32_t config_param_3);
 void dp_htt_stats_print_tag(uint8_t tag_type, uint32_t *tag_buf);
+int dp_peer_rxtid_stats(struct dp_peer *peer);
 #endif /* #ifndef _DP_INTERNAL_H_ */

+ 58 - 13
dp/wifi3.0/dp_main.c

@@ -422,9 +422,21 @@ static QDF_STATUS dp_soc_interrupt_attach(void *txrx_soc)
 		int rx_mon_mask =
 			wlan_cfg_get_rx_mon_ring_mask(soc->wlan_cfg_ctx, i);
 
+		/*
+		 * Mapping the exception/status rings to IRQ Group 0 (CPU 0).
+		 * Later add wlan_cfg interface for these masks
+		 */
+		int rx_err_ring_mask = 0x1;
+		int rx_wbm_rel_ring_mask = 0x1;
+		int reo_status_ring_mask = 0x1;
+
 		soc->intr_ctx[i].tx_ring_mask = tx_mask;
 		soc->intr_ctx[i].rx_ring_mask = rx_mask;
 		soc->intr_ctx[i].rx_mon_ring_mask = rx_mon_mask;
+		soc->intr_ctx[i].rx_err_ring_mask = rx_err_ring_mask;
+		soc->intr_ctx[i].rx_wbm_rel_ring_mask = rx_wbm_rel_ring_mask;
+		soc->intr_ctx[i].reo_status_ring_mask = reo_status_ring_mask;
+
 		soc->intr_ctx[i].soc = soc;
 
 		num_irq = 0;
@@ -446,6 +458,16 @@ static QDF_STATUS dp_soc_interrupt_attach(void *txrx_soc)
 					(rxdma2host_monitor_destination_mac1
 					 - j);
 			}
+
+			if (rx_wbm_rel_ring_mask & (1 << j))
+				irq_id_map[num_irq++] = wbm2host_rx_release;
+
+			if (rx_err_ring_mask & (1 << j))
+				irq_id_map[num_irq++] = reo2host_exception;
+
+			if (reo_status_ring_mask & (1 << j))
+				irq_id_map[num_irq++] = reo2host_status;
+
 		}
 
 
@@ -636,10 +658,10 @@ static int dp_hw_link_desc_pool_setup(struct dp_soc *soc)
 		for (i = 0; i < MAX_LINK_DESC_BANKS &&
 			soc->link_desc_banks[i].base_paddr; i++) {
 			uint32_t num_entries = (soc->link_desc_banks[i].size -
-				(unsigned long)(
+				((unsigned long)(
 				soc->link_desc_banks[i].base_vaddr) -
 				(unsigned long)(
-				soc->link_desc_banks[i].base_vaddr_unaligned))
+				soc->link_desc_banks[i].base_vaddr_unaligned)))
 				/ link_desc_size;
 			unsigned long paddr = (unsigned long)(
 				soc->link_desc_banks[i].base_paddr);
@@ -694,11 +716,11 @@ static int dp_hw_link_desc_pool_setup(struct dp_soc *soc)
 			soc->link_desc_banks[i].base_paddr; i++) {
 			uint32_t num_link_descs =
 				(soc->link_desc_banks[i].size -
-				(unsigned long)(
+				((unsigned long)(
 				soc->link_desc_banks[i].base_vaddr) -
 				(unsigned long)(
-				soc->link_desc_banks[i].base_vaddr_unaligned)) /
-				link_desc_size;
+				soc->link_desc_banks[i].base_vaddr_unaligned)))
+				/ link_desc_size;
 			unsigned long paddr = (unsigned long)(
 				soc->link_desc_banks[i].base_paddr);
 			void *desc = NULL;
@@ -1153,6 +1175,7 @@ static struct cdp_pdev *dp_pdev_attach_wifi3(struct cdp_soc_t *txrx_soc,
 	TAILQ_INIT(&pdev->vdev_list);
 	pdev->vdev_count = 0;
 
+	qdf_spinlock_create(&pdev->tx_mutex);
 	qdf_spinlock_create(&pdev->neighbour_peer_mutex);
 	TAILQ_INIT(&pdev->neighbour_peers_list);
 
@@ -1348,6 +1371,7 @@ static void dp_pdev_detach_wifi3(struct cdp_pdev *txrx_pdev, int force)
 	dp_rx_pdev_mon_detach(pdev);
 
 	dp_neighbour_peers_detach(pdev);
+	qdf_spinlock_destroy(&pdev->tx_mutex);
 
 	/* Setup per PDEV REO rings if configured */
 	if (wlan_cfg_per_pdev_rx_ring(soc->wlan_cfg_ctx)) {
@@ -2389,8 +2413,8 @@ static int dp_vdev_set_monitor_mode(struct cdp_vdev *vdev_handle,
 	htt_tlv_filter.enable_mo = 1;
 
 	htt_h2t_rx_ring_cfg(soc->htt_handle, pdev_id,
-		pdev->rxdma_mon_dst_ring.hal_srng,
-		RXDMA_MONITOR_BUF,  RX_BUFFER_SIZE, &htt_tlv_filter);
+		pdev->rxdma_mon_buf_ring.hal_srng,
+		RXDMA_MONITOR_BUF, RX_BUFFER_SIZE, &htt_tlv_filter);
 
 	htt_tlv_filter.mpdu_start = 1;
 	htt_tlv_filter.msdu_start = 1;
@@ -2405,13 +2429,12 @@ static int dp_vdev_set_monitor_mode(struct cdp_vdev *vdev_handle,
 	htt_tlv_filter.ppdu_end_user_stats_ext = 1;
 	htt_tlv_filter.ppdu_end_status_done = 1;
 	htt_tlv_filter.enable_fp = 1;
-	htt_tlv_filter.enable_md = 1;
+	htt_tlv_filter.enable_md = 0;
 	htt_tlv_filter.enable_mo = 1;
-	/*
-	 * htt_h2t_rx_ring_cfg(soc->htt_handle, pdev_id,
-	 * pdev->rxdma_mon_status_ring.hal_srng,
-	 * RXDMA_MONITOR_STATUS, RX_BUFFER_SIZE, &htt_tlv_filter);
-	 */
+
+	htt_h2t_rx_ring_cfg(soc->htt_handle, pdev_id,
+		pdev->rxdma_mon_status_ring.hal_srng, RXDMA_MONITOR_STATUS,
+		RX_BUFFER_SIZE, &htt_tlv_filter);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -2864,6 +2887,9 @@ dp_print_soc_rx_stats(struct dp_soc *soc)
 
 	DP_TRACE_STATS(FATAL, "SOC Rx Stats:\n");
 	DP_TRACE_STATS(FATAL, "Errors:\n");
+	DP_TRACE_STATS(FATAL, "Rx Decrypt Errors = %d",
+			(soc->stats.rx.err.rxdma_error[HAL_RXDMA_ERR_DECRYPT] +
+			soc->stats.rx.err.rxdma_error[HAL_RXDMA_ERR_TKIP_MIC]));
 	DP_TRACE_STATS(FATAL, "Invalid RBM = %d",
 			soc->stats.rx.err.invalid_rbm);
 	DP_TRACE_STATS(FATAL, "Invalid Vdev = %d",
@@ -2874,6 +2900,7 @@ dp_print_soc_rx_stats(struct dp_soc *soc)
 			soc->stats.rx.err.rx_invalid_peer.num);
 	DP_TRACE_STATS(FATAL, "HAL Ring Access Fail = %d",
 			soc->stats.rx.err.hal_ring_access_fail);
+
 	for (i = 0; i < MAX_RXDMA_ERRORS; i++) {
 		index += qdf_snprint(&rxdma_error[index],
 				DP_RXDMA_ERR_LENGTH - index,
@@ -3346,7 +3373,14 @@ dp_get_host_peer_stats(struct cdp_pdev *pdev_handle, char *mac_addr)
 	peer = (struct dp_peer *)dp_find_peer_by_addr(pdev_handle, mac_addr,
 			&local_id);
 
+	if (!peer) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			"%s: Invalid peer\n", __func__);
+		return;
+	}
+
 	dp_print_peer_stats(peer);
+	dp_peer_rxtid_stats(peer);
 	return;
 }
 
@@ -3389,6 +3423,7 @@ dp_get_fw_peer_stats(struct cdp_pdev *pdev_handle, uint8_t *mac_addr,
 	dp_h2t_ext_stats_msg_send(pdev, HTT_DBG_EXT_STATS_PEER_INFO,
 			config_param0, config_param1, config_param2,
 			config_param3);
+
 }
 
 /*
@@ -4002,6 +4037,16 @@ void *dp_soc_attach_wifi3(void *osif_soc, void *hif_handle,
 				FL("wlan_cfg_soc_attach failed"));
 		goto fail2;
 	}
+
+	if (soc->cdp_soc.ol_ops->get_dp_cfg_param) {
+		int ret = soc->cdp_soc.ol_ops->get_dp_cfg_param(soc,
+				CDP_CFG_MAX_PEER_ID);
+
+		if (ret != -EINVAL) {
+			wlan_cfg_set_max_peer_id(soc->wlan_cfg_ctx, ret);
+		}
+	}
+
 	qdf_spinlock_create(&soc->peer_ref_mutex);
 
 	qdf_spinlock_create(&soc->reo_desc_freelist_lock);

+ 91 - 0
dp/wifi3.0/dp_peer.c

@@ -318,6 +318,69 @@ int dp_peer_find_attach(struct dp_soc *soc)
 	return 0; /* success */
 }
 
+static void dp_rx_tid_stats_cb(struct dp_soc *soc, void *cb_ctxt,
+	union hal_reo_status *reo_status)
+{
+	struct dp_rx_tid *rx_tid = (struct dp_rx_tid *)cb_ctxt;
+	struct hal_reo_queue_status *queue_status = &(reo_status->queue_status);
+
+	if (queue_status->header.status != HAL_REO_CMD_SUCCESS) {
+		DP_TRACE_STATS(FATAL, "REO stats failure %d for TID %d\n",
+			queue_status->header.status, rx_tid->tid);
+		return;
+	}
+
+	DP_TRACE_STATS(FATAL, "REO queue stats (TID: %d): \n"
+		"ssn: %d\n"
+		"curr_idx  : %d\n"
+		"pn_31_0   : %08x\n"
+		"pn_63_32  : %08x\n"
+		"pn_95_64  : %08x\n"
+		"pn_127_96 : %08x\n"
+		"last_rx_enq_tstamp : %08x\n"
+		"last_rx_deq_tstamp : %08x\n"
+		"rx_bitmap_31_0     : %08x\n"
+		"rx_bitmap_63_32    : %08x\n"
+		"rx_bitmap_95_64    : %08x\n"
+		"rx_bitmap_127_96   : %08x\n"
+		"rx_bitmap_159_128  : %08x\n"
+		"rx_bitmap_191_160  : %08x\n"
+		"rx_bitmap_223_192  : %08x\n"
+		"rx_bitmap_255_224  : %08x\n"
+		"curr_mpdu_cnt      : %d\n"
+		"curr_msdu_cnt      : %d\n"
+		"fwd_timeout_cnt    : %d\n"
+		"fwd_bar_cnt        : %d\n"
+		"dup_cnt            : %d\n"
+		"frms_in_order_cnt  : %d\n"
+		"bar_rcvd_cnt       : %d\n"
+		"mpdu_frms_cnt      : %d\n"
+		"msdu_frms_cnt      : %d\n"
+		"total_byte_cnt     : %d\n"
+		"late_recv_mpdu_cnt : %d\n"
+		"win_jump_2k 	    : %d\n"
+		"hole_cnt 	    : %d\n",
+		rx_tid->tid,
+		queue_status->ssn, queue_status->curr_idx,
+		queue_status->pn_31_0, queue_status->pn_63_32,
+		queue_status->pn_95_64, queue_status->pn_127_96,
+		queue_status->last_rx_enq_tstamp,
+		queue_status->last_rx_deq_tstamp,
+		queue_status->rx_bitmap_31_0, queue_status->rx_bitmap_63_32,
+		queue_status->rx_bitmap_95_64, queue_status->rx_bitmap_127_96,
+		queue_status->rx_bitmap_159_128,
+		queue_status->rx_bitmap_191_160,
+		queue_status->rx_bitmap_223_192,
+		queue_status->rx_bitmap_255_224,
+		queue_status->curr_mpdu_cnt, queue_status->curr_msdu_cnt,
+		queue_status->fwd_timeout_cnt, queue_status->fwd_bar_cnt,
+		queue_status->dup_cnt, queue_status->frms_in_order_cnt,
+		queue_status->bar_rcvd_cnt, queue_status->mpdu_frms_cnt,
+		queue_status->msdu_frms_cnt, queue_status->total_cnt,
+		queue_status->late_recv_mpdu_cnt, queue_status->win_jump_2k,
+		queue_status->hole_cnt);
+}
+
 static inline void dp_peer_find_add_id(struct dp_soc *soc,
 	uint8_t *peer_mac_addr, uint16_t peer_id, uint16_t hw_peer_id,
 	uint8_t vdev_id)
@@ -1536,3 +1599,31 @@ uint8_t dp_get_peer_mac_addr_frm_id(struct cdp_soc_t *soc_handle,
 	qdf_mem_copy(peer_mac, peer->mac_addr.raw, 6);
 	return peer->vdev->vdev_id;
 }
+
+/**
+ * dp_peer_rxtid_stats: Retried Rx TID (REO queue) stats from HW
+ * @peer: DP peer handle
+ *
+ * Return: 0 on success, error code on failure
+ */
+int dp_peer_rxtid_stats(struct dp_peer *peer)
+{
+	struct dp_soc *soc = peer->vdev->pdev->soc;
+	struct hal_reo_cmd_params params;
+	int i;
+
+	qdf_mem_zero(&params, sizeof(params));
+	for (i = 0; i < DP_MAX_TIDS; i++) {
+		struct dp_rx_tid *rx_tid = &peer->rx_tid[i];
+		if (rx_tid->hw_qdesc_vaddr_unaligned != NULL) {
+			params.std.need_status = 1;
+			params.std.addr_lo =
+				rx_tid->hw_qdesc_paddr & 0xffffffff;
+			params.std.addr_hi =
+				(uint64_t)(rx_tid->hw_qdesc_paddr) >> 32;
+			dp_reo_send_cmd(soc, CMD_GET_QUEUE_STATS, &params,
+				dp_rx_tid_stats_cb, rx_tid);
+		}
+	}
+	return 0;
+}

+ 21 - 3
dp/wifi3.0/dp_rx.c

@@ -29,6 +29,19 @@
 #include "dp_internal.h"
 #include "dp_rx_mon.h"
 
+#ifdef RX_DESC_DEBUG_CHECK
+static inline void dp_rx_desc_prep(struct dp_rx_desc *rx_desc, qdf_nbuf_t nbuf)
+{
+	rx_desc->magic = DP_RX_DESC_MAGIC;
+	rx_desc->nbuf = nbuf;
+}
+#else
+static inline void dp_rx_desc_prep(struct dp_rx_desc *rx_desc, qdf_nbuf_t nbuf)
+{
+	rx_desc->nbuf = nbuf;
+}
+#endif
+
 /*
  * dp_rx_buffers_replenish() - replenish rxdma ring with rx nbufs
  *			       called during dp rx initialization
@@ -160,7 +173,7 @@ QDF_STATUS dp_rx_buffers_replenish(struct dp_soc *dp_soc, uint32_t mac_id,
 
 		next = (*desc_list)->next;
 
-		(*desc_list)->rx_desc.nbuf = rx_netbuf;
+		dp_rx_desc_prep(&((*desc_list)->rx_desc), rx_netbuf);
 
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
 				"rx_netbuf=%p, buf=%p, paddr=0x%llx, cookie=%d\n",
@@ -337,6 +350,8 @@ dp_rx_intrabss_fwd(struct dp_soc *soc,
 		if (da_peer->vdev == sa_peer->vdev && !da_peer->bss_peer) {
 			memset(nbuf->cb, 0x0, sizeof(nbuf->cb));
 			len = qdf_nbuf_len(nbuf);
+			qdf_nbuf_set_fctx_type(nbuf, (void *)NULL,
+						CB_FTYPE_INTRABSS_FWD);
 			if (!dp_tx_send(sa_peer->vdev, nbuf)) {
 				DP_STATS_INC_PKT(sa_peer, rx.intra_bss.pkts,
 						1, len);
@@ -363,9 +378,12 @@ dp_rx_intrabss_fwd(struct dp_soc *soc,
 			return false;
 		memset(nbuf_copy->cb, 0x0, sizeof(nbuf_copy->cb));
 		len = qdf_nbuf_len(nbuf_copy);
-		if (dp_tx_send(sa_peer->vdev, nbuf_copy))
+		qdf_nbuf_set_fctx_type(nbuf_copy, (void *)NULL,
+					CB_FTYPE_INTRABSS_FWD);
+		if (dp_tx_send(sa_peer->vdev, nbuf_copy)) {
+			DP_STATS_INC_PKT(sa_peer, rx.intra_bss.fail, 1, len);
 			qdf_nbuf_free(nbuf_copy);
-		else
+		} else
 			DP_STATS_INC_PKT(sa_peer, rx.intra_bss.pkts, 1, len);
 	}
 	/* return false as we have to still send the original pkt

+ 7 - 2
dp/wifi3.0/dp_rx.h

@@ -45,6 +45,8 @@
 	(((_peer_metadata) & DP_PEER_METADATA_VDEV_ID_MASK)	\
 			>> DP_PEER_METADATA_VDEV_ID_SHIFT)
 
+#define DP_RX_DESC_MAGIC 0xdec0de
+
 /**
  * struct dp_rx_desc
  *
@@ -65,6 +67,9 @@ struct dp_rx_desc {
 	uint8_t *rx_buf_start;
 	uint32_t cookie;
 	uint8_t	 pool_id;
+#ifdef RX_DESC_DEBUG_CHECK
+	uint32_t magic;
+#endif
 };
 
 #define RX_DESC_COOKIE_INDEX_SHIFT		0
@@ -343,13 +348,13 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc,
 
 	if (!hal_rx_msdu_end_sa_is_valid_get(rx_tlv_hdr)) {
 		ret = soc->cdp_soc.ol_ops->peer_add_wds_entry(
-						soc->osif_soc,
+						ta_peer->vdev->pdev->osif_pdev,
 						wds_src_mac,
 						ta_peer->mac_addr.raw,
 						flags);
 	} else if (sa_sw_peer_id != ta_peer->peer_ids[0]) {
 		ret = soc->cdp_soc.ol_ops->peer_update_wds_entry(
-						soc->osif_soc,
+						ta_peer->vdev->pdev->osif_pdev,
 						wds_src_mac,
 						ta_peer->mac_addr.raw,
 						flags);

+ 0 - 2
dp/wifi3.0/dp_rx_desc.c

@@ -55,13 +55,11 @@ QDF_STATUS dp_rx_desc_pool_alloc(struct dp_soc *soc, uint32_t pool_id,
 		rx_desc_pool->array[i].next = &rx_desc_pool->array[i+1];
 		rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18);
 		rx_desc_pool->array[i].rx_desc.pool_id = pool_id;
-		rx_desc_pool->array[i].rx_desc.nbuf = NULL;
 	}
 
 	rx_desc_pool->array[i].next = NULL;
 	rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18);
 	rx_desc_pool->array[i].rx_desc.pool_id = pool_id;
-	rx_desc_pool->array[i].rx_desc.nbuf = NULL;
 	qdf_spin_unlock_bh(&soc->rx_desc_mutex[pool_id]);
 	return QDF_STATUS_SUCCESS;
 }

+ 61 - 22
dp/wifi3.0/dp_rx_err.c

@@ -31,6 +31,22 @@
 #include "dp_rx_defrag.h"
 #include <enet.h>	/* LLC_SNAP_HDR_LEN */
 
+#ifdef RX_DESC_DEBUG_CHECK
+static inline bool dp_rx_desc_check_magic(struct dp_rx_desc *rx_desc)
+{
+	if (qdf_unlikely(rx_desc->magic != DP_RX_DESC_MAGIC)) {
+		return false;
+	}
+	rx_desc->magic = 0;
+	return true;
+}
+#else
+static inline bool dp_rx_desc_check_magic(struct dp_rx_desc *rx_desc)
+{
+	return true;
+}
+#endif
+
 /**
  * dp_rx_msdus_drop() - Drops all MSDU's per MPDU
  *
@@ -46,10 +62,10 @@
  * Return: uint32_t: No. of elements processed
  */
 static uint32_t dp_rx_msdus_drop(struct dp_soc *soc, void *ring_desc,
-		 struct hal_rx_mpdu_desc_info *mpdu_desc_info,
-		 union dp_rx_desc_list_elem_t **head,
-		 union dp_rx_desc_list_elem_t **tail,
-		 uint32_t quota)
+		struct hal_rx_mpdu_desc_info *mpdu_desc_info,
+		union dp_rx_desc_list_elem_t **head,
+		union dp_rx_desc_list_elem_t **tail,
+		uint32_t quota)
 {
 	uint32_t rx_bufs_used = 0;
 	void *link_desc_va;
@@ -72,6 +88,13 @@ static uint32_t dp_rx_msdus_drop(struct dp_soc *soc, void *ring_desc,
 
 		qdf_assert(rx_desc);
 
+		if (!dp_rx_desc_check_magic(rx_desc)) {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+					FL("Invalid rx_desc cookie=%d"),
+					msdu_list.sw_cookie[i]);
+			return rx_bufs_used;
+		}
+
 		rx_bufs_used++;
 
 		/* Just free the buffers */
@@ -224,6 +247,9 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc,
 	uint16_t peer_id = 0xFFFF;
 	struct dp_peer *peer = NULL;
 	uint32_t sgi, rate_mcs, tid;
+	uint8_t count;
+	struct mect_entry *mect_entry;
+	uint8_t *nbuf_data = NULL;
 
 	rx_bufs_used++;
 
@@ -293,11 +319,6 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc,
 		"%s: %d, SGI: %d, rate_mcs: %d, tid: %d",
 		__func__, __LINE__, sgi, rate_mcs, tid);
 
-	/* WDS Source Port Learning */
-	if (qdf_likely(vdev->rx_decap_type == htt_cmn_pkt_type_ethernet) &&
-			(vdev->wds_enabled))
-		dp_rx_wds_srcport_learn(soc, rx_desc->rx_buf_start, peer, nbuf);
-
 	/*
 	 * Advance the packet start pointer by total size of
 	 * pre-header TLV's
@@ -307,6 +328,28 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc,
 	if (l2_hdr_offset)
 		qdf_nbuf_pull_head(nbuf, l2_hdr_offset);
 
+	nbuf_data = qdf_nbuf_data(nbuf);
+	for (count = 0; count < soc->mect_cnt; count++) {
+		mect_entry = &soc->mect_table[count];
+		mect_entry->ts = jiffies_64;
+		if (!(memcmp(mect_entry->mac_addr, &nbuf_data[DP_MAC_ADDR_LEN],
+				DP_MAC_ADDR_LEN))) {
+			QDF_TRACE(QDF_MODULE_ID_DP,
+				QDF_TRACE_LEVEL_INFO,
+				FL("received pkt with same src MAC"));
+
+			/* Drop & free packet */
+			qdf_nbuf_free(nbuf);
+			/* Statistics */
+			goto fail;
+		}
+	}
+
+	/* WDS Source Port Learning */
+	if (qdf_likely(vdev->rx_decap_type == htt_cmn_pkt_type_ethernet) &&
+			(vdev->wds_enabled))
+		dp_rx_wds_srcport_learn(soc, rx_desc->rx_buf_start, peer, nbuf);
+
 	if (hal_rx_mpdu_start_mpdu_qos_control_valid_get(
 		rx_desc->rx_buf_start)) {
 		/* TODO: Assuming that qos_control_valid also indicates
@@ -633,12 +676,20 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota)
 		rx_desc = dp_rx_cookie_2_va_rxdma_buf(soc, rx_buf_cookie);
 		qdf_assert(rx_desc);
 
+		if (!dp_rx_desc_check_magic(rx_desc)) {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+					FL("Invalid rx_desc cookie=%d"),
+					rx_buf_cookie);
+			continue;
+		}
+
 		/* XXX */
 		buf_type = HAL_RX_WBM_BUF_TYPE_GET(ring_desc);
+
 		/*
 		 * For WBM ring, expect only MSDU buffers
 		 */
-		qdf_assert(buf_type == HAL_RX_WBM_BUF_TYPE_REL_BUF);
+		qdf_assert_always(buf_type == HAL_RX_WBM_BUF_TYPE_REL_BUF);
 
 		if (wbm_err_src == HAL_RX_WBM_ERR_SRC_REO) {
 
@@ -706,18 +757,6 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota)
 			}
 		} else {
 			/* Should not come here */
-			rx_buf_cookie = HAL_RX_WBM_BUF_COOKIE_GET(ring_desc);
-			rx_desc = dp_rx_cookie_2_va_rxdma_buf(soc, rx_buf_cookie);
-
-			qdf_assert(rx_desc);
-
-			qdf_nbuf_unmap_single(soc->osdev, rx_desc->nbuf,
-						QDF_DMA_BIDIRECTIONAL);
-
-			rx_desc->rx_buf_start = qdf_nbuf_data(rx_desc->nbuf);
-			hal_rx_dump_pkt_tlvs(rx_desc->rx_buf_start,
-							QDF_TRACE_LEVEL_INFO);
-
 			qdf_assert(0);
 		}
 

+ 52 - 70
dp/wifi3.0/dp_rx_mon_dest.c

@@ -99,8 +99,7 @@ done:
  * @tail: tail of decs list to be freed
  * Return: number of msdu in MPDU to be popped
  */
-static inline
-uint32_t
+static inline uint32_t
 dp_rx_mon_mpdu_pop(struct dp_soc *soc, uint32_t mac_id,
 	void *rxdma_dst_ring_desc, qdf_nbuf_t *head_msdu,
 	qdf_nbuf_t *tail_msdu, uint32_t *npackets, uint32_t *ppdu_id,
@@ -161,6 +160,23 @@ dp_rx_mon_mpdu_pop(struct dp_soc *soc, uint32_t mac_id,
 					"[%s][%d] msdu_nbuf=%p, data=%p\n",
 					__func__, __LINE__, msdu, data);
 
+				rx_desc_tlv = HAL_RX_MON_DEST_GET_DESC(data);
+				msdu_ppdu_id =
+					HAL_RX_MON_HW_DESC_GET_PPDUID_GET(rx_desc_tlv);
+
+				QDF_TRACE(QDF_MODULE_ID_DP,
+					QDF_TRACE_LEVEL_DEBUG,
+					"[%s][%d] i=%d, ppdu_id=%x, msdu_ppdu_id=%x\n",
+					__func__, __LINE__, i, *ppdu_id, msdu_ppdu_id);
+				if (*ppdu_id != msdu_ppdu_id) {
+					*ppdu_id = msdu_ppdu_id;
+					return rx_bufs_used;
+				}
+
+				if (hal_rx_desc_is_first_msdu(rx_desc_tlv))
+					hal_rx_mon_hw_desc_get_mpdu_status(rx_desc_tlv,
+						&(dp_pdev->ppdu_info.rx_status));
+
 				rx_pkt_offset = HAL_RX_MON_HW_RX_DESC_SIZE();
 				/*
 				 * HW structures call this L3 header padding
@@ -176,7 +192,6 @@ dp_rx_mon_mpdu_pop(struct dp_soc *soc, uint32_t mac_id,
 
 				qdf_nbuf_set_pktlen(msdu, rx_buf_size);
 
-				rx_desc_tlv = HAL_RX_MON_DEST_GET_DESC(data);
 
 #if 0
 				/* Disble it.see packet on msdu done set to 0 */
@@ -200,17 +215,6 @@ dp_rx_mon_mpdu_pop(struct dp_soc *soc, uint32_t mac_id,
 				}
 #endif
 
-				msdu_ppdu_id =
-				HAL_RX_MON_HW_DESC_GET_PPDUID_GET(rx_desc_tlv);
-
-#if 0
-				/* Temporary only handle destination ring */
-				if (*ppdu_id != msdu_ppdu_id) {
-					*ppdu_id = msdu_ppdu_id;
-					return rx_bufs_used;
-				}
-#endif
-
 				rx_bufs_used++;
 
 				QDF_TRACE(QDF_MODULE_ID_DP,
@@ -306,8 +310,6 @@ qdf_nbuf_t dp_rx_mon_restitch_mpdu_from_msdus(struct dp_soc *soc,
 
 	rx_desc = qdf_nbuf_data(head_msdu);
 
-	HAL_RX_MON_HW_DESC_GET_PPDU_START_STATUS(rx_desc, rx_status);
-
 	decap_format = HAL_RX_DESC_GET_DECAP_FORMAT(rx_desc);
 
 	/* Easy case - The MSDU status indicates that this is a non-decapped
@@ -616,7 +618,6 @@ QDF_STATUS dp_rx_mon_deliver(struct dp_soc *soc, uint32_t mac_id,
 	struct cdp_mon_status *rs = &pdev->rx_mon_recv_status;
 	qdf_nbuf_t mon_skb, skb_next;
 	qdf_nbuf_t mon_mpdu = NULL;
-	struct mon_rx_status rx_mon_status;
 
 	if ((pdev->monitor_vdev == NULL) ||
 		(pdev->monitor_vdev->osif_rx_mon == NULL)) {
@@ -628,13 +629,10 @@ QDF_STATUS dp_rx_mon_deliver(struct dp_soc *soc, uint32_t mac_id,
 				tail_msdu, rs);
 
 	if (mon_mpdu) {
-		/* Push radiotap header */
-		dp_rx_extract_radiotap_info(rs, &rx_mon_status);
-
-		qdf_nbuf_update_radiotap(&rx_mon_status, mon_mpdu,
-				sizeof(struct rx_pkt_tlvs));
+		qdf_nbuf_update_radiotap(&(pdev->ppdu_info.rx_status),
+			mon_mpdu, sizeof(struct rx_pkt_tlvs));
 		pdev->monitor_vdev->osif_rx_mon(
-				pdev->monitor_vdev->osif_vdev, mon_mpdu, rs);
+				pdev->monitor_vdev->osif_vdev, mon_mpdu, NULL);
 	} else {
 		goto mon_deliver_fail;
 	}
@@ -676,8 +674,8 @@ void dp_rx_mon_dest_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 	void *mon_dst_srng = pdev->rxdma_mon_dst_ring.hal_srng;
 	union dp_rx_desc_list_elem_t *head = NULL;
 	union dp_rx_desc_list_elem_t *tail = NULL;
-	struct dp_srng *dp_rxdma_srng;
-	struct rx_desc_pool *rx_desc_pool;
+	uint32_t ppdu_id;
+	uint32_t rx_bufs_used;
 
 #ifdef DP_INTR_POLL_BASED
 	if (!pdev)
@@ -687,12 +685,6 @@ void dp_rx_mon_dest_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 	pdev_id = pdev->pdev_id;
 	mon_dst_srng = pdev->rxdma_mon_dst_ring.hal_srng;
 
-#if 0
-	/* Temporary only handle destination ring */
-	if (pdev->mon_ppdu_status != DP_PPDU_STATUS_DONE)
-		return;
-#endif
-
 	if (!mon_dst_srng) {
 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
 			"%s %d : HAL Monitor Destination Ring Init \
@@ -713,44 +705,40 @@ void dp_rx_mon_dest_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota)
 		return;
 	}
 
+	ppdu_id = pdev->ppdu_info.com_info.ppdu_id;
+	rx_bufs_used = 0;
 	while (qdf_likely((rxdma_dst_ring_desc =
-		hal_srng_dst_peek(hal_soc, mon_dst_srng)))) {
-			qdf_nbuf_t head_msdu, tail_msdu;
-			uint32_t rx_bufs_used = 0;
-			uint32_t npackets, ppdu_id;
-			head_msdu = (qdf_nbuf_t) NULL;
-			tail_msdu = (qdf_nbuf_t) NULL;
-
-			ppdu_id = pdev->mon_ppdu_id;
-			rx_bufs_used += dp_rx_mon_mpdu_pop(soc, mac_id,
-						rxdma_dst_ring_desc,
-						&head_msdu, &tail_msdu,
-						&npackets, &ppdu_id,
-						&head, &tail);
-#if 0
-			/* Temporary only handle destination ring */
-			if (ppdu_id != pdev->mon_ppdu_id) {
-				pdev->mon_ppdu_status = DP_PPDU_STATUS_START;
-				break;
-			}
-#endif
-
-			dp_rx_mon_deliver(soc, mac_id, head_msdu, tail_msdu);
-
-			/* replenish function should be changed to include
-			 * ring pointer */
-			dp_rxdma_srng = &pdev->rxdma_mon_buf_ring;
-			rx_desc_pool = &soc->rx_desc_mon[pdev_id];
+		hal_srng_dst_peek(hal_soc, mon_dst_srng)) && quota--)) {
+		qdf_nbuf_t head_msdu, tail_msdu;
+		uint32_t npackets;
+		head_msdu = (qdf_nbuf_t) NULL;
+		tail_msdu = (qdf_nbuf_t) NULL;
+
+		rx_bufs_used += dp_rx_mon_mpdu_pop(soc, mac_id,
+					rxdma_dst_ring_desc,
+					&head_msdu, &tail_msdu,
+					&npackets, &ppdu_id,
+					&head, &tail);
+
+		if (ppdu_id != pdev->ppdu_info.com_info.ppdu_id) {
+			pdev->mon_ppdu_status = DP_PPDU_STATUS_START;
+			qdf_mem_zero(&(pdev->ppdu_info.rx_status),
+				sizeof(pdev->ppdu_info.rx_status));
+			break;
+		}
 
-			dp_rx_buffers_replenish(soc, pdev_id, dp_rxdma_srng,
-				rx_desc_pool, rx_bufs_used, &head, &tail,
-				HAL_RX_BUF_RBM_SW3_BM);
+		dp_rx_mon_deliver(soc, mac_id, head_msdu, tail_msdu);
 
-			rxdma_dst_ring_desc = hal_srng_dst_get_next(hal_soc,
-				mon_dst_srng);
+		rxdma_dst_ring_desc = hal_srng_dst_get_next(hal_soc,
+			mon_dst_srng);
 	}
-
 	hal_srng_access_end(hal_soc, mon_dst_srng);
+
+	if (rx_bufs_used) {
+		dp_rx_buffers_replenish(soc, pdev_id,
+			&pdev->rxdma_mon_buf_ring, &soc->rx_desc_mon[pdev_id],
+			rx_bufs_used, &head, &tail, HAL_RX_BUF_RBM_SW3_BM);
+	}
 }
 
 static QDF_STATUS
@@ -940,12 +928,6 @@ static int dp_mon_link_desc_pool_setup(struct dp_soc *soc, uint32_t mac_id)
 				hal_srng_src_get_next(soc->hal_soc,
 					mon_desc_srng))) {
 
-				QDF_TRACE(QDF_MODULE_ID_TXRX,
-					QDF_TRACE_LEVEL_DEBUG,
-					"[%s][%d] desc=%p, i=%d, vaddr=%lx, paddr=%lx",
-					__func__, __LINE__, desc, i,
-					(unsigned long)vaddr, (unsigned long)paddr);
-
 				hal_set_link_desc_addr(desc, i, paddr);
 				num_entries--;
 				num_replenish_buf++;

+ 11 - 16
dp/wifi3.0/dp_rx_mon_status.c

@@ -36,7 +36,9 @@
 * Return: none
 */
 static inline void
-dp_rx_mon_status_process_tlv(struct dp_soc *soc, uint32_t mac_id) {
+dp_rx_mon_status_process_tlv(struct dp_soc *soc, uint32_t mac_id,
+	uint32_t quota)
+{
 	struct dp_pdev *pdev = soc->pdev_list[mac_id];
 	struct hal_rx_ppdu_info *ppdu_info;
 	qdf_nbuf_t status_nbuf;
@@ -73,12 +75,8 @@ dp_rx_mon_status_process_tlv(struct dp_soc *soc, uint32_t mac_id) {
 		qdf_nbuf_free(status_nbuf);
 
 		if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) {
-
 			pdev->mon_ppdu_status = DP_PPDU_STATUS_DONE;
-			/* Temperary */
-			pdev->mon_ppdu_status =
-				DP_PPDU_STATUS_START;
-			break;
+			dp_rx_mon_dest_process(soc, mac_id, quota);
 		}
 	}
 	return;
@@ -237,8 +235,8 @@ dp_rx_mon_status_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota) {
 	uint32_t work_done;
 
 	work_done = dp_rx_mon_status_srng_process(soc, mac_id, quota);
-
-	dp_rx_mon_status_process_tlv(soc, mac_id);
+	quota -= work_done;
+	dp_rx_mon_status_process_tlv(soc, mac_id, quota);
 
 	return work_done;
 }
@@ -255,14 +253,9 @@ dp_rx_mon_status_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota) {
  */
 uint32_t
 dp_mon_process(struct dp_soc *soc, uint32_t mac_id, uint32_t quota) {
-	uint32_t work_done;
-
-	work_done = dp_rx_mon_status_process(soc, mac_id, quota);
-
-	dp_rx_mon_dest_process(soc, mac_id, quota);
-
-	return work_done;
+	return dp_rx_mon_status_process(soc, mac_id, quota);
 }
+
 /**
  * dp_rx_pdev_mon_detach() - detach dp rx for status ring
  * @pdev: core txrx pdev context
@@ -397,7 +390,7 @@ QDF_STATUS dp_rx_mon_status_buffers_replenish(struct dp_soc *dp_soc,
 		hal_rxdma_buff_addr_info_set(rxdma_ring_entry, paddr,
 			(*desc_list)->rx_desc.cookie, owner);
 
-		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
 			"[%s][%d] rx_desc=%p, cookie=%d, nbuf=%p, \
 			status_buf=%p paddr=%p\n",
 			__func__, __LINE__, &(*desc_list)->rx_desc,
@@ -474,6 +467,8 @@ dp_rx_pdev_mon_status_attach(struct dp_pdev *pdev) {
 	qdf_nbuf_queue_init(&pdev->rx_status_q);
 
 	pdev->mon_ppdu_status = DP_PPDU_STATUS_START;
+	qdf_mem_zero(&(pdev->ppdu_info.rx_status),
+		sizeof(pdev->ppdu_info.rx_status));
 
 	return QDF_STATUS_SUCCESS;
 }

+ 42 - 0
dp/wifi3.0/dp_tx.c

@@ -1397,11 +1397,53 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf)
 	struct dp_tx_msdu_info_s msdu_info;
 	struct dp_tx_seg_info_s seg_info;
 	struct dp_vdev *vdev = (struct dp_vdev *) vap_dev;
+	struct dp_soc *soc = vdev->pdev->soc;
 	uint16_t peer_id = HTT_INVALID_PEER;
+	uint8_t count;
+	uint8_t found = 0;
+	uint8_t oldest_mec_entry_idx = 0;
+	uint64_t oldest_mec_ts = 0;
+	struct mect_entry *mect_entry;
 
 	qdf_mem_set(&msdu_info, sizeof(msdu_info), 0x0);
 	qdf_mem_set(&seg_info, sizeof(seg_info), 0x0);
 
+	if (qdf_nbuf_get_ftype(nbuf) == CB_FTYPE_INTRABSS_FWD)
+		goto out;
+
+	eh = (struct ether_header *)qdf_nbuf_data(nbuf);
+	if (DP_FRAME_IS_MULTICAST((eh)->ether_dhost)) {
+		for (count = 0; count < soc->mect_cnt; count++) {
+			mect_entry = &soc->mect_table[count];
+			if (!memcmp(mect_entry->mac_addr, eh->ether_shost,
+					DP_MAC_ADDR_LEN)) {
+				found = 1;
+				break;
+			}
+
+			if (!oldest_mec_ts) {
+				oldest_mec_entry_idx = count;
+				oldest_mec_ts = mect_entry->ts;
+			} else if (mect_entry->ts < oldest_mec_ts) {
+				oldest_mec_entry_idx = count;
+				oldest_mec_ts = mect_entry->ts;
+			}
+		}
+
+		if (!found) {
+			if (count >= DP_MAX_MECT_ENTRIES)
+				count = oldest_mec_entry_idx;
+			else
+				soc->mect_cnt++;
+
+			mect_entry = &soc->mect_table[count];
+			mect_entry->ts = jiffies_64;
+			memcpy(mect_entry->mac_addr, eh->ether_shost,
+				DP_MAC_ADDR_LEN);
+		}
+	}
+
+out:
 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
 			"%s , skb %0x:%0x:%0x:%0x:%0x:%0x\n",
 			__func__, nbuf->data[0], nbuf->data[1], nbuf->data[2],

+ 11 - 1
dp/wifi3.0/dp_types.h

@@ -87,6 +87,7 @@
 #define MAX_TX_HW_QUEUES 3
 
 #define DP_MAX_INTERRUPT_CONTEXTS 8
+#define DP_MAX_MECT_ENTRIES 64
 
 struct dp_soc_cmn;
 struct dp_pdev;
@@ -378,6 +379,13 @@ struct dp_ast_entry {
 	TAILQ_ENTRY(dp_ast_entry) ast_entry_elem;
 };
 
+struct mect_entry {
+	uint8_t idx;
+	uint8_t valid;
+	uint8_t mac_addr[6];
+	uint64_t ts;
+};
+
 /* SOC level structure for data path */
 struct dp_soc {
 	/* Common base structure - Should be the first member */
@@ -612,6 +620,9 @@ struct dp_soc {
 #endif
 	qdf_list_t reo_desc_freelist;
 	qdf_spinlock_t reo_desc_freelist_lock;
+	struct mect_entry mect_table[DP_MAX_MECT_ENTRIES];
+	uint8_t mect_cnt;
+
 	/* Obj Mgr SoC */
 	struct wlan_objmgr_psoc *psoc;
 	qdf_nbuf_t invalid_peer_head_msdu;
@@ -791,7 +802,6 @@ struct dp_pdev {
 	uint8_t operating_channel;
 
 	qdf_nbuf_queue_t rx_status_q;
-	uint32_t mon_ppdu_id;
 	uint32_t mon_ppdu_status;
 	struct cdp_mon_status rx_mon_recv_status;
 

+ 41 - 4
dp/wifi3.0/hal_rx.h

@@ -1684,6 +1684,47 @@ enum hal_reo_error_code {
 	HAL_REO_ERR_QUEUE_DESC_BLOCKED_SET
 };
 
+/**
+ * enum hal_rxdma_error_code: Code describing the type of RxDMA error detected
+ *
+ * @HAL_RXDMA_ERR_OVERFLOW: MPDU frame is not complete due to a FIFO overflow
+ * @ HAL_RXDMA_ERR_OVERFLOW      : MPDU frame is not complete due to a FIFO
+ * 				   overflow
+ * @ HAL_RXDMA_ERR_MPDU_LENGTH   : MPDU frame is not complete due to receiving
+ * 				   incomplete
+ * 		               	   MPDU from the PHY
+ * @ HAL_RXDMA_ERR_FCS           : FCS check on the MPDU frame failed
+ * @ HAL_RXDMA_ERR_DECRYPT       : Decryption error
+ * @ HAL_RXDMA_ERR_TKIP_MIC      : TKIP MIC error
+ * @ HAL_RXDMA_ERR_UNECRYPTED    : Received a frame that was expected to be
+ * 			  	   encrypted but wasn’t
+ * @ HAL_RXDMA_ERR_MSDU_LEN      : MSDU related length error
+ * @ HAL_RXDMA_ERR_MSDU_LIMIT    : Number of MSDUs in the MPDUs exceeded
+ * 				   the max allowed
+ * @ HAL_RXDMA_ERR_WIFI_PARSE    : wifi parsing error
+ * @ HAL_RXDMA_ERR_AMSDU_PARSE   : Amsdu parsing error
+ * @ HAL_RXDMA_ERR_SA_TIMEOUT    : Source Address search timeout
+ * @ HAL_RXDMA_ERR_DA_TIMEOUT    : Destination Address  search timeout
+ * @ HAL_RXDMA_ERR_FLOW_TIMEOUT  : Flow Search Timeout
+ * @ HAL_RXDMA_ERR_FLUSH_REQUEST : RxDMA FIFO Flush request
+ */
+enum hal_rxdma_error_code {
+	HAL_RXDMA_ERR_OVERFLOW = 0,
+	HAL_RXDMA_ERR_MPDU_LENGTH,
+	HAL_RXDMA_ERR_FCS,
+	HAL_RXDMA_ERR_DECRYPT,
+	HAL_RXDMA_ERR_TKIP_MIC,
+	HAL_RXDMA_ERR_UNECRYPTED,
+	HAL_RXDMA_ERR_MSDU_LEN,
+	HAL_RXDMA_ERR_MSDU_LIMIT,
+	HAL_RXDMA_ERR_WIFI_PARSE,
+	HAL_RXDMA_ERR_AMSDU_PARSE,
+	HAL_RXDMA_ERR_SA_TIMEOUT,
+	HAL_RXDMA_ERR_DA_TIMEOUT,
+	HAL_RXDMA_ERR_FLOW_TIMEOUT,
+	HAL_RXDMA_ERR_FLUSH_REQUEST
+};
+
 #define HAL_RX_REO_ERROR_GET(reo_desc) (((*(((uint32_t *) reo_desc)+ \
 		(REO_DESTINATION_RING_7_REO_ERROR_CODE_OFFSET >> 2))) & \
 		REO_DESTINATION_RING_7_REO_ERROR_CODE_MASK) >> \
@@ -1916,10 +1957,6 @@ enum hal_rx_wbm_rxdma_push_reason {
 	HAL_RX_BUF_COOKIE_GET(&((struct wbm_release_ring *) \
 	wbm_desc)->released_buff_or_desc_addr_info)
 
-#define HAL_RX_WBM_BUF_COOKIE_GET(wbm_desc) \
-	HAL_RX_BUF_COOKIE_GET(&((struct wbm_release_ring *) \
-	wbm_desc)->released_buff_or_desc_addr_info)
-
 /**
  * hal_rx_dump_rx_attention_tlv: dump RX attention TLV in structured
  *				 humman readable format.

+ 234 - 61
hal/wifi3.0/hal_api_mon.h

@@ -32,6 +32,7 @@
 	HAL_RX_LSB(block, field))
 
 #define HAL_RX_PHY_DATA_RADAR 0x01
+#define HAL_SU_MU_CODING_LDPC 0x01
 
 #define HAL_RX_FCS_LEN (4)
 #define KEY_EXTIV 0x20
@@ -74,6 +75,17 @@
 
 #define HAL_MAX_UL_MU_USERS			8
 
+#define HAL_RX_PKT_TYPE_11A	0
+#define HAL_RX_PKT_TYPE_11B	1
+#define HAL_RX_PKT_TYPE_11N	2
+#define HAL_RX_PKT_TYPE_11AC	3
+#define HAL_RX_PKT_TYPE_11AX	4
+
+#define HAL_RX_RECEPTION_TYPE_SU	0
+#define HAL_RX_RECEPTION_TYPE_MU_MIMO	1
+#define HAL_RX_RECEPTION_TYPE_OFDMA	2
+#define HAL_RX_RECEPTION_TYPE_MU_OFDMA	3
+
 enum {
 	HAL_HW_RX_DECAP_FORMAT_RAW = 0,
 	HAL_HW_RX_DECAP_FORMAT_NWIFI,
@@ -154,6 +166,16 @@ uint32_t HAL_RX_MON_HW_DESC_GET_PPDUID_GET(void *hw_desc_addr)
 	return HAL_RX_GET(rx_attn, RX_ATTENTION_0, PHY_PPDU_ID);
 }
 
+/* TODO: Move all Rx descriptor functions to hal_rx.h to avoid duplication */
+static inline
+uint32_t hal_rx_desc_is_first_msdu(void *hw_desc_addr)
+{
+	struct rx_pkt_tlvs *rx_tlvs = (struct rx_pkt_tlvs *)hw_desc_addr;
+	struct rx_msdu_end *msdu_end = &rx_tlvs->msdu_end_tlv.rx_msdu_end;
+
+	return HAL_RX_GET(msdu_end, RX_MSDU_END_5, FIRST_MSDU);
+}
+
 #define HAL_RX_BUFFER_ADDR_31_0_GET(buff_addr_info)		\
 	(_HAL_MS((*_OFFSET_TO_WORD_PTR(buff_addr_info,		\
 		BUFFER_ADDR_INFO_0_BUFFER_ADDR_31_0_OFFSET)),	\
@@ -286,7 +308,7 @@ uint32 hal_get_rx_msdu_link_desc_size(void)
 
 enum {
 	HAL_PKT_TYPE_OFDM = 0,
-	HAL_CDP_PKT_TYPE_CCK,
+	HAL_PKT_TYPE_CCK,
 	HAL_PKT_TYPE_HT,
 	HAL_PKT_TYPE_VHT,
 	HAL_PKT_TYPE_HE,
@@ -313,73 +335,60 @@ enum {
 	HAL_RX_TYPE_MU_OFDMA_MIMO,
 };
 
+/**
+ * hal_rx_mon_hw_desc_get_mpdu_status: Retrieve MPDU status
+ *
+ * @ hw_desc_addr: Start address of Rx HW TLVs
+ * @ rs: Status for monitor mode
+ *
+ * Return: void
+ */
 static inline
-void HAL_RX_MON_HW_DESC_GET_PPDU_START_STATUS(void *hw_desc_addr,
-		struct cdp_mon_status *rs)
+void hal_rx_mon_hw_desc_get_mpdu_status(void *hw_desc_addr,
+		struct mon_rx_status *rs)
 {
 	struct rx_msdu_start *rx_msdu_start;
 	struct rx_pkt_tlvs *rx_desc = (struct rx_pkt_tlvs *)hw_desc_addr;
-	uint32_t rx_pream_type;
-	uint32_t rx_sgi;
-	uint32_t rx_type;
-	uint32_t rx_bw;
-static  uint32_t pkt_type_hw_to_cdp[] = {
-			CDP_PKT_TYPE_OFDM,
-			CDP_PKT_TYPE_CCK,
-			CDP_PKT_TYPE_HT,
-			CDP_PKT_TYPE_VHT,
-			CDP_PKT_TYPE_HE,
-		};
-
-static  uint32_t sgi_hw_to_cdp[] = {
-			CDP_SGI_0_8_US,
-			CDP_SGI_0_4_US,
-			CDP_SGI_1_6_US,
-			CDP_SGI_3_2_US,
-		};
-
-static uint32_t rx_type_hw_to_cdp[] = {
-			CDP_RX_TYPE_SU,
-			CDP_RX_TYPE_MU_MIMO,
-			CDP_RX_TYPE_MU_OFDMA,
-			CDP_RX_TYPE_MU_OFDMA_MIMO,
-		};
-
-static uint32_t rx_bw_hw_to_cdp[] = {
-			CDP_FULL_RX_BW_20,
-			CDP_FULL_RX_BW_40,
-			CDP_FULL_RX_BW_80,
-			CDP_FULL_RX_BW_160,
-		};
-
-	rx_msdu_start = &rx_desc->msdu_start_tlv.rx_msdu_start;
+	uint32_t reg_value;
 
-	rs->cdp_rs_tstamp.cdp_tsf = rx_msdu_start->ppdu_start_timestamp;
+	static uint32_t sgi_hw_to_cdp[] = {
+		CDP_SGI_0_8_US,
+		CDP_SGI_0_4_US,
+		CDP_SGI_1_6_US,
+		CDP_SGI_3_2_US,
+	};
 
-	rx_pream_type = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, PKT_TYPE);
-	rs->cdp_rs_pream_type = pkt_type_hw_to_cdp[rx_pream_type];
+	rx_msdu_start = &rx_desc->msdu_start_tlv.rx_msdu_start;
 
-	rs->cdp_rs_user_rssi = HAL_RX_GET(rx_msdu_start,
+	rs->ant_signal_db = HAL_RX_GET(rx_msdu_start,
 					RX_MSDU_START_5, USER_RSSI);
-
-	rs->cdp_rs_stbc = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, STBC);
-
-	rx_sgi = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, SGI);
-	rs->cdp_rs_sgi  = sgi_hw_to_cdp[rx_sgi];
-
-	rs->cdf_rs_rate_mcs = HAL_RX_GET(rx_msdu_start,
+	rs->mcs = HAL_RX_GET(rx_msdu_start,
 					RX_MSDU_START_5, RATE_MCS);
+	rs->is_stbc = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, STBC);
+
+	reg_value = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, SGI);
+	rs->sgi = sgi_hw_to_cdp[reg_value];
+	rs->nr_ant = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, NSS);
+
+	reg_value = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, PKT_TYPE);
+	switch (reg_value) {
+	case HAL_RX_PKT_TYPE_11AC:
+		rs->vht_flags = 1;
+		reg_value = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5,
+		RECEIVE_BANDWIDTH);
+		rs->vht_flag_values2 = 0x01 << reg_value;
+		rs->vht_flag_values3[0] = rs->mcs << 4;
+		break;
+	case HAL_RX_PKT_TYPE_11AX:
+		rs->he_flags = 1;
+		break;
+	default:
+		break;
+	}
 
-	rx_type = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, RECEPTION_TYPE);
-
-	rs->cdp_rs_reception_type = rx_type_hw_to_cdp[rx_type];
-
-	rx_bw = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, RECEIVE_BANDWIDTH);
-
-	rs->cdp_rs_bw = rx_bw_hw_to_cdp[rx_bw];
-
-	rs->cdp_rs_nss = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, NSS);
-
+	reg_value = HAL_RX_GET(rx_msdu_start, RX_MSDU_START_5, RECEPTION_TYPE);
+	rs->beamformed = (reg_value == HAL_RX_RECEPTION_TYPE_MU_MIMO) ? 1 : 0;
+	/* TODO: rs->beamformed should be set for SU beamforming also */
 }
 
 struct hal_rx_ppdu_user_info {
@@ -394,6 +403,7 @@ struct hal_rx_ppdu_common_info {
 struct hal_rx_ppdu_info {
 	struct hal_rx_ppdu_common_info com_info;
 	struct hal_rx_ppdu_user_info user_info[HAL_MAX_UL_MU_USERS];
+	struct mon_rx_status rx_status;
 };
 
 static inline uint32_t
@@ -404,9 +414,18 @@ hal_get_rx_status_buf_size(void) {
 
 static inline uint8_t*
 hal_rx_status_get_next_tlv(uint8_t *rx_tlv) {
-	uint32_t tlv_len;
+	uint32_t tlv_len, tlv_tag;
 
 	tlv_len = HAL_RX_GET_USER_TLV32_LEN(rx_tlv);
+	tlv_tag = HAL_RX_GET_USER_TLV32_TYPE(rx_tlv);
+
+	/* The actual length of PPDU_END is the combined lenght of many PHY
+	 * TLVs that follow. Skip the TLV header and
+	 * rx_rxpcu_classification_overview that follows the header to get to
+	 * next TLV.
+	 */
+	if (tlv_tag == WIFIRX_PPDU_END_E)
+		tlv_len = sizeof(struct rx_rxpcu_classification_overview);
 
 	return (uint8_t *)(((unsigned long)(rx_tlv + tlv_len +
 			HAL_RX_TLV32_HDR_SIZE + 3)) & (~((unsigned long)3)));
@@ -415,7 +434,7 @@ hal_rx_status_get_next_tlv(uint8_t *rx_tlv) {
 static inline uint32_t
 hal_rx_status_get_tlv_info(void *rx_tlv, struct hal_rx_ppdu_info *ppdu_info)
 {
-	uint32_t tlv_tag, user_id, tlv_len;
+	uint32_t tlv_tag, user_id, tlv_len, value;
 
 	tlv_tag = HAL_RX_GET_USER_TLV32_TYPE(rx_tlv);
 	user_id = HAL_RX_GET_USER_TLV32_USERID(rx_tlv);
@@ -432,6 +451,10 @@ hal_rx_status_get_tlv_info(void *rx_tlv, struct hal_rx_ppdu_info *ppdu_info)
 		ppdu_info->com_info.ppdu_id =
 			HAL_RX_GET(rx_tlv, RX_PPDU_START_0,
 				PHY_PPDU_ID);
+		/* TODO: Ensure channel number is set in PHY meta data */
+		ppdu_info->rx_status.chan_freq =
+			HAL_RX_GET(rx_tlv, RX_PPDU_START_1,
+				SW_PHY_META_DATA);
 		ppdu_info->com_info.ppdu_timestamp =
 			HAL_RX_GET(rx_tlv, RX_PPDU_START_2,
 				PPDU_START_TIMESTAMP);
@@ -444,9 +467,16 @@ hal_rx_status_get_tlv_info(void *rx_tlv, struct hal_rx_ppdu_info *ppdu_info)
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
 			"[%s][%d] ppdu_end_e len=%d\n",
 				__func__, __LINE__, tlv_len);
+		/* This is followed by sub-TLVs of PPDU_END */
 		break;
 
 	case WIFIRXPCU_PPDU_END_INFO_E:
+		ppdu_info->rx_status.tsft =
+			HAL_RX_GET(rx_tlv, RXPCU_PPDU_END_INFO_1,
+				WB_TIMESTAMP_UPPER_32);
+		ppdu_info->rx_status.tsft = (ppdu_info->rx_status.tsft << 32) |
+			HAL_RX_GET(rx_tlv, RXPCU_PPDU_END_INFO_0,
+				WB_TIMESTAMP_LOWER_32);
 		break;
 
 	case WIFIRX_PPDU_END_USER_STATS_E:
@@ -459,8 +489,147 @@ hal_rx_status_get_tlv_info(void *rx_tlv, struct hal_rx_ppdu_info *ppdu_info)
 		return HAL_TLV_STATUS_PPDU_DONE;
 
 	case WIFIDUMMY_E:
-		return HAL_TLV_STATUS_DUMMY;
+		return HAL_TLV_STATUS_PPDU_DONE;
 
+	case WIFIPHYRX_HT_SIG_E:
+	{
+		uint8_t *ht_sig_info = (uint8_t *)rx_tlv +
+				HAL_RX_OFFSET(PHYRX_HT_SIG_0,
+				HT_SIG_INFO_PHYRX_HT_SIG_INFO_DETAILS);
+		value = HAL_RX_GET(ht_sig_info, HT_SIG_INFO_1,
+				FEC_CODING);
+		ppdu_info->rx_status.ldpc = (value == HAL_SU_MU_CODING_LDPC) ?
+			1 : 0;
+		break;
+	}
+	case WIFIPHYRX_VHT_SIG_A_E:
+	{
+		uint8_t *vht_sig_a_info = (uint8_t *)rx_tlv +
+				HAL_RX_OFFSET(PHYRX_VHT_SIG_A_0,
+				VHT_SIG_A_INFO_PHYRX_VHT_SIG_A_INFO_DETAILS);
+		value = HAL_RX_GET(vht_sig_a_info, VHT_SIG_A_INFO_1,
+				SU_MU_CODING);
+		ppdu_info->rx_status.ldpc = (value == HAL_SU_MU_CODING_LDPC) ?
+			1 : 0;
+		break;
+	}
+	case WIFIPHYRX_HE_SIG_A_SU_E:
+		ppdu_info->rx_status.he_sig_A1 =
+			*((uint32_t *)((uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_HE_SIG_A_SU_0,
+			HE_SIG_A_SU_INFO_PHYRX_HE_SIG_A_SU_INFO_DETAILS)));
+		ppdu_info->rx_status.he_sig_A1 |=
+			QDF_MON_STATUS_HE_SIG_A1_HE_FORMAT_SU;
+		/* TODO: Enabling all known bits. Check if this should be
+		 * enabled selectively
+		 */
+		ppdu_info->rx_status.he_sig_A1_known =
+			QDF_MON_STATUS_HE_SIG_A1_SU_KNOWN_ALL;
+		ppdu_info->rx_status.he_sig_A2 =
+			*((uint32_t *)((uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_HE_SIG_A_SU_1,
+			HE_SIG_A_SU_INFO_PHYRX_HE_SIG_A_SU_INFO_DETAILS)));
+		ppdu_info->rx_status.he_sig_A2_known =
+			QDF_MON_STATUS_HE_SIG_A2_SU_KNOWN_ALL;
+		break;
+	case WIFIPHYRX_HE_SIG_A_MU_DL_E:
+		ppdu_info->rx_status.he_sig_A1 =
+			*((uint32_t *)((uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_HE_SIG_A_MU_DL_0,
+			HE_SIG_A_MU_DL_INFO_PHYRX_HE_SIG_A_MU_DL_INFO_DETAILS)));
+		ppdu_info->rx_status.he_sig_A1 |=
+			QDF_MON_STATUS_HE_SIG_A1_HE_FORMAT_MU;
+		ppdu_info->rx_status.he_sig_A1_known =
+			QDF_MON_STATUS_HE_SIG_A1_MU_KNOWN_ALL;
+
+		ppdu_info->rx_status.he_sig_A2 =
+			*((uint32_t *)((uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_HE_SIG_A_MU_DL_1,
+			HE_SIG_A_MU_DL_INFO_PHYRX_HE_SIG_A_MU_DL_INFO_DETAILS)));
+		ppdu_info->rx_status.he_sig_A2_known =
+			QDF_MON_STATUS_HE_SIG_A2_MU_KNOWN_ALL;
+		break;
+	case WIFIPHYRX_HE_SIG_B1_MU_E:
+	{
+		uint8_t *he_sig_b1_mu_info = (uint8_t *)rx_tlv +
+			*((uint32_t *)((uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_HE_SIG_B1_MU_0,
+			HE_SIG_B1_MU_INFO_PHYRX_HE_SIG_B1_MU_INFO_DETAILS)));
+
+		ppdu_info->rx_status.he_sig_b_common_RU[0] =
+			HAL_RX_GET(he_sig_b1_mu_info, HE_SIG_B1_MU_INFO_0,
+				RU_ALLOCATION);
+
+		ppdu_info->rx_status.he_sig_b_common_known =
+			QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU0;
+		/* TODO: Check on the availability of other fields in
+		 * sig_b_common
+		 */
+		break;
+	}
+	case WIFIPHYRX_HE_SIG_B2_MU_E:
+		ppdu_info->rx_status.he_sig_b_user =
+			*((uint32_t *)((uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_HE_SIG_B2_MU_0,
+			HE_SIG_B2_MU_INFO_PHYRX_HE_SIG_B2_MU_INFO_DETAILS)));
+		ppdu_info->rx_status.he_sig_b_user_known =
+			QDF_MON_STATUS_HE_SIG_B_USER_KNOWN_SIG_B_ALL;
+		break;
+	case WIFIPHYRX_HE_SIG_B2_OFDMA_E:
+		ppdu_info->rx_status.he_sig_b_user =
+			*((uint32_t *)((uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_HE_SIG_B2_OFDMA_0,
+			HE_SIG_B2_OFDMA_INFO_PHYRX_HE_SIG_B2_OFDMA_INFO_DETAILS)));
+		ppdu_info->rx_status.he_sig_b_user_known =
+			QDF_MON_STATUS_HE_SIG_B_USER_KNOWN_SIG_B_ALL;
+		break;
+	case WIFIPHYRX_RSSI_LEGACY_E:
+	{
+		uint8_t *rssi_info_tlv = (uint8_t *)rx_tlv +
+			HAL_RX_OFFSET(PHYRX_RSSI_LEGACY_3,
+			RECEIVE_RSSI_INFO_PRE_RSSI_INFO_DETAILS);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_0, RSSI_PRI20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_PRI20_CHAIN0: %d\n", value);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_0, RSSI_EXT20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_EXT20_CHAIN0: %d\n", value);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_0, RSSI_EXT40_LOW20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_EXT40_LOW20_CHAIN0: %d\n", value);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_0, RSSI_EXT40_HIGH20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_EXT40_HIGH20_CHAIN0: %d\n", value);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_1, RSSI_EXT80_LOW20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_EXT80_LOW20_CHAIN0: %d\n", value);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_1, RSSI_EXT80_LOW_HIGH20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_EXT80_LOW_HIGH20_CHAIN0: %d\n", value);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_1, RSSI_EXT80_HIGH_LOW20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_EXT80_HIGH_LOW20_CHAIN0: %d\n", value);
+
+		value = HAL_RX_GET(rssi_info_tlv,
+			RECEIVE_RSSI_INFO_1, RSSI_EXT80_HIGH20_CHAIN0);
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+			"RSSI_EXT80_HIGH20_CHAIN0: %d\n", value);
+		break;
+	}
 	case 0:
 		return HAL_TLV_STATUS_PPDU_DONE;
 
@@ -468,6 +637,10 @@ hal_rx_status_get_tlv_info(void *rx_tlv, struct hal_rx_ppdu_info *ppdu_info)
 		break;
 	}
 
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
+		"%s TLV type: %d, TLV len:%d\n",
+		__func__, tlv_tag, tlv_len);
+
 	return HAL_TLV_STATUS_PPDU_NOT_DONE;
 }
 

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

@@ -64,7 +64,18 @@
 #include "rx_ppdu_end_user_stats.h"
 #include "rx_ppdu_end_user_stats_ext.h"
 #include "rx_mpdu_desc_info.h"
+#include "rxpcu_ppdu_end_info.h"
+#include "phyrx_he_sig_a_su.h"
+#include "phyrx_he_sig_a_mu_dl.h"
+#include "phyrx_he_sig_b1_mu.h"
+#include "phyrx_he_sig_b2_mu.h"
+#include "phyrx_he_sig_b2_ofdma.h"
+#include "phyrx_vht_sig_a.h"
+#include "phyrx_ht_sig.h"
 #include "tx_msdu_extension.h"
+#include "receive_rssi_info.h"
+#include "phyrx_pkt_end.h"
+#include "phyrx_rssi_legacy.h"
 #include "wcss_version.h"
 #include "pld_common.h"
 #include "rx_msdu_link.h"

+ 2 - 1
hal/wifi3.0/hal_reo.h

@@ -136,7 +136,8 @@ enum reo_thres_index_reg {
 enum reo_cmd_exec_status {
 	HAL_REO_CMD_SUCCESS = 0,
 	HAL_REO_CMD_BLOCKED = 1,
-	HAL_REO_CMD_FAILED = 2
+	HAL_REO_CMD_FAILED = 2,
+	HAL_REO_CMD_RESOURCE_BLOCKED = 3
 };
 
 /**

+ 1 - 7
hif/inc/hif.h

@@ -122,7 +122,7 @@ enum hif_ic_irq {
 	host2rxdma_monitor_ring3,
 	host2rxdma_monitor_ring2,
 	host2rxdma_monitor_ring1,
-	reo2ost_exception,
+	reo2host_exception,
 	wbm2host_rx_release,
 	reo2host_status,
 	reo2host_destination_ring4,
@@ -853,12 +853,6 @@ int hif_bus_reset_resume(struct hif_opaque_softc *hif_ctx);
 void hif_set_attribute(struct hif_opaque_softc *osc, uint8_t hif_attrib);
 
 void *hif_get_lro_info(int ctx_id, struct hif_opaque_softc *hif_hdl);
-#ifdef WLAN_SUSPEND_RESUME_TEST
-typedef void (*hif_fake_resume_callback)(uint32_t val);
-void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx,
-			   hif_fake_resume_callback callback);
-void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx);
-#endif
 
 uint32_t hif_register_ext_group_int_handler(struct hif_opaque_softc *hif_ctx,
 		uint32_t numirq, uint32_t irq[], ext_intr_handler handler,

+ 59 - 0
hif/inc/hif_unit_test_suspend.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: Public unit-test related APIs for triggering WoW suspend/resume while
+ * the application processor is still up.
+ */
+
+#ifndef _HIF_UNIT_TEST_SUSPEND_H_
+#define _HIF_UNIT_TEST_SUSPEND_H_
+
+#ifdef WLAN_SUSPEND_RESUME_TEST
+
+#include "qdf_status.h"
+#include "hif.h"
+
+typedef void (*hif_ut_resume_callback)(void);
+
+/**
+ * hif_ut_apps_suspend() - Setup unit-test related suspend state.
+ * @opaque_scn: The HIF context to operate on
+ * @callback: The function to call when unit-test resume is triggered
+ *
+ * Call after a normal WoW suspend has been completed.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hif_ut_apps_suspend(struct hif_opaque_softc *opaque_scn,
+			       hif_ut_resume_callback callback);
+
+/**
+ * hif_ut_apps_resume() - Cleanup unit-test related suspend state.
+ * @opaque_scn: The HIF context to operate on
+ *
+ * Call before doing a normal WoW resume if suspend was initiated via
+ * unit-test suspend.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hif_ut_apps_resume(struct hif_opaque_softc *opaque_scn);
+
+#endif /* WLAN_SUSPEND_RESUME_TEST */
+
+#endif /* _HIF_UNIT_TEST_SUSPEND_H_ */

+ 8 - 9
hif/src/ce/ce_assignment.h

@@ -600,21 +600,20 @@ static struct CE_pipe_config target_ce_config_wlan_qca8074[] = {
 		(CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,},
 	/* NB: 50% of src nentries, since tx has 2 frags */
 	/* ipa_uc->target */
-	{ /* CE5 */ 5, PIPEDIR_OUT, 1024,   64,
-		(CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,},
+	{ /* CE5 */ 5, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,},
 	/* Reserved for target autonomous HIF_memcpy */
-	{ /* CE6 */ 6, PIPEDIR_INOUT, 32, 16384, CE_ATTR_FLAGS, 0,},
+	{ /* CE6 */ 6, PIPEDIR_INOUT, 32, 65535, 64, 0,},
 	/* CE7 used only by Host */
-	{ /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0,
-		(CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,},
+	{ /* CE7 */ 7, PIPEDIR_OUT, 32, 2048,
+		8192, 0,},
 	/* CE8 used only by IPA */
-	{ /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,},
+	{ /* CE8 */ 8, PIPEDIR_INOUT, 32, 65535, 112, 0,},
 	/* CE9 target->host HTT */
-	{ /* CE9 */ 9, PIPEDIR_IN,  32, 2048, CE_ATTR_FLAGS, 0,},
+	{ /* CE9 */ 9, PIPEDIR_OUT,  32, 2048, 8192, 0,},
 	/* CE10 target->host HTT */
-	{ /* CE10 */ 10, PIPEDIR_IN,  32, 2048, CE_ATTR_FLAGS, 0,},
+	{ /* CE10 */ 10, PIPEDIR_INOUT_H2H,  0, 0, 0, 0,},
 	/* Target -> host PKTLOG */
-	{ /* CE11 */ 11, PIPEDIR_IN,  32, 2048, CE_ATTR_FLAGS, 0,},
+	{ /* CE11 */ 11, PIPEDIR_IN,  32, 2048, 48, 0,},
 };
 
 static struct CE_attr host_ce_config_wlan_qca8074_pci[] = {

+ 28 - 11
hif/src/ce/ce_main.c

@@ -404,6 +404,29 @@ static struct service_to_pipe target_service_to_ce_map_wlan[] = {
 
 /* PIPEDIR_OUT = HOST to Target */
 /* PIPEDIR_IN  = TARGET to HOST */
+static struct service_to_pipe target_service_to_ce_map_qca8074[] = {
+	{ WMI_DATA_VO_SVC, PIPEDIR_OUT, 3, },
+	{ WMI_DATA_VO_SVC, PIPEDIR_IN, 2, },
+	{ WMI_DATA_BK_SVC, PIPEDIR_OUT, 3, },
+	{ WMI_DATA_BK_SVC, PIPEDIR_IN, 2, },
+	{ WMI_DATA_BE_SVC, PIPEDIR_OUT, 3, },
+	{ WMI_DATA_BE_SVC, PIPEDIR_IN, 2, },
+	{ WMI_DATA_VI_SVC, PIPEDIR_OUT, 3, },
+	{ WMI_DATA_VI_SVC, PIPEDIR_IN, 2, },
+	{ WMI_CONTROL_SVC, PIPEDIR_OUT, 3, },
+	{ WMI_CONTROL_SVC, PIPEDIR_IN, 2, },
+	{ WMI_CONTROL_SVC_WMAC1, PIPEDIR_OUT, 7},
+	{ WMI_CONTROL_SVC_WMAC1, PIPEDIR_IN, 2},
+	{ HTC_CTRL_RSVD_SVC, PIPEDIR_OUT, 0, },
+	{ HTC_CTRL_RSVD_SVC, PIPEDIR_IN, 1, },
+	{ HTC_RAW_STREAMS_SVC, PIPEDIR_OUT, 0},
+	{ HTC_RAW_STREAMS_SVC, PIPEDIR_IN, 1 },
+	{ HTT_DATA_MSG_SVC, PIPEDIR_OUT, 4, },
+	{ HTT_DATA_MSG_SVC, PIPEDIR_IN, 1, },
+	/* (Additions here) */
+	{ 0, 0, 0, },
+};
+
 static struct service_to_pipe target_service_to_ce_map_qca6290[] = {
 	{ WMI_DATA_VO_SVC, PIPEDIR_OUT, 3, },
 	{ WMI_DATA_VO_SVC, PIPEDIR_IN , 2, },
@@ -579,6 +602,11 @@ static void hif_select_service_to_pipe_map(struct hif_softc *scn,
 			*sz_tgt_svc_map_to_use =
 				sizeof(target_service_to_ce_map_qca6290);
 			break;
+		case TARGET_TYPE_QCA8074:
+			*tgt_svc_map_to_use = target_service_to_ce_map_qca8074;
+			*sz_tgt_svc_map_to_use =
+				sizeof(target_service_to_ce_map_qca8074);
+			break;
 		}
 	}
 }
@@ -2415,16 +2443,6 @@ static inline void hif_post_static_buf_to_target(struct hif_softc *scn)
 }
 #endif
 
-#ifdef WLAN_SUSPEND_RESUME_TEST
-static void hif_fake_apps_init_ctx(struct hif_softc *scn)
-{
-	INIT_WORK(&scn->fake_apps_ctx.resume_work,
-		  hif_fake_apps_resume_work);
-}
-#else
-static inline void hif_fake_apps_init_ctx(struct hif_softc *scn) {}
-#endif
-
 /**
  * hif_config_ce() - configure copy engines
  * @scn: hif context
@@ -2511,7 +2529,6 @@ int hif_config_ce(struct hif_softc *scn)
 	HIF_DBG("%s: ce_init done", __func__);
 
 	init_tasklet_workers(hif_hdl);
-	hif_fake_apps_init_ctx(scn);
 
 	HIF_DBG("%s: X, ret = %d", __func__, rv);
 

+ 16 - 10
hif/src/ce/ce_service.c

@@ -2106,12 +2106,15 @@ more_watermarks:
 		    more_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) {
 			goto more_completions;
 		} else {
-			HIF_ERROR(
-				"%s:Potential infinite loop detected during Rx processing nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x",
-				__func__, CE_state->dest_ring->nentries_mask,
-				CE_state->dest_ring->sw_index,
-				CE_DEST_RING_READ_IDX_GET(scn,
+			if (!ce_srng_based(scn)) {
+				HIF_ERROR(
+					"%s:Potential infinite loop detected during Rx processing nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x",
+					__func__,
+					CE_state->dest_ring->nentries_mask,
+					CE_state->dest_ring->sw_index,
+					CE_DEST_RING_READ_IDX_GET(scn,
 							  CE_state->ctrl_addr));
+			}
 		}
 	}
 
@@ -2122,12 +2125,15 @@ more_watermarks:
 		    more_snd_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) {
 			goto more_completions;
 		} else {
-			HIF_ERROR(
-				"%s:Potential infinite loop detected during send completion nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x",
-				__func__, CE_state->src_ring->nentries_mask,
-				CE_state->src_ring->sw_index,
-				CE_SRC_RING_READ_IDX_GET(scn,
+			if (!ce_srng_based(scn)) {
+				HIF_ERROR(
+					"%s:Potential infinite loop detected during send completion nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x",
+					__func__,
+					CE_state->src_ring->nentries_mask,
+					CE_state->src_ring->sw_index,
+					CE_SRC_RING_READ_IDX_GET(scn,
 							 CE_state->ctrl_addr));
+			}
 		}
 	}
 

+ 11 - 91
hif/src/ce/ce_tasklet.c

@@ -270,73 +270,19 @@ int hif_drain_tasklets(struct hif_softc *scn)
 
 #ifdef WLAN_SUSPEND_RESUME_TEST
 /**
- * hif_fake_apps_resume_work() - Work handler for fake apps resume callback
- * @work:	The work struct being passed from the linux kernel
+ * hif_interrupt_is_ut_resume(): Tests if an irq on the given copy engine should
+ *	trigger a unit-test resume.
+ * @scn: The HIF context to operate on
+ * @ce_id: The copy engine Id from the originating interrupt
  *
- * Return: none
+ * Return: true if the raised irq should trigger a unit-test resume
  */
-void hif_fake_apps_resume_work(struct work_struct *work)
+static bool hif_interrupt_is_ut_resume(struct hif_softc *scn, int ce_id)
 {
-	struct fake_apps_context *ctx =
-		container_of(work, struct fake_apps_context, resume_work);
-
-	QDF_BUG(ctx->resume_callback);
-	ctx->resume_callback(0);
-	ctx->resume_callback = NULL;
-}
-
-/**
- * hif_fake_apps_suspend(): Setup unit-test related suspend state. Call after
- *	a normal WoW suspend has been completed.
- * @hif_ctx:	The HIF context to operate on
- * @callback:	The function to call when fake apps resume is triggered
- *
- * Set the fake suspend flag such that hif knows that it will need
- * to fake the apps resume process using hdd_trigger_fake_apps_resume
- *
- * Return: none
- */
-void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx,
-			   hif_fake_resume_callback callback)
-{
-	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
-
-	scn->fake_apps_ctx.resume_callback = callback;
-	set_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state);
-}
-
-/**
- * hif_fake_apps_resume(): Cleanup unit-test related suspend state. Call before
- *	doing a normal WoW resume if suspend was initiated via fake apps
- *	suspend.
- * @hif_ctx:	The HIF context to operate on
- *
- * Return: none
- */
-void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx)
-{
-	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
-
-	clear_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state);
-	scn->fake_apps_ctx.resume_callback = NULL;
-}
-
-/**
- * hif_interrupt_is_fake_apps_resume(): Determines if the raised irq should
- *	trigger a fake apps resume.
- * @hif_ctx:	The HIF context to operate on
- * @ce_id:	The copy engine Id from the originating interrupt
- *
- * Return: true if the raised irq should trigger a fake apps resume
- */
-static bool hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx,
-					      int ce_id)
-{
-	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
 	int errno;
 	uint8_t wake_ce_id;
 
-	if (!test_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state))
+	if (!hif_is_ut_suspended(scn))
 		return false;
 
 	/* ensure passed ce_id matches wake ce_id */
@@ -348,39 +294,13 @@ static bool hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx,
 
 	return ce_id == wake_ce_id;
 }
-
-/**
- * hif_trigger_fake_apps_resume(): Trigger a fake apps resume by scheduling the
- *	previously registered callback for execution
- * @hif_ctx:	The HIF context to operate on
- *
- * Return: None
- */
-static void hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx)
-{
-	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
-
-	if (!test_and_clear_bit(HIF_FA_SUSPENDED_BIT,
-				&scn->fake_apps_ctx.state))
-		return;
-
-	schedule_work(&scn->fake_apps_ctx.resume_work);
-}
-
 #else
-
 static inline bool
-hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx, int ce_id)
+hif_interrupt_is_ut_resume(struct hif_softc *scn, int ce_id)
 {
 	return false;
 }
-
-static inline void
-hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx)
-{
-}
-
-#endif /* End of WLAN_SUSPEND_RESUME_TEST */
+#endif /* WLAN_SUSPEND_RESUME_TEST */
 
 /**
  * hif_snoc_interrupt_handler() - hif_snoc_interrupt_handler
@@ -482,8 +402,8 @@ irqreturn_t ce_dispatch_interrupt(int ce_id,
 	hif_record_ce_desc_event(scn, ce_id, HIF_IRQ_EVENT, NULL, NULL, 0);
 	hif_ce_increment_interrupt_count(hif_ce_state, ce_id);
 
-	if (unlikely(hif_interrupt_is_fake_apps_resume(hif_hdl, ce_id))) {
-		hif_trigger_fake_apps_resume(hif_hdl);
+	if (unlikely(hif_interrupt_is_ut_resume(scn, ce_id))) {
+		hif_ut_fw_resume(scn);
 		hif_irq_enable(scn, ce_id);
 		return IRQ_HANDLED;
 	}

+ 3 - 0
hif/src/hif_main.c

@@ -50,6 +50,7 @@
 #include "hal_api.h"
 #endif
 #include "hif_napi.h"
+#include "hif_unit_test_suspend_i.h"
 
 void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start)
 {
@@ -534,6 +535,8 @@ QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev,
 		return status;
 	}
 
+	hif_ut_suspend_init(scn);
+
 	/*
 	 * Flag to avoid potential unallocated memory access from MSI
 	 * interrupt handler which could get scheduled as soon as MSI

+ 2 - 17
hif/src/hif_main.h

@@ -47,6 +47,7 @@
 #include "cepci.h"
 #include "hif.h"
 #include "multibus.h"
+#include "hif_unit_test_suspend_i.h"
 
 #define HIF_MIN_SLEEP_INACTIVITY_TIME_MS     50
 #define HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS 60
@@ -118,20 +119,6 @@ struct hif_ce_stats {
 	int ce_ring_delta_fail_count;
 };
 
-#ifdef WLAN_SUSPEND_RESUME_TEST
-struct fake_apps_context {
-	unsigned long state;
-	hif_fake_resume_callback resume_callback;
-	struct work_struct resume_work;
-};
-
-enum hif_fake_apps_state_bits {
-	HIF_FA_SUSPENDED_BIT = 0
-};
-
-void hif_fake_apps_resume_work(struct work_struct *work);
-#endif /* WLAN_SUSPEND_RESUME_TEST */
-
 struct hif_softc {
 	struct hif_opaque_softc osc;
 	struct hif_config_info hif_config;
@@ -178,9 +165,7 @@ struct hif_softc {
 	uint32_t nss_wifi_ol_mode;
 #endif
 	void *hal_soc;
-#ifdef WLAN_SUSPEND_RESUME_TEST
-	struct fake_apps_context fake_apps_ctx;
-#endif /* WLAN_SUSPEND_RESUME_TEST */
+	struct hif_ut_suspend_context ut_suspend_ctx;
 	uint32_t hif_attribute;
 };
 

+ 114 - 0
hif/src/hif_unit_test_suspend.c

@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "qdf_status.h"
+#include "hif_main.h"
+#include "hif_unit_test_suspend.h"
+#include "hif_unit_test_suspend_i.h"
+
+enum hif_ut_suspend_state_bits {
+	UT_SUSPENDED_BIT = 0
+};
+
+/**
+ * hif_ut_fw_resume_work() - Work handler for firmware-triggered resume
+ * @work: The work struct being passed from the linux kernel
+ *
+ * Return: None
+ */
+static void hif_ut_fw_resume_work(struct work_struct *work)
+{
+	struct hif_ut_suspend_context *ctx =
+		container_of(work, struct hif_ut_suspend_context, resume_work);
+
+	QDF_BUG(ctx);
+	if (!ctx)
+		return;
+
+	QDF_BUG(ctx->resume_callback);
+	if (!ctx->resume_callback)
+		return;
+
+	ctx->resume_callback();
+	ctx->resume_callback = NULL;
+}
+
+void hif_ut_suspend_init(struct hif_softc *scn)
+{
+	INIT_WORK(&scn->ut_suspend_ctx.resume_work, hif_ut_fw_resume_work);
+}
+
+bool hif_is_ut_suspended(struct hif_softc *scn)
+{
+	QDF_BUG(scn);
+	if (!scn)
+		return false;
+
+	return test_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state);
+}
+
+QDF_STATUS hif_ut_apps_suspend(struct hif_opaque_softc *opaque_scn,
+			       hif_ut_resume_callback callback)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(opaque_scn);
+
+	QDF_BUG(scn);
+	if (!scn)
+		return QDF_STATUS_E_INVAL;
+
+	QDF_BUG(callback);
+	if (!callback)
+		return QDF_STATUS_E_INVAL;
+
+	if (test_and_set_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state))
+		return QDF_STATUS_E_INVAL;
+
+	scn->ut_suspend_ctx.resume_callback = callback;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS hif_ut_apps_resume(struct hif_opaque_softc *opaque_scn)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(opaque_scn);
+
+	QDF_BUG(scn);
+	if (!scn)
+		return QDF_STATUS_E_INVAL;
+
+	if (!test_and_clear_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state))
+		return QDF_STATUS_E_INVAL;
+
+	scn->ut_suspend_ctx.resume_callback = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS hif_ut_fw_resume(struct hif_softc *scn)
+{
+	QDF_BUG(scn);
+	if (!scn)
+		return QDF_STATUS_E_INVAL;
+
+	if (!test_and_clear_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state))
+		return QDF_STATUS_E_INVAL;
+
+	schedule_work(&scn->ut_suspend_ctx.resume_work);
+
+	return QDF_STATUS_SUCCESS;
+}

+ 84 - 0
hif/src/hif_unit_test_suspend_i.h

@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: HIF internal unit-test related APIs for triggering WoW suspend/resume
+ * while the application processor is still up.
+ */
+
+#ifndef _HIF_UNIT_TEST_SUSPEND_I_H_
+#define _HIF_UNIT_TEST_SUSPEND_I_H_
+
+#include "qdf_status.h"
+#include "hif_main.h"
+#include "hif_unit_test_suspend.h"
+
+#ifdef WLAN_SUSPEND_RESUME_TEST
+
+struct hif_ut_suspend_context {
+	unsigned long state;
+	hif_ut_resume_callback resume_callback;
+	struct work_struct resume_work;
+};
+
+/**
+ * hif_ut_suspend_init() - Initialize the unit-test suspend context
+ * @scn: the hif context to initialize
+ *
+ * Return: None
+ */
+void hif_ut_suspend_init(struct hif_softc *scn);
+
+/**
+ * hif_is_ut_suspended() - Tests if the given hif context is unit-test suspended
+ * @scn: The HIF context to check
+ *
+ * Return: true, if unit-test suspended, otherwise false
+ */
+bool hif_is_ut_suspended(struct hif_softc *scn);
+
+/**
+ * hif_ut_fw_resume() - Initiate a firmware triggered unit-test resume
+ * @scn: The HIF context to operate on
+ *
+ * This schedules the callback previously registered via a call to
+ * hif_ut_apps_suspend for execution.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hif_ut_fw_resume(struct hif_softc *scn);
+
+#else /* WLAN_SUSPEND_RESUME_TEST */
+
+struct hif_ut_suspend_context {};
+
+static inline void hif_ut_suspend_init(struct hif_softc *scn) {}
+
+static inline bool hif_is_ut_suspended(struct hif_softc *scn)
+{
+	return false;
+}
+
+static inline QDF_STATUS hif_ut_fw_resume(struct hif_softc *scn)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+#endif /* WLAN_SUSPEND_RESUME_TEST */
+
+#endif /* _HIF_UNIT_TEST_SUSPEND_I_H_ */

+ 2 - 1
hif/src/snoc/if_ahb.c

@@ -301,7 +301,8 @@ int hif_ahb_configure_grp_irq(struct hif_softc *scn)
 				ic_irqnum[hif_ext_group->irq[j]] = irq;
 				ret = request_irq(irq,
 					hif_ext_group_ahb_interrupt_handler,
-						IRQF_TRIGGER_RISING, "wlan_ahb",
+						IRQF_TRIGGER_RISING,
+						ic_irqname[hif_ext_group->irq[j]],
 						hif_ext_group);
 				if (ret) {
 					dev_err(&pdev->dev,

+ 2 - 0
os_if/linux/scan/inc/wlan_cfg80211_scan.h

@@ -76,11 +76,13 @@ typedef struct {
 /**
  * struct osif_scan_pdev - OS scan private strcutre
  * scan_req_q: Scan request queue
+ * scan_req_q_lock: Protect scan request queue
  * req_id: Scan request Id
  * runtime_pm_lock: Runtime suspend lock
  */
 struct osif_scan_pdev{
 	qdf_list_t scan_req_q;
+	qdf_mutex_t scan_req_q_lock;
 	wlan_scan_requester req_id;
 	qdf_runtime_lock_t runtime_pm_lock;
 };

+ 40 - 4
os_if/linux/scan/src/wlan_cfg80211_scan.c

@@ -458,9 +458,10 @@ static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev,
 	scan_req->source = source;
 	scan_req->scan_id = scan_id;
 
+	qdf_mutex_acquire(&osif_scan->scan_req_q_lock);
 	status = qdf_list_insert_back(&osif_scan->scan_req_q,
 					&scan_req->node);
-
+	qdf_mutex_release(&osif_scan->scan_req_q_lock);
 	if (QDF_STATUS_SUCCESS != status) {
 		cfg80211_err("Failed to enqueue Scan Req");
 		qdf_mem_free(scan_req);
@@ -509,8 +510,10 @@ static QDF_STATUS wlan_scan_request_dequeue(
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	qdf_mutex_acquire(&scan_priv->scan_req_q_lock);
 	if (QDF_STATUS_SUCCESS !=
 		qdf_list_peek_front(&scan_priv->scan_req_q, &next_node)) {
+		qdf_mutex_release(&scan_priv->scan_req_q_lock);
 		cfg80211_err("Failed to remove Scan Req from queue");
 		return QDF_STATUS_E_FAILURE;
 	}
@@ -526,11 +529,13 @@ static QDF_STATUS wlan_scan_request_dequeue(
 				*req = scan_req->scan_request;
 				*source = scan_req->source;
 				qdf_mem_free(scan_req);
+				qdf_mutex_release(&scan_priv->scan_req_q_lock);
 				cfg80211_info("removed Scan id: %d, req = %p, pending scans %d",
 				      scan_id, req,
 				      qdf_list_size(&scan_priv->scan_req_q));
 				return QDF_STATUS_SUCCESS;
 			} else {
+				qdf_mutex_release(&scan_priv->scan_req_q_lock);
 				cfg80211_err("Failed to remove node scan id %d, pending scans %d",
 				      scan_id,
 				      qdf_list_size(&scan_priv->scan_req_q));
@@ -539,7 +544,7 @@ static QDF_STATUS wlan_scan_request_dequeue(
 		}
 	} while (QDF_STATUS_SUCCESS ==
 		qdf_list_peek_next(&scan_priv->scan_req_q, node, &next_node));
-
+	qdf_mutex_release(&scan_priv->scan_req_q_lock);
 	cfg80211_err("Failed to find scan id %d", scan_id);
 
 	return status;
@@ -727,6 +732,26 @@ static void wlan_cfg80211_scan_done_callback(
 		goto allow_suspend;
 	}
 
+	if (req->wdev == NULL) {
+		cfg80211_err("wirless dev is NULL,Drop scan event Id: %d",
+				 scan_id);
+		goto allow_suspend;
+	}
+
+	if (req->wdev->netdev == NULL) {
+		cfg80211_err("net dev is NULL,Drop scan event Id: %d",
+				 scan_id);
+		goto allow_suspend;
+	}
+
+	/* Make sure vdev is active */
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_OSIF_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("Failed to get vdev reference: scan Id: %d",
+				 scan_id);
+		goto allow_suspend;
+	}
+
 	/*
 	 * Scan can be triggred from NL or vendor scan
 	 * - If scan is triggered from NL then cfg80211 scan done should be
@@ -739,6 +764,7 @@ static void wlan_cfg80211_scan_done_callback(
 	else
 		wlan_vendor_scan_callback(req, aborted);
 
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
 allow_suspend:
 	osif_priv = wlan_pdev_get_ospriv(pdev);
 	if (qdf_list_empty(&osif_priv->osif_scan->scan_req_q))
@@ -770,6 +796,7 @@ QDF_STATUS wlan_cfg80211_scan_priv_init(struct wlan_objmgr_pdev *pdev)
 	/* Initialize the scan request queue */
 	osif_priv->osif_scan = scan_priv;
 	qdf_list_create(&scan_priv->scan_req_q, WLAN_MAX_SCAN_COUNT);
+	qdf_mutex_create(&scan_priv->scan_req_q_lock);
 	scan_priv->req_id = req_id;
 	scan_priv->runtime_pm_lock = qdf_runtime_lock_init("scan");
 
@@ -791,6 +818,7 @@ QDF_STATUS wlan_cfg80211_scan_priv_deinit(struct wlan_objmgr_pdev *pdev)
 	osif_priv->osif_scan = NULL;
 	ucfg_scan_unregister_requester(psoc, scan_priv->req_id);
 	qdf_list_destroy(&scan_priv->scan_req_q);
+	qdf_mutex_destroy(&scan_priv->scan_req_q_lock);
 	qdf_runtime_lock_deinit(scan_priv->runtime_pm_lock);
 	scan_priv->runtime_pm_lock = NULL;
 	qdf_mem_free(scan_priv);
@@ -818,15 +846,16 @@ void wlan_cfg80211_cleanup_scan_queue(struct wlan_objmgr_pdev *pdev)
 	wlan_pdev_obj_unlock(pdev);
 
 	scan_priv = osif_priv->osif_scan;
-
+	qdf_mutex_acquire(&scan_priv->scan_req_q_lock);
 	while (!qdf_list_empty(&scan_priv->scan_req_q)) {
 		if (QDF_STATUS_SUCCESS !=
 			qdf_list_remove_front(&scan_priv->scan_req_q,
 						&node)) {
+			qdf_mutex_release(&scan_priv->scan_req_q_lock);
 			cfg80211_err("Failed to remove scan request");
 			return;
 		}
-
+		qdf_mutex_release(&scan_priv->scan_req_q_lock);
 		scan_req = container_of(node, struct scan_req, node);
 		req = scan_req->scan_request;
 		source = scan_req->source;
@@ -835,7 +864,9 @@ void wlan_cfg80211_cleanup_scan_queue(struct wlan_objmgr_pdev *pdev)
 		else
 			wlan_vendor_scan_callback(req, aborted);
 		qdf_mem_free(scan_req);
+		qdf_mutex_acquire(&scan_priv->scan_req_q_lock);
 	}
+	qdf_mutex_release(&scan_priv->scan_req_q_lock);
 
 	return;
 }
@@ -1109,7 +1140,9 @@ static int wlan_get_scanid(struct wlan_objmgr_pdev *pdev,
 		return ret;
 	}
 	scan_priv = osif_ctx->osif_scan;
+	qdf_mutex_acquire(&scan_priv->scan_req_q_lock);
 	if (qdf_list_empty(&scan_priv->scan_req_q)) {
+		qdf_mutex_release(&scan_priv->scan_req_q_lock);
 		cfg80211_err("Failed to retrieve scan id");
 		return ret;
 	}
@@ -1117,6 +1150,7 @@ static int wlan_get_scanid(struct wlan_objmgr_pdev *pdev,
 	if (QDF_STATUS_SUCCESS !=
 			    qdf_list_peek_front(&scan_priv->scan_req_q,
 			    &ptr_node)) {
+		qdf_mutex_release(&scan_priv->scan_req_q_lock);
 		return ret;
 	}
 
@@ -1133,6 +1167,8 @@ static int wlan_get_scanid(struct wlan_objmgr_pdev *pdev,
 		 qdf_list_peek_next(&scan_priv->scan_req_q,
 		 node, &ptr_node));
 
+	qdf_mutex_release(&scan_priv->scan_req_q_lock);
+
 	return ret;
 }
 

+ 75 - 73
pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c

@@ -452,112 +452,114 @@ out:
 }
 
 QDF_STATUS pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc,
-	enum qdf_suspend_type suspend_type)
+				      enum qdf_suspend_type suspend_type)
 {
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	QDF_STATUS resume_status;
+	struct wlan_pmo_ctx *pmo_ctx;
+	uint8_t i;
 	pmo_psoc_suspend_handler handler;
-	uint8_t index = 0;
-	QDF_STATUS suspend_status = QDF_STATUS_SUCCESS;
-	QDF_STATUS resume_status = QDF_STATUS_SUCCESS;
 	void *arg;
-	struct wlan_pmo_ctx *pmo_ctx;
 
 	PMO_ENTER();
+
 	pmo_ctx = pmo_get_context();
 	if (!pmo_ctx) {
-		QDF_ASSERT(0);
 		pmo_err("unable to get pmo ctx");
-		suspend_status = QDF_STATUS_E_FAILURE;
-		goto out;
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_FAILURE;
+		goto exit_with_status;
 	}
 
-	/* call all component's Suspend Handler */
-	while (index < WLAN_UMAC_MAX_COMPONENTS) {
+	/* call each component's suspend handler */
+	for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) {
 		qdf_spin_lock_bh(&pmo_ctx->lock);
-		if (pmo_ctx->pmo_suspend_handler[index]) {
-			handler = pmo_ctx->pmo_suspend_handler[index];
-			arg = pmo_ctx->pmo_suspend_handler_arg[index];
-			qdf_spin_unlock_bh(&pmo_ctx->lock);
-			suspend_status = handler(psoc, arg);
-			if (suspend_status != QDF_STATUS_SUCCESS) {
-				pmo_err("component id: %d failed to suspend status: %d",
-					index, suspend_status);
-				QDF_ASSERT(0);
-				/* break, no need to suspend next components */
-				break;
-			}
-		} else {
-			qdf_spin_unlock_bh(&pmo_ctx->lock);
+		handler = pmo_ctx->pmo_suspend_handler[i];
+		arg = pmo_ctx->pmo_suspend_handler_arg[i];
+		qdf_spin_unlock_bh(&pmo_ctx->lock);
+
+		if (!handler)
+			continue;
+
+		status = handler(psoc, arg);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pmo_err("component %d failed to suspend; status: %d",
+				i, status);
+			QDF_ASSERT(0);
+			goto suspend_recovery;
 		}
-		index++;
-	}
-
-	/* resume the succefully suspended components */
-	if (suspend_status != QDF_STATUS_SUCCESS) {
-		while (index >= 0) {
-			/*
-			 * index points to id which refuse suspend
-			 * so go to previous id.
-			 */
-			index--;
-			qdf_spin_lock_bh(&pmo_ctx->lock);
-			handler = pmo_ctx->pmo_resume_handler[index];
-			arg = pmo_ctx->pmo_resume_handler_arg[index];
-			qdf_spin_unlock_bh(&pmo_ctx->lock);
-			/* TODO: if resume got failed for some component ?? */
-			resume_status = handler(psoc, arg);
-			if (resume_status != QDF_STATUS_SUCCESS) {
-				pmo_err("Component id: %d failed to resume status: %d",
-					index, resume_status);
-				QDF_ASSERT(0);
-			}
+	}
+
+	goto exit_with_status;
+
+suspend_recovery:
+	/* resume, starting with the last successfully suspended component */
+	for (i -= 1; i >= 0; i--) {
+		qdf_spin_lock_bh(&pmo_ctx->lock);
+		handler = pmo_ctx->pmo_resume_handler[i];
+		arg = pmo_ctx->pmo_resume_handler_arg[i];
+		qdf_spin_unlock_bh(&pmo_ctx->lock);
+
+		if (!handler)
+			continue;
+
+		resume_status = handler(psoc, arg);
+		if (QDF_IS_STATUS_ERROR(resume_status)) {
+			pmo_fatal("Non-recoverable failure occurred!");
+			pmo_fatal("component %d failed to resume; status: %d",
+				  i, resume_status);
+			QDF_BUG(0);
 		}
 	}
-out:
+
+exit_with_status:
 	PMO_EXIT();
 
-	return suspend_status;
+	return status;
 }
 
 QDF_STATUS pmo_resume_all_components(struct wlan_objmgr_psoc *psoc,
-	enum qdf_suspend_type suspend_type)
+				     enum qdf_suspend_type suspend_type)
 {
-	uint8_t index = 0;
-	QDF_STATUS component_ret = QDF_STATUS_SUCCESS;
-	void *arg;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct wlan_pmo_ctx *pmo_ctx;
+	uint8_t i;
 	pmo_psoc_suspend_handler handler;
+	void *arg;
 
 	PMO_ENTER();
+
 	pmo_ctx = pmo_get_context();
 	if (!pmo_ctx) {
-		QDF_ASSERT(0);
 		pmo_err("unable to get pmo ctx");
-		component_ret = QDF_STATUS_E_FAILURE;
-		goto out;
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_FAILURE;
+		goto exit_with_status;
 	}
 
-	/* call all components Resume Handler */
-	while (index < WLAN_UMAC_MAX_COMPONENTS) {
+	/* call each component's resume handler */
+	for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) {
 		qdf_spin_lock_bh(&pmo_ctx->lock);
-		if (pmo_ctx->pmo_resume_handler[index]) {
-			handler = pmo_ctx->pmo_resume_handler[index];
-			arg = pmo_ctx->pmo_resume_handler_arg[index];
-			qdf_spin_unlock_bh(&pmo_ctx->lock);
-			component_ret = handler(psoc, arg);
-			if (component_ret != QDF_STATUS_SUCCESS) {
-				pmo_err("Component id: %d failed to resume status: %d",
-					index, component_ret);
-				QDF_ASSERT(0);
-			}
-		} else {
-			qdf_spin_unlock_bh(&pmo_ctx->lock);
+		handler = pmo_ctx->pmo_resume_handler[i];
+		arg = pmo_ctx->pmo_resume_handler_arg[i];
+		qdf_spin_unlock_bh(&pmo_ctx->lock);
+
+		if (!handler)
+			continue;
+
+		status = handler(psoc, arg);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			pmo_fatal("Non-recoverable failure occurred!");
+			pmo_fatal("component %d failed to resume; status: %d",
+				  i, status);
+			QDF_BUG(0);
 		}
-		index++;
-}
-out:
+	}
+
+exit_with_status:
 	PMO_EXIT();
 
-	return component_ret;
+	return status;
 }
 
 QDF_STATUS pmo_register_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc,

+ 12 - 0
qdf/inc/qdf_nbuf.h

@@ -178,6 +178,18 @@ struct mon_rx_status {
 	uint8_t  he_sig_b_common_RU[4];
 };
 
+/* Masks for HE SIG known fields in mon_rx_status structure */
+#define QDF_MON_STATUS_HE_SIG_A1_SU_KNOWN_ALL		0x000007ff
+#define QDF_MON_STATUS_HE_SIG_A1_MU_KNOWN_ALL		0x000003ff
+#define QDF_MON_STATUS_HE_SIG_A2_SU_KNOWN_ALL		0x00000ffd
+#define QDF_MON_STATUS_HE_SIG_A2_MU_KNOWN_ALL		0x00000ffd
+#define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU0	0x00000001
+#define QDF_MON_STATUS_HE_SIG_B_USER_KNOWN_SIG_B_ALL	0x00fe0000
+#define QDF_MON_STATUS_HE_SIG_A1_HE_FORMAT_SU		0x00000000
+#define QDF_MON_STATUS_HE_SIG_A1_HE_FORMAT_EXT_SU	0x40000000
+#define QDF_MON_STATUS_HE_SIG_A1_HE_FORMAT_MU		0x80000000
+#define QDF_MON_STATUS_HE_SIG_A1_HE_FORMAT_TRIG		0xc0000000
+
 /* DHCP Related Mask */
 #define QDF_DHCP_OPTION53			(0x35)
 #define QDF_DHCP_OPTION53_LENGTH		(1)

+ 1 - 1
qdf/linux/src/i_qdf_lock.h

@@ -295,7 +295,7 @@ static inline void __qdf_spin_lock_bh(__qdf_spinlock_t *lock)
 static inline void __qdf_spin_unlock_bh(__qdf_spinlock_t *lock)
 {
 	if (unlikely(lock->flags & QDF_LINUX_UNLOCK_BH)) {
-		lock->flags &= ~QDF_LINUX_UNLOCK_BH;
+		lock->flags &= (unsigned long)~QDF_LINUX_UNLOCK_BH;
 		spin_unlock_bh(&lock->spinlock);
 	} else
 		spin_unlock(&lock->spinlock);

+ 3 - 15
qdf/linux/src/i_qdf_nbuf.h

@@ -569,28 +569,16 @@ void __qdf_nbuf_num_frags_init(struct sk_buff *skb)
 	QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) = 0;
 }
 
-#ifdef CONFIG_MCL
-typedef enum {
-	CB_FTYPE_INVALID = 0,
-	CB_FTYPE_MCAST2UCAST = 1,
-	CB_FTYPE_TSO = 2,
-	CB_FTYPE_TSO_SG = 3,
-	CB_FTYPE_SG = 4,
-} CB_FTYPE;
-#else
 typedef enum {
 	CB_FTYPE_INVALID = 0,
 	CB_FTYPE_MCAST2UCAST = 1,
 	CB_FTYPE_TSO = 2,
 	CB_FTYPE_TSO_SG = 3,
 	CB_FTYPE_SG = 4,
-#if ATH_DATA_RX_INFO_EN
-	CB_FTYPE_RX_INFO = 5,
-#else
-	CB_FTYPE_MESH_RX_INFO = 5,
-#endif
+	CB_FTYPE_INTRABSS_FWD = 5,
+	CB_FTYPE_RX_INFO = 6,
+	CB_FTYPE_MESH_RX_INFO = 7,
 } CB_FTYPE;
-#endif
 
 /*
  * prototypes. Implemented in qdf_nbuf.c

+ 1 - 1
qdf/linux/src/qdf_nbuf.c

@@ -2752,7 +2752,7 @@ unsigned int qdf_nbuf_update_radiotap(struct mon_rx_status *rx_status,
 		qdf_print("ERROR: not enough space to update radiotap\n");
 		return 0;
 	}
-	qdf_nbuf_pull_head(nbuf, headroom_sz  - rtap_len);
+	qdf_nbuf_push_head(nbuf, rtap_len);
 	qdf_mem_copy(qdf_nbuf_data(nbuf), rtap_buf, rtap_len);
 	return rtap_len;
 }

+ 5 - 7
qdf/linux/src/qdf_trace.c

@@ -927,7 +927,7 @@ void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir)
 EXPORT_SYMBOL(qdf_dp_trace_set_track);
 #if CONFIG_MCL
 #define DPTRACE_PRINT(args...) \
-	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, ## args)
+	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, ## args)
 #else
 #define DPTRACE_PRINT(args...) \
 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_NONE, ## args)
@@ -1702,15 +1702,13 @@ void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id)
 	int32_t i, tail;
 
 	if (!g_qdf_dp_trace_data.enable) {
-		QDF_TRACE(QDF_MODULE_ID_SYS,
-			  QDF_TRACE_LEVEL_ERROR, "Tracing Disabled");
+		DPTRACE_PRINT("Tracing Disabled");
 		return;
 	}
 
-	QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
-		  "Total Records: %d, Head: %d, Tail: %d",
-		  g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head,
-		  g_qdf_dp_trace_data.tail);
+	DPTRACE_PRINT("Total Records: %d, Head: %d, Tail: %d",
+		      g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head,
+		      g_qdf_dp_trace_data.tail);
 
 	/* aquire the lock so that only one thread at a time can read
 	 * the ring buffer

+ 11 - 0
umac/cmn_services/obj_mgr/src/wlan_objmgr_pdev_obj.c

@@ -221,10 +221,21 @@ static QDF_STATUS wlan_objmgr_pdev_obj_destroy(struct wlan_objmgr_pdev *pdev)
 
 QDF_STATUS wlan_objmgr_pdev_obj_delete(struct wlan_objmgr_pdev *pdev)
 {
+	uint8_t print_idx;
+
 	if (pdev == NULL) {
 		obj_mgr_err("pdev is NULL");
 		return QDF_STATUS_E_FAILURE;
 	}
+
+	print_idx = qdf_get_pidx();
+	if (qdf_print_is_verbose_enabled(print_idx, QDF_MODULE_ID_OBJ_MGR,
+		QDF_TRACE_LEVEL_DEBUG)) {
+		obj_mgr_debug("Logically deleting the pdev(id:%d)",
+					pdev->pdev_objmgr.wlan_pdev_id);
+		wlan_objmgr_print_ref_ids(pdev->pdev_objmgr.ref_id_dbg);
+	}
+
 	/*
 	 * Update PDEV object state to LOGICALLY DELETED
 	 * It prevents further access of this object

+ 18 - 0
umac/cmn_services/obj_mgr/src/wlan_objmgr_peer_obj.c

@@ -289,11 +289,29 @@ static QDF_STATUS wlan_objmgr_peer_obj_destroy(struct wlan_objmgr_peer *peer)
 
 QDF_STATUS wlan_objmgr_peer_obj_delete(struct wlan_objmgr_peer *peer)
 {
+	uint8_t print_idx;
+	uint8_t *macaddr;
+
 	if (peer == NULL) {
 		obj_mgr_err("PEER is NULL");
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	wlan_peer_obj_lock(peer);
+	macaddr = wlan_peer_get_macaddr(peer);
+	wlan_peer_obj_unlock(peer);
+
+
+	print_idx = qdf_get_pidx();
+	if (qdf_print_is_verbose_enabled(print_idx, QDF_MODULE_ID_OBJ_MGR,
+		QDF_TRACE_LEVEL_DEBUG)) {
+		obj_mgr_debug("Logically deleting the peer"
+					"(%02x:%02x:%02x:%02x:%02x:%02x)",
+					macaddr[0], macaddr[1], macaddr[2],
+					macaddr[3], macaddr[4], macaddr[5]);
+		wlan_objmgr_print_ref_ids(peer->peer_objmgr.ref_id_dbg);
+	}
+
 	/**
 	 * Update VDEV object state to LOGICALLY DELETED
 	 * It prevents further access of this object

+ 11 - 0
umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c

@@ -235,10 +235,21 @@ static QDF_STATUS wlan_objmgr_psoc_obj_destroy(struct wlan_objmgr_psoc *psoc)
 
 QDF_STATUS wlan_objmgr_psoc_obj_delete(struct wlan_objmgr_psoc *psoc)
 {
+	uint8_t print_idx;
+
 	if (psoc == NULL) {
 		obj_mgr_err("psoc is NULL");
 		return QDF_STATUS_E_FAILURE;
 	}
+
+	print_idx = qdf_get_pidx();
+
+	if (qdf_print_is_verbose_enabled(print_idx, QDF_MODULE_ID_OBJ_MGR,
+		QDF_TRACE_LEVEL_DEBUG)) {
+		obj_mgr_debug("Logically deleting the psoc");
+		wlan_objmgr_print_ref_ids(psoc->soc_objmgr.ref_id_dbg);
+	}
+
 	/*
 	 * Update PSOC object state to LOGICALLY DELETED
 	 * It prevents further access of this object

+ 11 - 0
umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c

@@ -276,10 +276,21 @@ static QDF_STATUS wlan_objmgr_vdev_obj_destroy(struct wlan_objmgr_vdev *vdev)
 
 QDF_STATUS wlan_objmgr_vdev_obj_delete(struct wlan_objmgr_vdev *vdev)
 {
+	uint8_t print_idx;
+
 	if (vdev == NULL) {
 		obj_mgr_err("vdev is NULL");
 		return QDF_STATUS_E_FAILURE;
 	}
+
+	print_idx = qdf_get_pidx();
+	if (qdf_print_is_verbose_enabled(print_idx, QDF_MODULE_ID_OBJ_MGR,
+		QDF_TRACE_LEVEL_DEBUG)) {
+		obj_mgr_debug("Logically deleting the vdev(id:%d)",
+					vdev->vdev_objmgr.vdev_id);
+		wlan_objmgr_print_ref_ids(vdev->vdev_objmgr.ref_id_dbg);
+	}
+
 	/*
 	 * Update VDEV object state to LOGICALLY DELETED
 	 * It prevents further access of this object

+ 19 - 3
umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -245,9 +245,9 @@ void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc,
  * mode. In the case of STA/P2P CLI/IBSS upon disconnection it is decremented
  * In the case of SAP/P2P GO upon bss stop it is decremented
  *
- * Return: None
+ * Return: QDF_STATUS
  */
-void policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
+QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
 		enum tQDF_ADAPTER_MODE mode, uint8_t sessionId);
 
 /**
@@ -782,7 +782,7 @@ struct policy_mgr_hdd_cbacks {
 	QDF_STATUS (*wlan_hdd_get_channel_for_sap_restart)(
 				struct wlan_objmgr_psoc *psoc,
 				uint8_t vdev_id, uint8_t *channel,
-				uint8_t *sec_ch, bool is_restart_sap);
+				uint8_t *sec_ch);
 	enum policy_mgr_con_mode (*get_mode_for_non_connected_vdev)(
 				struct wlan_objmgr_psoc *psoc,
 				uint8_t vdev_id);
@@ -1360,6 +1360,22 @@ uint32_t policy_mgr_mode_specific_connection_count(
 		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode,
 		uint32_t *list);
 
+/**
+ * policy_mgr_check_conn_with_mode_and_vdev_id() - checks if any active
+ * session with specific mode and vdev_id
+ * @psoc: PSOC object information
+ * @mode: type of connection
+ * @vdev_id: vdev_id of the connection
+ *
+ * This function checks if any active session with specific mode and vdev_id
+ * is present
+ *
+ * Return: QDF STATUS with success if active session is found, else failure
+ */
+QDF_STATUS policy_mgr_check_conn_with_mode_and_vdev_id(
+		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode,
+		uint32_t vdev_id);
+
 /**
  * policy_mgr_hw_mode_transition_cb() - Callback for HW mode
  * transition from FW

+ 1 - 27
umac/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c

@@ -599,27 +599,6 @@ static bool policy_mgr_is_restart_sap_allowed(
 	return true;
 }
 
-/**
- * policy_mgr_is_sap_channel_change_without_restart() - Check if
- * SAP channel change allowed without restart
- * @mcc_to_scc_switch: MCC to SCC switch enabled user config
- *
- * Check if SAP channel change allowed without restart
- *
- * Restart: true or false
- */
-static bool policy_mgr_is_sap_channel_change_without_restart(
-			uint32_t mcc_to_scc_switch) {
-	if (mcc_to_scc_switch ==
-	    QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION ||
-	    mcc_to_scc_switch ==
-	    QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) {
-		policy_mgr_info("SAP chan change without restart allowed");
-		return true;
-	}
-	return false;
-}
-
 /**
  * policy_mgr_check_sta_ap_concurrent_ch_intf() - Restart SAP in STA-AP case
  * @data: Pointer check concurrent channel work data
@@ -637,8 +616,6 @@ void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data)
 	QDF_STATUS status;
 	uint8_t channel, sec_ch;
 	uint8_t operating_channel, vdev_id;
-	bool restart_sap;
-
 
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {
@@ -661,9 +638,6 @@ void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data)
 		return;
 	}
 
-	restart_sap = policy_mgr_is_sap_channel_change_without_restart(
-		mcc_to_scc_switch) ? false : true;
-
 	if (!pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart) {
 		policy_mgr_err("SAP restart get channel callback in NULL");
 		return;
@@ -671,7 +645,7 @@ void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data)
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	status = pm_ctx->hdd_cbacks.
 		wlan_hdd_get_channel_for_sap_restart(psoc, vdev_id,
-			&channel, &sec_ch, restart_sap);
+			&channel, &sec_ch);
 	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 	if (status != QDF_STATUS_SUCCESS) {
 		policy_mgr_err("Failed to switch SAP channel");

+ 42 - 2
umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -838,6 +838,33 @@ uint32_t policy_mgr_mode_specific_connection_count(
 	return count;
 }
 
+QDF_STATUS policy_mgr_check_conn_with_mode_and_vdev_id(
+		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode,
+		uint32_t vdev_id)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
+	uint32_t conn_index = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return qdf_status;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if ((pm_conc_connection_list[conn_index].mode == mode) &&
+		    (pm_conc_connection_list[conn_index].vdev_id == vdev_id)) {
+			qdf_status = QDF_STATUS_SUCCESS;
+			break;
+		}
+		conn_index++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	return qdf_status;
+}
+
 void policy_mgr_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status,
 		uint32_t scan_config,
 		uint32_t fw_mode_config)
@@ -1122,16 +1149,27 @@ void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc,
 	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 }
 
-void policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
+QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
 				enum tQDF_ADAPTER_MODE mode,
 				uint8_t session_id)
 {
 	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	QDF_STATUS qdf_status;
 
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {
 		policy_mgr_err("context is NULL");
-		return;
+		return QDF_STATUS_E_EMPTY;
+	}
+
+	qdf_status = policy_mgr_check_conn_with_mode_and_vdev_id(psoc,
+			policy_mgr_convert_device_mode_to_qdf_type(mode),
+			session_id);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		policy_mgr_err("No connection with mode:%d vdev_id:%d",
+			policy_mgr_convert_device_mode_to_qdf_type(mode),
+			session_id);
+		return qdf_status;
 	}
 
 	switch (mode) {
@@ -1157,6 +1195,8 @@ void policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
 		pm_ctx->tdls_cbacks.tdls_notify_decrement_session(psoc);
 
 	policy_mgr_dump_current_concurrency(psoc);
+
+	return qdf_status;
 }
 
 QDF_STATUS policy_mgr_incr_connection_count(

+ 6 - 1
umac/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -103,7 +103,12 @@ void policy_mgr_decr_session_set_pcl(struct wlan_objmgr_psoc *psoc,
 		return;
 	}
 
-	policy_mgr_decr_active_session(psoc, mode, session_id);
+	qdf_status = policy_mgr_decr_active_session(psoc, mode, session_id);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		policy_mgr_err("Invalid active session");
+		return;
+	}
+
 	/*
 	 * After the removal of this connection, we need to check if
 	 * a STA connection still exists. The reason for this is that

+ 2 - 0
umac/scan/dispatcher/inc/wlan_scan_public_structs.h

@@ -534,6 +534,7 @@ enum scan_dwelltime_adaptive_mode {
  * @extraie: list of optional/vendor specific ie's to be added in probe requests
  * @htcap: htcap ie
  * @vhtcap: vhtcap ie
+ * @scan_ctrl_flags_ext: scan control flag extended
  */
 
 struct scan_req_params {
@@ -611,6 +612,7 @@ struct scan_req_params {
 	struct element_info extraie;
 	struct element_info htcap;
 	struct element_info vhtcap;
+	uint32_t scan_ctrl_flags_ext;
 };
 
 /**

+ 2 - 0
utils/host_diag_log/inc/host_diag_core_event.h

@@ -535,6 +535,7 @@ enum wifi_connectivity_events {
  * @WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP: Firmware response
  * @WIFI_POWER_EVENT_WAKELOCK_MISC: Miscellaneous wakelocks
  * @WIFI_POWER_EVENT_WAKELOCK_DHCP: DHCP negotiation under way
+ * @WIFI_POWER_EVENT_WAKELOCK_CONNECT: connection in progress
  *
  * Indicates the reason for which the wakelock was taken/released
  */
@@ -558,6 +559,7 @@ enum wake_lock_reason {
 	WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP,
 	WIFI_POWER_EVENT_WAKELOCK_MISC,
 	WIFI_POWER_EVENT_WAKELOCK_DHCP,
+	WIFI_POWER_EVENT_WAKELOCK_CONNECT,
 };
 
 #ifdef __cplusplus

+ 8 - 2
wlan_cfg/wlan_cfg.c

@@ -182,9 +182,10 @@ struct wlan_cfg_dp_pdev_ctxt {
  *
  * Return: wlan_cfg_ctx - Handle to Configuration context
  */
-struct wlan_cfg_dp_soc_ctxt *wlan_cfg_soc_attach(void)
+struct wlan_cfg_dp_soc_ctxt *wlan_cfg_soc_attach()
 {
 	int i = 0;
+
 	struct wlan_cfg_dp_soc_ctxt *wlan_cfg_ctx =
 		qdf_mem_malloc(sizeof(struct wlan_cfg_dp_soc_ctxt));
 
@@ -202,8 +203,8 @@ struct wlan_cfg_dp_soc_ctxt *wlan_cfg_soc_attach(void)
 	wlan_cfg_ctx->num_tx_ext_desc_pool = WLAN_CFG_NUM_TXEXT_DESC_POOL;
 	wlan_cfg_ctx->num_tx_desc = WLAN_CFG_NUM_TX_DESC;
 	wlan_cfg_ctx->num_tx_ext_desc = WLAN_CFG_NUM_TX_EXT_DESC;
-	wlan_cfg_ctx->max_peer_id = WLAN_CFG_MAX_PEER_ID;
 	wlan_cfg_ctx->htt_packet_type = WLAN_CFG_HTT_PKT_TYPE;
+	wlan_cfg_ctx->max_peer_id = WLAN_CFG_MAX_PEER_ID;
 
 	for (i = 0; i < WLAN_CFG_INT_NUM_CONTEXTS; i++) {
 		wlan_cfg_ctx->int_tx_ring_mask[i] = tx_ring_mask[i];
@@ -249,6 +250,11 @@ void wlan_cfg_set_num_contexts(struct wlan_cfg_dp_soc_ctxt *cfg, int num)
 	cfg->num_int_ctxts = num;
 }
 
+void wlan_cfg_set_max_peer_id(struct wlan_cfg_dp_soc_ctxt *cfg, uint32_t val)
+{
+	cfg->max_peer_id = val;;
+}
+
 void wlan_cfg_set_tx_ring_mask(struct wlan_cfg_dp_soc_ctxt *cfg,
 		int context, int mask)
 {

+ 3 - 0
wlan_cfg/wlan_cfg.h

@@ -106,6 +106,9 @@ void wlan_cfg_set_ce_ring_mask(struct wlan_cfg_dp_soc_ctxt *cfg,
 			       int context, int mask);
 void wlan_cfg_set_rxbuf_ring_mask(struct wlan_cfg_dp_soc_ctxt *cfg, int context,
 				  int mask);
+
+void wlan_cfg_set_max_peer_id(struct wlan_cfg_dp_soc_ctxt *cfg, uint32_t val);
+
 /**
  * wlan_cfg_get_num_contexts() - Number of interrupt contexts to be registered
  * @wlan_cfg_ctx - Configuration Handle

+ 2 - 0
wmi/inc/wmi_unified_api.h

@@ -1507,4 +1507,6 @@ void wmi_print_mgmt_event_log(wmi_unified_t wmi, uint32_t count,
 
 #endif /* WMI_INTERFACE_EVENT_LOGGING */
 
+QDF_STATUS wmi_unified_send_dbs_scan_sel_params_cmd(void *wmi_hdl,
+				struct wmi_dbs_scan_sel_params *wmi_param);
 #endif /* _WMI_UNIFIED_API_H_ */

+ 18 - 0
wmi/inc/wmi_unified_param.h

@@ -7285,4 +7285,22 @@ struct tbttoffset_params {
 	uint32_t tbttoffset;
 };
 
+#define WMI_SCAN_CLIENT_MAX        7
+
+/**
+ * struct wmi_dbs_scan_sel_params - DBS scan selection params
+ * @num_clients: Number of scan clients dutycycle
+ * @pdev_id: pdev_id for identifying the MAC
+ * @module_id: scan client module id
+ * @num_dbs_scans: number of DBS scans
+ * @num_non_dbs_scans: number of non-DBS scans
+ */
+struct wmi_dbs_scan_sel_params {
+	uint32_t num_clients;
+	uint32_t pdev_id;
+	uint32_t module_id[WMI_SCAN_CLIENT_MAX];
+	uint32_t num_dbs_scans[WMI_SCAN_CLIENT_MAX];
+	uint32_t num_non_dbs_scans[WMI_SCAN_CLIENT_MAX];
+};
+
 #endif /* _WMI_UNIFIED_PARAM_H_ */

+ 3 - 0
wmi/inc/wmi_unified_priv.h

@@ -1258,6 +1258,9 @@ QDF_STATUS (*send_multiple_vdev_restart_req_cmd)(wmi_unified_t wmi_handle,
 QDF_STATUS (*send_adapt_dwelltime_params_cmd)(wmi_unified_t wmi_handle,
 			struct wmi_adaptive_dwelltime_params *dwelltime_params);
 
+QDF_STATUS (*send_dbs_scan_sel_params_cmd)(wmi_unified_t wmi_handle,
+			struct wmi_dbs_scan_sel_params *dbs_scan_params);
+
 QDF_STATUS (*send_fw_test_cmd)(wmi_unified_t wmi_handle,
 			       struct set_fwtest_params *wmi_fwtest);
 

+ 20 - 0
wmi/src/wmi_unified_api.c

@@ -6683,3 +6683,23 @@ QDF_STATUS wmi_unified_set_country_cmd_send(void *wmi_hdl,
 	return QDF_STATUS_E_FAILURE;
 }
 
+/**
+ * wmi_unified_send_dbs_scan_sel_params_cmd() - send wmi cmd of
+ * DBS scan selection configuration params
+ * @wma_handle:  wma handler
+ * @dbs_scan_params: pointer to wmi_dbs_scan_sel_params
+ *
+ * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure
+ */
+QDF_STATUS wmi_unified_send_dbs_scan_sel_params_cmd(void *wmi_hdl,
+			struct wmi_dbs_scan_sel_params *dbs_scan_params)
+{
+	wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl;
+
+	if (wmi_handle->ops->send_dbs_scan_sel_params_cmd)
+		return wmi_handle->ops->
+			send_dbs_scan_sel_params_cmd(wmi_handle,
+						     dbs_scan_params);
+
+	return QDF_STATUS_E_FAILURE;
+}

+ 71 - 0
wmi/src/wmi_unified_tlv.c

@@ -2226,6 +2226,10 @@ static QDF_STATUS send_scan_start_cmd_tlv(wmi_unified_t wmi_handle,
 	cmd->num_ssids = params->num_ssids;
 	cmd->ie_len = params->extraie.len;
 	cmd->n_probes = params->n_probes;
+	cmd->scan_ctrl_flags_ext = params->scan_ctrl_flags_ext;
+
+	WMI_LOGD("scan_ctrl_flags_ext = %x", cmd->scan_ctrl_flags_ext);
+
 	buf_ptr += sizeof(*cmd);
 	tmp_ptr = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE);
 	for (i = 0; i < params->num_chan; ++i)
@@ -5766,6 +5770,71 @@ QDF_STATUS send_adapt_dwelltime_params_cmd_tlv(wmi_unified_t wmi_handle,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * send_dbs_scan_sel_params_cmd_tlv() - send wmi cmd of DBS scan selection
+ * configuration params
+ * @wmi_handle: wmi handler
+ * @dbs_scan_params: pointer to wmi_dbs_scan_sel_params
+ *
+ * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure
+ */
+static QDF_STATUS send_dbs_scan_sel_params_cmd_tlv(wmi_unified_t wmi_handle,
+			struct wmi_dbs_scan_sel_params *dbs_scan_params)
+{
+	wmi_scan_dbs_duty_cycle_fixed_param *dbs_scan_param;
+	wmi_scan_dbs_duty_cycle_tlv_param *cmd;
+	wmi_buf_t buf;
+	uint8_t *buf_ptr;
+	QDF_STATUS err;
+	uint32_t i;
+	int len;
+
+	len = sizeof(*dbs_scan_param);
+	len += WMI_TLV_HDR_SIZE;
+	len += dbs_scan_params->num_clients * sizeof(*cmd);
+
+	buf = wmi_buf_alloc(wmi_handle, len);
+	if (!buf) {
+		WMI_LOGE("%s:Failed to allocate buffer to send cmd", __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	buf_ptr = (uint8_t *) wmi_buf_data(buf);
+	dbs_scan_param = (wmi_scan_dbs_duty_cycle_fixed_param *) buf_ptr;
+	WMITLV_SET_HDR(&dbs_scan_param->tlv_header,
+		       WMITLV_TAG_STRUC_wmi_scan_dbs_duty_cycle_fixed_param,
+		       WMITLV_GET_STRUCT_TLVLEN
+		       (wmi_scan_dbs_duty_cycle_fixed_param));
+
+	dbs_scan_param->num_clients = dbs_scan_params->num_clients;
+	dbs_scan_param->pdev_id = dbs_scan_params->pdev_id;
+	buf_ptr += sizeof(*dbs_scan_param);
+	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
+		       (sizeof(*cmd) * dbs_scan_params->num_clients));
+	buf_ptr = buf_ptr + (uint8_t) WMI_TLV_HDR_SIZE;
+
+	for (i = 0; i < dbs_scan_params->num_clients; i++) {
+		cmd = (wmi_scan_dbs_duty_cycle_tlv_param *) buf_ptr;
+		WMITLV_SET_HDR(&cmd->tlv_header,
+			WMITLV_TAG_STRUC_wmi_scan_dbs_duty_cycle_param_tlv,
+			WMITLV_GET_STRUCT_TLVLEN(
+					wmi_scan_dbs_duty_cycle_tlv_param));
+		cmd->module_id = dbs_scan_params->module_id[i];
+		cmd->num_dbs_scans = dbs_scan_params->num_dbs_scans[i];
+		cmd->num_non_dbs_scans = dbs_scan_params->num_non_dbs_scans[i];
+		buf_ptr = buf_ptr + (uint8_t) sizeof(*cmd);
+	}
+
+	err = wmi_unified_cmd_send(wmi_handle, buf,
+				   len, WMI_SET_SCAN_DBS_DUTY_CYCLE_CMDID);
+	if (QDF_IS_STATUS_ERROR(err)) {
+		WMI_LOGE("Failed to send dbs scan selection cmd err=%d", err);
+		wmi_buf_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
 
 /**
  * send_roam_scan_filter_cmd_tlv() - Filter to be applied while roaming
@@ -18066,6 +18135,8 @@ struct wmi_ops tlv_ops =  {
 	.send_set_active_bpf_mode_cmd = send_set_active_bpf_mode_cmd_tlv,
 	.send_adapt_dwelltime_params_cmd =
 		send_adapt_dwelltime_params_cmd_tlv,
+	.send_dbs_scan_sel_params_cmd =
+		send_dbs_scan_sel_params_cmd_tlv,
 	.init_cmd_send = init_cmd_send_tlv,
 	.send_smart_ant_enable_cmd = send_smart_ant_enable_cmd_tlv,
 	.send_smart_ant_set_rx_ant_cmd = send_smart_ant_set_rx_ant_cmd_tlv,