Browse Source

qcacld-3.0: Update offchannel freq and bw based on peer caps

Update offchannel frequency based on peer caps such as
1. If 6 GHz is supported then select the ini preferred 6 GHz channel
   frequency if peer also supports the same channel.
2. If 6 GHz is supported and peer doesn't support the ini preffered
   channel frequency then select the very first 6 GHz channel which
   peer supports as preffered offchannel.
3. If peer doesn't support 6 GHz, then select ini preffered 5 GHz
   off channel frequency, given that peer should also support it.
4. If peer doesn support 6 GHz and also doesn't support ini preferred
   5 GHz offcahnnel, then select the very first 5 GHz channel it
   supports.

Update preffered offchannel Bandwidth such as take minimum of peer
supported max bandwith which is extracted from supported opclass and
max Bw device supports.

Change-Id: I93412774f35280105b22d5ec44895572f9d7aeef
CRs-Fixed: 3266066
Utkarsh Bhatnagar 2 years ago
parent
commit
0d8b108c4a
1 changed files with 124 additions and 0 deletions
  1. 124 0
      components/tdls/core/src/wlan_tdls_peer.c

+ 124 - 0
components/tdls/core/src/wlan_tdls_peer.c

@@ -818,6 +818,128 @@ void tdls_set_peer_link_status(struct tdls_peer *peer,
 	}
 }
 
+static void
+tdls_fill_peer_pref_offchan_bw(struct tdls_peer *peer,
+			       uint16_t bw)
+{
+	if (bw < BW_160_MHZ)
+		peer->pref_off_chan_width &= ~(1 << BW_160_OFFSET_BIT);
+
+	if (bw < BW_80_MHZ)
+		peer->pref_off_chan_width &= ~(1 << BW_80_OFFSET_BIT);
+
+	if (bw < BW_40_MHZ)
+		peer->pref_off_chan_width &= ~(1 << BW_40_OFFSET_BIT);
+}
+
+static void tdls_update_off_chan_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
+					   struct tdls_soc_priv_obj *soc_obj,
+					   struct tdls_peer *peer)
+{
+	struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev_obj->vdev);
+	qdf_freq_t ini_pref_6g_freq, ini_pref_non6g_freq, peer_freq;
+	enum channel_enum peer_chan;
+	qdf_freq_t peer_5g_freq = 0, peer_6g_freq = 0;
+	bool is_6g_support = false;
+	bool peer_6g_supportd = false;
+	bool peer_5g_supportd = false;
+	uint8_t i;
+	uint16_t temp_bw, max_pref_width, peer_supportd_max_bw = 0;
+	uint8_t reg_bw_offset;
+
+	if (!pdev) {
+		tdls_err("pdev is NULL");
+		return;
+	}
+
+	/*
+	 * Update Pref Offcahnnel BW such that:
+	 * 1. If 6 GHz is supported then select the ini preferred 6 GHz channel
+	 *    frequency.
+	 * 2. If 6 GHz is supported and peer doesn't support the ini preffered
+	 *    channel frequency then select the very first 6 GHz channel which
+	 *    peer supports as prefferd offchannel.
+	 * 3. If peer doesn't support 6 GHz, then select ini preffered 5 GHz
+	 *    off channel frequency, given that peer should also support it
+	 * 4. If peer doesn support 6 GHz and also doesn't support ini preferred
+	 *    5 GHz offcahnnel, then select the very first 5 GHz channel it
+	 *    supports.
+	 */
+	ini_pref_6g_freq = soc_obj->tdls_configs.tdls_pre_off_chan_freq_6g;
+	ini_pref_non6g_freq = wlan_reg_legacy_chan_to_freq(pdev,
+				soc_obj->tdls_configs.tdls_pre_off_chan_num);
+
+	if (ini_pref_6g_freq == peer->pref_off_chan_freq)
+		is_6g_support = true;
+
+	for (i = 0; i < peer->supported_channels_len; i++) {
+		peer_freq = peer->supported_chan_freq[i];
+		peer_chan = wlan_reg_get_chan_enum_for_freq(peer_freq);
+
+		if (!wlan_reg_is_freq_idx_enabled(pdev, peer_chan,
+						  REG_CLI_DEF_VLP))
+			continue;
+
+		if (peer->pref_off_chan_freq == peer_freq)
+			break;
+
+		if (ini_pref_non6g_freq == peer_freq) {
+			peer_5g_supportd = true;
+			peer_5g_freq = ini_pref_non6g_freq;
+		}
+		if (!peer_5g_supportd &&
+		    wlan_reg_is_5ghz_ch_freq(peer_freq)) {
+			peer_5g_freq = peer_freq;
+			peer_5g_supportd = true;
+		}
+		if (!peer_6g_supportd &&
+		    wlan_reg_is_6ghz_chan_freq(peer_freq)) {
+			peer_6g_freq = peer_freq;
+			peer_6g_supportd = true;
+		}
+	}
+
+	if (peer->pref_off_chan_freq == peer->supported_chan_freq[i])
+		goto bw_check;
+
+	if (is_6g_support && peer_6g_freq)
+		peer->pref_off_chan_freq = peer_6g_freq;
+	else if (peer_5g_freq)
+		peer->pref_off_chan_freq = peer_5g_freq;
+	else
+		peer->pref_off_chan_freq = 0;
+
+bw_check:
+	max_pref_width = wlan_reg_get_max_chwidth(pdev,
+						  peer->pref_off_chan_freq);
+	for (i = 0; i < peer->supported_oper_classes_len; i++) {
+		temp_bw = wlan_reg_get_op_class_width(pdev,
+						peer->supported_oper_classes[i],
+						false);
+		if (temp_bw > peer_supportd_max_bw)
+			peer_supportd_max_bw = temp_bw;
+	}
+
+	peer_supportd_max_bw = (peer_supportd_max_bw > max_pref_width) ?
+				max_pref_width : peer_supportd_max_bw;
+	if (wlan_reg_is_6ghz_chan_freq(peer->pref_off_chan_freq) &&
+	    peer_supportd_max_bw < BW_160_MHZ)
+		tdls_fill_peer_pref_offchan_bw(peer, peer_supportd_max_bw);
+	else if (wlan_reg_is_5ghz_ch_freq(peer->pref_off_chan_freq) &&
+		 peer_supportd_max_bw < BW_80_MHZ)
+		tdls_fill_peer_pref_offchan_bw(peer, peer_supportd_max_bw);
+
+	if (wlan_reg_is_5ghz_ch_freq(peer->pref_off_chan_freq) &&
+	    CHECK_BIT(peer->pref_off_chan_width, BW_160_OFFSET_BIT))
+		peer->pref_off_chan_width &= ~(1 << BW_160_OFFSET_BIT);
+
+	peer->op_class_for_pref_off_chan =
+		tdls_get_opclass_from_bandwidth(
+				vdev_obj->vdev, peer->pref_off_chan_freq,
+				peer->pref_off_chan_width,
+				&reg_bw_offset);
+}
+
 void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
 			const uint8_t *macaddr,
 			struct tdls_update_peer_params  *req_info)
@@ -870,6 +992,8 @@ void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
 		req_info->supported_oper_classes_len;
 
 	curr_peer->qos = is_qos_wmm_sta;
+
+	tdls_update_off_chan_peer_caps(vdev_obj, soc_obj, curr_peer);
 }
 
 QDF_STATUS tdls_set_valid(struct tdls_vdev_priv_obj *vdev_obj,