qcacmn: Check HW mode before sending join request to lower layers

When STA's join req times out on current BSS, SME issues next BSS
internally without checking HW mode for new channel

For example, STA tries to connect SSID="abc",
BSSID="a1:a2:a3:a4:a5:a6", channel=36 and lets say it fails. It
should try few more times to same BSSID and after that it will try
next bss. Lets say next BSS it found has, SSID="abc",
BSSID="b1:b2:b3:b4:b5:b6", channel=1 then it needs to check whether
hardware mode change is required for channel=1. If driver fails in
checking hardware mode then following check will prevent the bad
situation.

CRs-Fixed: 2261129
Change-Id: Ie31ac5b8b90c6e63122148647ad333fccfbf9dbf
diff --git a/inc/wlan_policy_mgr_api.h b/inc/wlan_policy_mgr_api.h
index 0244b14..c58f818 100644
--- a/inc/wlan_policy_mgr_api.h
+++ b/inc/wlan_policy_mgr_api.h
@@ -2302,6 +2302,24 @@
  */
 void policy_mgr_trim_acs_channel_list(struct wlan_objmgr_psoc *psoc,
 		uint8_t *org_ch_list, uint8_t *org_ch_list_count);
+
+/**
+ * policy_mgr_is_hwmode_set_for_given_chnl() - to check for given channel
+ * if the hw mode is properly set.
+ * @psoc: pointer to psoc
+ * @channel: given channel
+ *
+ * If HW mode is properly set for given channel then it returns true else
+ * it returns false.
+ * For example, when 2x2 DBS is supported and if the first connection is
+ * coming up on 2G band then driver expects DBS HW mode to be set first
+ * before the connection can be established. Driver can call this API to
+ * find-out if HW mode is set properly.
+ *
+ * Return: true if HW mode is set properly else false
+ */
+bool policy_mgr_is_hwmode_set_for_given_chnl(struct wlan_objmgr_psoc *psoc,
+					     uint8_t channel);
 /*
  * policy_mgr_get_connection_info() - Get info of all active connections
  * @info: Pointer to connection info
diff --git a/src/wlan_policy_mgr_action.c b/src/wlan_policy_mgr_action.c
index 7657787..3f22044 100644
--- a/src/wlan_policy_mgr_action.c
+++ b/src/wlan_policy_mgr_action.c
@@ -415,6 +415,76 @@
 	return ret;
 }
 
+static bool policy_mgr_is_chnl_in_diff_band(struct wlan_objmgr_psoc *psoc,
+					    uint8_t channel)
+{
+	uint8_t i, pm_chnl;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	/*
+	 * check given channel against already existing connections'
+	 * channels. if they differ then channels are in different bands
+	 */
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
+		pm_chnl = pm_conc_connection_list[i].chan;
+		if (pm_conc_connection_list[i].in_use)
+			if (!WLAN_REG_IS_SAME_BAND_CHANNELS(channel, pm_chnl)) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				policy_mgr_debug("channel is in diff band");
+				return true;
+			}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return false;
+}
+
+bool policy_mgr_is_hwmode_set_for_given_chnl(struct wlan_objmgr_psoc *psoc,
+					     uint8_t channel)
+{
+	enum policy_mgr_band band;
+	bool is_hwmode_dbs, is_2x2_dbs;
+
+	if (policy_mgr_is_hw_dbs_capable(psoc) == false)
+		return true;
+
+	if (WLAN_REG_IS_24GHZ_CH(channel))
+		band = POLICY_MGR_BAND_24;
+	else
+		band = POLICY_MGR_BAND_5;
+
+	is_hwmode_dbs = policy_mgr_is_current_hwmode_dbs(psoc);
+	is_2x2_dbs = policy_mgr_is_hw_dbs_2x2_capable(psoc);
+	/*
+	 * If HW supports 2x2 chains in DBS HW mode and if DBS HW mode is not
+	 * yet set then this is the right time to block the connection.
+	 */
+	if ((band == POLICY_MGR_BAND_24) && is_2x2_dbs && !is_hwmode_dbs) {
+		policy_mgr_err("HW mode is not yet in DBS!!!!!");
+		return false;
+	}
+
+	/*
+	 * If HW supports 1x1 chains DBS HW mode and if first connection is
+	 * 2G or 5G band and if second connection is coming up in diffrent
+	 * band than the first connection and if current HW mode is not yet
+	 * set in DBS then this is the right time to block the connection.
+	 */
+	if (policy_mgr_is_chnl_in_diff_band(psoc, channel) && !is_hwmode_dbs) {
+		policy_mgr_err("Given channel & existing conn is diff band & HW mode is not yet in DBS !!!!");
+		return false;
+	}
+
+	return true;
+}
+
 QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
 		uint32_t session_id,
 		uint8_t channel,