diff --git a/drivers/staging/qcacld-3.0/Kbuild b/drivers/staging/qcacld-3.0/Kbuild
index c01c511cd69f..f94c7c871e88 100644
--- a/drivers/staging/qcacld-3.0/Kbuild
+++ b/drivers/staging/qcacld-3.0/Kbuild
@@ -425,6 +425,7 @@ HDD_OBJS := $(HDD_SRC_DIR)/wlan_hdd_assoc.o \
$(HDD_SRC_DIR)/wlan_hdd_packet_filter.o \
$(HDD_SRC_DIR)/wlan_hdd_power.o \
$(HDD_SRC_DIR)/wlan_hdd_regulatory.o \
+ $(HDD_SRC_DIR)/wlan_hdd_request_manager.o \
$(HDD_SRC_DIR)/wlan_hdd_scan.o \
$(HDD_SRC_DIR)/wlan_hdd_softap_tx_rx.o \
$(HDD_SRC_DIR)/wlan_hdd_tx_rx.o \
diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c
index 2c240a7ab962..4ff620ddb07b 100644
--- a/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c
+++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c
@@ -131,6 +131,7 @@ v_CONTEXT_t cds_init(void)
qdf_lock_stats_init();
qdf_mem_init();
qdf_mc_timer_manager_init();
+ qdf_event_list_init();
gp_cds_context = &g_cds_context;
@@ -166,6 +167,7 @@ void cds_deinit(void)
qdf_mem_exit();
qdf_lock_stats_deinit();
qdf_debugfs_exit();
+ qdf_event_list_destroy();
gp_cds_context->qdf_ctx = NULL;
gp_cds_context = NULL;
@@ -626,8 +628,9 @@ QDF_STATUS cds_pre_enable(v_CONTEXT_t cds_context)
}
/* Need to update time out of complete */
- qdf_status = qdf_wait_single_event(&gp_cds_context->wmaCompleteEvent,
- CDS_WMA_TIMEOUT);
+ qdf_status = qdf_wait_for_event_completion(
+ &gp_cds_context->wmaCompleteEvent,
+ CDS_WMA_TIMEOUT);
if (qdf_status != QDF_STATUS_SUCCESS) {
if (qdf_status == QDF_STATUS_E_TIMEOUT) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
@@ -781,8 +784,9 @@ QDF_STATUS cds_enable(v_CONTEXT_t cds_context)
wma_setneedshutdown(cds_context);
} else {
qdf_status =
- qdf_wait_single_event(&(gp_cds_context->wmaCompleteEvent),
- CDS_WMA_TIMEOUT);
+ qdf_wait_for_event_completion(
+ &gp_cds_context->wmaCompleteEvent,
+ CDS_WMA_TIMEOUT);
if (qdf_status != QDF_STATUS_SUCCESS) {
if (qdf_status == QDF_STATUS_E_TIMEOUT) {
QDF_TRACE(QDF_MODULE_ID_QDF,
@@ -1814,7 +1818,7 @@ static QDF_STATUS cds_force_assert_target(qdf_device_t qdf_ctx)
}
/* wait for firmware assert to trigger a recovery event */
- status = qdf_wait_single_event(&wma->recovery_event,
+ status = qdf_wait_for_event_completion(&wma->recovery_event,
WMA_CRASH_INJECT_TIMEOUT);
if (QDF_IS_STATUS_ERROR(status)) {
cds_err("Failed target force assert wait; status:%d", status);
diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_concurrency.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_concurrency.c
index b560ddd3f3bf..a1dffae02554 100644
--- a/drivers/staging/qcacld-3.0/core/cds/src/cds_concurrency.c
+++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_concurrency.c
@@ -8503,7 +8503,7 @@ void cds_restart_sap(hdd_adapter_t *ap_adapter)
qdf_event_reset(&hostapd_state->qdf_stop_bss_event);
if (QDF_STATUS_SUCCESS == wlansap_stop_bss(sap_ctx)) {
qdf_status =
- qdf_wait_single_event(&hostapd_state->
+ qdf_wait_for_event_completion(&hostapd_state->
qdf_stop_bss_event,
SME_CMD_TIMEOUT_VALUE);
@@ -8536,7 +8536,7 @@ void cds_restart_sap(hdd_adapter_t *ap_adapter)
cds_debug("Waiting for SAP to start");
qdf_status =
- qdf_wait_single_event(&hostapd_state->qdf_event,
+ qdf_wait_for_event_completion(&hostapd_state->qdf_event,
SME_CMD_TIMEOUT_VALUE);
wlansap_reset_sap_config_add_ie(sap_config,
eUPDATE_IE_ALL);
@@ -8968,7 +8968,7 @@ QDF_STATUS qdf_wait_for_connection_update(void)
return QDF_STATUS_E_FAILURE;
}
- status = qdf_wait_single_event(
+ status = qdf_wait_for_event_completion(
&cds_context->connection_update_done_evt,
CONNECTION_UPDATE_TIMEOUT);
diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c
index 2d51d5f78b0c..2d5c418c0f02 100644
--- a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c
+++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c
@@ -2538,7 +2538,7 @@ ol_txrx_peer_attach(ol_txrx_vdev_handle vdev, uint8_t *peer_mac_addr)
sizeof(union ol_txrx_align_mac_addr_t));
if (wait_on_deletion) {
/* wait for peer deletion */
- rc = qdf_wait_single_event(&vdev->wait_delete_comp,
+ rc = qdf_wait_for_event_completion(&vdev->wait_delete_comp,
PEER_DELETION_TIMEOUT);
if (QDF_STATUS_SUCCESS != rc) {
ol_txrx_err(
diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h
index 80053e9ff463..5d0e51e59fdc 100644
--- a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h
+++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h
@@ -2146,6 +2146,53 @@ enum hdd_dot11_mode {
#define CFG_ROAM_BG_SCAN_CLIENT_BITMAP_MAX (0x7FF)
#define CFG_ROAM_BG_SCAN_CLIENT_BITMAP_DEFAULT (0x424)
+/*
+ *
+ * min_delay_btw_roam_scans - Min duration (in sec) allowed btw two
+ * consecutive roam scans
+ * @Min: 0
+ * @Max: 60
+ * @Default: 10
+ *
+ * Roam scan is not allowed if duration between two consecutive
+ * roam scans is less than this time.
+ *
+ * Related: None
+ *
+ * Supported Feature: Roaming
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_MIN_DELAY_BTW_ROAM_SCAN_NAME "min_delay_btw_roam_scans"
+#define CFG_MIN_DELAY_BTW_ROAM_SCAN_MIN (0)
+#define CFG_MIN_DELAY_BTW_ROAM_SCAN_MAX (60)
+#define CFG_MIN_DELAY_BTW_ROAM_SCAN_DEFAULT (10)
+
+/*
+ *
+ * roam_trigger_reason_bitmask - Contains roam_trigger_reasons
+ * @Min: 0
+ * @Max: 0xFFFFFFFF
+ * @Default: 0xDA
+ *
+ * Bitmask containing roam_trigger_reasons for which
+ * min_delay_btw_roam_scans constraint should be applied.
+ *
+ * Related: None
+ *
+ * Supported Feature: Roaming
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_NAME "roam_trigger_reason_bitmask"
+#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MIN (0)
+#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MAX (0xFFFFFFFF)
+#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_DEFAULT (0xDA)
+
/*
*
* roam_bad_rssi_thresh_offset_2g - RSSI threshold offset for 2G to 5G roam
@@ -2176,6 +2223,56 @@ enum hdd_dot11_mode {
#define CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_MAX (86)
#define CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_DEFAULT (40)
+/*
+ *
+ * ho_delay_for_rx - Delay Hand-off (In msec) by this duration to receive
+ * pending rx frames from current BSS
+ * @Min: 0
+ * @Max: 200
+ * @Default: 0
+ *
+ * For LFR 3.0 roaming scenario, once roam candidate is found, firmware
+ * waits for minimum this much duration to receive pending rx frames from
+ * current BSS before switching to new channel for handoff to new AP.
+ *
+ * Related: None
+ *
+ * Supported Feature: Roaming
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_ROAM_HO_DELAY_FOR_RX_NAME "ho_delay_for_rx"
+#define CFG_ROAM_HO_DELAY_FOR_RX_MIN (0)
+#define CFG_ROAM_HO_DELAY_FOR_RX_MAX (200)
+#define CFG_ROAM_HO_DELAY_FOR_RX_DEFAULT (0)
+
+/*
+ *
+ * roam_force_rssi_trigger - To set roam scan mode
+ * irrespective of channel list
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to set roam scan mode
+ * WMI_ROAM_SCAN_MODE_RSSI_CHANGE, irrespective of whether
+ * channel list type is CHANNEL_LIST_STATIC or not
+ *
+ * Related: None
+ *
+ * Supported Feature: Roaming
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_ROAM_FORCE_RSSI_TRIGGER_NAME "roam_force_rssi_trigger"
+#define CFG_ROAM_FORCE_RSSI_TRIGGER_MIN (0)
+#define CFG_ROAM_FORCE_RSSI_TRIGGER_MAX (1)
+#define CFG_ROAM_FORCE_RSSI_TRIGGER_DEFAULT (1)
+
/*
*
* roamscan_adaptive_dwell_mode - Sets dwell time adaptive mode
@@ -13876,6 +13973,9 @@ struct hdd_config {
uint32_t roam_dense_min_aps;
int8_t roam_bg_scan_bad_rssi_thresh;
uint8_t roam_bad_rssi_thresh_offset_2g;
+ uint32_t ho_delay_for_rx;
+ uint32_t min_delay_btw_roam_scans;
+ uint32_t roam_trigger_reason_bitmask;
uint32_t roam_bg_scan_client_bitmap;
bool enable_edca_params;
uint32_t edca_vo_cwmin;
@@ -14078,6 +14178,7 @@ struct hdd_config {
uint32_t neighbor_report_offload_cache_timeout;
uint32_t neighbor_report_offload_max_req_cap;
uint8_t enable_tx_sch_delay;
+ bool roam_force_rssi_trigger;
};
#define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var))
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c
index 043b917cfd73..320b251f379f 100644
--- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c
@@ -4043,6 +4043,30 @@ struct reg_table_entry g_registry_table[] = {
CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_MIN,
CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_MAX),
+ REG_VARIABLE(CFG_ROAM_HO_DELAY_FOR_RX_NAME,
+ WLAN_PARAM_Integer, struct hdd_config,
+ ho_delay_for_rx,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_ROAM_HO_DELAY_FOR_RX_DEFAULT,
+ CFG_ROAM_HO_DELAY_FOR_RX_MIN,
+ CFG_ROAM_HO_DELAY_FOR_RX_MAX),
+
+ REG_VARIABLE(CFG_MIN_DELAY_BTW_ROAM_SCAN_NAME,
+ WLAN_PARAM_Integer, struct hdd_config,
+ min_delay_btw_roam_scans,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_MIN_DELAY_BTW_ROAM_SCAN_DEFAULT,
+ CFG_MIN_DELAY_BTW_ROAM_SCAN_MIN,
+ CFG_MIN_DELAY_BTW_ROAM_SCAN_MAX),
+
+ REG_VARIABLE(CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_NAME,
+ WLAN_PARAM_HexInteger, struct hdd_config,
+ roam_trigger_reason_bitmask,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_DEFAULT,
+ CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MIN,
+ CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MAX),
+
REG_VARIABLE(CFG_ENABLE_FATAL_EVENT_TRIGGER, WLAN_PARAM_Integer,
struct hdd_config, enable_fatal_event,
VAR_FLAGS_OPTIONAL |
@@ -5271,6 +5295,15 @@ struct reg_table_entry g_registry_table[] = {
CFG_TX_SCH_DELAY_DEFAULT,
CFG_TX_SCH_DELAY_MIN,
CFG_TX_SCH_DELAY_MAX),
+
+ REG_VARIABLE(CFG_ROAM_FORCE_RSSI_TRIGGER_NAME,
+ WLAN_PARAM_Integer, struct hdd_config,
+ roam_force_rssi_trigger,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_ROAM_FORCE_RSSI_TRIGGER_DEFAULT,
+ CFG_ROAM_FORCE_RSSI_TRIGGER_MIN,
+ CFG_ROAM_FORCE_RSSI_TRIGGER_MAX),
+
};
/**
@@ -6753,6 +6786,15 @@ void hdd_cfg_print(hdd_context_t *pHddCtx)
hdd_debug("Name = [%s] Value = [%u]",
CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_NAME,
pHddCtx->config->roam_bad_rssi_thresh_offset_2g);
+ hdd_debug("Name = [%s] Value = [%u]",
+ CFG_ROAM_HO_DELAY_FOR_RX_NAME,
+ pHddCtx->config->ho_delay_for_rx);
+ hdd_debug("Name = [%s] Value = [%u]",
+ CFG_MIN_DELAY_BTW_ROAM_SCAN_NAME,
+ pHddCtx->config->min_delay_btw_roam_scans);
+ hdd_debug("Name = [%s] Value = [%u]",
+ CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_NAME,
+ pHddCtx->config->roam_trigger_reason_bitmask);
hdd_debug("Name = [%s] Value = [%u]",
CFG_MIN_REST_TIME_NAME,
pHddCtx->config->min_rest_time_conc);
@@ -7068,6 +7110,10 @@ void hdd_cfg_print(hdd_context_t *pHddCtx)
pHddCtx->config->enable_tx_sch_delay);
hdd_cfg_print_11k_offload_params(pHddCtx);
+ hdd_debug("Name = [%s] Value = [%u]",
+ CFG_ROAM_FORCE_RSSI_TRIGGER_NAME,
+ pHddCtx->config->roam_force_rssi_trigger);
+
}
/**
@@ -9546,6 +9592,12 @@ QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx)
pHddCtx->config->roam_bg_scan_client_bitmap;
smeConfig->csrConfig.roam_bad_rssi_thresh_offset_2g =
pHddCtx->config->roam_bad_rssi_thresh_offset_2g;
+ smeConfig->csrConfig.ho_delay_for_rx =
+ pHddCtx->config->ho_delay_for_rx;
+ smeConfig->csrConfig.min_delay_btw_roam_scans =
+ pHddCtx->config->min_delay_btw_roam_scans;
+ smeConfig->csrConfig.roam_trigger_reason_bitmask =
+ pHddCtx->config->roam_trigger_reason_bitmask;
smeConfig->csrConfig.obss_width_interval =
pHddCtx->config->obss_width_trigger_interval;
smeConfig->csrConfig.obss_active_dwelltime =
@@ -9560,6 +9612,8 @@ QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx)
pHddCtx->config->scan_adaptive_dwell_mode;
smeConfig->csrConfig.roamscan_adaptive_dwell_mode =
pHddCtx->config->roamscan_adaptive_dwell_mode;
+ smeConfig->csrConfig.roam_force_rssi_trigger =
+ pHddCtx->config->roam_force_rssi_trigger;
hdd_update_per_config_to_sme(pHddCtx, smeConfig);
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c
index 813a7eeffd0f..a30cce86d9d7 100644
--- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c
@@ -15928,7 +15928,7 @@ static bool wlan_hdd_handle_sap_sta_dfs_conc(hdd_adapter_t *adapter,
* machine from disconnected to started and set this event.
* wait for 10 secs to finish this.
*/
- status = qdf_wait_single_event(&hostapd_state->qdf_event, 10000);
+ status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, 10000);
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("wait for qdf_event failed, STA not allowed!!");
return false;
@@ -18679,7 +18679,7 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
pAdapter->aStaInfo[i].
isDeauthInProgress = true;
qdf_status =
- qdf_wait_single_event(
+ qdf_wait_for_event_completion(
&hapd_state->
qdf_sta_disassoc_event,
SME_CMD_TIMEOUT_VALUE);
@@ -18744,10 +18744,10 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
MAC_ADDR_ARRAY(mac));
return -ENOENT;
} else {
- qdf_status = qdf_wait_single_event(
- &hapd_state->
- qdf_sta_disassoc_event,
- SME_CMD_TIMEOUT_VALUE);
+ qdf_status = qdf_wait_for_event_completion(
+ &hapd_state->
+ qdf_sta_disassoc_event,
+ SME_CMD_TIMEOUT_VALUE);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
hdd_warn("Deauth wait time expired");
}
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c
index 5624731d91b2..0b4079aa0e9d 100644
--- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c
@@ -1294,6 +1294,7 @@ static void hdd_cleanup_on_fw_down(void)
ENTER();
hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+ qdf_complete_wait_events();
cds_set_target_ready(false);
if (hdd_ctx != NULL)
hdd_cleanup_scan_queue(hdd_ctx, NULL);
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c
index eabc11098f9f..4621651ad6e6 100644
--- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c
@@ -5353,7 +5353,7 @@ __iw_softap_stopbss(struct net_device *dev,
WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter));
if (QDF_IS_STATUS_SUCCESS(status)) {
qdf_status =
- qdf_wait_single_event(&pHostapdState->
+ qdf_wait_for_event_completion(&pHostapdState->
qdf_stop_bss_event,
SME_CMD_TIMEOUT_VALUE);
@@ -8665,7 +8665,7 @@ int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter,
hdd_debug("Waiting for Scan to complete(auto mode) and BSS to start");
- qdf_status = qdf_wait_single_event(&pHostapdState->qdf_event,
+ qdf_status = qdf_wait_for_event_completion(&pHostapdState->qdf_event,
SME_CMD_TIMEOUT_VALUE);
wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL);
@@ -8891,7 +8891,7 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
status = wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter));
if (QDF_IS_STATUS_SUCCESS(status)) {
qdf_status =
- qdf_wait_single_event(&pHostapdState->
+ qdf_wait_for_event_completion(&pHostapdState->
qdf_stop_bss_event,
SME_CMD_TIMEOUT_VALUE);
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c
index 092afd6e4de3..95a7c948e5c8 100644
--- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c
@@ -54,6 +54,7 @@
#include "wlan_hdd_power.h"
#include "wlan_hdd_stats.h"
#include "wlan_hdd_scan.h"
+#include "wlan_hdd_request_manager.h"
#include "qdf_types.h"
#include "qdf_trace.h"
#include
@@ -4206,8 +4207,8 @@ QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter,
qdf_event_reset(&hostapd_state->
qdf_stop_bss_event);
qdf_status =
- qdf_wait_single_event(&hostapd_state->
- qdf_stop_bss_event,
+ qdf_wait_for_event_completion(
+ &hostapd_state->qdf_stop_bss_event,
SME_CMD_TIMEOUT_VALUE);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
@@ -5915,6 +5916,7 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx)
*/
hdd_green_ap_deinit(hdd_ctx);
+ hdd_request_manager_deinit();
hdd_runtime_suspend_context_deinit(hdd_ctx);
hdd_close_all_adapters(hdd_ctx, false);
@@ -9953,6 +9955,7 @@ int hdd_wlan_startup(struct device *dev)
if (QDF_IS_STATUS_ERROR(ret))
goto err_hdd_free_context;
+ hdd_request_manager_init();
hdd_green_ap_init(hdd_ctx);
hdd_init_spectral_scan(hdd_ctx);
@@ -10076,6 +10079,7 @@ int hdd_wlan_startup(struct device *dev)
}
hdd_green_ap_deinit(hdd_ctx);
+ hdd_request_manager_deinit();
hdd_exit_netlink_services(hdd_ctx);
cds_deinit_ini_config();
@@ -10963,8 +10967,8 @@ void wlan_hdd_stop_sap(hdd_adapter_t *ap_adapter)
qdf_event_reset(&hostapd_state->qdf_stop_bss_event);
if (QDF_STATUS_SUCCESS == wlansap_stop_bss(hdd_ap_ctx->
sapContext)) {
- qdf_status = qdf_wait_single_event(&hostapd_state->
- qdf_stop_bss_event,
+ qdf_status = qdf_wait_for_event_completion(
+ &hostapd_state->qdf_stop_bss_event,
SME_CMD_TIMEOUT_VALUE);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
mutex_unlock(&hdd_ctx->sap_lock);
@@ -11030,7 +11034,7 @@ void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter, bool reinit)
goto end;
hdd_debug("Waiting for SAP to start");
- qdf_status = qdf_wait_single_event(&hostapd_state->qdf_event,
+ qdf_status = qdf_wait_for_event_completion(&hostapd_state->qdf_event,
SME_CMD_TIMEOUT_VALUE);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("SAP Start failed");
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_request_manager.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_request_manager.c
new file mode 100644
index 000000000000..a90b928e8c9d
--- /dev/null
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_request_manager.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2017-2018 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
+#include "wlan_hdd_request_manager.h"
+#include "wlan_hdd_main.h"
+#include "qdf_list.h"
+#include "qdf_event.h"
+#include "qdf_mem.h"
+
+/* arbitrary value */
+#define MAX_NUM_REQUESTS 20
+
+static bool is_initialized;
+static qdf_list_t requests;
+static qdf_spinlock_t spinlock;
+static void *cookie;
+
+struct hdd_request {
+ qdf_list_node_t node;
+ void *cookie;
+ uint32_t reference_count;
+ struct hdd_request_params params;
+ qdf_event_t completed;
+};
+
+/* must be called with spinlock held */
+static void hdd_request_unlink(struct hdd_request *request)
+{
+ qdf_list_remove_node(&requests, &request->node);
+}
+
+static void hdd_request_destroy(struct hdd_request *request)
+{
+ struct hdd_request_params *params;
+
+ params = &request->params;
+ if (params->dealloc) {
+ void *priv = hdd_request_priv(request);
+
+ params->dealloc(priv);
+ }
+ qdf_event_destroy(&request->completed);
+ qdf_mem_free(request);
+}
+
+/* must be called with spinlock held */
+static struct hdd_request *hdd_request_find(void *cookie)
+{
+ QDF_STATUS status;
+ struct hdd_request *request;
+ qdf_list_node_t *node;
+
+ status = qdf_list_peek_front(&requests, &node);
+ while (QDF_IS_STATUS_SUCCESS(status)) {
+ request = qdf_container_of(node, struct hdd_request, node);
+ if (request->cookie == cookie)
+ return request;
+ status = qdf_list_peek_next(&requests, node, &node);
+ }
+
+ return NULL;
+}
+
+struct hdd_request *hdd_request_alloc(const struct hdd_request_params *params)
+{
+ size_t length;
+ struct hdd_request *request;
+
+ if (!is_initialized) {
+ hdd_err("invoked when not initialized from %pS",
+ (void *)_RET_IP_);
+ return NULL;
+ }
+
+ length = sizeof(*request) + params->priv_size;
+ request = qdf_mem_malloc(length);
+ if (!request) {
+ hdd_err("allocation failed for %pS", (void *)_RET_IP_);
+ return NULL;
+ }
+ request->reference_count = 1;
+ request->params = *params;
+ qdf_event_create(&request->completed);
+ qdf_spin_lock_bh(&spinlock);
+ request->cookie = cookie++;
+ qdf_list_insert_back(&requests, &request->node);
+ qdf_spin_unlock_bh(&spinlock);
+ hdd_debug("request %pK, cookie %pK, caller %pS",
+ request, request->cookie, (void *)_RET_IP_);
+
+ return request;
+}
+
+void *hdd_request_priv(struct hdd_request *request)
+{
+ /* private data area immediately follows the struct hdd_request */
+ return request + 1;
+}
+
+void *hdd_request_cookie(struct hdd_request *request)
+{
+ return request->cookie;
+}
+
+struct hdd_request *hdd_request_get(void *cookie)
+{
+ struct hdd_request *request;
+
+ if (!is_initialized) {
+ hdd_err("invoked when not initialized from %pS",
+ (void *)_RET_IP_);
+ return NULL;
+ }
+ qdf_spin_lock_bh(&spinlock);
+ request = hdd_request_find(cookie);
+ if (request)
+ request->reference_count++;
+ qdf_spin_unlock_bh(&spinlock);
+ hdd_debug("cookie %pK, request %pK, caller %pS",
+ cookie, request, (void *)_RET_IP_);
+
+ return request;
+}
+
+void hdd_request_put(struct hdd_request *request)
+{
+ bool unlinked = false;
+
+ hdd_debug("request %pK, cookie %pK, caller %pS",
+ request, request->cookie, (void *)_RET_IP_);
+ qdf_spin_lock_bh(&spinlock);
+ request->reference_count--;
+ if (0 == request->reference_count) {
+ hdd_request_unlink(request);
+ unlinked = true;
+ }
+ qdf_spin_unlock_bh(&spinlock);
+ if (unlinked)
+ hdd_request_destroy(request);
+}
+
+int hdd_request_wait_for_response(struct hdd_request *request)
+{
+ QDF_STATUS status;
+
+ status = qdf_wait_for_event_completion(&request->completed,
+ request->params.timeout_ms);
+
+ return qdf_status_to_os_return(status);
+}
+
+void hdd_request_complete(struct hdd_request *request)
+{
+ (void) qdf_event_set(&request->completed);
+}
+
+void hdd_request_manager_init(void)
+{
+ hdd_debug("%pS", (void *)_RET_IP_);
+ if (is_initialized)
+ return;
+
+ qdf_list_create(&requests, MAX_NUM_REQUESTS);
+ qdf_spinlock_create(&spinlock);
+ is_initialized = true;
+}
+
+/*
+ * hdd_request_manager_deinit implementation note:
+ * It is intentional that we do not destroy the list or the spinlock.
+ * This allows threads to still access the infrastructure even when it
+ * has been deinitialized. Since neither lists nor spinlocks consume
+ * resources this does not result in a resource leak.
+ */
+void hdd_request_manager_deinit(void)
+{
+ hdd_debug("%pS", (void *)_RET_IP_);
+ is_initialized = false;
+}
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_request_manager.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_request_manager.h
new file mode 100644
index 000000000000..357ef2a12d69
--- /dev/null
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_request_manager.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2017-2018 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.
+ */
+
+#ifndef __WLAN_HDD_REQUEST_MANAGER_H__
+#define __WLAN_HDD_REQUEST_MANAGER_H__
+
+/**
+ * DOC: WLAN HDD REQUEST MANAGER
+ *
+ * Many operations within the wlan driver occur in an asynchronous
+ * manner. Requests are received by HDD via one of the kernel
+ * interfaces (ioctl, nl80211, virtual file system, etc.). The
+ * requests are translated to an internal format and are then passed
+ * to lower layers, usually via SME, for processing. For requests
+ * which require a response, that response comes up from the lower
+ * layers in a separate thread of execution, ultimately resulting in a
+ * call to a callback function that was provided by HDD as part of the
+ * initial request. So a mechanism is needed to synchronize the
+ * request and response. This framework provides that mechanism.
+ *
+ * Once the framework has been initialized, the typical sequence of
+ * events is as follows:
+ *
+ * Request Thread:
+ * 1. Create a &struct hdd_request_params which describes the request.
+ * 2. Call hdd_request_alloc() to allocate a &struct hdd_request.
+ * 3. Call hdd_request_priv() to get a pointer to the private data.
+ * 4. Place any information which must be shared with the Response
+ * Callback in the private data area.
+ * 5. Call hdd_request_cookie() to get the unique cookie assigned
+ * to the request.
+ * 6. Call the underlying request handling API, passing the cookie
+ * as the callback's private context.
+ * 7. Call hdd_request_wait_for_response() to wait for the response
+ * (or for the request to time out).
+ * 8. Use the return status to see if the request was successful. If
+ * it was, retrieve any response information from the private
+ * structure and prepare a response for userspace.
+ * 9. Call hdd_request_put() to relinquish access to the request.
+ * 10. Return status to the caller.
+ *
+ * Response Callback:
+ * 1. Call hdd_request_get() with the provided cookie to see if the
+ * request structure is still valid. If it returns %NULL then
+ * return since this means the request thread has already timed
+ * out.
+ * 2. Call hdd_request_priv() to get access to the private data area.
+ * 3. Write response data into the private data area.
+ * 4. Call hdd_request_complete() to indicate that the response is
+ * ready to be processed by the request thread.
+ * 5. Call hdd_request_put() to relinquish the callback function's
+ * reference to the request.
+ */
+
+/* this is opaque to clients */
+struct hdd_request;
+
+/**
+ * typedef hdd_request_dealloc - Private data deallocation function
+ */
+typedef void (*hdd_request_dealloc)(void *priv);
+
+/**
+ * struct hdd_request_params - HDD request parameters
+ * @priv_size: Size of the private data area required to pass
+ * information between the request thread and the response callback.
+ * @timeout_ms: The amount of time to wait for a response in milliseconds.
+ * @dealloc: Function to be called when the request is destroyed to
+ * deallocate any allocations made in the private area of the
+ * request struct. Can be %NULL if no private allocations are
+ * made.
+ */
+struct hdd_request_params {
+ uint32_t priv_size;
+ uint32_t timeout_ms;
+ hdd_request_dealloc dealloc;
+};
+
+/**
+ * hdd_request_alloc() - Allocate a request struct
+ * @params: parameter block that specifies the attributes of the
+ * request
+ *
+ * This function will attempt to allocate a &struct hdd_request with
+ * the specified @params. If successful, the caller can then use
+ * request struct to make an asynchronous request. Once the request is
+ * no longer needed, the reference should be relinquished via a call
+ * to hdd_request_put().
+ *
+ * Return: A pointer to an allocated &struct hdd_request (which also
+ * contains room for the private buffer) if the allocation is
+ * successful, %NULL if the allocation fails.
+ */
+struct hdd_request *hdd_request_alloc(const struct hdd_request_params *params);
+
+/**
+ * hdd_request_priv() - Get pointer to request private data
+ * @request: The request struct that contains the private data
+ *
+ * This function will return a pointer to the private data area that
+ * is part of the request struct. The caller must already have a valid
+ * reference to @request from either hdd_request_alloc() or
+ * hdd_request_get().
+ *
+ * Returns: pointer to the private data area. Note that this pointer
+ * will always be an offset from the input @request pointer and hence
+ * this function will never return %NULL.
+ */
+void *hdd_request_priv(struct hdd_request *request);
+
+/**
+ * hdd_request_cookie() - Get cookie of a request
+ * @request: The request struct associated with the request
+ *
+ * This function will return the unique cookie that has been assigned
+ * to the request. This cookie can subsequently be passed to
+ * hdd_request_get() to retrieve the request.
+ *
+ * Note that the cookie is defined as a void pointer as it is intended
+ * to be passed as an opaque context pointer from HDD to underlying
+ * layers when making a request, and subsequently passed back to HDD
+ * as an opaque pointer in an asynchronous callback.
+ *
+ * Returns: The cookie assigned to the request.
+ */
+void *hdd_request_cookie(struct hdd_request *request);
+
+/**
+ * hdd_request_get() - Get a reference to a request struct
+ * @cookie: The cookie of the request struct that needs to be
+ * referenced
+ *
+ * This function will use the cookie to determine if the associated
+ * request struct is valid, and if so, will increment the reference
+ * count of the struct. This means the caller is guaranteed that the
+ * request struct is valid and the underlying private data can be
+ * dereferenced.
+ *
+ * Returns: The pointer to the request struct associated with @cookie
+ * if the request is still valid, %NULL if the underlying request
+ * struct is no longer valid.
+ */
+struct hdd_request *hdd_request_get(void *cookie);
+
+/**
+ * hdd_request_put() - Release a reference to a request struct
+ * @request: The request struct that no longer needs to be referenced
+ *
+ * This function will decrement the reference count of the struct, and
+ * will clean up the request if this is the last reference. The caller
+ * must already have a valid reference to @request, either from
+ * hdd_request_alloc() or hdd_request_get().
+ *
+ * Returns: Nothing
+ */
+void hdd_request_put(struct hdd_request *request);
+
+/**
+ * hdd_request_wait_for_response() - Wait for a response
+ * @request: The request struct associated with the request
+ *
+ * This function will wait until either a response is received and
+ * communicated via hdd_request_complete(), or until the request
+ * timeout period expires.
+ *
+ * Returns: 0 if a response was received, -ETIMEDOUT if the response
+ * timed out.
+ */
+int hdd_request_wait_for_response(struct hdd_request *request);
+
+/**
+ * hdd_request_complete() - Complete a request
+ * @request: The request struct associated with the request
+ *
+ * This function is used to indicate that a response has been received
+ * and that any information required by the request thread has been
+ * copied into the private data area of the request struct. This will
+ * unblock any hdd_request_wait_for_response() that is pending on this
+ * @request.
+ *
+ * Returns: Nothing
+ */
+void hdd_request_complete(struct hdd_request *request);
+
+/**
+ * hdd_request_manager_init() - Initialize the HDD Request Manager
+ *
+ * This function must be called during system initialization to
+ * initialize the HDD Request Manager.
+ *
+ * Returns: Nothing
+ */
+void hdd_request_manager_init(void);
+
+/**
+ * hdd_request_manager_deinit() - Deinitialize the HDD Request Manager
+ *
+ * This function must be called during system shutdown to deinitialize
+ * the HDD Request Manager.
+ *
+ * Returns: Nothing
+ */
+void hdd_request_manager_deinit(void);
+
+#endif /* __WLAN_HDD_REQUEST_MANAGER_H__ */
diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c
index 824c9da2c7d5..121949deb814 100644
--- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c
+++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c
@@ -94,6 +94,7 @@
#include "wlan_hdd_lro.h"
#include "cds_utils.h"
#include "wlan_hdd_packet_filter_api.h"
+#include "wlan_hdd_request_manager.h"
#define HDD_FINISH_ULA_TIME_OUT 800
#define HDD_SET_MCBC_FILTERS_TO_FW 1
@@ -5053,9 +5054,9 @@ static int __iw_get_bitrate(struct net_device *dev,
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
- qdf_status =
- qdf_wait_single_event(&pWextState->hdd_qdf_event,
- WLAN_WAIT_TIME_STATS);
+ qdf_status = qdf_wait_for_event_completion(
+ &pWextState->hdd_qdf_event,
+ WLAN_WAIT_TIME_STATS);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("SME timeout while retrieving statistics");
@@ -6051,60 +6052,43 @@ static int iw_get_range(struct net_device *dev, struct iw_request_info *info,
return ret;
}
+struct class_a_stats {
+ tCsrGlobalClassAStatsInfo class_a_stats;
+};
+
/**
* hdd_get_class_a_statistics_cb() - Get Class A stats callback function
- * @pStats: pointer to Class A stats
- * @pContext: user context originally registered with SME
+ * @stats: pointer to Class A stats
+ * @context: user context originally registered with SME (always the
+ * cookie from the request context)
*
* Return: None
*/
-static void hdd_get_class_a_statistics_cb(void *pStats, void *pContext)
+static void hdd_get_class_a_statistics_cb(void *stats, void *context)
{
- struct statsContext *pStatsContext;
- tCsrGlobalClassAStatsInfo *pClassAStats;
- hdd_adapter_t *pAdapter;
+ struct hdd_request *request;
+ struct class_a_stats *priv;
+ tCsrGlobalClassAStatsInfo *returned_stats;
- if ((NULL == pStats) || (NULL == pContext)) {
- hdd_err("Bad param, pStats [%pK] pContext [%pK]",
- pStats, pContext);
+ ENTER();
+ if ((NULL == stats) || (NULL == context)) {
+ hdd_err("Bad param, stats [%p] context [%p]",
+ stats, context);
return;
}
- pClassAStats = pStats;
- pStatsContext = pContext;
- pAdapter = pStatsContext->pAdapter;
-
- /* there is a race condition that exists between this callback
- * function and the caller since the caller could time out
- * either before or while this code is executing. we use a
- * spinlock to serialize these actions
- */
- spin_lock(&hdd_context_lock);
-
- if ((NULL == pAdapter) ||
- (STATS_CONTEXT_MAGIC != pStatsContext->magic)) {
- /* the caller presumably timed out so there is nothing
- * we can do
- */
- spin_unlock(&hdd_context_lock);
- hdd_warn("Invalid context, pAdapter [%pK] magic [%08x]",
- pAdapter, pStatsContext->magic);
+ request = hdd_request_get(context);
+ if (!request) {
+ hdd_err("Obsolete request");
return;
}
- /* context is valid so caller is still waiting */
-
- /* paranoia: invalidate the magic */
- pStatsContext->magic = 0;
-
- /* copy over the stats. do so as a struct copy */
- pAdapter->hdd_stats.ClassA_stat = *pClassAStats;
-
- /* notify the caller */
- complete(&pStatsContext->completion);
-
- /* serialization is complete */
- spin_unlock(&hdd_context_lock);
+ returned_stats = stats;
+ priv = hdd_request_priv(request);
+ priv->class_a_stats = *returned_stats;
+ hdd_request_complete(request);
+ hdd_request_put(request);
+ EXIT();
}
/**
@@ -6117,8 +6101,14 @@ QDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter)
{
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
QDF_STATUS hstatus;
- unsigned long rc;
- static struct statsContext context;
+ int ret;
+ void *cookie;
+ struct hdd_request *request;
+ struct class_a_stats *priv;
+ static const struct hdd_request_params params = {
+ .priv_size = sizeof(*priv),
+ .timeout_ms = WLAN_WAIT_TIME_STATS,
+ };
if (NULL == pAdapter) {
hdd_err("pAdapter is NULL");
@@ -6130,10 +6120,13 @@ QDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter)
return QDF_STATUS_SUCCESS;
}
- /* we are connected so prepare our callback context */
- init_completion(&context.completion);
- context.pAdapter = pAdapter;
- context.magic = STATS_CONTEXT_MAGIC;
+ request = hdd_request_alloc(¶ms);
+ if (!request) {
+ hdd_err("Request allocation failure");
+ return QDF_STATUS_E_NOMEM;
+ }
+ cookie = hdd_request_cookie(request);
+
/* query only for Class A statistics (which include link speed) */
hstatus = sme_get_statistics(WLAN_HDD_GET_HAL_CTX(pAdapter),
eCSR_HDD, SME_GLOBAL_CLASSA_STATS,
@@ -6141,37 +6134,30 @@ QDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter)
0, /* not periodic */
false, /* non-cached results */
pHddStaCtx->conn_info.staId[0],
- &context, pAdapter->sessionId);
+ cookie, pAdapter->sessionId);
if (QDF_STATUS_SUCCESS != hstatus) {
hdd_debug("Unable to retrieve Class A statistics");
- /* we'll returned a cached value below */
- } else {
- /* request was sent -- wait for the response */
- rc = wait_for_completion_timeout
- (&context.completion,
- msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- if (!rc)
- hdd_warn("SME timed out while retrieving Class A statistics");
+ goto return_cached_results;
+ }
+ /* request was sent -- wait for the response */
+ ret = hdd_request_wait_for_response(request);
+ if (ret) {
+ hdd_warn("SME timed out while retrieving Class A statistics");
+ goto return_cached_results;
}
- /* either we never sent a request, we sent a request and
- * received a response or we sent a request and timed out. if
- * we never sent a request or if we sent a request and got a
- * response, we want to clear the magic out of paranoia. if
- * we timed out there is a race condition such that the
- * callback function could be executing at the same time we
- * are. of primary concern is if the callback function had
- * already verified the "magic" but had not yet set the
- * completion variable when a timeout occurred. we serialize
- * these activities by invalidating the magic while holding a
- * shared spinlock which will cause us to block if the
- * callback is currently executing
+ /* update the adapter with the fresh results */
+ priv = hdd_request_priv(request);
+ pAdapter->hdd_stats.ClassA_stat = priv->class_a_stats;
+
+return_cached_results:
+ /*
+ * either we never sent a request, we sent a request and
+ * received a response or we sent a request and timed out.
+ * regardless we are done with the request.
*/
- spin_lock(&hdd_context_lock);
- context.magic = 0;
- spin_unlock(&hdd_context_lock);
+ hdd_request_put(request);
- /* either callback updated pAdapter stats or it has cached data */
return QDF_STATUS_SUCCESS;
}
@@ -11858,9 +11844,10 @@ static int __iw_get_statistics(struct net_device *dev,
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
- qdf_status =
- qdf_wait_single_event(&pWextState->hdd_qdf_event,
- WLAN_WAIT_TIME_STATS);
+ qdf_status = qdf_wait_for_event_completion(
+ &pWextState->hdd_qdf_event,
+ WLAN_WAIT_TIME_STATS);
+
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
hdd_err("SME timeout while retrieving statistics");
/* Remove the SME statistics list by
diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h
index 64c5c9c1e60f..8681739467ff 100644
--- a/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h
+++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h
@@ -3566,6 +3566,10 @@ typedef struct sSirRoamOffloadScanReq {
#endif
struct scoring_param score_params;
struct wmi_11k_offload_params offload_11k_params;
+ uint32_t ho_delay_for_rx;
+ uint32_t min_delay_btw_roam_scans;
+ uint32_t roam_trigger_reason_bitmask;
+ bool roam_force_rssi_trigger;
} tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq;
typedef struct sSirRoamOffloadScanRsp {
diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c
index 56404085797b..1693ecc050a7 100644
--- a/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c
+++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c
@@ -120,7 +120,8 @@ QDF_STATUS sys_stop(v_CONTEXT_t p_cds_context)
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_status = QDF_STATUS_E_BADMSG;
- qdf_status = qdf_wait_single_event(&g_stop_evt, SYS_STOP_TIMEOUT);
+ qdf_status = qdf_wait_for_event_completion(&g_stop_evt,
+ SYS_STOP_TIMEOUT);
QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
qdf_status = qdf_event_destroy(&g_stop_evt);
diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c
index b0a8eab4f8a8..2fe092c7b28f 100644
--- a/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c
+++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c
@@ -2558,8 +2558,9 @@ QDF_STATUS sap_open_session(tHalHandle hHal, ptSapContext sapContext,
return QDF_STATUS_E_FAILURE;
}
- status = qdf_wait_single_event(&sapContext->sap_session_opened_evt,
- SME_CMD_TIMEOUT_VALUE);
+ status = qdf_wait_for_event_completion(
+ &sapContext->sap_session_opened_evt,
+ SME_CMD_TIMEOUT_VALUE);
if (!QDF_IS_STATUS_SUCCESS(status)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h
index 1136fd9c655c..b5a4b7c2021d 100644
--- a/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h
+++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h
@@ -1303,6 +1303,9 @@ typedef struct tagCsrConfigParam {
uint8_t rx_ldpc_support_for_2g;
uint8_t max_amsdu_num;
uint8_t nSelect5GHzMargin;
+ uint32_t ho_delay_for_rx;
+ uint32_t min_delay_btw_roam_scans;
+ uint32_t roam_trigger_reason_bitmask;
uint8_t isCoalesingInIBSSAllowed;
#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
uint8_t cc_switch_mode;
@@ -1392,6 +1395,7 @@ typedef struct tagCsrConfigParam {
struct sir_score_config bss_score_params;
uint32_t offload_11k_enable_bitmask;
struct csr_neighbor_report_offload_params neighbor_report_offload;
+ bool roam_force_rssi_trigger;
} tCsrConfigParam;
/* Tush */
diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h
index 5090a3191f82..336fe05d4721 100644
--- a/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h
+++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h
@@ -610,6 +610,9 @@ typedef struct tagCsrConfig {
bool enableHeartBeatOffload;
uint8_t max_amsdu_num;
uint8_t nSelect5GHzMargin;
+ uint32_t ho_delay_for_rx;
+ uint32_t min_delay_btw_roam_scans;
+ uint32_t roam_trigger_reason_bitmask;
uint8_t isCoalesingInIBSSAllowed;
#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
uint8_t cc_switch_mode;
@@ -676,6 +679,7 @@ typedef struct tagCsrConfig {
struct sir_score_config bss_score_params;
uint32_t offload_11k_enable_bitmask;
struct csr_neighbor_report_offload_params neighbor_report_offload;
+ bool roam_force_rssi_trigger;
} tCsrConfig;
typedef struct tagCsrChannelPowerInfo {
diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c
index 773420d9d513..e5d0f3f9690e 100644
--- a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c
+++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c
@@ -2083,6 +2083,8 @@ csr_fetch_ch_lst_from_received_list(tpAniSirGlobal mac_ctx,
}
req_buf->ConnectedNetwork.ChannelCount = num_channels;
req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE;
+ sme_debug("ChannelCacheType %dChannelCount %d",
+ req_buf->ChannelCacheType, num_channels);
}
/**
@@ -2693,6 +2695,12 @@ QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac,
pParam->max_amsdu_num;
pMac->roam.configParam.nSelect5GHzMargin =
pParam->nSelect5GHzMargin;
+ pMac->roam.configParam.ho_delay_for_rx =
+ pParam->ho_delay_for_rx;
+ pMac->roam.configParam.min_delay_btw_roam_scans =
+ pParam->min_delay_btw_roam_scans;
+ pMac->roam.configParam.roam_trigger_reason_bitmask =
+ pParam->roam_trigger_reason_bitmask;
pMac->roam.configParam.isCoalesingInIBSSAllowed =
pParam->isCoalesingInIBSSAllowed;
#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
@@ -2853,6 +2861,8 @@ QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac,
pParam->rssi_channel_penalization;
pMac->roam.configParam.num_disallowed_aps =
pParam->num_disallowed_aps;
+ pMac->roam.configParam.roam_force_rssi_trigger =
+ pParam->roam_force_rssi_trigger;
qdf_mem_copy(&pMac->roam.configParam.bss_score_params,
&pParam->bss_score_params,
@@ -3013,6 +3023,10 @@ QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam)
cfg_params->rx_ldpc_support_for_2g;
pParam->max_amsdu_num = cfg_params->max_amsdu_num;
pParam->nSelect5GHzMargin = cfg_params->nSelect5GHzMargin;
+ pParam->ho_delay_for_rx = cfg_params->ho_delay_for_rx;
+ pParam->min_delay_btw_roam_scans = cfg_params->min_delay_btw_roam_scans;
+ pParam->roam_trigger_reason_bitmask =
+ cfg_params->roam_trigger_reason_bitmask;
pParam->isCoalesingInIBSSAllowed = cfg_params->isCoalesingInIBSSAllowed;
pParam->allowDFSChannelRoam = cfg_params->allowDFSChannelRoam;
pParam->nInitialDwellTime = cfg_params->nInitialDwellTime;
@@ -3155,6 +3169,7 @@ QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam)
pMac->roam.configParam.rssi_channel_penalization;
pParam->num_disallowed_aps =
pMac->roam.configParam.num_disallowed_aps;
+ pParam->roam_force_rssi_trigger = cfg_params->roam_force_rssi_trigger;
qdf_mem_copy(&pParam->bss_score_params,
&pMac->roam.configParam.bss_score_params,
@@ -18025,6 +18040,14 @@ csr_update_roam_scan_offload_request(tpAniSirGlobal mac_ctx,
req_buf->Prefer5GHz = mac_ctx->roam.configParam.nRoamPrefer5GHz;
req_buf->RoamRssiCatGap = mac_ctx->roam.configParam.bCatRssiOffset;
req_buf->Select5GHzMargin = mac_ctx->roam.configParam.nSelect5GHzMargin;
+ req_buf->ho_delay_for_rx = mac_ctx->roam.configParam.ho_delay_for_rx;
+ req_buf->min_delay_btw_roam_scans =
+ mac_ctx->roam.configParam.min_delay_btw_roam_scans;
+ req_buf->roam_trigger_reason_bitmask =
+ mac_ctx->roam.configParam.roam_trigger_reason_bitmask;
+ req_buf->roam_force_rssi_trigger =
+ mac_ctx->roam.configParam.roam_force_rssi_trigger;
+
if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT,
(uint32_t *) &req_buf->ReassocFailureTimeout)
!= eSIR_SUCCESS) {
@@ -18158,6 +18181,8 @@ csr_fetch_ch_lst_from_ini(tpAniSirGlobal mac_ctx,
}
req_buf->ConnectedNetwork.ChannelCount = num_channels;
req_buf->ChannelCacheType = CHANNEL_LIST_STATIC;
+ sme_debug("ChannelCacheType %dChannelCount %d",
+ req_buf->ChannelCacheType, num_channels);
return QDF_STATUS_SUCCESS;
}
@@ -18258,6 +18283,8 @@ csr_fetch_ch_lst_from_occupied_lst(tpAniSirGlobal mac_ctx,
else
req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE;
}
+ sme_debug("ChannelCacheType %dChannelCount %d",
+ req_buf->ChannelCacheType, num_channels);
}
/**
@@ -18359,11 +18386,10 @@ csr_fetch_valid_ch_lst(tpAniSirGlobal mac_ctx,
}
req_buf->ValidChannelCount = num_channels;
- if (CSR_IS_ROAM_INTRA_BAND_ENABLED(mac_ctx)) {
- req_buf->ChannelCacheType = CHANNEL_LIST_STATIC;
- req_buf->ConnectedNetwork.ChannelCount = num_channels;
- }
-
+ req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE;
+ req_buf->ConnectedNetwork.ChannelCount = num_channels;
+ sme_debug("ChannelCacheType %dChannelCount %d",
+ req_buf->ChannelCacheType, num_channels);
return status;
}
diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c
index bc7ec1179478..698af36e2fea 100644
--- a/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c
+++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c
@@ -3030,7 +3030,7 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen,
* @ Discrete : Target Download Complete
*/
qdf_status =
- qdf_wait_single_event(&wma_handle->
+ qdf_wait_for_event_completion(&wma_handle->
tx_frm_download_comp_event,
WMA_TX_FRAME_COMPLETE_TIMEOUT);
diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c
index f8cdc6524479..707c0b97cec1 100644
--- a/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c
+++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c
@@ -5069,7 +5069,7 @@ static void wma_wait_tx_complete(tp_wma_handle wma,
while (ol_txrx_get_tx_pending(pdev) && max_wait_iterations) {
WMA_LOGW(FL("Waiting for outstanding packet to drain."));
- qdf_wait_single_event(&wma->tx_queue_empty_event,
+ qdf_wait_for_event_completion(&wma->tx_queue_empty_event,
WMA_TX_Q_RECHECK_TIMER_WAIT);
max_wait_iterations--;
}
diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c
index 65315642688a..b74f516c456f 100644
--- a/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c
+++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c
@@ -5350,7 +5350,7 @@ QDF_STATUS wma_enable_d0wow_in_fw(WMA_HANDLE handle)
return status;
}
- status = qdf_wait_single_event(&wma->target_suspend,
+ status = qdf_wait_for_event_completion(&wma->target_suspend,
WMA_TGT_SUSPEND_COMPLETE_TIMEOUT);
if (QDF_IS_STATUS_ERROR(status)) {
WMA_LOGE("Failed to receive D0-WoW enable HTC ACK from FW! "
@@ -5450,7 +5450,7 @@ QDF_STATUS wma_enable_wow_in_fw(WMA_HANDLE handle, uint32_t wow_flags)
wmi_set_target_suspend(wma->wmi_handle, true);
- if (qdf_wait_single_event(&wma->target_suspend,
+ if (qdf_wait_for_event_completion(&wma->target_suspend,
WMA_TGT_SUSPEND_COMPLETE_TIMEOUT)
!= QDF_STATUS_SUCCESS) {
WMA_LOGE("Failed to receive WoW Enable Ack from FW");
@@ -6215,7 +6215,7 @@ static QDF_STATUS wma_send_host_wakeup_ind_to_fw(tp_wma_handle wma)
WMA_LOGD("Host wakeup indication sent to fw");
- qdf_status = qdf_wait_single_event(&(wma->wma_resume_event),
+ qdf_status = qdf_wait_for_event_completion(&(wma->wma_resume_event),
WMA_RESUME_TIMEOUT);
if (QDF_STATUS_SUCCESS != qdf_status) {
WMA_LOGP("%s: Timeout waiting for resume event from FW",
@@ -6271,7 +6271,7 @@ QDF_STATUS wma_disable_d0wow_in_fw(WMA_HANDLE handle)
return status;
}
- status = qdf_wait_single_event(&(wma->wma_resume_event),
+ status = qdf_wait_for_event_completion(&(wma->wma_resume_event),
WMA_RESUME_TIMEOUT);
if (QDF_IS_STATUS_ERROR(status)) {
WMA_LOGP("%s: Timeout waiting for resume event from FW!",
@@ -8173,7 +8173,7 @@ static QDF_STATUS wma_post_runtime_suspend_msg(WMA_HANDLE handle)
if (qdf_status != QDF_STATUS_SUCCESS)
goto failure;
- if (qdf_wait_single_event(&wma->runtime_suspend,
+ if (qdf_wait_for_event_completion(&wma->runtime_suspend,
WMA_TGT_SUSPEND_COMPLETE_TIMEOUT) !=
QDF_STATUS_SUCCESS) {
WMA_LOGE("Failed to get runtime suspend event");
@@ -8446,7 +8446,7 @@ QDF_STATUS wma_suspend_target(WMA_HANDLE handle, int disable_target_intr)
wmi_set_target_suspend(wma_handle->wmi_handle, true);
- if (qdf_wait_single_event(&wma_handle->target_suspend,
+ if (qdf_wait_for_event_completion(&wma_handle->target_suspend,
WMA_TGT_SUSPEND_COMPLETE_TIMEOUT)
!= QDF_STATUS_SUCCESS) {
WMA_LOGE("Failed to get ACK from firmware for pdev suspend");
@@ -8570,7 +8570,7 @@ QDF_STATUS wma_resume_target(WMA_HANDLE handle)
if (QDF_IS_STATUS_ERROR(qdf_status))
WMA_LOGE("Failed to send WMI_PDEV_RESUME_CMDID command");
- qdf_status = qdf_wait_single_event(&(wma->wma_resume_event),
+ qdf_status = qdf_wait_for_event_completion(&(wma->wma_resume_event),
WMA_RESUME_TIMEOUT);
if (QDF_STATUS_SUCCESS != qdf_status) {
WMA_LOGP("%s: Timeout waiting for resume event from FW",
diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c
index 22f862b64c0a..d219c1a17f15 100644
--- a/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c
+++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c
@@ -6118,8 +6118,9 @@ QDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle)
QDF_STATUS qdf_status;
/* wait until WMI_READY_EVENTID received from FW */
- qdf_status = qdf_wait_single_event(&(wma_handle->wma_ready_event),
- WMA_READY_EVENTID_TIMEOUT);
+ qdf_status = qdf_wait_for_event_completion(
+ &wma_handle->wma_ready_event,
+ WMA_READY_EVENTID_TIMEOUT);
if (QDF_STATUS_SUCCESS != qdf_status) {
WMA_LOGE("%s: Timeout waiting for ready event from FW",
diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c
index da3df9629c14..9300ce61b7a5 100644
--- a/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c
+++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c
@@ -875,6 +875,8 @@ QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle,
params->is_roam_req_valid = 1;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
params->roam_offload_enabled = roam_req->RoamOffloadEnabled;
+ params->roam_offload_params.ho_delay_for_rx =
+ roam_req->ho_delay_for_rx;
params->prefer_5ghz = roam_req->Prefer5GHz;
params->roam_rssi_cat_gap = roam_req->RoamRssiCatGap;
params->select_5ghz_margin = roam_req->Select5GHzMargin;
@@ -895,6 +897,10 @@ QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle,
params->fw_okc = roam_req->pmkid_modes.fw_okc;
params->fw_pmksa_cache = roam_req->pmkid_modes.fw_pmksa_cache;
#endif
+ params->min_delay_btw_roam_scans =
+ roam_req->min_delay_btw_roam_scans;
+ params->roam_trigger_reason_bitmask =
+ roam_req->roam_trigger_reason_bitmask;
params->is_ese_assoc = roam_req->IsESEAssoc;
params->mdid.mdie_present = roam_req->MDID.mdiePresent;
params->mdid.mobility_domain = roam_req->MDID.mobilityDomain;
@@ -905,10 +911,14 @@ QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle,
wma_roam_scan_fill_fils_params(wma_handle, params, roam_req);
}
- WMA_LOGD(FL("qos_caps: %d, qos_enabled: %d, roam_scan_mode: %d"),
+ WMA_LOGD(FL("qos_caps: %d, qos_enabled: %d, ho_delay_for_rx: %d, roam_scan_mode: %d"),
params->roam_offload_params.qos_caps,
params->roam_offload_params.qos_enabled,
- params->mode);
+ params->roam_offload_params.ho_delay_for_rx, params->mode);
+
+ WMA_LOGD(FL("min_delay_btw_roam_scans: %d, roam_trigger_reason_bitmask: %d"),
+ params->min_delay_btw_roam_scans,
+ params->roam_trigger_reason_bitmask);
status = wmi_unified_roam_scan_offload_mode_cmd(wma_handle->wmi_handle,
scan_cmd_fp, params);
@@ -1972,7 +1982,8 @@ QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle,
/* Don't use rssi triggered roam scans if external app
* is in control of channel list.
*/
- if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC)
+ if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC ||
+ roam_req->roam_force_rssi_trigger)
mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE;
} else {
@@ -2239,7 +2250,8 @@ QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle,
/* Don't use rssi triggered roam scans if external app
* is in control of channel list.
*/
- if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC)
+ if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC ||
+ roam_req->roam_force_rssi_trigger)
mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE;
} else {
diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c
index 001849e9b1c8..f314c7eba420 100644
--- a/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c
+++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c
@@ -1526,8 +1526,8 @@ static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle,
return -EINVAL;
}
- if (fixed_param->radio_id > link_stats_results->num_radio) {
- WMA_LOGD("%s: Invalid radio_id %d num_radio %d",
+ if (fixed_param->radio_id >= link_stats_results->num_radio) {
+ WMA_LOGE("%s: Invalid radio_id %d num_radio %d",
__func__, fixed_param->radio_id,
link_stats_results->num_radio);
return -EINVAL;
@@ -1692,6 +1692,13 @@ static int wma_unified_link_radio_stats_event_handler(void *handle,
link_stats_results_size = sizeof(*link_stats_results) +
fixed_param->num_radio * radio_stats_size;
+ if (radio_stats->radio_id >= fixed_param->num_radio) {
+ WMA_LOGE("%s: Invalid radio_id %d num_radio %d",
+ __func__, radio_stats->radio_id,
+ fixed_param->num_radio);
+ return -EINVAL;
+ }
+
if (!wma_handle->link_stats_results) {
wma_handle->link_stats_results = qdf_mem_malloc(
link_stats_results_size);