Explorar o código

qcacld-3.0: Add MIC handling to DP component

Add MIC handling and periodic stats display API
in DP component

Change-Id: I5648b9ebe5bd529a83e607b07621c9867d19d402
CRs-Fixed: 3165076
Amit Mehta %!s(int64=3) %!d(string=hai) anos
pai
achega
30c5e2a0fa

+ 29 - 0
components/dp/core/inc/wlan_dp_main.h

@@ -390,4 +390,33 @@ void dp_try_set_rps_cpu_mask(struct wlan_objmgr_psoc *psoc);
  */
 void dp_clear_rps_cpu_mask(struct wlan_dp_psoc_context *dp_ctx);
 
+/**
+ * dp_mic_init_work() - init mic error work
+ * @dp_intf: Pointer to dp interface
+ *
+ * Return: None
+ */
+void dp_mic_init_work(struct wlan_dp_intf *dp_intf);
+
+/**
+ * dp_mic_deinit_work() - deinitialize mic error work
+ * @dp_intf: Pointer to dp interface
+ *
+ * Return: None
+ */
+void dp_mic_deinit_work(struct wlan_dp_intf *dp_intf);
+
+/**
+ * dp_rx_mic_error_ind() - MIC error indication handler
+ * @psoc: opaque handle for UMAC psoc object
+ * @pdev_id: physical device instance id
+ * @mic_failure_info: mic failure information
+ *
+ * This function indicates the Mic failure to the supplicant
+ *
+ * Return: None
+ */
+void
+dp_rx_mic_error_ind(struct cdp_ctrl_objmgr_psoc *psoc, uint8_t pdev_id,
+		    struct cdp_rx_mic_err_info *mic_failure_info);
 #endif

+ 6 - 1
components/dp/core/inc/wlan_dp_priv.h

