qcacmn: Get phymode from HE phy capability

WLAN phy mode is calculated from HE capability.

Change-Id: I217cf6609f526a761c183395fe67f67adc95c4af
CRs-Fixed: 2550362
diff --git a/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h b/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h
index 2db8c0e..b0bec37 100644
--- a/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h
+++ b/umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h
@@ -165,6 +165,15 @@
 /* 80 + 80 MHz Operating Channel  (revised signalling) */
 #define WLAN_VHTOP_CHWIDTH_REVSIG_80_80  1
 
+#define WLAN_HEOP_VHTOP_PRESENT_MASK       0x00004000  /* B14 */
+#define WLAN_HEOP_CO_LOCATED_BSS_MASK      0x00008000  /* B15 */
+#define WLAN_HEOP_6GHZ_INFO_PRESENT_MASK   0X00020000  /* B17 */
+
+#define WLAN_HE_6GHZ_CHWIDTH_20           0 /* 20MHz Oper Ch width */
+#define WLAN_HE_6GHZ_CHWIDTH_40           1 /* 40MHz Oper Ch width */
+#define WLAN_HE_6GHZ_CHWIDTH_80           2 /* 80MHz Oper Ch width */
+#define WLAN_HE_6GHZ_CHWIDTH_160_80_80    3 /* 160/80+80 MHz Oper Ch width */
+
 #define WLAN_RATE_VAL              0x7f
 
 #define WLAN_RV(v)     ((v) & WLAN_RATE_VAL)
@@ -186,6 +195,20 @@
 	((vhtop)->vht_op_ch_freq_seg2 != 0) && \
 	(abs((vhtop)->vht_op_ch_freq_seg2 - (vhtop)->vht_op_ch_freq_seg1) > 8))
 
