diff --git a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h b/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h index 15901a98ce..b767cfb11f 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h +++ b/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h @@ -726,6 +726,16 @@ static inline QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg) } #endif +/** + * wlan_cm_get_associated_ch_width() - get associated channel width + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * Return: enum phy_ch_width + */ +enum phy_ch_width +wlan_cm_get_associated_ch_width(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + #ifdef WLAN_FEATURE_ROAM_OFFLOAD /** * wlan_cm_fw_roam_abort_req() - roam abort request handling diff --git a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h b/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h index 919f1221a8..10160172a8 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h +++ b/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h @@ -123,6 +123,12 @@ ucfg_cm_update_session_assoc_ie(struct wlan_objmgr_psoc *psoc, cm_update_session_assoc_ie(psoc, vdev_id, assoc_ie); } +static inline enum phy_ch_width +ucfg_cm_get_associated_ch_width(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return wlan_cm_get_associated_ch_width(psoc, vdev_id); +} + #ifdef WLAN_FEATURE_ROAM_OFFLOAD #ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER /** diff --git a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c index 9d860e7e95..7032f0128e 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c +++ b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c @@ -2118,6 +2118,32 @@ QDF_STATUS wlan_cm_update_fils_ft(struct wlan_objmgr_psoc *psoc, } #endif +enum phy_ch_width +wlan_cm_get_associated_ch_width(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + enum phy_ch_width ch_width = CH_WIDTH_INVALID; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + + if (!vdev) { + mlme_err("vdev%d: vdev object is NULL", vdev_id); + goto release; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + goto release; + + ch_width = mlme_priv->connect_info.ch_width_orig; + mlme_debug("vdev %d: associated_ch_width:%d", vdev_id, ch_width); +release: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return ch_width; +} + #ifdef WLAN_FEATURE_ROAM_OFFLOAD QDF_STATUS wlan_cm_update_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index c9e7031426..d0ae771f25 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -25508,6 +25508,81 @@ static int wlan_hdd_cfg80211_nan_change_conf(struct wiphy *wiphy, } #endif +/** + * wlan_hdd_fill_subband_scan_info - Fill subband channel info + * @hdd_ctx: hdd context + * @info: struct scan_chan_info + * @chan: scan channel info + * + * update channel info into HDD context on scan done + * + * Return: None. + */ +static void wlan_hdd_fill_subband_scan_info(struct hdd_context *hdd_ctx, + struct scan_chan_info *info, + struct scan_chan_info *chan) +{ + uint8_t idx, info_index, freq_info_num; + enum phy_ch_width ch_width; + const struct bonded_channel_freq *range = NULL; + uint32_t start_freq, end_freq; + + ch_width = ucfg_cm_get_associated_ch_width(hdd_ctx->psoc, + info->subband_info.vdev_id); + if (ch_width == CH_WIDTH_INVALID) { + hdd_debug("vdev %d: Invalid ch width", + info->subband_info.vdev_id); + return; + } + + if (ch_width == CH_WIDTH_20MHZ) { + start_freq = info->freq; + end_freq = info->freq; + } else { + range = wlan_reg_get_bonded_chan_entry(info->freq, ch_width, 0); + if (!range) { + hdd_err("vdev %d: bonded_chan_array is NULL for freq %d, ch_width %d", + info->subband_info.vdev_id, info->freq, + ch_width); + return; + } + start_freq = range->start_freq; + end_freq = range->end_freq; + } + + freq_info_num = info->subband_info.num_chan; + info_index = 0; + + hdd_debug("vdev %d: freq :%d bw %d, range [%d-%d], num_freq:%d", + info->subband_info.vdev_id, info->freq, ch_width, start_freq, + end_freq, freq_info_num); + + for (idx = 0; idx < SIR_MAX_NUM_CHANNELS; idx++) { + if (chan[idx].freq == 0) + continue; + + if (start_freq > end_freq || info_index >= freq_info_num || + info_index >= MAX_WIDE_BAND_SCAN_CHAN) + break; + + if (chan[idx].freq == start_freq) { + /*update channel info as per cca busy info */ + info->freq = start_freq; + info->rx_clear_count = + info->subband_info.cca_busy_subband_info[info_index]; + + hdd_update_chan_info(hdd_ctx, &chan[idx], info, + info->cmd_flag); + + hdd_debug("updated info for freq:%u rcc:%d at index:%d", + chan[idx].freq, chan[idx].rx_clear_count, + idx); + start_freq += BW_20_MHZ; + info_index++; + } + } +} + /** * wlan_hdd_chan_info_cb() - channel info callback * @info: struct scan_chan_info @@ -25532,6 +25607,12 @@ static void wlan_hdd_chan_info_cb(struct scan_chan_info *info) } chan = hdd_ctx->chan_info; + + if (info->subband_info.is_wide_band_scan) { + wlan_hdd_fill_subband_scan_info(hdd_ctx, info, chan); + return; + } + for (idx = 0; idx < SIR_MAX_NUM_CHANNELS; idx++) { if (chan[idx].freq == info->freq) { hdd_update_chan_info(hdd_ctx, &chan[idx], info, diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 345273aaac..6e6f79e68c 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -4349,6 +4349,24 @@ struct wow_pulse_mode { */ QDF_STATUS umac_send_mb_message_to_mac(void *msg); +/* Max supported bandwidth is 320Mhz, so max 16 subbands fo 20Mhz */ +#define MAX_WIDE_BAND_SCAN_CHAN 16 + +/** + * struct wide_band_scan_chan_info - wide band scan channel info + * @vdev_id: vdev id + * @num_chan: number of channels (for each subbands fo 20Mhz) + * @is_wide_band_scan: wide band scan or not + * @cca_busy_subband_info: CCA busy for each possible 20Mhz subbands + * of the wideband scan channel + */ +struct wide_band_scan_chan_info { + uint32_t vdev_id; + uint8_t num_chan; + bool is_wide_band_scan; + uint32_t cca_busy_subband_info[MAX_WIDE_BAND_SCAN_CHAN]; +}; + /** * struct scan_chan_info - channel info * @freq: radio frequence @@ -4358,6 +4376,8 @@ QDF_STATUS umac_send_mb_message_to_mac(void *msg); * @rx_clear_count: rx clear count * @tx_frame_count: TX frame count * @clock_freq: clock frequence MHZ + * @cca_busy_subband_info: CCA busy for each possible 20Mhz subbands + * of the wideband scan channel */ struct scan_chan_info { uint32_t freq; @@ -4367,6 +4387,7 @@ struct scan_chan_info { uint32_t rx_clear_count; uint32_t tx_frame_count; uint32_t clock_freq; + struct wide_band_scan_chan_info subband_info; }; /** diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index ca5cdf9e42..05a2b6cb20 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -5343,6 +5343,49 @@ wma_vdev_bcn_latency_event_handler(void *handle, } #endif +static void +wma_update_sacn_channel_info_buf(wmi_unified_t wmi_handle, + wmi_chan_info_event_fixed_param *event, + struct scan_chan_info *buf, + wmi_cca_busy_subband_info *cca_info, + uint32_t num_tlvs) +{ + uint32_t i; + bool is_cca_busy_info; + + buf->tx_frame_count = event->tx_frame_cnt; + buf->clock_freq = event->mac_clk_mhz; + buf->cmd_flag = event->cmd_flags; + buf->freq = event->freq; + buf->noise_floor = event->noise_floor; + buf->cycle_count = event->cycle_count; + buf->rx_clear_count = event->rx_clear_count; + + is_cca_busy_info = wmi_service_enabled(wmi_handle, + wmi_service_cca_busy_info_for_each_20mhz); + + if (!is_cca_busy_info || num_tlvs == 0) + return; + + wma_debug("is_cca_busy_info: %d, num_tlvs:%d", is_cca_busy_info, + num_tlvs); + + if (cca_info && num_tlvs > 0) { + buf->subband_info.num_chan = 0; + for (i = 0; i < num_tlvs && i < MAX_WIDE_BAND_SCAN_CHAN; i++) { + buf->subband_info.cca_busy_subband_info[i] = + cca_info->rx_clear_count; + wma_debug("cca_info->rx_clear_count:%d", + cca_info->rx_clear_count); + buf->subband_info.num_chan++; + cca_info++; + } + + buf->subband_info.is_wide_band_scan = true; + buf->subband_info.vdev_id = event->vdev_id; + } +} + int wma_chan_info_event_handler(void *handle, uint8_t *event_buf, uint32_t len) { @@ -5356,6 +5399,8 @@ int wma_chan_info_event_handler(void *handle, uint8_t *event_buf, struct wlan_objmgr_vdev *vdev; enum QDF_OPMODE mode; struct scheduler_msg sme_msg = {0}; + wmi_cca_busy_subband_info *cca_info = NULL; + uint32_t num_tlvs = 0; if (wma && wma->cds_context) mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); @@ -5374,18 +5419,6 @@ int wma_chan_info_event_handler(void *handle, uint8_t *event_buf, return -EINVAL; } - snr_monitor_enabled = wlan_scan_is_snr_monitor_enabled(mac->psoc); - if (snr_monitor_enabled && mac->chan_info_cb) { - buf.tx_frame_count = event->tx_frame_cnt; - buf.clock_freq = event->mac_clk_mhz; - buf.cmd_flag = event->cmd_flags; - buf.freq = event->freq; - buf.noise_floor = event->noise_floor; - buf.cycle_count = event->cycle_count; - buf.rx_clear_count = event->rx_clear_count; - mac->chan_info_cb(&buf); - } - /* Ignore the last channel event data whose command flag is set to 1. * It’s basically an event with empty data only to indicate scan event * completion. @@ -5393,6 +5426,15 @@ int wma_chan_info_event_handler(void *handle, uint8_t *event_buf, if (event->cmd_flags == WMI_CHAN_INFO_END_RESP) return 0; + snr_monitor_enabled = wlan_scan_is_snr_monitor_enabled(mac->psoc); + if (snr_monitor_enabled && mac->chan_info_cb) { + cca_info = param_buf->cca_busy_subband_info; + num_tlvs = param_buf->num_cca_busy_subband_info; + wma_update_sacn_channel_info_buf(wma->wmi_handle, event, + &buf, cca_info, num_tlvs); + mac->chan_info_cb(&buf); + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, event->vdev_id, WLAN_LEGACY_WMA_ID);