@@ -258,6 +258,7 @@ struct dp_stats {
  * @vdev: object manager vdev context
  * @dev: netdev reference
  * @stats: Netdev stats
+ * @mic_work: Work to handle MIC error
  */
 struct wlan_dp_intf {
 	struct wlan_dp_psoc_context *dp_ctx;
@@ -294,7 +295,7 @@ struct wlan_dp_intf {
 	unsigned long mscs_prev_tx_vo_pkts;
 	uint32_t mscs_counter;
 #endif /* WLAN_FEATURE_MSCS */
-
+	struct dp_mic_work mic_work;
 };
 
 /**
@@ -368,6 +369,10 @@ struct wlan_dp_psoc_context {
 	struct dp_rtpm_tput_policy_context rtpm_tput_policy_ctx;
 #endif
 #endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/
+	/* disable RX offload (GRO/LRO) in concurrency scenarios */
+	qdf_atomic_t disable_rx_ol_in_concurrency;
+	/* disable RX offload (GRO/LRO) in low throughput scenarios */
+	qdf_atomic_t disable_rx_ol_in_low_tput;
 #ifdef WLAN_NS_OFFLOAD
 	/* IPv6 notifier callback for handling NS offload on change in IP */
 	struct notifier_block ipv6_notifier;

+ 146 - 3
components/dp/core/src/wlan_dp_bus_bandwidth.c

@@ -36,6 +36,7 @@
 #include <wlan_cm_ucfg_api.h>
 #include <qdf_threads.h>
 #include "wlan_dp_periodic_sta_stats.h"
+#include "wlan_mlme_ucfg_api.h"
 #include <i_qdf_net_stats.h>
 
 #ifdef FEATURE_BUS_BANDWIDTH_MGR
@@ -1018,6 +1019,149 @@ static void wlan_dp_deinit_tx_rx_histogram(struct wlan_dp_psoc_context *dp_ctx)
 	dp_ctx->txrx_hist = NULL;
 }
 
+/**
+ * wlan_dp_display_txrx_stats() - Display tx/rx histogram stats
+ * @dp_ctx: dp context
+ *
+ * Return: none
+ */
+static void wlan_dp_display_txrx_stats(struct wlan_dp_psoc_context *dp_ctx)
+{
+	struct wlan_dp_intf *dp_intf = NULL, *next_dp_intf = NULL;
+	struct dp_tx_rx_stats *stats;
+	hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx;
+	int i = 0;
+	uint32_t total_rx_pkt, total_rx_dropped,
+		 total_rx_delv, total_rx_refused;
+	uint32_t total_tx_pkt;
+	uint32_t total_tx_dropped;
+	uint32_t total_tx_orphaned;
+
+	dp_for_each_intf_held_safe(dp_ctx, dp_intf, next_dp_intf) {
+		total_rx_pkt = 0;
+		total_rx_dropped = 0;
+		total_rx_delv = 0;
+		total_rx_refused = 0;
+		total_tx_pkt = 0;
+		total_tx_dropped = 0;
+		total_tx_orphaned = 0;
+		stats = &dp_intf->dp_stats.tx_rx_stats;
+
+		if (dp_intf->intf_id == WLAN_INVALID_VDEV_ID)
+			continue;
+
+		dp_info("dp_intf: %u", dp_intf->intf_id);
+		for (i = 0; i < NUM_CPUS; i++) {
+			total_rx_pkt += stats->per_cpu[i].rx_packets;
+			total_rx_dropped += stats->per_cpu[i].rx_dropped;
+			total_rx_delv += stats->per_cpu[i].rx_delivered;
+			total_rx_refused += stats->per_cpu[i].rx_refused;
+			total_tx_pkt += stats->per_cpu[i].tx_called;
+			total_tx_dropped += stats->per_cpu[i].tx_dropped;
+			total_tx_orphaned += stats->per_cpu[i].tx_orphaned;
+		}
+
+		for (i = 0; i < NUM_CPUS; i++) {
+			if (!stats->per_cpu[i].tx_called)
+				continue;
+
+			dp_info("Tx CPU[%d]: called %u, dropped %u, orphaned %u",
+				i, stats->per_cpu[i].tx_called,
+				stats->per_cpu[i].tx_dropped,
+				stats->per_cpu[i].tx_orphaned);
+		}
+
+		dp_info("TX - called %u, dropped %u orphan %u",
+			total_tx_pkt, total_tx_dropped,
+			total_tx_orphaned);
+
+		dp_ctx->dp_ops.wlan_dp_display_tx_multiq_stats(ctx, dp_intf->intf_id);
+
+		for (i = 0; i < NUM_CPUS; i++) {
+			if (stats->per_cpu[i].rx_packets == 0)
+				continue;
+			dp_info("Rx CPU[%d]: packets %u, dropped %u, delivered %u, refused %u",
+				i, stats->per_cpu[i].rx_packets,
+				stats->per_cpu[i].rx_dropped,
+				stats->per_cpu[i].rx_delivered,
+				stats->per_cpu[i].rx_refused);
+		}
+
+		dp_info("RX - packets %u, dropped %u, unsol_arp_mcast_drp %u, delivered %u, refused %u GRO - agg %u drop %u non-agg %u flush_skip %u low_tput_flush %u disabled(conc %u low-tput %u)",
+			total_rx_pkt, total_rx_dropped,
+			qdf_atomic_read(&stats->rx_usolict_arp_n_mcast_drp),
+			total_rx_delv,
+			total_rx_refused, stats->rx_aggregated,
+			stats->rx_gro_dropped, stats->rx_non_aggregated,
+			stats->rx_gro_flush_skip,
+			stats->rx_gro_low_tput_flush,
+			qdf_atomic_read(&dp_ctx->disable_rx_ol_in_concurrency),
+			qdf_atomic_read(&dp_ctx->disable_rx_ol_in_low_tput));
+	}
+}
+
+/**
+ * dp_display_periodic_stats() - Function to display periodic stats
+ * @dp_ctx - handle to dp context
+ * @bool data_in_interval - true, if data detected in bw time interval
+ *
+ * The periodicity is determined by dp_ctx->dp_cfg->periodic_stats_disp_time.
+ * Stats show up in wlan driver logs.
+ *
+ * Returns: None
+ */
+static void dp_display_periodic_stats(struct wlan_dp_psoc_context *dp_ctx,
+				      bool data_in_interval)
+{
+	static uint32_t counter;
+	static bool data_in_time_period;
+	ol_txrx_soc_handle soc;
+	uint32_t periodic_stats_disp_time = 0;
+	hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx;
+
+	ucfg_mlme_stats_get_periodic_display_time(dp_ctx->psoc,
+						  &periodic_stats_disp_time);
+	if (!periodic_stats_disp_time)
+		return;
+
+	soc = cds_get_context(QDF_MODULE_ID_SOC);
+	if (!soc)
+		return;
+
+	counter++;
+	if (data_in_interval)
+		data_in_time_period = data_in_interval;
+
+	if (counter * dp_ctx->dp_cfg.bus_bw_compute_interval >=
+		periodic_stats_disp_time * 1000) {
+		if (data_in_time_period) {
+			wlan_dp_display_txrx_stats(dp_ctx);
+			dp_txrx_ext_dump_stats(soc, CDP_DP_RX_THREAD_STATS);
+			cdp_display_stats(soc,
+					  CDP_RX_RING_STATS,
+					  QDF_STATS_VERBOSITY_LEVEL_LOW);
+			cdp_display_stats(soc,
+					  CDP_DP_NAPI_STATS,
+					  QDF_STATS_VERBOSITY_LEVEL_LOW);
+			cdp_display_stats(soc,
+					  CDP_TXRX_PATH_STATS,
+					  QDF_STATS_VERBOSITY_LEVEL_LOW);
+			cdp_display_stats(soc,
+					  CDP_DUMP_TX_FLOW_POOL_INFO,
+					  QDF_STATS_VERBOSITY_LEVEL_LOW);
+			cdp_display_stats(soc,
+					  CDP_DP_SWLM_STATS,
+					  QDF_STATS_VERBOSITY_LEVEL_LOW);
+			dp_ctx->dp_ops.wlan_dp_display_netif_queue_history
+				(ctx, QDF_STATS_VERBOSITY_LEVEL_LOW);
+			cdp_display_txrx_hw_info(soc);
+			qdf_dp_trace_dump_stats();
+		}
+		counter = 0;
+		data_in_time_period = false;
+	}
+}
+
 /**
  * dp_pm_qos_update_cpu_mask() - Prepare CPU mask for PM_qos voting
  * @mask: return variable of cpumask for the TPUT
@@ -1470,9 +1614,8 @@ static void dp_pld_request_bus_bandwidth(struct wlan_dp_psoc_context *dp_ctx,
 	 * scheduler thread can utilize CPU.
 	 */
 	if (!dp_ops->dp_is_roaming_in_progress(ctx)) {
-		dp_ops->dp_display_periodic_stats(ctx,
-						  (total_pkts > 0) ?
-						  true : false);
+		dp_display_periodic_stats(dp_ctx, (total_pkts > 0) ?
+					  true : false);
 		dp_periodic_sta_stats_display(dp_ctx);
 	}
 }

