Przeglądaj źródła

qcacld-3.0: Update connected VDEV channel bandwidth

Host receives QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH vendor
command indication to update STA adapter channel width.

On receiving channel width update indication from upper layer,
first host updates internally and send new channel width value
to FW via WMI_VDEV_PARAM_CHWIDTH_WITH_NOTIFY.

Target firmware should take care of notifying associated peers
(except TDLS) about change in bandwidth, through OMN/OMI
notification before performing bandwidth update internally.

Change-Id: I517ed1fbf8d074e511f8fb43c9c1dac824c9f084
CRs-Fixed: 3469473
abhinav kumar 2 lat temu
rodzic
commit
80fc700acf

+ 16 - 0
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -1071,6 +1071,22 @@ enum phy_ch_width wlan_mlme_convert_vht_op_bw_to_phy_ch_width(
 void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev,
 					struct scan_event *event, void *arg);
 
+/**
+ * wlan_mlme_send_ch_width_update_with_notify() - update connected VDEV
+ * channel bandwidth
+ * @psoc: pointer to psoc object
+ * @vdev: pointer to vdev object
+ * @vdev_id: vdev id
+ * @ch_width: channel width to update
+ *
+ * Return: none
+ */
+QDF_STATUS
+wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
+					   struct wlan_objmgr_vdev *vdev,
+					   uint8_t vdev_id,
+					   enum phy_ch_width ch_width);
+
 #ifdef WLAN_FEATURE_11BE
 /**
  * mlme_update_tgt_eht_caps_in_cfg() - Update tgt eht cap in mlme component

+ 24 - 0
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -4589,6 +4589,30 @@ QDF_STATUS
 ucfg_mlme_set_vdev_traffic_low_latency(struct wlan_objmgr_psoc *psoc,
 				       uint8_t vdev_id, bool set);
 
+/**
+ * ucfg_mlme_send_ch_width_update_with_notify() - Send chwidth with notify
+ * capability of FW
+ * @psoc: pointer to psoc object
+ * @vdev_id: Vdev id
+ * @ch_width: channel width to update
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id,
+					   enum phy_ch_width ch_width);
+
+/**
+ * ucfg_mlme_is_chwidth_with_notify_supported() - Get chwidth with notify
+ * capability of FW
+ * @psoc: pointer to psoc object
+ *
+ * Return: true if chwidth with notify feature supported
+ */
+bool
+ucfg_mlme_is_chwidth_with_notify_supported(struct wlan_objmgr_psoc *psoc);
+
 /**
  * ucfg_mlme_connected_chan_stats_request() - process connected channel stats
  * request

+ 116 - 0
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -35,6 +35,7 @@
 #include "wlan_psoc_mlme_api.h"
 #include "wlan_action_oui_main.h"
 #include "target_if.h"
+#include "wlan_vdev_mgr_tgt_if_tx_api.h"
 
 /* quota in milliseconds */
 #define MCC_DUTY_CYCLE 70
@@ -6682,6 +6683,121 @@ void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev,
 	mlme_send_scan_done_complete_cb(event->vdev_id);
 }
 
