diff --git a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c index 379a04bd2349..8aed7d8c994f 100644 --- a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c +++ b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c @@ -76,11 +76,28 @@ QDF_STATUS policy_mgr_get_updated_scan_config( bool dbs_plus_agile_scan, bool single_mac_scan_with_dfs) { + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + *scan_config = pm_ctx->dual_mac_cfg.cur_scan_config; + + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, dbs_scan); + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(*scan_config, + dbs_plus_agile_scan); + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(*scan_config, + single_mac_scan_with_dfs); + + policy_mgr_debug("scan_config:%x ", *scan_config); return QDF_STATUS_SUCCESS; } /** - * policy_mgr_get_updated_fw_mode_config() - Get the updated fw mode configuration + * policy_mgr_get_updated_fw_mode_config() - Get the updated fw + * mode configuration * @fw_mode_config: Pointer containing the updated fw mode config * @dbs: 0 or 1 indicating if DBS needs to be enabled/disabled * @agile_dfs: 0 or 1 indicating if agile DFS needs to be enabled/disabled @@ -97,11 +114,25 @@ QDF_STATUS policy_mgr_get_updated_fw_mode_config( bool dbs, bool agile_dfs) { + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + *fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config; + + WMI_DBS_FW_MODE_CFG_DBS_SET(*fw_mode_config, dbs); + WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(*fw_mode_config, agile_dfs); + + policy_mgr_debug("fw_mode_config:%x ", *fw_mode_config); return QDF_STATUS_SUCCESS; } /** - * policy_mgr_is_dual_mac_disabled_in_ini() - Check if dual mac is disabled in INI + * policy_mgr_is_dual_mac_disabled_in_ini() - Check if dual mac + * is disabled in INI * * Checks if the dual mac feature is disabled in INI * @@ -110,7 +141,7 @@ QDF_STATUS policy_mgr_get_updated_fw_mode_config( bool policy_mgr_is_dual_mac_disabled_in_ini( struct wlan_objmgr_psoc *psoc) { - return false; + return wlan_objmgr_psoc_get_dual_mac_disable(psoc); } /** @@ -122,7 +153,22 @@ bool policy_mgr_is_dual_mac_disabled_in_ini( */ bool policy_mgr_get_dbs_config(struct wlan_objmgr_psoc *psoc) { - return false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t fw_mode_config; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config); } /** @@ -134,7 +180,22 @@ bool policy_mgr_get_dbs_config(struct wlan_objmgr_psoc *psoc) */ bool policy_mgr_get_agile_dfs_config(struct wlan_objmgr_psoc *psoc) { - return false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t fw_mode_config; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config); } /** @@ -146,11 +207,27 @@ bool policy_mgr_get_agile_dfs_config(struct wlan_objmgr_psoc *psoc) */ bool policy_mgr_get_dbs_scan_config(struct wlan_objmgr_psoc *psoc) { - return false; + uint32_t scan_config; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = pm_ctx->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config); } /** - * policy_mgr_get_tx_rx_ss_from_config() - Get Tx/Rx spatial stream from HW mode config + * policy_mgr_get_tx_rx_ss_from_config() - Get Tx/Rx spatial + * stream from HW mode config * @mac_ss: Config which indicates the HW mode as per 'hw_mode_ss_config' * @tx_ss: Contains the Tx spatial stream * @rx_ss: Contains the Rx spatial stream @@ -217,7 +294,75 @@ int8_t policy_mgr_get_matching_hw_mode_index( enum hw_mode_agile_dfs_capab dfs, enum hw_mode_sbs_capab sbs) { - return 0; + uint32_t i; + uint32_t t_mac0_tx_ss, t_mac0_rx_ss, t_mac0_bw; + uint32_t t_mac1_tx_ss, t_mac1_rx_ss, t_mac1_bw; + uint32_t dbs_mode, agile_dfs_mode, sbs_mode; + int8_t found = -EINVAL; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return found; + } + + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + t_mac0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac0_tx_ss != mac0_tx_ss) + continue; + + t_mac0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac0_rx_ss != mac0_rx_ss) + continue; + + t_mac0_bw = POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + /* + * Firmware advertises max bw capability as CBW 80+80 + * for single MAC. Thus CBW 20/40/80 should also be + * supported, if CBW 80+80 is supported. + */ + if (t_mac0_bw < mac0_bw) + continue; + + t_mac1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac1_tx_ss != mac1_tx_ss) + continue; + + t_mac1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac1_rx_ss != mac1_rx_ss) + continue; + + t_mac1_bw = POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac1_bw < mac1_bw) + continue; + + dbs_mode = POLICY_MGR_HW_MODE_DBS_MODE_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (dbs_mode != dbs) + continue; + + agile_dfs_mode = POLICY_MGR_HW_MODE_AGILE_DFS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (agile_dfs_mode != dfs) + continue; + + sbs_mode = POLICY_MGR_HW_MODE_SBS_MODE_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (sbs_mode != sbs) + continue; + + found = i; + policy_mgr_notice("hw_mode index %d found", i); + break; + } + return found; } /** @@ -245,7 +390,25 @@ int8_t policy_mgr_get_hw_mode_idx_from_dbs_hw_list( enum hw_mode_agile_dfs_capab dfs, enum hw_mode_sbs_capab sbs) { - return 0; + uint32_t mac0_tx_ss, mac0_rx_ss; + uint32_t mac1_tx_ss, mac1_rx_ss; + + policy_mgr_get_tx_rx_ss_from_config(mac0_ss, &mac0_tx_ss, &mac0_rx_ss); + policy_mgr_get_tx_rx_ss_from_config(mac1_ss, &mac1_tx_ss, &mac1_rx_ss); + + policy_mgr_notice("MAC0: TxSS=%d, RxSS=%d, BW=%d", + mac0_tx_ss, mac0_rx_ss, mac0_bw); + policy_mgr_notice("MAC1: TxSS=%d, RxSS=%d, BW=%d", + mac1_tx_ss, mac1_rx_ss, mac1_bw); + policy_mgr_notice("DBS=%d, Agile DFS=%d, SBS=%d", + dbs, dfs, sbs); + + return policy_mgr_get_matching_hw_mode_index(psoc, mac0_tx_ss, + mac0_rx_ss, + mac0_bw, + mac1_tx_ss, mac1_rx_ss, + mac1_bw, + dbs, dfs, sbs); } /** @@ -262,6 +425,37 @@ QDF_STATUS policy_mgr_get_hw_mode_from_idx( uint32_t idx, struct policy_mgr_hw_mode_params *hw_mode) { + uint32_t param; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (idx > pm_ctx->num_dbs_hw_modes) { + policy_mgr_err("Invalid index"); + return QDF_STATUS_E_FAILURE; + } + + if (!pm_ctx->num_dbs_hw_modes) { + policy_mgr_err("No dbs hw modes available"); + return QDF_STATUS_E_FAILURE; + } + + param = pm_ctx->hw_mode.hw_mode_list[idx]; + + hw_mode->mac0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(param); + hw_mode->mac0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(param); + hw_mode->mac0_bw = POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(param); + hw_mode->mac1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(param); + hw_mode->mac1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(param); + hw_mode->mac1_bw = POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(param); + hw_mode->dbs_cap = POLICY_MGR_HW_MODE_DBS_MODE_GET(param); + hw_mode->agile_dfs_cap = POLICY_MGR_HW_MODE_AGILE_DFS_GET(param); + hw_mode->sbs_cap = POLICY_MGR_HW_MODE_SBS_MODE_GET(param); + return QDF_STATUS_SUCCESS; } @@ -283,6 +477,17 @@ QDF_STATUS policy_mgr_get_old_and_new_hw_index( uint32_t *old_hw_mode_index, uint32_t *new_hw_mode_index) { + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + *old_hw_mode_index = pm_ctx->old_hw_mode_index; + *new_hw_mode_index = pm_ctx->new_hw_mode_index; + return QDF_STATUS_SUCCESS; } @@ -312,6 +517,32 @@ void policy_mgr_update_conc_list(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id, bool in_use) { + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (conn_index >= MAX_NUMBER_OF_CONC_CONNECTIONS) { + policy_mgr_err("Number of connections exceeded conn_index: %d", + conn_index); + return; + } + pm_conc_connection_list[conn_index].mode = mode; + pm_conc_connection_list[conn_index].chan = chan; + pm_conc_connection_list[conn_index].bw = bw; + pm_conc_connection_list[conn_index].mac = mac; + pm_conc_connection_list[conn_index].chain_mask = chain_mask; + pm_conc_connection_list[conn_index].original_nss = original_nss; + pm_conc_connection_list[conn_index].vdev_id = vdev_id; + pm_conc_connection_list[conn_index].in_use = in_use; + + policy_mgr_dump_connection_status_info(psoc); + if (pm_ctx->cdp_cbacks.cdp_update_mac_id) + pm_ctx->cdp_cbacks.cdp_update_mac_id(psoc, vdev_id, mac); + } /** @@ -329,6 +560,42 @@ void policy_mgr_store_and_del_conn_info(struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, struct policy_mgr_conc_connection_info *info) { + uint32_t conn_index = 0; + bool found = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (mode == pm_conc_connection_list[conn_index].mode) { + found = true; + break; + } + conn_index++; + } + + if (!found) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_err("Mode:%d not available in the conn info", mode); + return; + } + + /* Storing the STA entry which will be temporarily deleted */ + *info = pm_conc_connection_list[conn_index]; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* Deleting the STA entry */ + policy_mgr_decr_connection_count(psoc, info->vdev_id); + + policy_mgr_notice("Stored %d (%d), deleted STA entry with vdev id %d, index %d", + info->vdev_id, info->mode, info->vdev_id, conn_index); + + /* Caller should set the PCL and restore the STA entry in conn info */ } /** @@ -343,10 +610,33 @@ void policy_mgr_store_and_del_conn_info(struct wlan_objmgr_psoc *psoc, void policy_mgr_restore_deleted_conn_info(struct wlan_objmgr_psoc *psoc, struct policy_mgr_conc_connection_info *info) { + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + conn_index = policy_mgr_get_connection_count(psoc); + if (MAX_NUMBER_OF_CONC_CONNECTIONS <= conn_index) { + policy_mgr_err("Failed to restore the deleted information %d/%d", + conn_index, MAX_NUMBER_OF_CONC_CONNECTIONS); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + pm_conc_connection_list[conn_index] = *info; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + policy_mgr_notice("Restored the deleleted conn info, vdev:%d, index:%d", + info->vdev_id, conn_index); } /** - * policy_mgr_update_hw_mode_conn_info() - Update connection info based on HW mode + * policy_mgr_update_hw_mode_conn_info() - Update connection + * info based on HW mode * @num_vdev_mac_entries: Number of vdev-mac id entries that follow * @vdev_mac_map: Mapping of vdev-mac id * @hw_mode: HW mode @@ -360,6 +650,42 @@ void policy_mgr_update_hw_mode_conn_info(struct wlan_objmgr_psoc *psoc, struct policy_mgr_vdev_mac_map *vdev_mac_map, struct policy_mgr_hw_mode_params hw_mode) { + uint32_t i, conn_index, found; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < num_vdev_mac_entries; i++) { + conn_index = 0; + found = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_mac_map[i].vdev_id == + pm_conc_connection_list[conn_index].vdev_id) { + found = 1; + break; + } + conn_index++; + } + if (found) { + pm_conc_connection_list[conn_index].mac = + vdev_mac_map[i].mac_id; + policy_mgr_notice("vdev:%d, mac:%d", + pm_conc_connection_list[conn_index].vdev_id, + pm_conc_connection_list[conn_index].mac); + if (pm_ctx->cdp_cbacks.cdp_update_mac_id) + pm_ctx->cdp_cbacks.cdp_update_mac_id( + psoc, + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_dump_connection_status_info(psoc); } /** @@ -381,6 +707,278 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, struct policy_mgr_vdev_mac_map *vdev_mac_map, void *context) { + QDF_STATUS ret; + struct policy_mgr_hw_mode_params hw_mode; + uint32_t i; + + if (status != SET_HW_MODE_STATUS_OK) { + policy_mgr_err("Set HW mode failed with status %d", status); + return; + } + + if (!vdev_mac_map) { + policy_mgr_err("vdev_mac_map is NULL"); + return; + } + + policy_mgr_notice("cfgd_hw_mode_index=%d", cfgd_hw_mode_index); + + for (i = 0; i < num_vdev_mac_entries; i++) + policy_mgr_notice("vdev_id:%d mac_id:%d", + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + + ret = policy_mgr_get_hw_mode_from_idx(context, cfgd_hw_mode_index, + &hw_mode); + if (ret != QDF_STATUS_SUCCESS) { + policy_mgr_err("Get HW mode failed: %d", ret); + return; + } + + policy_mgr_notice("MAC0: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss, hw_mode.mac0_bw); + policy_mgr_notice("MAC1: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss, hw_mode.mac1_bw); + policy_mgr_notice("DBS:%d, Agile DFS:%d, SBS:%d", + hw_mode.dbs_cap, hw_mode.agile_dfs_cap, hw_mode.sbs_cap); + + /* update pm_conc_connection_list */ + policy_mgr_update_hw_mode_conn_info(context, num_vdev_mac_entries, + vdev_mac_map, + hw_mode); + + ret = policy_mgr_set_connection_update(context); + if (!QDF_IS_STATUS_SUCCESS(ret)) + policy_mgr_err("ERROR: set connection_update_done event failed"); + + return; +} + +/** + * policy_mgr_dump_current_concurrency_one_connection() - To dump the + * current concurrency info with one connection + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t policy_mgr_dump_current_concurrency_one_connection( + char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + enum policy_mgr_con_mode mode; + + mode = pm_conc_connection_list[0].mode; + + switch (mode) { + case PM_STA_MODE: + count = strlcat(cc_mode, "STA", + length); + break; + case PM_SAP_MODE: + count = strlcat(cc_mode, "SAP", + length); + break; + case PM_P2P_CLIENT_MODE: + count = strlcat(cc_mode, "P2P CLI", + length); + break; + case PM_P2P_GO_MODE: + count = strlcat(cc_mode, "P2P GO", + length); + break; + case PM_IBSS_MODE: + count = strlcat(cc_mode, "IBSS", + length); + break; + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + + return count; +} + +/** + * policy_mgr_dump_current_concurrency_two_connection() - To dump the + * current concurrency info with two connections + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t policy_mgr_dump_current_concurrency_two_connection( + char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + enum policy_mgr_con_mode mode; + + mode = pm_conc_connection_list[1].mode; + + switch (mode) { + case PM_STA_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+STA", + length); + break; + case PM_SAP_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case PM_P2P_CLIENT_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case PM_P2P_GO_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case PM_IBSS_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+IBSS", + length); + break; + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + + return count; +} + +/** + * policy_mgr_dump_current_concurrency_three_connection() - To dump the + * current concurrency info with three connections + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t policy_mgr_dump_current_concurrency_three_connection( + char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + enum policy_mgr_con_mode mode; + + mode = pm_conc_connection_list[2].mode; + + switch (mode) { + case PM_STA_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+STA", + length); + break; + case PM_SAP_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case PM_P2P_CLIENT_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case PM_P2P_GO_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case PM_IBSS_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+IBSS", + length); + break; + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + + return count; +} + +/** + * policy_mgr_dump_dbs_concurrency() - To dump the dbs concurrency + * combination + * @cc_mode: connection string + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void policy_mgr_dump_dbs_concurrency(struct wlan_objmgr_psoc *psoc, + char *cc_mode, uint32_t length) +{ + char buf[4] = {0}; + uint8_t mac = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + strlcat(cc_mode, " DBS", length); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (pm_conc_connection_list[0].mac == + pm_conc_connection_list[1].mac) { + if (pm_conc_connection_list[0].chan == + pm_conc_connection_list[1].chan) + strlcat(cc_mode, + " with SCC for 1st two connections on mac ", + length); + else + strlcat(cc_mode, + " with MCC for 1st two connections on mac ", + length); + mac = pm_conc_connection_list[0].mac; + } + if (pm_conc_connection_list[0].mac == pm_conc_connection_list[2].mac) { + if (pm_conc_connection_list[0].chan == + pm_conc_connection_list[2].chan) + strlcat(cc_mode, + " with SCC for 1st & 3rd connections on mac ", + length); + else + strlcat(cc_mode, + " with MCC for 1st & 3rd connections on mac ", + length); + mac = pm_conc_connection_list[0].mac; + } + if (pm_conc_connection_list[1].mac == pm_conc_connection_list[2].mac) { + if (pm_conc_connection_list[1].chan == + pm_conc_connection_list[2].chan) + strlcat(cc_mode, + " with SCC for 2nd & 3rd connections on mac ", + length); + else + strlcat(cc_mode, + " with MCC for 2nd & 3rd connections on mac ", + length); + mac = pm_conc_connection_list[1].mac; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + snprintf(buf, sizeof(buf), "%d ", mac); + strlcat(cc_mode, buf, length); } /** @@ -393,6 +991,72 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, */ void policy_mgr_dump_current_concurrency(struct wlan_objmgr_psoc *psoc) { + uint32_t num_connections = 0; + char cc_mode[POLICY_MGR_MAX_CON_STRING_LEN] = {0}; + uint32_t count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + num_connections = policy_mgr_get_connection_count(psoc); + + switch (num_connections) { + case 1: + policy_mgr_dump_current_concurrency_one_connection(cc_mode, + sizeof(cc_mode)); + policy_mgr_err("%s Standalone", cc_mode); + break; + case 2: + count = policy_mgr_dump_current_concurrency_two_connection( + cc_mode, sizeof(cc_mode)); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (pm_conc_connection_list[0].chan == + pm_conc_connection_list[1].chan) { + strlcat(cc_mode, " SCC", sizeof(cc_mode)); + } else if (pm_conc_connection_list[0].mac == + pm_conc_connection_list[1].mac) { + strlcat(cc_mode, " MCC", sizeof(cc_mode)); + } else + strlcat(cc_mode, " DBS", sizeof(cc_mode)); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_err("%s", cc_mode); + break; + case 3: + count = policy_mgr_dump_current_concurrency_three_connection( + cc_mode, sizeof(cc_mode)); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if ((pm_conc_connection_list[0].chan == + pm_conc_connection_list[1].chan) && + (pm_conc_connection_list[0].chan == + pm_conc_connection_list[2].chan)){ + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + strlcat(cc_mode, " SCC", + sizeof(cc_mode)); + } else if ((pm_conc_connection_list[0].mac == + pm_conc_connection_list[1].mac) + && (pm_conc_connection_list[0].mac == + pm_conc_connection_list[2].mac)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + strlcat(cc_mode, " MCC on single MAC", + sizeof(cc_mode)); + } else { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_dump_dbs_concurrency(psoc, cc_mode, + sizeof(cc_mode)); + } + policy_mgr_err("%s", cc_mode); + break; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + break; + } + + return; } /** @@ -408,6 +1072,55 @@ void policy_mgr_dump_current_concurrency(struct wlan_objmgr_psoc *psoc) void policy_mgr_pdev_set_pcl(struct wlan_objmgr_psoc *psoc, enum tQDF_ADAPTER_MODE mode) { + QDF_STATUS status; + enum policy_mgr_con_mode con_mode; + struct policy_mgr_pcl_list pcl; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + pcl.pcl_len = 0; + + switch (mode) { + case QDF_STA_MODE: + con_mode = PM_STA_MODE; + break; + case QDF_P2P_CLIENT_MODE: + con_mode = PM_P2P_CLIENT_MODE; + break; + case QDF_P2P_GO_MODE: + con_mode = PM_P2P_GO_MODE; + break; + case QDF_SAP_MODE: + con_mode = PM_SAP_MODE; + break; + case QDF_IBSS_MODE: + con_mode = PM_IBSS_MODE; + break; + default: + policy_mgr_err("Unable to set PCL to FW: %d", mode); + return; + } + + policy_mgr_debug("get pcl to set it to the FW"); + + status = policy_mgr_get_pcl(psoc, con_mode, + pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list)); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Unable to set PCL to FW, Get PCL failed"); + return; + } + + status = pm_ctx->sme_cbacks.sme_pdev_set_pcl(pcl); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Send soc set PCL to SME failed"); + else + policy_mgr_notice("Set PCL to FW for mode:%d", mode); } @@ -422,6 +1135,39 @@ void policy_mgr_pdev_set_pcl(struct wlan_objmgr_psoc *psoc, void policy_mgr_set_pcl_for_existing_combo( struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode) { + struct policy_mgr_conc_connection_info info; + enum tQDF_ADAPTER_MODE pcl_mode; + + switch (mode) { + case PM_STA_MODE: + pcl_mode = QDF_STA_MODE; + break; + case PM_SAP_MODE: + pcl_mode = QDF_SAP_MODE; + break; + case PM_P2P_CLIENT_MODE: + pcl_mode = QDF_P2P_CLIENT_MODE; + break; + case PM_P2P_GO_MODE: + pcl_mode = QDF_P2P_GO_MODE; + break; + case PM_IBSS_MODE: + pcl_mode = QDF_IBSS_MODE; + break; + default: + policy_mgr_err("Invalid mode to set PCL"); + return; + }; + + if (policy_mgr_mode_specific_connection_count(psoc, mode, NULL) > 0) { + /* Check, store and temp delete the mode's parameter */ + policy_mgr_store_and_del_conn_info(psoc, mode, &info); + /* Set the PCL to the FW since connection got updated */ + policy_mgr_pdev_set_pcl(psoc, pcl_mode); + policy_mgr_notice("Set PCL to FW for mode:%d", mode); + /* Restore the connection info */ + policy_mgr_restore_deleted_conn_info(psoc, &info); + } } /** @@ -435,6 +1181,60 @@ void policy_mgr_set_pcl_for_existing_combo( */ void pm_dbs_opportunistic_timer_handler(void *data) { + enum policy_mgr_conc_next_action action = PM_NOP; + struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)data; + + if (!psoc) { + policy_mgr_err("Invalid Context"); + return; + } + + /* if we still need it */ + action = policy_mgr_need_opportunistic_upgrade(psoc); + policy_mgr_notice("action:%d", action); + if (action) { + /* lets call for action */ + /* session id is being used only + * in hidden ssid case for now. + * So, session id 0 is ok here. + */ + policy_mgr_next_actions(psoc, 0, action, + POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC); + } +} + +/** + * policy_mgr_get_connection_for_vdev_id() - provides the + * perticular connection with the requested vdev id + * @vdev_id: vdev id of the connection + * + * This function provides the specific connection with the + * requested vdev id + * + * Return: index in the connection table + */ +static uint32_t policy_mgr_get_connection_for_vdev_id( + struct wlan_objmgr_psoc *psoc, uint32_t vdev_id) +{ + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return conn_index; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) && + pm_conc_connection_list[conn_index].in_use) { + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return conn_index; } /** @@ -450,7 +1250,347 @@ void pm_dbs_opportunistic_timer_handler(void *data) enum policy_mgr_con_mode policy_mgr_get_mode(uint8_t type, uint8_t subtype) { - return PM_MAX_NUM_OF_MODE; + enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE; + + if (type == WMI_VDEV_TYPE_AP) { + switch (subtype) { + case 0: + mode = PM_SAP_MODE; + break; + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO: + mode = PM_P2P_GO_MODE; + break; + default: + policy_mgr_err("Unknown subtype %d for type %d", + subtype, type); + break; + } + } else if (type == WMI_VDEV_TYPE_STA) { + switch (subtype) { + case 0: + mode = PM_STA_MODE; + break; + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT: + mode = PM_P2P_CLIENT_MODE; + break; + default: + policy_mgr_err("Unknown subtype %d for type %d", + subtype, type); + break; + } + } else if (type == WMI_VDEV_TYPE_IBSS) { + mode = PM_IBSS_MODE; + } else { + policy_mgr_err("Unknown type %d", type); + } + + return mode; +} + +/** + * policy_mgr_get_bw() - Get channel bandwidth type used by WMI + * @chan_width: channel bandwidth type defined by host + * + * Get the channel bandwidth type used by WMI + * + * Return: hw_mode_bandwidth + */ +enum hw_mode_bandwidth policy_mgr_get_bw(enum phy_ch_width chan_width) +{ + enum hw_mode_bandwidth bw = HW_MODE_BW_NONE; + + switch (chan_width) { + case CH_WIDTH_20MHZ: + bw = HW_MODE_20_MHZ; + break; + case CH_WIDTH_40MHZ: + bw = HW_MODE_40_MHZ; + break; + case CH_WIDTH_80MHZ: + bw = HW_MODE_80_MHZ; + break; + case CH_WIDTH_160MHZ: + bw = HW_MODE_160_MHZ; + break; + case CH_WIDTH_80P80MHZ: + bw = HW_MODE_80_PLUS_80_MHZ; + break; + case CH_WIDTH_5MHZ: + bw = HW_MODE_5_MHZ; + break; + case CH_WIDTH_10MHZ: + bw = HW_MODE_10_MHZ; + break; + default: + policy_mgr_err("Unknown channel BW type %d", chan_width); + break; + } + + return bw; +} + +/** + * policy_mgr_get_sbs_channels() - provides the sbs channel(s) + * with respect to current connection(s) + * @channels: the channel(s) on which current connection(s) is + * @len: Number of channels + * @pcl_weight: Pointer to the weights of PCL + * @weight_len: Max length of the weight list + * @index: Index from which the weight list needs to be populated + * @group_id: Next available groups for weight assignment + * @available_5g_channels: List of available 5g channels + * @available_5g_channels_len: Length of the 5g channels list + * @add_5g_channels: If this flag is true append 5G channel list as well + * + * This function provides the channel(s) on which current + * connection(s) is/are + * + * Return: QDF_STATUS + */ + +static QDF_STATUS policy_mgr_get_sbs_channels(uint8_t *channels, + uint32_t *len, uint8_t *pcl_weight, uint32_t weight_len, + uint32_t *index, enum policy_mgr_pcl_group_id group_id, + uint8_t *available_5g_channels, + uint32_t available_5g_channels_len, + bool add_5g_channels) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t conn_index = 0, num_channels = 0; + uint32_t num_5g_channels = 0, cur_5g_channel = 0; + uint8_t remaining_5g_Channels[QDF_MAX_NUM_CHAN] = {}; + uint32_t remaining_channel_index = 0; + uint32_t j = 0, i = 0, weight1, weight2; + + if ((NULL == channels) || (NULL == len)) { + policy_mgr_err("channels or len is NULL"); + status = QDF_STATUS_E_FAILURE; + return status; + } + + if (group_id == POLICY_MGR_PCL_GROUP_ID1_ID2) { + weight1 = WEIGHT_OF_GROUP1_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + } else if (group_id == POLICY_MGR_PCL_GROUP_ID2_ID3) { + weight1 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + } else { + weight1 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP4_PCL_CHANNELS; + } + + policy_mgr_debug("weight1=%d weight2=%d index=%d ", + weight1, weight2, *index); + + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if ((WLAN_REG_IS_5GHZ_CH( + pm_conc_connection_list[conn_index].chan)) + && (pm_conc_connection_list[conn_index].in_use)) { + num_5g_channels++; + cur_5g_channel = + pm_conc_connection_list[conn_index].chan; + } + conn_index++; + } + + conn_index = 0; + if (num_5g_channels > 1) { + /* This case we are already in SBS so return the channels */ + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + channels[num_channels++] = + pm_conc_connection_list[conn_index++].chan; + if (*index < weight_len) + pcl_weight[(*index)++] = weight1; + } + *len = num_channels; + /* fix duplicate issue later */ + if (add_5g_channels) + for (j = 0; j < available_5g_channels_len; j++) + remaining_5g_Channels[ + remaining_channel_index++] = + available_5g_channels[j]; + } else { + /* Get list of valid sbs channels for the current + * connected channel + */ + for (j = 0; j < available_5g_channels_len; j++) { + if (WLAN_REG_IS_CHANNEL_VALID_5G_SBS( + cur_5g_channel, available_5g_channels[j])) { + channels[num_channels++] = + available_5g_channels[j]; + } else { + remaining_5g_Channels[ + remaining_channel_index++] = + available_5g_channels[j]; + continue; + } + if (*index < weight_len) + pcl_weight[(*index)++] = weight1; + } + *len = num_channels; + } + + if (add_5g_channels) { + qdf_mem_copy(channels+num_channels, remaining_5g_Channels, + remaining_channel_index); + *len += remaining_channel_index; + for (i = 0; ((i < remaining_channel_index) + && (i < weight_len)); i++) + pcl_weight[i] = weight2; + } + + return status; +} + + +/** + * policy_mgr_get_connection_channels() - provides the channel(s) + * on which current connection(s) is + * @channels: the channel(s) on which current connection(s) is + * @len: Number of channels + * @order: no order OR 2.4 Ghz channel followed by 5 Ghz + * channel OR 5 Ghz channel followed by 2.4 Ghz channel + * @skip_dfs_channel: if this flag is true then skip the dfs channel + * @pcl_weight: Pointer to the weights of PCL + * @weight_len: Max length of the weight list + * @index: Index from which the weight list needs to be populated + * @group_id: Next available groups for weight assignment + * + * + * This function provides the channel(s) on which current + * connection(s) is/are + * + * Return: QDF_STATUS + */ +static +QDF_STATUS policy_mgr_get_connection_channels(struct wlan_objmgr_psoc *psoc, + uint8_t *channels, + uint32_t *len, enum policy_mgr_pcl_channel_order order, + bool skip_dfs_channel, + uint8_t *pcl_weight, uint32_t weight_len, + uint32_t *index, enum policy_mgr_pcl_group_id group_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t conn_index = 0, num_channels = 0; + uint32_t weight1, weight2; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + if ((NULL == channels) || (NULL == len)) { + policy_mgr_err("channels or len is NULL"); + status = QDF_STATUS_E_FAILURE; + return status; + } + + /* POLICY_MGR_PCL_GROUP_ID1_ID2 indicates that all three weights are + * available for assignment. i.e., WEIGHT_OF_GROUP1_PCL_CHANNELS, + * WEIGHT_OF_GROUP2_PCL_CHANNELS and WEIGHT_OF_GROUP3_PCL_CHANNELS + * are all available. Since in this function only two weights are + * assigned at max, only group1 and group2 weights are considered. + * + * The other possible group id POLICY_MGR_PCL_GROUP_ID2_ID3 indicates + * group1 was assigned the weight WEIGHT_OF_GROUP1_PCL_CHANNELS and + * only weights WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS are available for further weight + * assignments. + * + * e.g., when order is POLICY_MGR_PCL_ORDER_24G_THEN_5G and group id is + * POLICY_MGR_PCL_GROUP_ID2_ID3, WEIGHT_OF_GROUP2_PCL_CHANNELS is + * assigned to 2.4GHz channels and the weight + * WEIGHT_OF_GROUP3_PCL_CHANNELS is assigned to the 5GHz channels. + */ + if (group_id == POLICY_MGR_PCL_GROUP_ID1_ID2) { + weight1 = WEIGHT_OF_GROUP1_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + } else { + weight1 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (POLICY_MGR_PCL_ORDER_NONE == order) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && wlan_reg_is_dfs_ch(psoc, + pm_conc_connection_list[conn_index].chan)) { + conn_index++; + } else if (*index < weight_len) { + channels[num_channels++] = + pm_conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight1; + } else { + conn_index++; + } + } + *len = num_channels; + } else if (POLICY_MGR_PCL_ORDER_24G_THEN_5G == order) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (WLAN_REG_IS_24GHZ_CH( + pm_conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + pm_conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight1; + } else { + conn_index++; + } + } + conn_index = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && wlan_reg_is_dfs_ch(psoc, + pm_conc_connection_list[conn_index].chan)) { + conn_index++; + } else if (WLAN_REG_IS_5GHZ_CH( + pm_conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + pm_conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight2; + } else { + conn_index++; + } + } + *len = num_channels; + } else if (POLICY_MGR_PCL_ORDER_5G_THEN_2G == order) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && wlan_reg_is_dfs_ch(psoc, + pm_conc_connection_list[conn_index].chan)) { + conn_index++; + } else if (WLAN_REG_IS_5GHZ_CH( + pm_conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + pm_conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight1; + } else { + conn_index++; + } + } + conn_index = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (WLAN_REG_IS_24GHZ_CH( + pm_conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + pm_conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight2; + + } else { + conn_index++; + } + } + *len = num_channels; + } else { + policy_mgr_err("unknown order %d", order); + status = QDF_STATUS_E_FAILURE; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; } /** @@ -475,7 +1615,422 @@ QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, uint8_t *pcl_weights, uint32_t weight_len) { - return QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t num_channels = 0; + uint32_t sbs_num_channels = 0; + uint32_t chan_index = 0, chan_index_24 = 0, chan_index_5 = 0; + uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0}; + uint8_t channel_list_24[QDF_MAX_NUM_CHAN] = {0}; + uint8_t channel_list_5[QDF_MAX_NUM_CHAN] = {0}; + uint8_t sbs_channel_list[QDF_MAX_NUM_CHAN] = {0}; + bool skip_dfs_channel = false; + uint32_t i = 0, j = 0; + + if ((NULL == pcl_channels) || (NULL == len)) { + policy_mgr_err("pcl_channels or len is NULL"); + return status; + } + + if (PM_MAX_PCL_TYPE == pcl) { + /* msg */ + policy_mgr_err("pcl is invalid"); + return status; + } + + if (PM_NONE == pcl) { + /* msg */ + policy_mgr_notice("pcl is 0"); + return QDF_STATUS_SUCCESS; + } + /* get the channel list for current domain */ + status = policy_mgr_get_valid_chans(psoc, channel_list, &num_channels); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Error in getting valid channels"); + return status; + } + + /* + * if you have atleast one STA connection then don't fill DFS channels + * in the preferred channel list + */ + if (((mode == PM_SAP_MODE) || (mode == PM_P2P_GO_MODE)) && + (policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, NULL) > 0)) { + policy_mgr_notice("STA present, skip DFS channels from pcl for SAP/Go"); + skip_dfs_channel = true; + } + + /* Let's divide the list in 2.4 & 5 Ghz lists */ + while ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] <= 11) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) + channel_list_24[chan_index_24++] = channel_list[chan_index++]; + if ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] == 12) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) { + channel_list_24[chan_index_24++] = channel_list[chan_index++]; + if ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] == 13) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) { + channel_list_24[chan_index_24++] = + channel_list[chan_index++]; + if ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] == 14) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) + channel_list_24[chan_index_24++] = + channel_list[chan_index++]; + } + } + + while ((chan_index < num_channels) && + (chan_index_5 < QDF_MAX_NUM_CHAN)) { + if ((true == skip_dfs_channel) && + wlan_reg_is_dfs_ch(psoc, channel_list[chan_index])) { + chan_index++; + continue; + } + channel_list_5[chan_index_5++] = channel_list[chan_index++]; + } + + num_channels = 0; + sbs_num_channels = 0; + /* In the below switch case, the channel list is populated based on the + * pcl. e.g., if the pcl is PM_SCC_CH_24G, the SCC channel group is + * populated first followed by the 2.4GHz channel group. Along with + * this, the weights are also populated in the same order for each of + * these groups. There are three weight groups: + * WEIGHT_OF_GROUP1_PCL_CHANNELS, WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS. + * + * e.g., if pcl is PM_SCC_ON_5_SCC_ON_24_24G: scc on 5GHz (group1) + * channels take the weight WEIGHT_OF_GROUP1_PCL_CHANNELS, scc on 2.4GHz + * (group2) channels take the weight WEIGHT_OF_GROUP2_PCL_CHANNELS and + * 2.4GHz (group3) channels take the weight + * WEIGHT_OF_GROUP3_PCL_CHANNELS. + * + * When the weight to be assigned to the group is known along with the + * number of channels, the weights are directly assigned to the + * pcl_weights list. But, the channel list is populated using + * policy_mgr_get_connection_channels(), the order of weights to be used + * is passed as an argument to the function + * policy_mgr_get_connection_channels() using + * 'enum policy_mgr_pcl_group_id' which indicates the next available + * weights to be used and policy_mgr_get_connection_channels() will take + * care of the weight assignments. + * + * e.g., 'enum policy_mgr_pcl_group_id' value of + * POLICY_MGR_PCL_GROUP_ID2_ID3 indicates that the next available groups + * for weight assignment are WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS and that the + * weight WEIGHT_OF_GROUP1_PCL_CHANNELS was already allocated. + * So, in the same example, when order is + * POLICY_MGR_PCL_ORDER_24G_THEN_5G, + * policy_mgr_get_connection_channels() will assign the weight + * WEIGHT_OF_GROUP2_PCL_CHANNELS to 2.4GHz channels and assign the + * weight WEIGHT_OF_GROUP3_PCL_CHANNELS to 5GHz channels. + */ + switch (pcl) { + case PM_24G: + chan_index_24 = QDF_MIN(chan_index_24, weight_len); + qdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + for (i = 0; i < *len; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case PM_5G: + chan_index_5 = QDF_MIN(chan_index_5, weight_len); + qdf_mem_copy(pcl_channels, channel_list_5, + chan_index_5); + *len = chan_index_5; + for (i = 0; i < *len; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH: + case PM_MCC_CH: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH_24G: + case PM_MCC_CH_24G: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_24 = QDF_MIN((num_channels + chan_index_24), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + for (j = 0; j < chan_index_24; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH_5G: + case PM_MCC_CH_5G: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, + num_channels); + *len = num_channels; + chan_index_5 = QDF_MIN((num_channels + chan_index_5), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + for (j = 0; j < chan_index_5; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case PM_24G_SCC_CH: + case PM_24G_MCC_CH: + chan_index_24 = QDF_MIN(chan_index_24, weight_len); + qdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + for (i = 0; i < chan_index_24; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID2_ID3); + qdf_mem_copy(&pcl_channels[chan_index_24], + channel_list, num_channels); + *len += num_channels; + status = QDF_STATUS_SUCCESS; + break; + case PM_5G_SCC_CH: + case PM_5G_MCC_CH: + chan_index_5 = QDF_MIN(chan_index_5, weight_len); + qdf_mem_copy(pcl_channels, channel_list_5, + chan_index_5); + *len = chan_index_5; + for (i = 0; i < chan_index_5; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID2_ID3); + qdf_mem_copy(&pcl_channels[chan_index_5], + channel_list, num_channels); + *len += num_channels; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24_SCC_ON_5: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, + POLICY_MGR_PCL_ORDER_24G_THEN_5G, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, + num_channels); + *len = num_channels; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_SCC_ON_24: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, + POLICY_MGR_PCL_ORDER_5G_THEN_2G, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24_SCC_ON_5_24G: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, + POLICY_MGR_PCL_ORDER_24G_THEN_5G, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_24 = QDF_MIN((num_channels + chan_index_24), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + for (j = 0; j < chan_index_24; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24_SCC_ON_5_5G: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, + POLICY_MGR_PCL_ORDER_24G_THEN_5G, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_5 = QDF_MIN((num_channels + chan_index_5), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + for (j = 0; j < chan_index_5; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_SCC_ON_24_24G: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, + POLICY_MGR_PCL_ORDER_5G_THEN_2G, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_24 = QDF_MIN((num_channels + chan_index_24), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + for (j = 0; j < chan_index_24; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_SCC_ON_24_5G: + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, + POLICY_MGR_PCL_ORDER_5G_THEN_2G, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_5 = QDF_MIN((num_channels + chan_index_5), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + for (j = 0; j < chan_index_5; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case PM_24G_SCC_CH_SBS_CH: + qdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + for (i = 0; ((i < chan_index_24) && (i < weight_len)); i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID2_ID3); + qdf_mem_copy(&pcl_channels[chan_index_24], + channel_list, num_channels); + *len += num_channels; + if (policy_mgr_is_hw_sbs_capable(psoc)) { + policy_mgr_get_sbs_channels( + sbs_channel_list, &sbs_num_channels, pcl_weights, + weight_len, &i, POLICY_MGR_PCL_GROUP_ID3_ID4, + channel_list_5, chan_index_5, false); + qdf_mem_copy( + &pcl_channels[chan_index_24 + num_channels], + sbs_channel_list, sbs_num_channels); + *len += sbs_num_channels; + } + status = QDF_STATUS_SUCCESS; + break; + case PM_24G_SCC_CH_SBS_CH_5G: + qdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + for (i = 0; ((i < chan_index_24) && (i < weight_len)); i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID2_ID3); + qdf_mem_copy(&pcl_channels[chan_index_24], + channel_list, num_channels); + *len += num_channels; + if (policy_mgr_is_hw_sbs_capable(psoc)) { + policy_mgr_get_sbs_channels( + sbs_channel_list, &sbs_num_channels, pcl_weights, + weight_len, &i, POLICY_MGR_PCL_GROUP_ID3_ID4, + channel_list_5, chan_index_5, true); + qdf_mem_copy( + &pcl_channels[chan_index_24 + num_channels], + sbs_channel_list, sbs_num_channels); + *len += sbs_num_channels; + } else { + qdf_mem_copy( + &pcl_channels[chan_index_24 + num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + for (i = chan_index_24 + num_channels; + ((i < *len) && (i < weight_len)); i++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + } + status = QDF_STATUS_SUCCESS; + break; + case PM_24G_SBS_CH_MCC_CH: + qdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + for (i = 0; ((i < chan_index_24) && (i < weight_len)); i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + if (policy_mgr_is_hw_sbs_capable(psoc)) { + policy_mgr_get_sbs_channels( + sbs_channel_list, &sbs_num_channels, pcl_weights, + weight_len, &i, POLICY_MGR_PCL_GROUP_ID2_ID3, + channel_list_5, chan_index_5, false); + qdf_mem_copy(&pcl_channels[num_channels], + sbs_channel_list, sbs_num_channels); + *len += sbs_num_channels; + } + policy_mgr_get_connection_channels(psoc, + channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + POLICY_MGR_PCL_GROUP_ID2_ID3); + qdf_mem_copy(&pcl_channels[chan_index_24], + channel_list, num_channels); + *len += num_channels; + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_5G: + if (policy_mgr_is_hw_sbs_capable(psoc)) { + policy_mgr_get_sbs_channels( + sbs_channel_list, &sbs_num_channels, pcl_weights, + weight_len, &i, POLICY_MGR_PCL_GROUP_ID1_ID2, + channel_list_5, chan_index_5, true); + qdf_mem_copy(&pcl_channels[num_channels], + sbs_channel_list, sbs_num_channels); + *len += sbs_num_channels; + } else { + qdf_mem_copy(pcl_channels, channel_list_5, + chan_index_5); + *len = chan_index_5; + for (i = 0; ((i < *len) && (i < weight_len)); i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + } + status = QDF_STATUS_SUCCESS; + break; + default: + policy_mgr_err("unknown pcl value %d", pcl); + break; + } + + if ((*len != 0) && (*len != i)) + policy_mgr_notice("pcl len (%d) and weight list len mismatch (%d)", + *len, i); + + /* check the channel avoidance list */ + policy_mgr_update_with_safe_channel_list(pcl_channels, len, + pcl_weights, weight_len); + + return status; } /** @@ -492,7 +2047,35 @@ QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, bool policy_mgr_disallow_mcc(struct wlan_objmgr_psoc *psoc, uint8_t channel) { - return false; + uint32_t index = 0; + bool match = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return match; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(index)) { + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + if (pm_conc_connection_list[index].chan != + channel) { + match = true; + break; + } + } else if (WLAN_REG_IS_5GHZ_CH + (pm_conc_connection_list[index].chan)) { + if (pm_conc_connection_list[index].chan != channel) { + match = true; + break; + } + } + index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return match; } /** @@ -510,7 +2093,44 @@ bool policy_mgr_disallow_mcc(struct wlan_objmgr_psoc *psoc, bool policy_mgr_allow_new_home_channel(struct wlan_objmgr_psoc *psoc, uint8_t channel, uint32_t num_connections) { - return true; + bool status = true; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if ((num_connections == 2) && + (pm_conc_connection_list[0].chan != + pm_conc_connection_list[1].chan) && + (pm_conc_connection_list[0].mac == + pm_conc_connection_list[1].mac)) { + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + if ((channel != pm_conc_connection_list[0].chan) && + (channel != pm_conc_connection_list[1].chan)) { + policy_mgr_err("don't allow 3rd home channel on same MAC"); + status = false; + } + } else if (((WLAN_REG_IS_24GHZ_CH(channel)) && + (WLAN_REG_IS_24GHZ_CH + (pm_conc_connection_list[0].chan)) && + (WLAN_REG_IS_24GHZ_CH + (pm_conc_connection_list[1].chan))) || + ((WLAN_REG_IS_5GHZ_CH(channel)) && + (WLAN_REG_IS_5GHZ_CH + (pm_conc_connection_list[0].chan)) && + (WLAN_REG_IS_5GHZ_CH + (pm_conc_connection_list[1].chan)))) { + policy_mgr_err("don't allow 3rd home channel on same MAC"); + status = false; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; } /** @@ -524,7 +2144,31 @@ bool policy_mgr_allow_new_home_channel(struct wlan_objmgr_psoc *psoc, */ bool policy_mgr_vht160_conn_exist(struct wlan_objmgr_psoc *psoc) { - return false; + uint32_t conn_index; + bool status = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use && + ((pm_conc_connection_list[conn_index].bw == + HW_MODE_80_PLUS_80_MHZ) || + (pm_conc_connection_list[conn_index].bw == + HW_MODE_160_MHZ))) { + status = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; } /** @@ -545,9 +2189,77 @@ bool policy_mgr_is_5g_channel_allowed(struct wlan_objmgr_psoc *psoc, uint8_t channel, uint32_t *list, enum policy_mgr_con_mode mode) { + uint32_t index = 0, count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + count = policy_mgr_mode_specific_connection_count(psoc, mode, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (index < count) { + if (wlan_reg_is_dfs_ch(psoc, + pm_conc_connection_list[list[index]].chan) && + WLAN_REG_IS_5GHZ_CH(channel) && + (channel != + pm_conc_connection_list[list[index]].chan)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_err("don't allow MCC if SAP/GO on DFS channel"); + return false; + } + index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; } +/** + * policy_mgr_nss_update_cb() - callback from SME confirming nss + * update + * @hdd_ctx: HDD Context + * @tx_status: tx completion status for updated beacon with new + * nss value + * @vdev_id: vdev id for the specific connection + * @next_action: next action to happen at policy mgr after + * beacon update + * @reason: Reason for nss update + * + * This function is the callback registered with SME at nss + * update request time + * + * Return: None + */ +static void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc, + uint8_t tx_status, + uint8_t vdev_id, + uint8_t next_action, + enum policy_mgr_conn_update_reason reason) +{ + uint32_t conn_index = 0; + + if (QDF_STATUS_SUCCESS != tx_status) + policy_mgr_err("nss update failed(%d) for vdev %d", + tx_status, vdev_id); + + /* + * Check if we are ok to request for HW mode change now + */ + conn_index = policy_mgr_get_connection_for_vdev_id(psoc, vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + policy_mgr_err("connection not found for vdev %d", vdev_id); + return; + } + + policy_mgr_debug("nss update successful for vdev:%d", vdev_id); + policy_mgr_next_actions(psoc, vdev_id, next_action, reason); + + return; +} + /** * policy_mgr_complete_action() - initiates actions needed on * current connections once channel has been decided for the new @@ -569,14 +2281,115 @@ QDF_STATUS policy_mgr_complete_action(struct wlan_objmgr_psoc *psoc, enum policy_mgr_conn_update_reason reason, uint32_t session_id) { - return QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t index, count; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t conn_index = 0; + uint32_t vdev_id; + uint32_t original_nss; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + policy_mgr_err("driver isn't dbs capable, no further action needed"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* policy_mgr_complete_action() is called by policy_mgr_next_actions(). + * All other callers of policy_mgr_next_actions() have taken mutex + * protection. So, not taking any lock inside + * policy_mgr_complete_action() during pm_conc_connection_list access. + */ + count = policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_GO_MODE, list); + for (index = 0; index < count; index++) { + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + vdev_id = pm_conc_connection_list[list[index]].vdev_id; + original_nss = + pm_conc_connection_list[list[index]].original_nss; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + conn_index = policy_mgr_get_connection_for_vdev_id( + psoc, vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + policy_mgr_err("connection not found for vdev %d", + vdev_id); + continue; + } + + if (2 == original_nss) { + status = pm_ctx->sme_cbacks.sme_nss_update_request( + vdev_id, new_nss, + policy_mgr_nss_update_cb, + next_action, psoc, reason); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("sme_nss_update_request() failed for vdev %d", + vdev_id); + } + } + } + + count = policy_mgr_mode_specific_connection_count(psoc, + PM_SAP_MODE, list); + for (index = 0; index < count; index++) { + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + vdev_id = pm_conc_connection_list[list[index]].vdev_id; + original_nss = + pm_conc_connection_list[list[index]].original_nss; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + conn_index = policy_mgr_get_connection_for_vdev_id( + psoc, vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + policy_mgr_err("connection not found for vdev %d", + vdev_id); + continue; + } + if (2 == original_nss) { + status = pm_ctx->sme_cbacks.sme_nss_update_request( + vdev_id, new_nss, + policy_mgr_nss_update_cb, + next_action, psoc, reason); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("sme_nss_update_request() failed for vdev %d", + vdev_id); + } + } + } + if (!QDF_IS_STATUS_SUCCESS(status)) + status = policy_mgr_next_actions(psoc, session_id, + next_action, reason); + + return status; } enum policy_mgr_con_mode policy_mgr_get_mode_by_vdev_id( struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) { - return PM_MAX_NUM_OF_MODE; + enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return mode; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) + if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) && + pm_conc_connection_list[conn_index].in_use){ + mode = pm_conc_connection_list[conn_index].mode; + break; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return mode; } /** @@ -591,11 +2404,21 @@ enum policy_mgr_con_mode policy_mgr_get_mode_by_vdev_id( QDF_STATUS policy_mgr_init_connection_update( struct policy_mgr_psoc_priv_obj *pm_ctx) { + QDF_STATUS qdf_status; + + qdf_status = qdf_event_create(&pm_ctx->connection_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + policy_mgr_err("init event failed"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; } /** - * policy_mgr_get_current_pref_hw_mode_dbs_2x2() - Get the current preferred hw mode + * policy_mgr_get_current_pref_hw_mode_dbs_2x2() - Get the + * current preferred hw mode * * Get the preferred hw mode based on the current connection combinations * @@ -606,11 +2429,106 @@ enum policy_mgr_conc_next_action policy_mgr_get_current_pref_hw_mode_dbs_2x2( struct wlan_objmgr_psoc *psoc) { - return PM_NOP; + uint32_t num_connections; + uint8_t band1, band2, band3; + struct policy_mgr_hw_mode_params hw_mode; + QDF_STATUS status; + + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return PM_NOP; + } + + num_connections = policy_mgr_get_connection_count(psoc); + + policy_mgr_debug("chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d dbs:%d", + pm_conc_connection_list[0].chan, + pm_conc_connection_list[1].chan, + pm_conc_connection_list[2].chan, num_connections, + hw_mode.dbs_cap); + + /* If the band of operation of both the MACs is the same, + * single MAC is preferred, otherwise DBS is preferred. + */ + switch (num_connections) { + case 1: + band1 = reg_chan_to_band(pm_conc_connection_list[0].chan); + if (band1 == BAND_2G) + return PM_DBS; + else + return PM_NOP; + case 2: + band1 = reg_chan_to_band(pm_conc_connection_list[0].chan); + band2 = reg_chan_to_band(pm_conc_connection_list[1].chan); + if ((band1 == BAND_2G) || + (band2 == BAND_2G)) { + if (!hw_mode.dbs_cap) + return PM_DBS; + else + return PM_NOP; + } else if ((band1 == BAND_5G) && + (band2 == BAND_5G)) { + if (WLAN_REG_IS_CHANNEL_VALID_5G_SBS( + pm_conc_connection_list[0].chan, + pm_conc_connection_list[1].chan)) { + if (!hw_mode.sbs_cap) + return PM_SBS; + else + return PM_NOP; + } else { + if (hw_mode.sbs_cap || hw_mode.dbs_cap) + return PM_SINGLE_MAC; + else + return PM_NOP; + } + } else + return PM_NOP; + case 3: + band1 = reg_chan_to_band(pm_conc_connection_list[0].chan); + band2 = reg_chan_to_band(pm_conc_connection_list[1].chan); + band3 = reg_chan_to_band(pm_conc_connection_list[2].chan); + if ((band1 == BAND_2G) || + (band2 == BAND_2G) || + (band3 == BAND_2G)) { + if (!hw_mode.dbs_cap) + return PM_DBS; + else + return PM_NOP; + } else if ((band1 == BAND_5G) && + (band2 == BAND_5G) && + (band3 == BAND_5G)) { + if (WLAN_REG_IS_CHANNEL_VALID_5G_SBS( + pm_conc_connection_list[0].chan, + pm_conc_connection_list[2].chan) && + WLAN_REG_IS_CHANNEL_VALID_5G_SBS( + pm_conc_connection_list[1].chan, + pm_conc_connection_list[2].chan) && + WLAN_REG_IS_CHANNEL_VALID_5G_SBS( + pm_conc_connection_list[0].chan, + pm_conc_connection_list[1].chan)) { + if (!hw_mode.sbs_cap) + return PM_SBS; + else + return PM_NOP; + } else { + if (hw_mode.sbs_cap || hw_mode.dbs_cap) + return PM_SINGLE_MAC; + else + return PM_NOP; + } + } else + return PM_NOP; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + return PM_NOP; + } } /** - * policy_mgr_get_current_pref_hw_mode_dbs_1x1() - Get the current preferred hw mode + * policy_mgr_get_current_pref_hw_mode_dbs_1x1() - Get the + * current preferred hw mode * * Get the preferred hw mode based on the current connection combinations * @@ -621,7 +2539,79 @@ enum policy_mgr_conc_next_action policy_mgr_get_current_pref_hw_mode_dbs_1x1( struct wlan_objmgr_psoc *psoc) { - return PM_NOP; + uint32_t num_connections; + uint8_t band1, band2, band3; + struct policy_mgr_hw_mode_params hw_mode; + QDF_STATUS status; + enum policy_mgr_conc_next_action next_action; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return PM_NOP; + } + + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return PM_NOP; + } + + num_connections = policy_mgr_get_connection_count(psoc); + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d dbs:%d", + pm_conc_connection_list[0].chan, + pm_conc_connection_list[1].chan, + pm_conc_connection_list[2].chan, num_connections, + hw_mode.dbs_cap); + + /* If the band of operation of both the MACs is the same, + * single MAC is preferred, otherwise DBS is preferred. + */ + switch (num_connections) { + case 1: + /* The driver would already be in the required hw mode */ + next_action = PM_NOP; + break; + case 2: + band1 = reg_chan_to_band(pm_conc_connection_list[0].chan); + band2 = reg_chan_to_band(pm_conc_connection_list[1].chan); + if ((band1 == band2) && (hw_mode.dbs_cap)) + next_action = PM_SINGLE_MAC_UPGRADE; + else if ((band1 != band2) && (!hw_mode.dbs_cap)) + next_action = PM_DBS_DOWNGRADE; + else + next_action = PM_NOP; + + break; + + case 3: + band1 = reg_chan_to_band(pm_conc_connection_list[0].chan); + band2 = reg_chan_to_band(pm_conc_connection_list[1].chan); + band3 = reg_chan_to_band(pm_conc_connection_list[2].chan); + if (((band1 == band2) && (band2 == band3)) && + (hw_mode.dbs_cap)) { + next_action = PM_SINGLE_MAC_UPGRADE; + } else if (((band1 != band2) || (band2 != band3) || + (band1 != band3)) && + (!hw_mode.dbs_cap)) { + next_action = PM_DBS_DOWNGRADE; + } else { + next_action = PM_NOP; + } + break; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + next_action = PM_NOP; + break; + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return next_action; } /** @@ -634,5 +2624,9 @@ enum policy_mgr_conc_next_action QDF_STATUS policy_mgr_reset_sap_mandatory_channels( struct policy_mgr_psoc_priv_obj *pm_ctx) { + pm_ctx->sap_mandatory_channels_len = 0; + qdf_mem_zero(pm_ctx->sap_mandatory_channels, + QDF_ARRAY_SIZE(pm_ctx->sap_mandatory_channels)); + return QDF_STATUS_SUCCESS; } diff --git a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h index d9b3873d9ced..0787042f2ed3 100644 --- a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h +++ b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h @@ -387,6 +387,7 @@ void policy_mgr_set_pcl_for_existing_combo( void pm_dbs_opportunistic_timer_handler(void *data); enum policy_mgr_con_mode policy_mgr_get_mode(uint8_t type, uint8_t subtype); +enum hw_mode_bandwidth policy_mgr_get_bw(enum phy_ch_width chan_width); QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, enum policy_mgr_pcl_type pcl, uint8_t *pcl_channels, uint32_t *len,