+ 223 - 0
components/dp/core/src/wlan_dp_main.c

@@ -28,6 +28,7 @@
 #include <wlan_nlink_common.h>
 #include <qdf_net_types.h>
 #include "wlan_objmgr_vdev_obj.h"
+#include <wlan_cm_ucfg_api.h>
 
 /* Global DP context */
 static struct wlan_dp_psoc_context *gp_dp_ctx;
@@ -123,10 +124,228 @@ dp_get_intf_by_macaddr(struct wlan_dp_psoc_context *dp_ctx,
 	return NULL;
 }
 
+/**
+ * validate_interface_id() - Check if interface ID is valid
+ * @intf_id: interface ID
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int validate_interface_id(uint8_t intf_id)
+{
+	if (intf_id == WLAN_UMAC_VDEV_ID_MAX) {
+		dp_err("Interface is not up");
+		return -EINVAL;
+	}
+	if (intf_id >= WLAN_MAX_VDEVS) {
+		dp_err("Bad interface id:%u", intf_id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * is_dp_intf_valid() - Check if interface is valid
+ * @dp_intf: interface context
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int is_dp_intf_valid(struct wlan_dp_intf *dp_intf)
+{
+	if (!dp_intf) {
+		dp_err("Interface is NULL");
+		return -EINVAL;
+	}
+	return validate_interface_id(dp_intf->intf_id);
+}
+
 static void dp_cfg_init(struct wlan_dp_psoc_context *ctx)
 {
 }
 
+/**
+ * __dp_process_mic_error() - Indicate mic error to supplicant
+ * @dp_intf: Pointer to dp interface
+ *
+ * Return: None
+ */
+static void
+__dp_process_mic_error(struct wlan_dp_intf *dp_intf)
+{
+	struct wlan_dp_psoc_callbacks *ops = &dp_intf->dp_ctx->dp_ops;
+	struct wlan_objmgr_vdev *vdev = dp_intf->vdev;
+
+	if (!vdev) {
+		dp_err("vdev is NULL");
+		return;
+	}
+
+	if (dp_comp_vdev_get_ref(vdev)) {
+		dp_err("vdev ref get error");
+		return;
+	}
+
+	if ((dp_intf->device_mode == QDF_STA_MODE ||
+	     dp_intf->device_mode == QDF_P2P_CLIENT_MODE) &&
+	    ucfg_cm_is_vdev_active(vdev))
+		ops->osif_dp_process_sta_mic_error(dp_intf->mic_work.info,
+						   vdev);
+	else if (dp_intf->device_mode == QDF_SAP_MODE ||
+		 dp_intf->device_mode == QDF_P2P_GO_MODE)
+		ops->osif_dp_process_sap_mic_error(dp_intf->mic_work.info,
+						   vdev);
+	else
+		dp_err("Invalid interface type:%d", dp_intf->device_mode);
+
+	dp_comp_vdev_put_ref(vdev);
+}
+
+/**
+ * dp_process_mic_error() - process mic error work
+ * @data: void pointer to dp interface
+ *
+ * Return: None
+ */
+static void
+dp_process_mic_error(void *data)
+{
+	struct wlan_dp_intf *dp_intf = data;
+
+	if (is_dp_intf_valid(dp_intf))
+		goto exit;
+
+	__dp_process_mic_error(dp_intf);
+
+exit:
+	qdf_spin_lock_bh(&dp_intf->mic_work.lock);
+	if (dp_intf->mic_work.info) {
+		qdf_mem_free(dp_intf->mic_work.info);
+		dp_intf->mic_work.info = NULL;
+	}
+	if (dp_intf->mic_work.status == DP_MIC_SCHEDULED)
+		dp_intf->mic_work.status = DP_MIC_INITIALIZED;
+	qdf_spin_unlock_bh(&dp_intf->mic_work.lock);
+}
+
+void
+dp_rx_mic_error_ind(struct cdp_ctrl_objmgr_psoc *psoc, uint8_t pdev_id,
+		    struct cdp_rx_mic_err_info *mic_failure_info)
+{
+	struct dp_mic_error_info *dp_mic_info;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_dp_intf *dp_intf;
+
+	if (!psoc)
+		return;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc((struct wlan_objmgr_psoc *)psoc,
+						    mic_failure_info->vdev_id,
+						    WLAN_DP_ID);
+	if (!vdev)
+		return;
+	dp_intf = dp_get_vdev_priv_obj(vdev);
+	if (!dp_intf) {
+		dp_comp_vdev_put_ref(vdev);
+		return;
+	}
+
+	dp_mic_info = qdf_mem_malloc(sizeof(*dp_mic_info));
+	if (!dp_mic_info) {
+		dp_comp_vdev_put_ref(vdev);
+		return;
+	}
+
+	qdf_copy_macaddr(&dp_mic_info->ta_mac_addr,
+			 &mic_failure_info->ta_mac_addr);
+	dp_mic_info->multicast = mic_failure_info->multicast;
+	dp_mic_info->key_id = mic_failure_info->key_id;
+	qdf_mem_copy(&dp_mic_info->tsc, &mic_failure_info->tsc,
+		     SIR_CIPHER_SEQ_CTR_SIZE);
+	dp_mic_info->vdev_id = mic_failure_info->vdev_id;
+
+	qdf_spin_lock_bh(&dp_intf->mic_work.lock);
+	if (dp_intf->mic_work.status != DP_MIC_INITIALIZED) {
+		qdf_spin_unlock_bh(&dp_intf->mic_work.lock);
+		qdf_mem_free(dp_mic_info);
+		dp_comp_vdev_put_ref(vdev);
+		return;
+	}
+	/*
+	 * Store mic error info pointer in dp_intf
+	 * for freeing up the alocated memory in case
+	 * the work scheduled below is flushed or deinitialized.
+	 */
+	dp_intf->mic_work.status = DP_MIC_SCHEDULED;
+	dp_intf->mic_work.info = dp_mic_info;
+	qdf_sched_work(0, &dp_intf->mic_work.work);
+	qdf_spin_unlock_bh(&dp_intf->mic_work.lock);
+	dp_comp_vdev_put_ref(vdev);
+}
+
+/**
+ * dp_mic_flush_work() - disable and flush pending mic work
+ * @dp_intf: Pointer to dp interface
+ *
+ * Return: None
+ */
+static void
+dp_mic_flush_work(struct wlan_dp_intf *dp_intf)
+{
+	dp_info("Flush the MIC error work");
+
+	qdf_spin_lock_bh(&dp_intf->mic_work.lock);
+	if (dp_intf->mic_work.status != DP_MIC_SCHEDULED) {
+		qdf_spin_unlock_bh(&dp_intf->mic_work.lock);
+		return;
+	}
+	dp_intf->mic_work.status = DP_MIC_DISABLED;
+	qdf_spin_unlock_bh(&dp_intf->mic_work.lock);
+
+	qdf_flush_work(&dp_intf->mic_work.work);
+}
+
+/**
+ * dp_mic_enable_work() - enable mic error work
+ * @dp_intf: Pointer to dp interface
+ *
+ * Return: None
+ */
+static void dp_mic_enable_work(struct wlan_dp_intf *dp_intf)
+{
+	dp_info("Enable the MIC error work");
+
+	qdf_spin_lock_bh(&dp_intf->mic_work.lock);
+	if (dp_intf->mic_work.status == DP_MIC_DISABLED)
+		dp_intf->mic_work.status = DP_MIC_INITIALIZED;
+	qdf_spin_unlock_bh(&dp_intf->mic_work.lock);
+}
+
+void dp_mic_deinit_work(struct wlan_dp_intf *dp_intf)
+{
+	dp_info("DeInitialize the MIC error work");
+
+	if (dp_intf->mic_work.status != DP_MIC_UNINITIALIZED) {
+		qdf_destroy_work(NULL, &dp_intf->mic_work.work);
+
+		qdf_spin_lock_bh(&dp_intf->mic_work.lock);
+		dp_intf->mic_work.status = DP_MIC_UNINITIALIZED;
+		if (dp_intf->mic_work.info) {
+			qdf_mem_free(dp_intf->mic_work.info);
+			dp_intf->mic_work.info = NULL;
+		}
+		qdf_spin_unlock_bh(&dp_intf->mic_work.lock);
+		qdf_spinlock_destroy(&dp_intf->mic_work.lock);
+	}
+}
+
+void dp_mic_init_work(struct wlan_dp_intf *dp_intf)
+{
+	qdf_spinlock_create(&dp_intf->mic_work.lock);
+	qdf_create_work(0, &dp_intf->mic_work.work,
+			dp_process_mic_error, dp_intf);
+	dp_intf->mic_work.status = DP_MIC_INITIALIZED;
+	dp_intf->mic_work.info = NULL;
+}
+
 QDF_STATUS
 dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 {
@@ -167,6 +386,8 @@ dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 		return status;
 	}
 