+static QDF_STATUS
+wlan_mlme_update_vdev_chwidth_with_notify(struct wlan_objmgr_psoc *psoc,
+					  struct wlan_objmgr_vdev *vdev,
+					  uint8_t vdev_id,
+					  enum phy_ch_width ch_width)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct vdev_set_params param = {0};
+	QDF_STATUS status;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme)
+		return QDF_STATUS_E_FAILURE;
+
+	param.param_id = wmi_vdev_param_chwidth_with_notify;
+	param.vdev_id = vdev_id;
+	param.param_value = ch_width;
+	status = tgt_vdev_mgr_set_param_send(vdev_mlme, &param);
+	policy_mgr_handle_ml_sta_link_on_traffic_type_change(psoc, vdev);
+
+	return status;
+}
+
+static QDF_STATUS wlan_mlme_update_ch_width(struct wlan_objmgr_vdev *vdev,
+					    uint8_t vdev_id,
+					    enum phy_ch_width ch_width)
+{
+	struct wlan_channel *des_chan;
+	struct wlan_channel *bss_chan;
+	uint16_t curr_op_freq;
+	struct ch_params ch_params = {0};
+	struct wlan_objmgr_pdev *pdev;
+
+	des_chan = wlan_vdev_mlme_get_des_chan(vdev);
+	if (!des_chan)
+		return QDF_STATUS_E_FAILURE;
+
+	bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
+	if (!bss_chan)
+		return QDF_STATUS_E_FAILURE;
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		mlme_err("vdev %d: Pdev is NULL", vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	ch_params.ch_width = ch_width;
+	curr_op_freq = des_chan->ch_freq;
+
+	wlan_reg_set_channel_params_for_pwrmode(pdev, curr_op_freq,
+						0, &ch_params,
+						REG_CURRENT_PWR_MODE);
+
+	des_chan->ch_width = ch_width;
+	des_chan->ch_freq_seg1 = ch_params.center_freq_seg0;
+	des_chan->ch_freq_seg2 = ch_params.center_freq_seg1;
+	des_chan->ch_cfreq1 = ch_params.mhz_freq_seg0;
+	des_chan->ch_cfreq2 = ch_params.mhz_freq_seg1;
+
+	qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel));
+
+	mlme_legacy_debug("vdev id %d freq %d seg0 %d seg1 %d ch_width %d mhz seg0 %d mhz seg1 %d",
+			  vdev_id, curr_op_freq, ch_params.center_freq_seg0,
+			  ch_params.center_freq_seg1, ch_params.ch_width,
+			  ch_params.mhz_freq_seg0, ch_params.mhz_freq_seg1);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
+					   struct wlan_objmgr_vdev *vdev,
+					   uint8_t vdev_id,
+					   enum phy_ch_width ch_width)
+{
+	QDF_STATUS status;
+	enum phy_ch_width associated_ch_width;
+	struct wlan_channel *des_chan;
+
+	des_chan = wlan_vdev_mlme_get_des_chan(vdev);
+	if (!des_chan)
+		return QDF_STATUS_E_INVAL;
+
+	if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq)) {
+		mlme_debug("vdev %d: CW:%d update not supported for freq:%d",
+			   vdev_id, ch_width, des_chan->ch_freq);
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	associated_ch_width = wlan_cm_get_associated_ch_width(psoc, vdev_id);
+	if (ch_width > associated_ch_width) {
+		mlme_debug("vdev %d: Invalid new chwidth:%d, assoc ch_width:%d",
+			   vdev_id, ch_width, associated_ch_width);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* update ch width to internal host structure */
+	status = wlan_mlme_update_ch_width(vdev, vdev_id, ch_width);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("vdev %d: Failed to update CW:%d to host, status:%d",
+			 vdev_id, ch_width, status);
+		return status;
+	}
+
+	/* update ch width to fw */
+	status = wlan_mlme_update_vdev_chwidth_with_notify(psoc, vdev, vdev_id,
+							   ch_width);
+	if (QDF_IS_STATUS_ERROR(status))
+		mlme_err("vdev %d: Failed to update CW:%d to fw, status:%d",
+			 vdev_id, ch_width, status);
+
+	return status;
+}
+
 enum phy_ch_width wlan_mlme_convert_vht_op_bw_to_phy_ch_width(
 						uint8_t channel_width)
 {

+ 40 - 0
components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c

@@ -373,6 +373,46 @@ void ucfg_mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc,
 	mlme_connected_chan_stats_request(psoc, vdev_id);
 }
 