+/* Check if channel width is HE160 in HE 6ghz params */
+#define WLAN_IS_HE160(he_6g_param) (((he_6g_param)->width == \
+	WLAN_HE_6GHZ_CHWIDTH_160_80_80) && \
+	((he_6g_param)->chan_freq_seg1 != 0) && \
+	(abs((he_6g_param)->chan_freq_seg1 - \
+	(he_6g_param)->chan_freq_seg0) == 8))
+
+/* Check if channel width is HE80p80 in HE 6ghz params */
+#define WLAN_IS_HE80_80(he_6g_param) (((he_6g_param)->width == \
+	WLAN_HE_6GHZ_CHWIDTH_160_80_80) && \
+	((he_6g_param)->chan_freq_seg1 != 0) && \
+	(abs((he_6g_param)->chan_freq_seg1 - \
+	(he_6g_param)->chan_freq_seg0) > 8))
+
 #define LE_READ_2(p) \
 	((uint16_t)\
 	((((const uint8_t *)(p))[0]) |\
@@ -949,6 +972,26 @@
 } qdf_packed;
 
 /**
+ * struct he_oper_6g_param: 6 Ghz params for HE
+ * @primary_channel: HE 6GHz Primary channel number
+ * @width: HE 6GHz BSS Channel Width
+ * @duplicate_beacon: HE 6GHz Duplicate beacon field
+ * @reserved: Reserved bits
+ * @chan_freq_seg0: HE 6GHz Channel Centre Frequency Segment 0
+ * @chan_freq_seg1: HE 6GHz Channel Centre Frequency Segment 1
+ * @minimum_rate: HE 6GHz Minimum Rate
+ */
+struct he_oper_6g_param {
+	uint8_t primary_channel;
+	uint8_t width:2,
+		duplicate_beacon:1,
+		reserved:5;
+	uint8_t chan_freq_seg0;
+	uint8_t chan_freq_seg1;
+	uint8_t minimum_rate;
+} qdf_packed;
+
+/**
  * struct wlan_country_ie: country IE
  * @ie: country IE
  * @len: IE len
diff --git a/umac/cmn_services/inc/wlan_cmn.h b/umac/cmn_services/inc/wlan_cmn.h
index e23330b..42e516d 100644
--- a/umac/cmn_services/inc/wlan_cmn.h
+++ b/umac/cmn_services/inc/wlan_cmn.h
@@ -422,6 +422,26 @@
 	((mode) == WLAN_PHYMODE_11AXG_HE40PLUS)  || \
 	((mode) == WLAN_PHYMODE_11AXG_HE40MINUS); })
 
+#define IS_WLAN_PHYMODE_HT(_mode) ({typeof(_mode) mode = (_mode); \
+	((mode) == WLAN_PHYMODE_11NA_HT20) || \
+	((mode) == WLAN_PHYMODE_11NG_HT20)     || \
+	((mode) == WLAN_PHYMODE_11NA_HT40)  || \
+	((mode) == WLAN_PHYMODE_11NG_HT40PLUS)  || \
+	((mode) == WLAN_PHYMODE_11NG_HT40MINUS)  || \
+	((mode) == WLAN_PHYMODE_11NG_HT40); })
+
+#define IS_WLAN_PHYMODE_VHT(_mode) ({typeof(_mode) mode = (_mode); \
+	((mode) == WLAN_PHYMODE_11AC_VHT20) || \
+	((mode) == WLAN_PHYMODE_11AC_VHT20_2G)     || \
+	((mode) == WLAN_PHYMODE_11AC_VHT40)  || \
+	((mode) == WLAN_PHYMODE_11AC_VHT40PLUS_2G)  || \
+	((mode) == WLAN_PHYMODE_11AC_VHT40MINUS_2G)  || \
+	((mode) == WLAN_PHYMODE_11AC_VHT40_2G)  || \
+	((mode) == WLAN_PHYMODE_11AC_VHT80)  || \
+	((mode) == WLAN_PHYMODE_11AC_VHT80_2G)  || \
+	((mode) == WLAN_PHYMODE_11AC_VHT160)  || \
+	((mode) == WLAN_PHYMODE_11AC_VHT80_80); })
+
 #define IS_WLAN_PHYMODE_HE(_mode) ({typeof(_mode) mode = (_mode); \
 	((mode) == WLAN_PHYMODE_11AXA_HE20) || \
 	((mode) == WLAN_PHYMODE_11AXG_HE20)     || \
diff --git a/umac/scan/core/src/wlan_scan_cache_db.c b/umac/scan/core/src/wlan_scan_cache_db.c
index f343343..bab81ed 100644
--- a/umac/scan/core/src/wlan_scan_cache_db.c
+++ b/umac/scan/core/src/wlan_scan_cache_db.c
@@ -832,7 +832,7 @@
 			continue;
 		}
 
-		scm_nofl_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %d  ssid:%.*s, rssi: %d snr = %d frequency %d pdev_id = %d",
+		scm_nofl_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %d  ssid:%.*s, rssi: %d snr = %d frequency %d phy_mode %d pdev_id = %d",
 			       (bcn->frm_type == MGMT_SUBTYPE_PROBE_RESP) ?
 			       "Probe Rsp" : "Beacon", scan_entry->bssid.bytes,
 			       scan_entry->tsf_delta, scan_entry->seq_num,
@@ -840,6 +840,7 @@
 			       scan_entry->rssi_raw,
 			       scan_entry->snr,
 			       scan_entry->channel.chan_freq,
+			       scan_entry->phy_mode,
 			       wlan_objmgr_pdev_get_pdev_id(pdev));
 
 		if (scan_obj->cb.update_beacon)
diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c
index cc5bb96..690c785 100644
--- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c
+++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c
@@ -180,6 +180,98 @@
 
 	return pureg;
 }
+
+#ifdef CONFIG_BAND_6GHZ
+static enum wlan_phymode
+util_scan_get_phymode_6g(struct scan_cache_entry *scan_params)
+{
+	uint8_t len;
+	struct he_oper_6g_param *he_6g_params;
+	uint32_t he_oper_params;
+	enum wlan_phymode phymode = WLAN_PHYMODE_11AXA_HE20;
+	uint8_t *he_ops;
+
+	he_ops = util_scan_entry_heop(scan_params);
+	if (!util_scan_entry_hecap(scan_params) || !he_ops)
+		return phymode;
+
+	len = he_ops[1];
+	he_ops += 2;
+
+	/* Length less than fixed params length */
+	if (len < 7)
+		return phymode;
+
+	/* element id extension */
+	he_ops++;
+	len--;
+
+	he_oper_params = LE_READ_4(he_ops);
+	if (!(he_oper_params & WLAN_HEOP_6GHZ_INFO_PRESENT_MASK))
+		return phymode;
+
+	/* fixed params */
+	he_ops += 6;
+	len -= 6;
+
+	if (!len)
+		return phymode;
+
+	/* vht oper params */
+	if (he_oper_params & WLAN_HEOP_VHTOP_PRESENT_MASK) {
+		if (len < 3)
+			return phymode;
+		he_ops += 3;
+		len -= 3;
+	}
+
+	if (!len)
+		return phymode;
+
+	if (he_oper_params & WLAN_HEOP_CO_LOCATED_BSS_MASK) {
+		he_ops += 1;
+		len -= 1;
+	}
+
+	if (len < sizeof(*he_6g_params))
+		return phymode;
+
+	he_6g_params = (struct he_oper_6g_param *)he_ops;
+
+	switch (he_6g_params->width) {
+	case WLAN_HE_6GHZ_CHWIDTH_20:
+		phymode = WLAN_PHYMODE_11AXA_HE20;
+		break;
+	case WLAN_HE_6GHZ_CHWIDTH_40:
+		phymode = WLAN_PHYMODE_11AXA_HE40;
+		break;
+	case WLAN_HE_6GHZ_CHWIDTH_80:
+		phymode = WLAN_PHYMODE_11AXA_HE80;
+		break;
+	case WLAN_HE_6GHZ_CHWIDTH_160_80_80:
+		if (WLAN_IS_HE80_80(he_6g_params))
+			phymode = WLAN_PHYMODE_11AXA_HE80_80;
+		else if (WLAN_IS_HE160(he_6g_params))
+			phymode = WLAN_PHYMODE_11AXA_HE160;
+		else
+			phymode = WLAN_PHYMODE_11AXA_HE80;
+		break;
+	default:
+		scm_err("Invalid he_6g_params width: %d", he_6g_params->width);
+		phymode = WLAN_PHYMODE_11AXA_HE20;
+		break;
+	}
+
+	return phymode;
+}
+#else
+static inline enum wlan_phymode
+util_scan_get_phymode_6g(struct scan_cache_entry *scan_params)
+{
+	return WLAN_PHYMODE_AUTO;
+}
+#endif
+
 static enum wlan_phymode
 util_scan_get_phymode_5g(struct scan_cache_entry *scan_params)
 {
@@ -202,6 +294,11 @@
 	if (htcap)
 		ht_cap = le16toh(htcap->hc_cap);
 
+	if (ht_cap & WLAN_HTCAP_C_CHWIDTH40)
+		phymode = WLAN_PHYMODE_11NA_HT40;
+	else
+		phymode = WLAN_PHYMODE_11NA_HT20;
+
 	if (util_scan_entry_vhtcap(scan_params) && vhtop) {
 		switch (vhtop->vht_op_chwidth) {
 		case WLAN_VHTOP_CHWIDTH_2040:
@@ -230,10 +327,34 @@
 			phymode = WLAN_PHYMODE_11AC_VHT20;
 			break;
 		}
-	} else if (ht_cap & WLAN_HTCAP_C_CHWIDTH40) {
-		phymode = WLAN_PHYMODE_11NA_HT40;
-	} else {
-		phymode = WLAN_PHYMODE_11NA_HT20;
+	}
+
+	if (!util_scan_entry_hecap(scan_params))
+		return phymode;
+
+	/* for 5Ghz Check for HE, only if VHT cap and HE cap are present */
+	if (!IS_WLAN_PHYMODE_VHT(phymode))
+		return phymode;
+
+	switch (phymode) {
+	case WLAN_PHYMODE_11AC_VHT20:
+		phymode = WLAN_PHYMODE_11AXA_HE20;
+		break;
+	case WLAN_PHYMODE_11AC_VHT40:
+		phymode = WLAN_PHYMODE_11AXA_HE40;
+		break;
+	case WLAN_PHYMODE_11AC_VHT80:
+		phymode = WLAN_PHYMODE_11AXA_HE80;
+		break;
+	case WLAN_PHYMODE_11AC_VHT160:
+		phymode = WLAN_PHYMODE_11AXA_HE160;
+		break;
+	case WLAN_PHYMODE_11AC_VHT80_80:
+		phymode = WLAN_PHYMODE_11AXA_HE80_80;
+		break;
+	default:
+		phymode = WLAN_PHYMODE_11AXA_HE20;
+		break;
 	}
 
 	return phymode;
@@ -283,6 +404,10 @@
 		}
 	}
 
