diff --git a/umac/regulatory/core/src/reg_priv.h b/umac/regulatory/core/src/reg_priv.h index db870d19c8ea..16bbfa4525e0 100644 --- a/umac/regulatory/core/src/reg_priv.h +++ b/umac/regulatory/core/src/reg_priv.h @@ -57,6 +57,18 @@ #define reg_nofl_debug(params...) \ QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_REGULATORY, params) +/** + * struct wlan_regulatory_psoc_priv_obj - wlan regulatory psoc private object + * @new_user_ctry_pending: In this array, element[phy_id] is true if any user + * country update is pending for pdev (phy_id), used in case of MCL. + * @new_init_ctry_pending: In this array, element[phy_id] is true if any user + * country update is pending for pdev (phy_id), used in case of WIN. + * @new_11d_ctry_pending: In this array, element[phy_id] is true if any 11d + * country update is pending for pdev (phy_id). + * @world_country_pending: In this array, element[phy_id] is true if any world + * country update is pending for pdev (phy_id). + * @def_pdev_id: Default pdev id, used in case of MCL + */ struct wlan_regulatory_psoc_priv_obj { struct mas_chan_params mas_chan_params[PSOC_MAX_PHY_REG_CAP]; bool offload_enabled; @@ -67,9 +79,10 @@ struct wlan_regulatory_psoc_priv_obj { uint16_t def_region_domain; enum country_src cc_src; struct wlan_objmgr_psoc *psoc_ptr; - bool new_user_ctry_pending; - bool new_11d_ctry_pending; - bool world_country_pending; + bool new_user_ctry_pending[PSOC_MAX_PHY_REG_CAP]; + bool new_init_ctry_pending[PSOC_MAX_PHY_REG_CAP]; + bool new_11d_ctry_pending[PSOC_MAX_PHY_REG_CAP]; + bool world_country_pending[PSOC_MAX_PHY_REG_CAP]; bool dfs_enabled; enum band_info band_capability; bool indoor_chan_enabled; @@ -100,6 +113,7 @@ struct wlan_regulatory_psoc_priv_obj { bool force_ssc_disable_indoor_channel; bool enable_srd_chan_in_master_mode; bool enable_11d_in_world_mode; + int8_t def_pdev_id; qdf_spinlock_t cbk_list_lock; }; diff --git a/umac/regulatory/core/src/reg_services.c b/umac/regulatory/core/src/reg_services.c index 15f2f3602448..afc0ad0853ac 100644 --- a/umac/regulatory/core/src/reg_services.c +++ b/umac/regulatory/core/src/reg_services.c @@ -1439,6 +1439,7 @@ QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev, struct set_country country_code; struct wlan_objmgr_psoc *psoc; struct cc_regdmn_s rd; + uint8_t pdev_id; if (!pdev) { reg_err("pdev is NULL"); @@ -1450,6 +1451,8 @@ QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_E_INVAL; } + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + psoc = wlan_pdev_get_psoc(pdev); psoc_reg = reg_get_psoc_obj(psoc); @@ -1468,12 +1471,12 @@ QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev, qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1); - country_code.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + country_code.pdev_id = pdev_id; if (reg_is_world_alpha2(country)) - psoc_reg->world_country_pending = true; + psoc_reg->world_country_pending[pdev_id] = true; else - psoc_reg->new_user_ctry_pending = true; + psoc_reg->new_user_ctry_pending[pdev_id] = true; if (psoc_reg->offload_enabled) { tx_ops = reg_get_psoc_tx_ops(psoc); @@ -1481,7 +1484,7 @@ QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev, tx_ops->set_country_code(psoc, &country_code); } else { reg_err("country set fw handler not present"); - psoc_reg->new_user_ctry_pending = false; + psoc_reg->new_user_ctry_pending[pdev_id] = false; return QDF_STATUS_E_FAULT; } } else { @@ -1489,6 +1492,8 @@ QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev, pdev_priv_obj = reg_get_pdev_obj(pdev); if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { reg_err("reg component pdev priv is NULL"); + psoc_reg->new_user_ctry_pending[pdev_id] = + false; return QDF_STATUS_E_INVAL; } if (reg_is_world_ctry_code( @@ -1519,12 +1524,15 @@ QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev, struct cc_regdmn_s rd; QDF_STATUS status; struct wlan_lmac_if_reg_tx_ops *tx_ops; + uint8_t pdev_id; if (!country) { reg_err("country code is NULL"); return QDF_STATUS_E_INVAL; } + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + psoc = wlan_pdev_get_psoc(pdev); psoc_reg = reg_get_psoc_obj(psoc); if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) { @@ -1543,9 +1551,9 @@ QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev, qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1); - country_code.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + country_code.pdev_id = pdev_id; - psoc_reg->new_11d_ctry_pending = true; + psoc_reg->new_11d_ctry_pending[pdev_id] = true; if (psoc_reg->offload_enabled) { tx_ops = reg_get_psoc_tx_ops(psoc); @@ -1553,7 +1561,7 @@ QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev, tx_ops->set_country_code(psoc, &country_code); } else { reg_err("country set fw handler not present"); - psoc_reg->new_11d_ctry_pending = false; + psoc_reg->new_11d_ctry_pending[pdev_id] = false; return QDF_STATUS_E_FAULT; } status = QDF_STATUS_SUCCESS; @@ -3038,6 +3046,125 @@ static void reg_run_11d_state_machine(struct wlan_objmgr_psoc *psoc) } } +void reg_reset_ctry_pending_hints(struct wlan_regulatory_psoc_priv_obj + *soc_reg) +{ + uint8_t ctr; + + if (!soc_reg->offload_enabled) + return; + + for (ctr = 0; ctr < PSOC_MAX_PHY_REG_CAP; ctr++) { + soc_reg->new_user_ctry_pending[ctr] = false; + soc_reg->new_init_ctry_pending[ctr] = false; + soc_reg->new_11d_ctry_pending[ctr] = false; + soc_reg->world_country_pending[ctr] = false; + } +} + +/** + * reg_set_curr_country() - Set current country update + * @soc_reg: regulatory private object + * @regulat_info: regulatory info from firmware + * @tx_ops: send operations for regulatory component + * + * During SSR or restart of wlan modules after interface change timer phase, + * this function is used to send the recent user/11d country code to firmware. + * + * Return: QDF_STATUS_SUCCESS if correct country is configured + * else return failure + * error code. + */ +static QDF_STATUS reg_set_curr_country( + struct wlan_regulatory_psoc_priv_obj *soc_reg, + struct cur_regulatory_info *regulat_info, + struct wlan_lmac_if_reg_tx_ops *tx_ops) +{ + struct wlan_objmgr_psoc *psoc = regulat_info->psoc; + uint8_t pdev_id; + struct set_country country_code; + QDF_STATUS status; + + /* + * During SSR/WLAN restart ignore master channel list + * for all events and in the last event handling if + * current country and default country is different, send the last + * configured (soc_reg->cur_country) country. + */ + if ((regulat_info->num_phy != regulat_info->phy_id + 1) || + (!qdf_mem_cmp(soc_reg->cur_country, regulat_info->alpha2, + REG_ALPHA2_LEN))) + return QDF_STATUS_SUCCESS; + + pdev_id = soc_reg->def_pdev_id; + if (soc_reg->cc_src == SOURCE_USERSPACE) + soc_reg->new_user_ctry_pending[pdev_id] = true; + else if (soc_reg->cc_src == SOURCE_11D) + soc_reg->new_11d_ctry_pending[pdev_id] = true; + else + soc_reg->world_country_pending[pdev_id] = true; + + qdf_mem_zero(&country_code, sizeof(country_code)); + qdf_mem_copy(country_code.country, soc_reg->cur_country, + sizeof(soc_reg->cur_country)); + country_code.pdev_id = pdev_id; + + if (!tx_ops || !tx_ops->set_country_code) { + reg_err("No regulatory tx_ops for set_country_code"); + status = QDF_STATUS_E_FAULT; + goto error; + } + + status = tx_ops->set_country_code(psoc, &country_code); + if (QDF_IS_STATUS_ERROR(status)) { + reg_err("Failed to send country code to firmware"); + goto error; + } + + reg_debug("Target CC: %.2s, Restore to Previous CC: %.2s", + regulat_info->alpha2, soc_reg->cur_country); + + return status; + +error: + reg_reset_ctry_pending_hints(soc_reg); + + return status; +} + +/** + * reg_ignore_default_country() - Ignore default country update + * @soc_reg: regulatory private object + * @regulat_info: regulatory info from firmware + * + * During SSR or restart of wlan modules after interface change timer phase, + * this function is used to ignore default country code from firmware. + * + * Return: If default country needs to be ignored return true else false. + */ +static bool +reg_ignore_default_country(struct wlan_regulatory_psoc_priv_obj *soc_reg, + struct cur_regulatory_info *regulat_info) +{ + uint8_t pdev_id; + + if (!soc_reg->offload_enabled) + return false; + + if (soc_reg->cc_src == SOURCE_UNKNOWN) + return false; + + pdev_id = regulat_info->phy_id; + + if (soc_reg->new_user_ctry_pending[pdev_id] || + soc_reg->new_init_ctry_pending[pdev_id] || + soc_reg->new_11d_ctry_pending[pdev_id] || + soc_reg->world_country_pending[pdev_id]) + return false; + + return true; +} + QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info *regulat_info) { @@ -3054,7 +3181,7 @@ QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info struct wlan_objmgr_pdev *pdev; struct wlan_lmac_if_reg_tx_ops *tx_ops; struct reg_rule_info *reg_rules; - struct set_country country_code; + QDF_STATUS status; psoc = regulat_info->psoc; soc_reg = reg_get_psoc_obj(psoc); @@ -3065,30 +3192,19 @@ QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info } tx_ops = reg_get_psoc_tx_ops(psoc); + phy_id = regulat_info->phy_id; - if (qdf_is_recovering()) { - if (soc_reg->offload_enabled && - qdf_mem_cmp(soc_reg->cur_country, - regulat_info->alpha2, - REG_ALPHA2_LEN)) { - reg_debug("target cc:%.2s, restore %.2s to target", - regulat_info->alpha2, - soc_reg->cur_country); - qdf_mem_copy(country_code.country, - soc_reg->cur_country, - REG_ALPHA2_LEN + 1); - country_code.pdev_id = regulat_info->phy_id; - if (tx_ops && tx_ops->set_country_code) - tx_ops->set_country_code(psoc, &country_code); + if (reg_ignore_default_country(soc_reg, regulat_info)) { + status = reg_set_curr_country(soc_reg, regulat_info, tx_ops); + if (QDF_IS_STATUS_SUCCESS(status)) { + reg_debug("WLAN restart - Ignore default CC for phy_id: %u", + phy_id); + return QDF_STATUS_SUCCESS; } - reg_debug("ignore chan list update in ssr"); - return QDF_STATUS_SUCCESS; } reg_debug("process reg master chan list"); - phy_id = regulat_info->phy_id; - if (soc_reg->offload_enabled) { dbg_id = WLAN_REGULATORY_NB_ID; dir = NORTHBOUND; @@ -3203,24 +3319,29 @@ QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info reg_rule_5g, num_5g_reg_rules, min_bw_5g, mas_chan_list); - if (soc_reg->new_user_ctry_pending == true) { - soc_reg->new_user_ctry_pending = false; + if (soc_reg->new_user_ctry_pending[phy_id]) { + soc_reg->new_user_ctry_pending[phy_id] = false; soc_reg->cc_src = SOURCE_USERSPACE; soc_reg->user_ctry_set = true; - reg_debug("new country code is set"); + reg_debug("new user country is set"); reg_run_11d_state_machine(psoc); - } else if (soc_reg->new_11d_ctry_pending == true) { - soc_reg->new_11d_ctry_pending = false; + } else if (soc_reg->new_init_ctry_pending[phy_id]) { + soc_reg->new_init_ctry_pending[phy_id] = false; + soc_reg->cc_src = SOURCE_USERSPACE; + reg_debug("new init country is set"); + } else if (soc_reg->new_11d_ctry_pending[phy_id]) { + soc_reg->new_11d_ctry_pending[phy_id] = false; soc_reg->cc_src = SOURCE_11D; soc_reg->user_ctry_set = false; reg_run_11d_state_machine(psoc); - } else if (soc_reg->world_country_pending == true) { - soc_reg->world_country_pending = false; + } else if (soc_reg->world_country_pending[phy_id]) { + soc_reg->world_country_pending[phy_id] = false; soc_reg->cc_src = SOURCE_CORE; soc_reg->user_ctry_set = false; reg_run_11d_state_machine(psoc); } else { - if (soc_reg->cc_src == SOURCE_UNKNOWN) + if (soc_reg->cc_src == SOURCE_UNKNOWN && + soc_reg->num_phy == phy_id + 1) soc_reg->cc_src = SOURCE_DRIVER; qdf_mem_copy(soc_reg->mas_chan_params[phy_id].default_country, @@ -3240,11 +3361,11 @@ QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info soc_reg->def_country_code = regulat_info->ctry_code; soc_reg->def_region_domain = regulat_info->reg_dmn_pair; - } - if (reg_is_world_alpha2(regulat_info->alpha2)) { - soc_reg->cc_src = SOURCE_CORE; - reg_run_11d_state_machine(psoc); + if (reg_is_world_alpha2(regulat_info->alpha2)) { + soc_reg->cc_src = SOURCE_CORE; + reg_run_11d_state_machine(psoc); + } } } @@ -3296,6 +3417,7 @@ QDF_STATUS wlan_regulatory_psoc_obj_created_notification( soc_reg_obj->restart_beaconing = CH_AVOID_RULE_RESTART; soc_reg_obj->enable_srd_chan_in_master_mode = false; soc_reg_obj->enable_11d_in_world_mode = false; + soc_reg_obj->def_pdev_id = -1; for (i = 0; i < MAX_STA_VDEV_CNT; i++) soc_reg_obj->vdev_ids_11d[i] = INVALID_VDEV_ID; @@ -3690,6 +3812,11 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification( return QDF_STATUS_E_FAULT; } + if (psoc_priv_obj->def_pdev_id == -1) + psoc_priv_obj->def_pdev_id = pdev_id; + else + reg_err("reg cannot handle more than one pdev"); + pdev_priv_obj->pdev_ptr = pdev; pdev_priv_obj->dfs_enabled = psoc_priv_obj->dfs_enabled; pdev_priv_obj->set_fcc_channel = false; @@ -4431,8 +4558,10 @@ QDF_STATUS reg_program_chan_list(struct wlan_objmgr_pdev *pdev, pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); tx_ops = reg_get_psoc_tx_ops(psoc); - if (tx_ops->set_user_country_code) + if (tx_ops->set_user_country_code) { + soc_reg->new_init_ctry_pending[pdev_id] = true; return tx_ops->set_user_country_code(psoc, pdev_id, rd); + } return QDF_STATUS_E_FAILURE; } @@ -4721,6 +4850,7 @@ QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc, uint8_t *country) { struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; + uint8_t pdev_id; psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_REGULATORY); @@ -4731,7 +4861,8 @@ QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_E_FAILURE; } - psoc_priv_obj->new_11d_ctry_pending = true; + pdev_id = psoc_priv_obj->def_pdev_id; + psoc_priv_obj->new_11d_ctry_pending[pdev_id] = true; return QDF_STATUS_SUCCESS; } diff --git a/umac/regulatory/core/src/reg_services.h b/umac/regulatory/core/src/reg_services.h index 3e3c6c5a2ac0..81705df81335 100644 --- a/umac/regulatory/core/src/reg_services.h +++ b/umac/regulatory/core/src/reg_services.h @@ -554,6 +554,15 @@ QDF_STATUS reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev); struct wlan_regulatory_psoc_priv_obj *reg_get_psoc_obj( struct wlan_objmgr_psoc *psoc); +/** + * reg_reset_ctry_pending_hints() - Reset all country pending hints + * @soc_reg: regulatory private object + * + * Return: None + */ +void +reg_reset_ctry_pending_hints(struct wlan_regulatory_psoc_priv_obj *soc_reg); + /** * reg_set_regdb_offloaded() - set/clear regulatory offloaded flag * diff --git a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c index fe39aeb9c0a1..2a23132837b0 100644 --- a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c +++ b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c @@ -423,6 +423,18 @@ QDF_STATUS regulatory_pdev_open(struct wlan_objmgr_pdev *pdev) QDF_STATUS regulatory_pdev_close(struct wlan_objmgr_pdev *pdev) { + struct wlan_objmgr_psoc *psoc; + struct wlan_regulatory_psoc_priv_obj *soc_reg; + + psoc = wlan_pdev_get_psoc(pdev); + soc_reg = reg_get_psoc_obj(psoc); + if (!soc_reg) { + reg_err("reg psoc private obj is NULL"); + return QDF_STATUS_E_FAULT; + } + + reg_reset_ctry_pending_hints(soc_reg); + return QDF_STATUS_SUCCESS; } diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 0a0e9cc5d621..042c7c0bdba7 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1722,6 +1722,19 @@ QDF_STATUS (*send_set_country_cmd)(wmi_unified_t wmi_handle, uint32_t (*convert_pdev_id_host_to_target)(uint32_t pdev_id); uint32_t (*convert_pdev_id_target_to_host)(uint32_t pdev_id); +/* + * For MCL, convert_pdev_id_host_to_target returns legacy pdev id value. + * But in converged firmware, WMI_SET_CURRENT_COUNTRY_CMDID expects target + * mapping of pdev_id to give only one WMI_REG_CHAN_LIST_CC_EVENTID. + * wmi_pdev_id_conversion_enable cannot be used since it overwrites + * convert_pdev_id_host_to_target which effects legacy cases. + * Below two commands: convert_host_pdev_id_to_target and + * convert_target_pdev_id_to_host should be used for any WMI + * command/event where FW expects target/host mapping of pdev_id respectively. + */ +uint32_t (*convert_host_pdev_id_to_target)(uint32_t pdev_id); +uint32_t (*convert_target_pdev_id_to_host)(uint32_t pdev_id); + QDF_STATUS (*send_user_country_code_cmd)(wmi_unified_t wmi_handle, uint8_t pdev_id, struct cc_regdmn_s *rd); diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 104c32cfd61a..8352c770aeba 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -9908,10 +9908,13 @@ static QDF_STATUS extract_reg_chan_list_update_event_tlv( reg_info->min_bw_5g = chan_list_event_hdr->min_bw_5g; reg_info->max_bw_5g = chan_list_event_hdr->max_bw_5g; - WMI_LOGD("%s:cc %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d", - __func__, reg_info->alpha2, reg_info->dfs_region, - reg_info->min_bw_2g, reg_info->max_bw_2g, - reg_info->min_bw_5g, reg_info->max_bw_5g); + WMI_LOGD(FL("num_phys = %u and phy_id = %u"), + reg_info->num_phy, reg_info->phy_id); + + WMI_LOGD("%s:cc %s dfs %d BW: min_2g %d max_2g %d min_5g %d max_5g %d", + __func__, reg_info->alpha2, reg_info->dfs_region, + reg_info->min_bw_2g, reg_info->max_bw_2g, + reg_info->min_bw_5g, reg_info->max_bw_5g); WMI_LOGD("%s: num_2g_reg_rules %d num_5g_reg_rules %d", __func__, num_2g_reg_rules, num_5g_reg_rules); @@ -10323,6 +10326,7 @@ static QDF_STATUS send_set_country_cmd_tlv(wmi_unified_t wmi_handle, QDF_STATUS qdf_status; wmi_set_current_country_cmd_fixed_param *cmd; uint16_t len = sizeof(*cmd); + uint8_t pdev_id = params->pdev_id; buf = wmi_buf_alloc(wmi_handle, len); if (!buf) { @@ -10337,12 +10341,12 @@ static QDF_STATUS send_set_country_cmd_tlv(wmi_unified_t wmi_handle, WMITLV_GET_STRUCT_TLVLEN (wmi_set_current_country_cmd_fixed_param)); - WMI_LOGD("setting cuurnet country to %s", params->country); + cmd->pdev_id = wmi_handle->ops->convert_host_pdev_id_to_target(pdev_id); + WMI_LOGD("setting current country to %s and target pdev_id = %u", + params->country, cmd->pdev_id); qdf_mem_copy((uint8_t *)&cmd->new_alpha2, params->country, 3); - cmd->pdev_id = params->pdev_id; - wmi_mtrace(WMI_SET_CURRENT_COUNTRY_CMDID, NO_SESSION, 0); qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_SET_CURRENT_COUNTRY_CMDID); @@ -11391,6 +11395,11 @@ struct wmi_ops tlv_ops = { .convert_pdev_id_target_to_host = convert_target_pdev_id_to_host_pdev_id_legacy, + .convert_host_pdev_id_to_target = + convert_host_pdev_id_to_target_pdev_id, + .convert_target_pdev_id_to_host = + convert_target_pdev_id_to_host_pdev_id, + .send_start_11d_scan_cmd = send_start_11d_scan_cmd_tlv, .send_stop_11d_scan_cmd = send_stop_11d_scan_cmd_tlv, .extract_reg_11d_new_country_event =