Browse Source

qcacld-3.0: Fix issue for SMM before vdev start on 2.4ghz

Scenario:-
1. Turn on SAP and STA on 2.4ghz and 5ghz
2. Turn off SAP
3. Turn off STA
4. Turn on SAP on 2.4ghz

Issue:-
In the start ap function, the driver calls
the stop opportunistic timer and calls the handler
to goto SMM mode.
After this, the SAP checks whether it requires the
DBS or not and then requests for DBS also, but since
the driver is already in DBS mode this command gets
rejected, so there would be 2 commands in the serialization
queue which would be SMM and start AP, which would lead to
a crash as SMM is sent before a connection on 2.4ghz as
Hastings is not capable to start a vdev in 2.4ghz without
DBS mode.

Fix:-
1.Not allow SMM if the current connection requires DBS
2. Check the HW capabilty in the active command only and
not before that to protect the reliability of hw mode.

Change-Id: I1c0c05ea05ba14d1556af2612daa3de2ffcba367
CRs-Fixed: 2587508
gaurank kathpalia 5 years ago
parent
commit
570f0aff4f

+ 21 - 1
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -1186,6 +1186,7 @@ QDF_STATUS policy_mgr_check_n_start_opportunistic_timer(
  * @reason: Reason for connection update
  * @next_action: next action to happen at policy mgr after
  *		HW mode change
+ * @action: action to be applied before hw mode change
  *
  * Sends the set hw mode request to FW
  *
@@ -1233,7 +1234,7 @@ QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc,
 		enum hw_mode_agile_dfs_capab dfs,
 		enum hw_mode_sbs_capab sbs,
 		enum policy_mgr_conn_update_reason reason,
-		uint8_t next_action);
+		uint8_t next_action, enum policy_mgr_conc_next_action action);
 
 /**
  * policy_mgr_pdev_set_hw_mode_cback() - callback invoked by
@@ -1453,6 +1454,25 @@ QDF_STATUS policy_mgr_next_actions(struct wlan_objmgr_psoc *psoc,
 		enum policy_mgr_conc_next_action action,
 		enum policy_mgr_conn_update_reason reason);
 
+/**
+ * policy_mgr_validate_dbs_switch() - Check DBS action valid or not
+ * @psoc: Pointer to psoc
+ * @action: action requested
+ *
+ * This routine will check the current hw mode with requested action.
+ * If we are already in the mode, the caller will do nothing.
+ * This will be called by policy_mgr_next_actions to check the action needed
+ * or not.
+ *
+ * return : QDF_STATUS_SUCCESS, action is allowed.
+ *          QDF_STATUS_E_ALREADY, action is not needed.
+ *          QDF_STATUS_E_FAILURE, error happens.
+ *          QDF_STATUS_E_NOSUPPORT, the requested mode not supported.
+ */
+QDF_STATUS
+policy_mgr_validate_dbs_switch(struct wlan_objmgr_psoc *psoc,
+			       enum policy_mgr_conc_next_action action);
+
 /**
  * policy_mgr_set_dual_mac_scan_config() - Set the dual MAC scan config
  * @psoc: PSOC object information

+ 5 - 1
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020 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
@@ -949,6 +949,7 @@ enum hw_mode_bandwidth {
  * enum set_hw_mode_status - Status of set HW mode command
  * @SET_HW_MODE_STATUS_OK: command successful
  * @SET_HW_MODE_STATUS_EINVAL: Requested invalid hw_mode
+ * @SET_HW_MODE_STATUS_ALREADY: Requested hw mode is already applied to FW.
  * @SET_HW_MODE_STATUS_ECANCELED: HW mode change cancelled
  * @SET_HW_MODE_STATUS_ENOTSUP: HW mode not supported
  * @SET_HW_MODE_STATUS_EHARDWARE: HW mode change prevented by hardware
@@ -958,6 +959,7 @@ enum hw_mode_bandwidth {
 enum set_hw_mode_status {
 	SET_HW_MODE_STATUS_OK,
 	SET_HW_MODE_STATUS_EINVAL,
+	SET_HW_MODE_STATUS_ALREADY,
 	SET_HW_MODE_STATUS_ECANCELED,
 	SET_HW_MODE_STATUS_ENOTSUP,
 	SET_HW_MODE_STATUS_EHARDWARE,
@@ -1123,6 +1125,7 @@ struct policy_mgr_dual_mac_config {
  * @reason: Reason for HW mode change
  * @session_id: Session id
  * @next_action: next action to happen at policy mgr
+ * @action: current hw change action to be done
  * @context: psoc context
  */
 struct policy_mgr_hw_mode {
@@ -1131,6 +1134,7 @@ struct policy_mgr_hw_mode {
 	enum policy_mgr_conn_update_reason reason;
 	uint32_t session_id;
 	uint8_t next_action;
+	enum policy_mgr_conc_next_action action;
 	struct wlan_objmgr_psoc *context;
 };
 

+ 24 - 46
components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c

@@ -131,7 +131,7 @@ QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc,
 		enum hw_mode_agile_dfs_capab dfs,
 		enum hw_mode_sbs_capab sbs,
 		enum policy_mgr_conn_update_reason reason,
-		uint8_t next_action)
+		uint8_t next_action, enum policy_mgr_conc_next_action action)
 {
 	int8_t hw_mode_index;
 	struct policy_mgr_hw_mode msg;
@@ -181,10 +181,11 @@ QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc,
 	msg.reason = reason;
 	msg.session_id = session_id;
 	msg.next_action = next_action;
+	msg.action = action;
 	msg.context = psoc;
 
-	policy_mgr_debug("set hw mode to sme: hw_mode_index: %d session:%d reason:%d",
-		msg.hw_mode_index, msg.session_id, msg.reason);
+	policy_mgr_debug("set hw mode to sme: hw_mode_index: %d session:%d reason:%d action %d",
+			 msg.hw_mode_index, msg.session_id, msg.reason, action);
 
 	status = pm_ctx->sme_cbacks.sme_pdev_set_hw_mode(msg);
 	if (status != QDF_STATUS_SUCCESS) {
@@ -932,29 +933,9 @@ policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
-/**
- * policy_mgr_validate_dbs_switch() - Check DBS action valid or not
- * @psoc: Pointer to psoc
- * @session_id: vdev id
- * @action: action requested
- * @reason: reason of hw mode change
- *
- * This routine will check the current hw mode with requested action.
- * If we are already in the mode, the caller will do nothing.
- * This will be called by policy_mgr_next_actions to check the action needed
- * or not.
- *
- * return : QDF_STATUS_SUCCESS, action is allowed.
- *          QDF_STATUS_E_ALREADY, action is not needed.
- *          QDF_STATUS_E_FAILURE, error happens.
- *          QDF_STATUS_E_NOSUPPORT, the requested mode not supported.
- */
-static
-QDF_STATUS policy_mgr_validate_dbs_switch(
-		struct wlan_objmgr_psoc *psoc,
-		uint32_t session_id,
-		enum policy_mgr_conc_next_action action,
-		enum policy_mgr_conn_update_reason reason)
+QDF_STATUS
+policy_mgr_validate_dbs_switch(struct wlan_objmgr_psoc *psoc,
+			       enum policy_mgr_conc_next_action action)
 {
 	QDF_STATUS status;
 	struct policy_mgr_hw_mode_params hw_mode;
@@ -1046,15 +1027,6 @@ QDF_STATUS policy_mgr_next_actions(
 		return status;
 	}
 
-	/* check for the current HW index to see if really need any action */
-	status = policy_mgr_validate_dbs_switch(psoc, session_id, action,
-						reason);
-	if (!QDF_IS_STATUS_SUCCESS(status)) {
-		policy_mgr_err(" not take action %d reason %d session %d status %d",
-			       action, reason, session_id, status);
-		return status;
-	}
-
 	switch (action) {
 	case PM_DBS_DOWNGRADE:
 		/*
@@ -1077,7 +1049,7 @@ QDF_STATUS policy_mgr_next_actions(
 						     HW_MODE_DBS,
 						     HW_MODE_AGILE_DFS_NONE,
 						     HW_MODE_SBS_NONE,
-						     reason, PM_NOP);
+						     reason, PM_NOP, PM_DBS);
 		break;
 	case PM_SINGLE_MAC_UPGRADE:
 		/*
@@ -1091,7 +1063,8 @@ QDF_STATUS policy_mgr_next_actions(
 						HW_MODE_DBS_NONE,
 						HW_MODE_AGILE_DFS_NONE,
 						HW_MODE_SBS_NONE,
-						reason, PM_UPGRADE);
+						reason, PM_UPGRADE,
+						PM_SINGLE_MAC_UPGRADE);
 		break;
 	case PM_SINGLE_MAC:
 		status = policy_mgr_pdev_set_hw_mode(psoc, session_id,
@@ -1102,7 +1075,7 @@ QDF_STATUS policy_mgr_next_actions(
 						HW_MODE_DBS_NONE,
 						HW_MODE_AGILE_DFS_NONE,
 						HW_MODE_SBS_NONE,
-						reason, PM_NOP);
+						reason, PM_NOP, PM_SINGLE_MAC);
 		break;
 	case PM_DBS_UPGRADE:
 		status = policy_mgr_pdev_set_hw_mode(psoc, session_id,
@@ -1113,7 +1086,8 @@ QDF_STATUS policy_mgr_next_actions(
 						HW_MODE_DBS,
 						HW_MODE_AGILE_DFS_NONE,
 						HW_MODE_SBS_NONE,
-						reason, PM_UPGRADE);
+						reason, PM_UPGRADE,
+						PM_DBS_UPGRADE);
 		break;
 	case PM_SBS_DOWNGRADE:
 		status = policy_mgr_complete_action(psoc, POLICY_MGR_RX_NSS_1,
@@ -1128,7 +1102,7 @@ QDF_STATUS policy_mgr_next_actions(
 						HW_MODE_DBS,
 						HW_MODE_AGILE_DFS_NONE,
 						HW_MODE_SBS,
-						reason, PM_NOP);
+						reason, PM_NOP, PM_SBS);
 		break;
 	case PM_DOWNGRADE:
 		/*
@@ -1178,7 +1152,7 @@ QDF_STATUS policy_mgr_next_actions(
 					HW_MODE_DBS,
 					HW_MODE_AGILE_DFS_NONE,
 					HW_MODE_SBS_NONE,
-					reason, next_action);
+					reason, next_action, PM_DBS1);
 		break;
 	case PM_DBS2:
 		/*
@@ -1200,7 +1174,7 @@ QDF_STATUS policy_mgr_next_actions(
 						HW_MODE_DBS,
 						HW_MODE_AGILE_DFS_NONE,
 						HW_MODE_SBS_NONE,
-						reason, next_action);
+						reason, next_action, PM_DBS2);
 		break;
 	case PM_UPGRADE_5G:
 		status = policy_mgr_nss_update(
@@ -2483,10 +2457,15 @@ void policy_mgr_checkn_update_hw_mode_single_mac_mode(
 		return;
 	}
 
-	if (QDF_TIMER_STATE_RUNNING ==
-		pm_ctx->dbs_opportunistic_timer.state)
+	if (QDF_TIMER_STATE_RUNNING == pm_ctx->dbs_opportunistic_timer.state)
 		qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer);
 
+	if (policy_mgr_is_hw_dbs_required_for_band(psoc, HW_MODE_MAC_BAND_2G) &&
+	    (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq))) {
+		policy_mgr_debug("DBS required for new connection");
+		return;
+	}
+
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
 		if (pm_conc_connection_list[i].in_use) {
@@ -2498,9 +2477,8 @@ void policy_mgr_checkn_update_hw_mode_single_mac_mode(
 			}
 			if (policy_mgr_is_hw_dbs_required_for_band(
 					psoc, HW_MODE_MAC_BAND_2G) &&
-			    (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq) ||
 			    WLAN_REG_IS_24GHZ_CH_FREQ(
-					pm_conc_connection_list[i].freq))) {
+					pm_conc_connection_list[i].freq)) {
 				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 				policy_mgr_debug("DBS required");
 				return;

+ 8 - 6
components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020 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
@@ -924,7 +924,7 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status,
 
 	if (status != SET_HW_MODE_STATUS_OK) {
 		policy_mgr_err("Set HW mode failed with status %d", status);
-		goto set_done_event;
+		goto next_action;
 	}
 
 	/* vdev mac map for NAN Discovery is expected in NAN Enable resp */
@@ -966,20 +966,22 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status,
 	if (pm_ctx->mode_change_cb)
 		pm_ctx->mode_change_cb();
 
-	ret = policy_mgr_set_connection_update(context);
-	if (!QDF_IS_STATUS_SUCCESS(ret))
-		policy_mgr_err("ERROR: set connection_update_done event failed");
 	/* Notify tdls */
 	if (pm_ctx->tdls_cbacks.tdls_notify_decrement_session)
 		pm_ctx->tdls_cbacks.tdls_notify_decrement_session(pm_ctx->psoc);
 
-	if (PM_NOP != next_action)
+next_action:
+	if (PM_NOP != next_action && (status == SET_HW_MODE_STATUS_ALREADY ||
+	    status == SET_HW_MODE_STATUS_OK))
 		policy_mgr_next_actions(context, session_id,
 			next_action, reason);
 	else
 		policy_mgr_debug("No action needed right now");
 
 set_done_event:
+	ret = policy_mgr_set_connection_update(context);
+	if (!QDF_IS_STATUS_SUCCESS(ret))
+		policy_mgr_err("ERROR: set connection_update_done event failed");
 	ret = policy_mgr_set_opportunistic_update(context);
 	if (!QDF_IS_STATUS_SUCCESS(ret))
 		policy_mgr_err("ERROR: set opportunistic_update event failed");

+ 8 - 2
core/hdd/src/wlan_hdd_wext.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2020 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
@@ -7509,6 +7509,7 @@ hdd_policy_mgr_set_hw_mode_ut(struct hdd_context *hdd_ctx,
 	enum hw_mode_bandwidth mac1_bw;
 	enum hw_mode_mac_band_cap mac0_band_cap;
 	enum hw_mode_dbs_capab dbs;
+	enum policy_mgr_conc_next_action action;
 
 	switch (cmd) {
 	case 0:
@@ -7519,6 +7520,7 @@ hdd_policy_mgr_set_hw_mode_ut(struct hdd_context *hdd_ctx,
 		mac1_bw = HW_MODE_BW_NONE;
 		mac0_band_cap = HW_MODE_MAC_BAND_NONE;
 		dbs = HW_MODE_DBS_NONE;
+		action = PM_SINGLE_MAC;
 		break;
 	case 1:
 		hdd_debug("set hw mode for dual mac");
@@ -7528,6 +7530,7 @@ hdd_policy_mgr_set_hw_mode_ut(struct hdd_context *hdd_ctx,
 		mac1_bw = HW_MODE_40_MHZ;
 		mac0_band_cap = HW_MODE_MAC_BAND_NONE;
 		dbs = HW_MODE_DBS;
+		action = PM_DBS;
 		break;
 	case 2:
 		hdd_debug("set hw mode for 2x2 5g + 1x1 2g");
@@ -7537,6 +7540,7 @@ hdd_policy_mgr_set_hw_mode_ut(struct hdd_context *hdd_ctx,
 		mac1_bw = HW_MODE_40_MHZ;
 		mac0_band_cap = HW_MODE_MAC_BAND_5G;
 		dbs = HW_MODE_DBS;
+		action = PM_DBS1;
 		break;
 	case 3:
 		hdd_debug("set hw mode for 2x2 2g + 1x1 5g");
@@ -7546,6 +7550,7 @@ hdd_policy_mgr_set_hw_mode_ut(struct hdd_context *hdd_ctx,
 		mac1_bw = HW_MODE_40_MHZ;
 		mac0_band_cap = HW_MODE_MAC_BAND_2G;
 		dbs = HW_MODE_DBS;
+		action = PM_DBS2;
 		break;
 	default:
 		hdd_err("unknown cmd %d", cmd);
@@ -7555,7 +7560,8 @@ hdd_policy_mgr_set_hw_mode_ut(struct hdd_context *hdd_ctx,
 				    mac0_ss, mac0_bw, mac1_ss, mac1_bw,
 				    mac0_band_cap, dbs, HW_MODE_AGILE_DFS_NONE,
 				    HW_MODE_SBS_NONE,
-				    POLICY_MGR_UPDATE_REASON_UT, PM_NOP);
+				    POLICY_MGR_UPDATE_REASON_UT, PM_NOP,
+				    action);
 }
 
 static int iw_get_policy_manager_ut_ops(struct hdd_context *hdd_ctx,

+ 4 - 2
core/sme/src/common/sme_api.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020 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
@@ -199,7 +199,8 @@ static QDF_STATUS sme_process_set_hw_mode_resp(struct mac_context *mac, uint8_t
 		 * needs to be handled after the response of set hw
 		 * mode
 		 */
-		if (param->status == SET_HW_MODE_STATUS_OK) {
+		if (param->status == SET_HW_MODE_STATUS_OK ||
+		    param->status == SET_HW_MODE_STATUS_ALREADY) {
 			sme_debug("search for ssid success");
 			csr_scan_handle_search_for_ssid(mac,
 					session_id);
@@ -12332,6 +12333,7 @@ QDF_STATUS sme_pdev_set_hw_mode(struct policy_mgr_hw_mode msg)
 	cmd->u.set_hw_mode_cmd.reason = msg.reason;
 	cmd->u.set_hw_mode_cmd.session_id = msg.session_id;
 	cmd->u.set_hw_mode_cmd.next_action = msg.next_action;
+	cmd->u.set_hw_mode_cmd.action = msg.action;
 	cmd->u.set_hw_mode_cmd.context = msg.context;
 
 	sme_debug("Queuing set hw mode to CSR, session: %d reason: %d",

+ 14 - 1
core/sme/src/csr/csr_api_roam.c

@@ -21223,6 +21223,9 @@ void csr_process_set_hw_mode(struct mac_context *mac, tSmeCmd *command)
 	struct scheduler_msg msg = {0};
 	struct sir_set_hw_mode_resp *param;
 	enum policy_mgr_hw_mode_change hw_mode;
+	enum policy_mgr_conc_next_action action;
+	enum set_hw_mode_status hw_mode_change_status =
+						SET_HW_MODE_STATUS_ECANCELED;
 
 	/* Setting HW mode is for the entire system.
 	 * So, no need to check session
@@ -21241,6 +21244,7 @@ void csr_process_set_hw_mode(struct mac_context *mac, tSmeCmd *command)
 		 */
 		goto fail;
 
+	action = command->u.set_hw_mode_cmd.action;
 	/* For hidden SSID case, if there is any scan command pending
 	 * it needs to be cleared before issuing set HW mode
 	 */
@@ -21255,6 +21259,15 @@ void csr_process_set_hw_mode(struct mac_context *mac, tSmeCmd *command)
 		}
 	}
 
+	status = policy_mgr_validate_dbs_switch(mac->psoc, action);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		sme_err("Hw mode change not sent to FW status = %d", status);
+		if (status == QDF_STATUS_E_ALREADY)
+			hw_mode_change_status = SET_HW_MODE_STATUS_ALREADY;
+		goto fail;
+	}
+
 	hw_mode = policy_mgr_get_hw_mode_change_from_hw_mode_index(
 			mac->psoc, command->u.set_hw_mode_cmd.hw_mode_index);
 
@@ -21315,7 +21328,7 @@ fail:
 		return;
 
 	sme_err("Sending set HW fail response to SME");
-	param->status = SET_HW_MODE_STATUS_ECANCELED;
+	param->status = hw_mode_change_status;
 	param->cfgd_hw_mode_index = 0;
 	param->num_vdev_mac_entries = 0;
 	msg.type = eWNI_SME_SET_HW_MODE_RESP;