+	/* Check for VHT only if HT cap is present */
+	if (!IS_WLAN_PHYMODE_HT(phymode))
+		return phymode;
+
 	if (util_scan_entry_vhtcap(scan_params) && vhtop) {
 		switch (vhtop->vht_op_chwidth) {
 		case WLAN_VHTOP_CHWIDTH_2040:
@@ -302,9 +427,32 @@
 		}
 	}
 
+	if (!util_scan_entry_hecap(scan_params))
+		return phymode;
+
+	if (phymode == WLAN_PHYMODE_11AC_VHT40PLUS_2G ||
+	    phymode == WLAN_PHYMODE_11NG_HT40PLUS)
+		phymode = WLAN_PHYMODE_11AXG_HE40PLUS;
+	else if (phymode == WLAN_PHYMODE_11AC_VHT40MINUS_2G ||
+		 phymode == WLAN_PHYMODE_11NG_HT40MINUS)
+		phymode = WLAN_PHYMODE_11AXG_HE40MINUS;
+	else
+		phymode = WLAN_PHYMODE_11AXG_HE20;
+
 	return phymode;
 }
 
+static enum wlan_phymode
+util_scan_get_phymode(struct scan_cache_entry *scan_params)
+{
+	if (WLAN_REG_IS_24GHZ_CH_FREQ(scan_params->channel.chan_freq))
+		return util_scan_get_phymode_2g(scan_params);
+	else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(scan_params->channel.chan_freq))
+		return util_scan_get_phymode_6g(scan_params);
+	else
+		return util_scan_get_phymode_5g(scan_params);
+}
+
 static QDF_STATUS
 util_scan_parse_chan_switch_wrapper_ie(struct scan_cache_entry *scan_params,
 	struct ie_header *sub_ie, qdf_size_t sub_ie_len)
@@ -1173,10 +1321,8 @@
 	}
 	qdf_mem_copy(&scan_entry->mbssid_info, mbssid_info,
 		     sizeof(scan_entry->mbssid_info));
-	if (WLAN_REG_IS_5GHZ_CH_FREQ(scan_entry->channel.chan_freq))
-		scan_entry->phy_mode = util_scan_get_phymode_5g(scan_entry);
-	else
-		scan_entry->phy_mode = util_scan_get_phymode_2g(scan_entry);
+
+	scan_entry->phy_mode = util_scan_get_phymode(scan_entry);
 
 	scan_entry->nss = util_scan_scm_calc_nss_supported_by_ap(scan_entry);
 	scm_fill_adaptive_11r_cap(scan_entry);