diff --git a/target_if/core/inc/target_if.h b/target_if/core/inc/target_if.h index a03135d8b0..bfe0a94c16 100644 --- a/target_if/core/inc/target_if.h +++ b/target_if/core/inc/target_if.h @@ -140,6 +140,17 @@ struct comp_hdls { struct common_dbglog_handle *dbglog_hdl; }; +/** + * struct target_supported_modes - List of HW modes supported by target. + * + * @num_modes: Number of modes supported + * @hw_mode_ids: List of HW mode ids + */ +struct target_supported_modes { + uint8_t num_modes; + uint32_t hw_mode_ids[WMI_HOST_HW_MODE_MAX]; +}; + /** * struct tgt_info - FW or lower layer related info(required by target_if), * it is a sub structure of taarget psoc information @@ -162,6 +173,7 @@ struct comp_hdls { * @mac_phy_cap: phy caps array * @reg_cap: regulatory caps array * @num_mem_chunks: number of mem chunks allocated + * @hw_mode_caps: HW mode caps of preferred mode * @mem_chunks: allocated memory blocks for FW */ struct tgt_info { @@ -186,6 +198,8 @@ struct tgt_info { struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap; uint32_t num_mem_chunks; struct wmi_host_mem_chunk mem_chunks[MAX_MEM_CHUNKS]; + struct wlan_psoc_host_hw_mode_caps hw_mode_cap; + struct target_supported_modes hw_modes; }; /** @@ -672,6 +686,23 @@ static inline uint32_t target_psoc_get_preferred_hw_mode return psoc_info->info.preferred_hw_mode; } +/** + * target_psoc_get_supported_hw_modes() - get supported_hw_mode in target + * @psoc_info: pointer to structure target_psoc_info + * + * API to get list of supported HW modes + * + * Return: pointer to target_supported_modes + */ +static inline struct target_supported_modes *target_psoc_get_supported_hw_modes + (struct target_psoc_info *psoc_info) +{ + if (!psoc_info) + return NULL; + + return &psoc_info->info.hw_modes; +} + /** * target_psoc_set_wmi_timeout() - set wmi_timeout * @psoc_info: pointer to structure target_psoc_info diff --git a/target_if/init_deinit/src/init_event_handler.c b/target_if/init_deinit/src/init_event_handler.c index 65dec28a85..b8db17926f 100644 --- a/target_if/init_deinit/src/init_event_handler.c +++ b/target_if/init_deinit/src/init_event_handler.c @@ -222,8 +222,26 @@ static int init_deinit_service_ext_ready_event_handler(ol_scn_t scn_handle, goto exit; if (init_deinit_is_preferred_hw_mode_supported(psoc, tgt_hdl) - == FALSE) + == FALSE) { + target_if_err("Preferred mode %d not supported", + info->preferred_hw_mode); return -EINVAL; + } + + if (info->preferred_hw_mode != WMI_HOST_HW_MODE_MAX) { + struct wlan_psoc_host_hw_mode_caps *hw_cap = &info->hw_mode_cap; + /* prune info mac_phy cap to preferred/selected mode caps */ + info->total_mac_phy_cnt = 0; + err_code = init_deinit_populate_mac_phy_capability(wmi_handle, + event, + hw_cap, + info); + if (err_code) + goto exit; + + info->num_radios = info->total_mac_phy_cnt; + target_if_debug("num radios is %d\n", info->num_radios); + } target_if_print_service_ready_ext_param(psoc, tgt_hdl); diff --git a/target_if/init_deinit/src/service_ready_util.c b/target_if/init_deinit/src/service_ready_util.c index 60182d69bf..6daa243c7a 100644 --- a/target_if/init_deinit/src/service_ready_util.c +++ b/target_if/init_deinit/src/service_ready_util.c @@ -218,6 +218,76 @@ static int get_sar_version(void *handle, uint8_t *evt, return 0; } +static bool new_hw_mode_preferred(uint32_t current_hw_mode, + uint32_t new_hw_mode) +{ + uint8_t hw_mode_id_precedence[WMI_HOST_HW_MODE_MAX + 1] = { 5, 1, 4, + 3, 0, 2, + 6 }; + + if (current_hw_mode > WMI_HOST_HW_MODE_MAX || + new_hw_mode > WMI_HOST_HW_MODE_MAX) + return false; + + /* Above precedence is defined by low to high, lower the value + * higher the precedence + */ + if (hw_mode_id_precedence[current_hw_mode] > + hw_mode_id_precedence[new_hw_mode]) + return true; + + return false; +} + +/** + * select_preferred_mode() - Select preferred hw mode based on current mode. + * @tgt_hdl: target_psoc_info object + * @hw_mode_caps: HW mode caps of new mode id that needs to checked for + * selection. + * @current_mode: Current mode. + * + * API to select preferred hw mode based on the current config. + * Based on host config for preferred mode, final mode selected as follows- + * 1) If preferred_mode == WMI_HOST_HW_MODE_DETECT, Then select mode from FW + * supported modes such that it is a super set of all modes FW advertises. + * For e.g., If FW supports DBS(2 radio) and DBS_SBS(3 radio)- Choose DBS_SBS + * 2) If preferred_mode == WMI_HOST_HW_MODE_MAX, Then do not select any mode + * from FW advertised modes. Host needs to maintain all modes supported in FW + * and can switch dynamically. + * 3) Else, A valid preferred_mode is set, Hence check if this is part of FW + * supported modes. If it is found, then use it to bring up the device. + * + * Return: selected_mode based on the above criteria. + */ +static uint32_t +select_preferred_hw_mode(struct target_psoc_info *tgt_hdl, + struct wlan_psoc_host_hw_mode_caps *hw_mode_caps, + uint32_t current_mode) +{ + uint32_t preferred_mode, selected_mode = current_mode; + struct tgt_info *info; + + info = &tgt_hdl->info; + preferred_mode = target_psoc_get_preferred_hw_mode(tgt_hdl); + if (preferred_mode == WMI_HOST_HW_MODE_DETECT) { + uint32_t new_mode = hw_mode_caps->hw_mode_id; + + /* Choose hw_mode_id based on precedence */ + if (new_hw_mode_preferred(selected_mode, new_mode)) { + selected_mode = new_mode; + qdf_mem_copy(&info->hw_mode_cap, hw_mode_caps, + sizeof(info->hw_mode_cap)); + } + } else if ((preferred_mode != WMI_HOST_HW_MODE_MAX) && + (preferred_mode == hw_mode_caps->hw_mode_id)) { + selected_mode = preferred_mode; + qdf_mem_copy(&info->hw_mode_cap, hw_mode_caps, + sizeof(info->hw_mode_cap)); + } + + return selected_mode; +} + int init_deinit_populate_hw_mode_capability(void *wmi_handle, uint8_t *event, struct target_psoc_info *tgt_hdl) { @@ -225,7 +295,7 @@ int init_deinit_populate_hw_mode_capability(void *wmi_handle, uint8_t hw_idx; uint32_t num_hw_modes; struct wlan_psoc_host_hw_mode_caps hw_mode_caps[PSOC_MAX_HW_MODE]; - uint32_t preferred_mode; + uint32_t preferred_mode, selected_mode = WMI_HOST_HW_MODE_MAX; struct tgt_info *info; info = &tgt_hdl->info; @@ -237,6 +307,8 @@ int init_deinit_populate_hw_mode_capability(void *wmi_handle, target_if_debug("num_hw_modes %d", num_hw_modes); qdf_mem_zero(&hw_mode_caps, sizeof(hw_mode_caps)); + info->hw_modes.num_modes = 0; + info->hw_mode_cap.hw_mode_id = WMI_HOST_HW_MODE_MAX; preferred_mode = target_psoc_get_preferred_hw_mode(tgt_hdl); for (hw_idx = 0; hw_idx < num_hw_modes; hw_idx++) { @@ -245,21 +317,28 @@ int init_deinit_populate_hw_mode_capability(void *wmi_handle, if (status) goto return_exit; - if ((preferred_mode != WMI_HOST_HW_MODE_MAX) && - (hw_mode_caps[hw_idx].hw_mode_id != preferred_mode)) - continue; + if (hw_idx < WMI_HOST_HW_MODE_MAX) { + info->hw_modes.hw_mode_ids[hw_idx] = + hw_mode_caps[hw_idx].hw_mode_id; + info->hw_modes.num_modes++; + } status = init_deinit_populate_mac_phy_capability(wmi_handle, event, &hw_mode_caps[hw_idx], info); if (status) goto return_exit; - if ((preferred_mode != WMI_HOST_HW_MODE_MAX) && - (hw_mode_caps[hw_idx].hw_mode_id == preferred_mode)) { - info->num_radios = info->total_mac_phy_cnt; - target_if_debug("num radios is %d\n", info->num_radios); - } + selected_mode = select_preferred_hw_mode(tgt_hdl, + &hw_mode_caps[hw_idx], + selected_mode); } + + if (preferred_mode == WMI_HOST_HW_MODE_DETECT) { + target_if_info("Preferred mode is not set, use mode id %d\n", + selected_mode); + target_psoc_set_preferred_hw_mode(tgt_hdl, selected_mode); + } + status = get_sar_version(wmi_handle, event, &info->service_ext_param); target_if_debug("sar version %d", info->service_ext_param.sar_version); diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 3d6072798c..2ec62aec85 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -6853,6 +6853,8 @@ enum wmi_userspace_log_level { * @WMI_HOST_HW_MODE_DBS_OR_SBS: Two PHY with one PHY capabale of both 2G and * 5G. It can support SBS (5G + 5G) OR DBS (5G + 2G). * @WMI_HOST_HW_MODE_MAX: Max hw_mode_id. Used to indicate invalid mode. + * @WMI_HOST_HW_MODE_DETECT: Mode id used by host to choose mode from target + * supported modes. */ enum wmi_host_hw_mode_config_type { WMI_HOST_HW_MODE_SINGLE = 0, @@ -6862,6 +6864,7 @@ enum wmi_host_hw_mode_config_type { WMI_HOST_HW_MODE_DBS_SBS = 4, WMI_HOST_HW_MODE_DBS_OR_SBS = 5, WMI_HOST_HW_MODE_MAX, + WMI_HOST_HW_MODE_DETECT, }; /*