+bool
+ucfg_mlme_is_chwidth_with_notify_supported(struct wlan_objmgr_psoc *psoc)
+{
+	return wlan_psoc_nif_fw_ext2_cap_get(psoc,
+				WLAN_VDEV_PARAM_CHWIDTH_WITH_NOTIFY_SUPPORT);
+}
+
+QDF_STATUS
+ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id,
+					   enum phy_ch_width ch_width)
+{
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+	enum QDF_OPMODE mode;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_OBJMGR_ID);
+	if (!vdev) {
+		mlme_legacy_err("vdev %d: vdev not found", vdev_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_STA_MODE) {
+		mlme_legacy_debug("vdev %d: mode %d, CW update not supported",
+				  vdev_id, mode);
+		status = QDF_STATUS_E_NOSUPPORT;
+		goto release;
+	}
+
+	status = wlan_mlme_send_ch_width_update_with_notify(psoc, vdev,
+							    vdev_id, ch_width);
+
+release:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+
+	return status;
+}
+
 QDF_STATUS
 ucfg_mlme_set_vdev_traffic_low_latency(struct wlan_objmgr_psoc *psoc,
 				       uint8_t vdev_id, bool set)

+ 53 - 0
core/hdd/src/wlan_hdd_cfg.c

@@ -52,6 +52,7 @@
 #include <wma_api.h>
 #include "wlan_hdd_object_manager.h"
 #include "wlan_dp_ucfg_api.h"
+#include "wlan_cmn.h"
 
 #ifndef WLAN_MAC_ADDR_UPDATE_DISABLE
 /**
@@ -2151,6 +2152,45 @@ int hdd_set_rx_stbc(struct hdd_adapter *adapter, int value)
 	return ret;
 }
 
+/**
+ * hdd_convert_chwidth_to_phy_chwidth() - convert channel width of type enum
+ * eSirMacHTChannelWidth to enum phy_ch_width
+ * @chwidth: channel width of type enum eSirMacHTChannelWidth
+ *
+ * Return: channel width of type enum phy_ch_width
+ */
+static enum phy_ch_width
+hdd_convert_chwidth_to_phy_chwidth(enum eSirMacHTChannelWidth chwidth)
+{
+	enum phy_ch_width ch_width = CH_WIDTH_INVALID;
+
+	switch (chwidth) {
+	case eHT_CHANNEL_WIDTH_20MHZ:
+		ch_width = CH_WIDTH_20MHZ;
+		break;
+	case eHT_CHANNEL_WIDTH_40MHZ:
+		ch_width = CH_WIDTH_40MHZ;
+		break;
+	case eHT_CHANNEL_WIDTH_80MHZ:
+		ch_width = CH_WIDTH_80MHZ;
+		break;
+	case eHT_CHANNEL_WIDTH_160MHZ:
+		ch_width = CH_WIDTH_160MHZ;
+		break;
+	case eHT_CHANNEL_WIDTH_80P80MHZ:
+		ch_width = CH_WIDTH_80P80MHZ;
+		break;
+	case eHT_CHANNEL_WIDTH_320MHZ:
+		ch_width = CH_WIDTH_320MHZ;
+		break;
+	default:
+		hdd_debug("Invalid channel width %d", chwidth);
+		break;
+	}
+
+	return ch_width;
+}
+
 int hdd_update_channel_width(struct hdd_adapter *adapter,
 			     enum eSirMacHTChannelWidth chwidth,
 			     uint32_t bonding_mode)
@@ -2158,6 +2198,8 @@ int hdd_update_channel_width(struct hdd_adapter *adapter,
 	struct hdd_context *hdd_ctx;
 	struct sme_config_params *sme_config;
 	int ret;
+	enum phy_ch_width ch_width;
+	QDF_STATUS status;
 
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	if (!hdd_ctx) {
@@ -2165,6 +2207,17 @@ int hdd_update_channel_width(struct hdd_adapter *adapter,
 		return -EINVAL;
 	}
 
+	if (ucfg_mlme_is_chwidth_with_notify_supported(hdd_ctx->psoc)) {
+		ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth);
+		hdd_debug("vdev %d : process update ch width request to %d",
+			  adapter->deflink->vdev_id, ch_width);
+		status =
+		    ucfg_mlme_send_ch_width_update_with_notify(hdd_ctx->psoc,
+					adapter->deflink->vdev_id, ch_width);
+		if (QDF_IS_STATUS_ERROR(status))
+			return -EIO;
+	}
+
 	sme_config = qdf_mem_malloc(sizeof(*sme_config));
 	if (!sme_config)
 		return -ENOMEM;