+	dp_mic_enable_work(dp_intf);
+
 	return status;
 }
 
@@ -185,6 +406,8 @@ dp_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 		return QDF_STATUS_E_INVAL;
 	}
 
+	dp_mic_flush_work(dp_intf);
+
 	status = wlan_objmgr_vdev_component_obj_detach(vdev,
 						       WLAN_COMP_DP,
 						       (void *)dp_intf);

+ 53 - 1
components/dp/dispatcher/inc/wlan_dp_public_struct.h

@@ -29,6 +29,47 @@
 #include "qdf_status.h"
 #include <wlan_nlink_common.h>
 #include <qca_vendor.h>
+#include <ani_system_defs.h>
+#include <qdf_defer.h>
+
+/**
+ * struct dp_mic_info - mic error info in dp
+ * @ta_mac_addr: transmitter mac address
+ * @multicast: Flag for multicast
+ * @key_id: Key ID
+ * @tsc: Sequence number
+ * @vdev_id: vdev id
+ *
+ */
+struct dp_mic_error_info {
+	struct qdf_mac_addr ta_mac_addr;
+	bool multicast;
+	uint8_t key_id;
+	uint8_t tsc[SIR_CIPHER_SEQ_CTR_SIZE];
+	uint16_t vdev_id;
+};
+
+enum dp_mic_work_status {
+	DP_MIC_UNINITIALIZED,
+	DP_MIC_INITIALIZED,
+	DP_MIC_SCHEDULED,
+	DP_MIC_DISABLED
+};
+
+/**
+ * struct dp_mic_work - mic work info in dp
+ * @mic_error_work: mic error work
+ * @status: sattus of mic error work
+ * @info: Pointer to mic error information
+ * @lock: lock to synchronixe mic error work
+ *
+ */
+struct dp_mic_work {
+	qdf_work_t work;
+	enum dp_mic_work_status status;
+	struct dp_mic_error_info *info;
+	qdf_spinlock_t lock;
+};
 
 /**
  * typedef hdd_cb_handle - HDD Handle
@@ -208,6 +249,10 @@ union wlan_tp_data {
  * @dp_is_roaming_in_progress:Callback to check if roaming is in progress
  * @dp_is_ap_active:Callback to check if AP is active
  * @dp_napi_apply_throughput_policy:Callback to apply NAPI throughput policy
+ * @wlan_dp_display_tx_multiq_stats: Callback to display Tx Mulit queue stats
+ * @wlan_dp_display_netif_queue_history: Callback to display Netif queue history
+ * @osif_dp_process_sta_mic_error: osif callback to process STA MIC error
+ * @osif_dp_process_sap_mic_error: osif callback to process SAP MIC error
  */
 struct wlan_dp_psoc_callbacks {
 	void (*os_if_dp_gro_rx)(struct sk_buff *skb, uint8_t napi_to_use,
@@ -242,12 +287,19 @@ struct wlan_dp_psoc_callbacks {
 					uint8_t user_triggered, int size);
 	bool (*dp_is_roaming_in_progress)(hdd_cb_handle context);
 	bool (*dp_is_ap_active)(hdd_cb_handle context, uint8_t vdev_id);
-	void (*dp_display_periodic_stats)(hdd_cb_handle context, bool interval);
 	void (*dp_disable_rx_ol_for_low_tput)(hdd_cb_handle context,
 					      bool disable);
 	int (*dp_napi_apply_throughput_policy)(hdd_cb_handle context,
 					       uint64_t tx_packets,
 					       uint64_t rx_packets);
+	void (*wlan_dp_display_tx_multiq_stats)(hdd_cb_handle context,
+						uint8_t vdev_id);
+	void (*wlan_dp_display_netif_queue_history)(hdd_cb_handle context,
+				enum qdf_stats_verbosity_level verb_lvl);
+	void (*osif_dp_process_sta_mic_error)(struct dp_mic_error_info *info,
+					      struct wlan_objmgr_vdev *vdev);
+	void (*osif_dp_process_sap_mic_error)(struct dp_mic_error_info *info,
+					      struct wlan_objmgr_vdev *vdev);
 };
 
 /**

+ 7 - 0
components/dp/dispatcher/inc/wlan_dp_ucfg_api.h

@@ -32,6 +32,7 @@
 #include <wlan_objmgr_vdev_obj.h>
 #include "pld_common.h"
 #include <wlan_dp_public_struct.h>
+#include <cdp_txrx_misc.h>
 
 /**
  * ucfg_dp_create_intf() - update DP interface MAC address
@@ -130,6 +131,12 @@ ucfg_dp_update_config(struct wlan_objmgr_psoc *psoc,
 uint64_t
 ucfg_dp_get_rx_softirq_yield_duration(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * ucfg_dp_register_rx_mic_error_ind_handler : register mic error handler.
+ * @soc: soc handle
+ */
+void ucfg_dp_register_rx_mic_error_ind_handler(void *soc);
+
 /**
  * ucfg_dp_bbm_context_init() - Initialize BBM context
  * @psoc: psoc handle

+ 12 - 2
components/dp/dispatcher/src/wlan_dp_ucfg_api.c

@@ -82,6 +82,7 @@ ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc,
 
 	dp_periodic_sta_stats_init(dp_intf);
 	dp_periodic_sta_stats_mutex_create(dp_intf);
+	dp_mic_init_work(dp_intf);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -106,6 +107,8 @@ ucfg_dp_destroy_intf(struct wlan_objmgr_psoc *psoc,
 	}
 
 	dp_periodic_sta_stats_mutex_destroy(dp_intf);
+	dp_mic_deinit_work(dp_intf);
+
 	qdf_spin_lock_bh(&dp_ctx->intf_list_lock);
 	qdf_list_remove_node(&dp_ctx->intf_list, &dp_intf->node);
 	qdf_spin_unlock_bh(&dp_ctx->intf_list_lock);
@@ -478,6 +481,11 @@ ucfg_dp_get_rx_softirq_yield_duration(struct wlan_objmgr_psoc *psoc)
 	return dp_ctx->dp_cfg.rx_softirq_max_yield_duration_ns;
 }
 
+void ucfg_dp_register_rx_mic_error_ind_handler(void *soc)
+{
+	cdp_register_rx_mic_error_ind_handler(soc, dp_rx_mic_error_ind);
+}
+
 int ucfg_dp_bbm_context_init(struct wlan_objmgr_psoc *psoc)
 {
 	return dp_bbm_context_init(psoc);
@@ -623,6 +631,10 @@ void ucfg_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
 	dp_ctx->dp_ops.dp_pm_qos_add_request = cb_obj->dp_pm_qos_add_request;
 	dp_ctx->dp_ops.dp_pm_qos_remove_request =
 		cb_obj->dp_pm_qos_remove_request;
+	dp_ctx->dp_ops.wlan_dp_display_tx_multiq_stats =
+		cb_obj->wlan_dp_display_tx_multiq_stats;
+	dp_ctx->dp_ops.wlan_dp_display_netif_queue_history =
+		cb_obj->wlan_dp_display_netif_queue_history;
 	dp_ctx->dp_ops.dp_send_mscs_action_frame =
 		cb_obj->dp_send_mscs_action_frame;
 	dp_ctx->dp_ops.dp_pktlog_enable_disable =
@@ -630,8 +642,6 @@ void ucfg_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
 	dp_ctx->dp_ops.dp_is_roaming_in_progress =
 		cb_obj->dp_is_roaming_in_progress;
 	dp_ctx->dp_ops.dp_is_ap_active = cb_obj->dp_is_ap_active;
-	dp_ctx->dp_ops.dp_display_periodic_stats =
-		cb_obj->dp_display_periodic_stats;
 	dp_ctx->dp_ops.dp_disable_rx_ol_for_low_tput =
 		cb_obj->dp_disable_rx_ol_for_low_tput;
 	dp_ctx->dp_ops.dp_napi_apply_throughput_policy =

+ 95 - 0
os_if/dp/src/os_if_dp.c

@@ -27,6 +27,7 @@
 #include <cdp_txrx_cmn.h>
 #include "qca_vendor.h"
 #include "wlan_dp_ucfg_api.h"
+#include "osif_vdev_sync.h"
 
 #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH
 /**
@@ -157,11 +158,105 @@ void osif_dp_send_tcp_param_update_event(struct wlan_objmgr_psoc *psoc,
 }
 #endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/
 
+/**
+ * osif_dp_get_net_dev_from_vdev() - Get netdev object from vdev
+ * @vdev: Pointer to vdev manager
+ * @out_net_dev: Pointer to output netdev
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int osif_dp_get_net_dev_from_vdev(struct wlan_objmgr_vdev *vdev,
+					 struct net_device **out_net_dev)
+{
+	struct vdev_osif_priv *priv;
+
+	if (!vdev)
+		return -EINVAL;
+
+	priv = wlan_vdev_get_ospriv(vdev);
+	if (!priv || !priv->wdev || !priv->wdev->netdev)
+		return -EINVAL;
+
+	*out_net_dev = priv->wdev->netdev;
+
+	return 0;
+}
+
+/**
+ * osif_dp_process_sta_mic_error() - Indicate STA mic error to supplicant
+ * @info: MIC error information
+ * @vdev: vdev handle
+ *
+ * Return: None
+ */
+static void
+osif_dp_process_sta_mic_error(struct dp_mic_error_info *info,
+			      struct wlan_objmgr_vdev *vdev)
+{
+	struct net_device *dev;
+	struct osif_vdev_sync *vdev_sync;
+	int errno;
+
+	errno = osif_dp_get_net_dev_from_vdev(vdev, &dev);
+	if (errno) {
+		dp_err("failed to get netdev");
+		return;
+	}
+	if (osif_vdev_sync_op_start(dev, &vdev_sync))
+		return;
+
+	/* inform mic failure to nl80211 */
+	cfg80211_michael_mic_failure(dev,
+				     (uint8_t *)&info->ta_mac_addr,
+				     info->multicast ?
+				     NL80211_KEYTYPE_GROUP :
+				     NL80211_KEYTYPE_PAIRWISE,
+				     info->key_id,
+				     info->tsc,
+				     GFP_KERNEL);
+}
+
+/**
+ * osif_dp_process_sap_mic_error() - Indicate SAP mic error to supplicant
+ * @info: MIC error information
+ * @vdev: vdev handle
+ *
+ * Return: None
+ */
+static void
+osif_dp_process_sap_mic_error(struct dp_mic_error_info *info,
+			      struct wlan_objmgr_vdev *vdev)
+{
+	struct net_device *dev;
+	int errno;
+	struct osif_vdev_sync *vdev_sync;
+
+	errno = osif_dp_get_net_dev_from_vdev(vdev, &dev);
+	if (errno) {
+		dp_err("failed to get netdev");
+		return;
+	}
+	if (osif_vdev_sync_op_start(dev, &vdev_sync))
+		return;
+
+	/* inform mic failure to nl80211 */
+	cfg80211_michael_mic_failure(dev,
+				     (uint8_t *)&info->ta_mac_addr,
+				     info->multicast ?
+				     NL80211_KEYTYPE_GROUP :
+				     NL80211_KEYTYPE_PAIRWISE,
+				     info->key_id,
+				     info->tsc,
+				     GFP_KERNEL);
+}
+
 void os_if_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
 				     struct wlan_dp_psoc_callbacks *cb_obj)
 {
 	cb_obj->osif_dp_send_tcp_param_update_event =
 		osif_dp_send_tcp_param_update_event;
+	cb_obj->osif_dp_process_sta_mic_error = osif_dp_process_sta_mic_error;
+	cb_obj->osif_dp_process_sap_mic_error = osif_dp_process_sap_mic_error;
 
 	ucfg_dp_register_hdd_callbacks(psoc, cb_obj);
 }