diff --git a/components/mlme/dispatcher/inc/wlan_mlme_api.h b/components/mlme/dispatcher/inc/wlan_mlme_api.h index 4ef0c1eb11..7e77ed3e60 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_api.h +++ b/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 diff --git a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h index 5fef7ce955..ae85e9780e 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h +++ b/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 diff --git a/components/mlme/dispatcher/src/wlan_mlme_api.c b/components/mlme/dispatcher/src/wlan_mlme_api.c index c4023d2b23..1457c84510 100644 --- a/components/mlme/dispatcher/src/wlan_mlme_api.c +++ b/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, ¶m); + 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) { diff --git a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c b/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c index 200810f73f..07973655cd 100644 --- a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c +++ b/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) diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index da9246786d..83ee1bdca5 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -52,6 +52,7 @@ #include #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;