From 3fd5776306d5ffb33dcdb300374efd8bb941591f Mon Sep 17 00:00:00 2001 From: Manikandan Mohan Date: Thu, 13 Aug 2020 22:48:56 -0700 Subject: [PATCH 1/2] cnss2: Setup interconnect path for bandwidth voting Setup bandwidth voting data for different interconnect path configured in device tree. Change-Id: Icf69d2ca89c1978e7d6c2fd2c876d0365c577148 Signed-off-by: Manikandan Mohan --- drivers/net/wireless/cnss2/main.c | 151 ++++++++++++++++++++---------- drivers/net/wireless/cnss2/main.h | 42 +++++++-- drivers/net/wireless/cnss2/pci.c | 86 +++++++++-------- 3 files changed, 188 insertions(+), 91 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 588fbea06e10..a0803ffbec3f 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -2078,75 +2078,130 @@ int cnss_minidump_remove_region(struct cnss_plat_data *plat_priv, return ret; } +/** + * cnss_register_bus_scale() - Setup interconnect voting data + * @plat_priv: Platform data structure + * + * For different interconnect path configured in device tree setup voting data + * for list of bandwidth requirements. + * + * Result: 0 for success. -EINVAL if not configured + */ static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv) { - int ret = 0, len = 0, i, j; - struct cnss_bus_bw_info *bus_bw_info; - const u32 *cfg_arr; + int ret = -EINVAL; + u32 idx, i, j, cfg_arr_size, *cfg_arr; + struct cnss_bus_bw_info *bus_bw_info, *tmp; + struct device *dev = &plat_priv->plat_dev->dev; - bus_bw_info = &plat_priv->bus_bw_info; - - bus_bw_info->cnss_path = - of_icc_get(&plat_priv->plat_dev->dev, NULL); - - if (!bus_bw_info->cnss_path) { - cnss_pr_err("Skip Bus BW setup. Interconnect not configured\n"); - return 0; - } - - if (IS_ERR(bus_bw_info->cnss_path)) { - ret = PTR_ERR(bus_bw_info->cnss_path); - if (ret != -EPROBE_DEFER) { - cnss_pr_err("Failed to get Interconnect path: %d!\n", - ret); - goto out; - } + INIT_LIST_HEAD(&plat_priv->icc.list_head); + ret = of_property_read_u32(dev->of_node, + "qcom,icc-path-count", + &plat_priv->icc.path_count); + if (ret) { + cnss_pr_err("Platform Bus Interconnect path not configured\n"); + return -EINVAL; } ret = of_property_read_u32(plat_priv->plat_dev->dev.of_node, - "qcom,bus-bw-cfg-num", - &bus_bw_info->num_cfg); + "qcom,bus-bw-cfg-count", + &plat_priv->icc.bus_bw_cfg_count); if (ret) { cnss_pr_err("Failed to get Bus BW Config table size\n"); - goto out; + goto cleanup; } - - cfg_arr = of_get_property(plat_priv->plat_dev->dev.of_node, - "qcom,bus-bw-cfg", &len); + cfg_arr_size = plat_priv->icc.path_count * + plat_priv->icc.bus_bw_cfg_count * CNSS_ICC_VOTE_MAX; + cfg_arr = kzalloc(cfg_arr_size, GFP_KERNEL); if (!cfg_arr) { - cnss_pr_err("Bus BW Config Table not setup!\n"); - ret = -EINVAL; - goto out; + cnss_pr_err("Failed to alloc cfg table mem\n"); + ret = -ENOMEM; + goto cleanup; } - bus_bw_info->cfg_table = kcalloc(bus_bw_info->num_cfg, - sizeof(*bus_bw_info->cfg_table), - GFP_KERNEL); - if (!bus_bw_info->cfg_table) { - cnss_pr_err("No mem for Bus BW config table\n"); - return -ENOMEM; + ret = of_property_read_u32_array(plat_priv->plat_dev->dev.of_node, + "qcom,bus-bw-cfg", cfg_arr, + cfg_arr_size); + if (ret) { + cnss_pr_err("Invalid Bus BW Config Table\n"); + goto cleanup; } - for (i = 0, j = 0; i < bus_bw_info->num_cfg; i++, j += 2) { - bus_bw_info->cfg_table[i].ab = be32_to_cpu(cfg_arr[j]); - bus_bw_info->cfg_table[i].ib = be32_to_cpu(cfg_arr[j + 1]); - cnss_pr_dbg("Bandwidth Type: %d bw_cfg.ab: %d bw_cfg.ib: %d\n", - i, bus_bw_info->cfg_table[i].ab, - bus_bw_info->cfg_table[i].ib); + + cnss_pr_dbg("ICC Path_Count: %d BW_CFG_Count: %d\n", + plat_priv->icc.path_count, plat_priv->icc.bus_bw_cfg_count); + + for (idx = 0; idx < plat_priv->icc.path_count; idx++) { + bus_bw_info = devm_kzalloc(dev, sizeof(*bus_bw_info), + GFP_KERNEL); + if (!bus_bw_info) { + ret = -ENOMEM; + goto out; + } + ret = of_property_read_string_index(dev->of_node, + "interconnect-names", idx, + &bus_bw_info->icc_name); + if (ret) + goto out; + + bus_bw_info->icc_path = + of_icc_get(&plat_priv->plat_dev->dev, + bus_bw_info->icc_name); + + if (IS_ERR(bus_bw_info->icc_path)) { + ret = PTR_ERR(bus_bw_info->icc_path); + if (ret != -EPROBE_DEFER) { + cnss_pr_err("Failed to get Interconnect path for %s. Err: %d\n", + bus_bw_info->icc_name, ret); + goto out; + } + } + + bus_bw_info->cfg_table = + devm_kcalloc(dev, plat_priv->icc.bus_bw_cfg_count, + sizeof(*bus_bw_info->cfg_table), + GFP_KERNEL); + if (!bus_bw_info->cfg_table) { + ret = -ENOMEM; + goto out; + } + cnss_pr_dbg("ICC Vote CFG for path: %s\n", + bus_bw_info->icc_name); + for (i = 0, j = (idx * plat_priv->icc.bus_bw_cfg_count * + CNSS_ICC_VOTE_MAX); + i < plat_priv->icc.bus_bw_cfg_count; + i++, j += 2) { + bus_bw_info->cfg_table[i].avg_bw = cfg_arr[j]; + bus_bw_info->cfg_table[i].peak_bw = cfg_arr[j + 1]; + cnss_pr_dbg("ICC Vote BW: %d avg: %d peak: %d\n", + i, bus_bw_info->cfg_table[i].avg_bw, + bus_bw_info->cfg_table[i].peak_bw); + } + list_add_tail(&bus_bw_info->list, + &plat_priv->icc.list_head); } + kfree(cfg_arr); return 0; out: + list_for_each_entry_safe(bus_bw_info, tmp, + &plat_priv->icc.list_head, list) { + list_del(&bus_bw_info->list); + } +cleanup: + kfree(cfg_arr); + memset(&plat_priv->icc, 0, sizeof(plat_priv->icc)); return ret; } static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv) { - struct cnss_bus_bw_info *bus_bw_info; + struct cnss_bus_bw_info *bus_bw_info, *tmp; - bus_bw_info = &plat_priv->bus_bw_info; - - if (bus_bw_info->cnss_path) - icc_put(bus_bw_info->cnss_path); - - kfree(bus_bw_info->cfg_table); + list_for_each_entry_safe(bus_bw_info, tmp, + &plat_priv->icc.list_head, list) { + list_del(&bus_bw_info->list); + if (bus_bw_info->icc_path) + icc_put(bus_bw_info->icc_path); + } + memset(&plat_priv->icc, 0, sizeof(plat_priv->icc)); } static ssize_t recovery_store(struct device *dev, diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 1ebe33c1e79d..f03cc12a86f8 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -136,18 +136,48 @@ struct cnss_esoc_info { }; #endif +/** + * struct cnss_bus_bw_cfg - Interconnect vote data + * @avg_bw: Vote for average bandwidth + * @peak_bw: Vote for peak bandwidth + */ struct cnss_bus_bw_cfg { - u32 ab; - u32 ib; + u32 avg_bw; + u32 peak_bw; }; +/* Number of bw votes (avg, peak) entries that ICC requires */ +#define CNSS_ICC_VOTE_MAX 2 + +/** + * struct cnss_bus_bw_info - Bus bandwidth config for interconnect path + * @list: Kernel linked list + * @icc_name: Name of interconnect path as defined in Device tree + * @icc_path: Interconnect path data structure + * @cfg_table: Interconnect vote data for average and peak bandwidth + */ struct cnss_bus_bw_info { - struct icc_path *cnss_path; - int current_bw_vote; - u32 num_cfg; + struct list_head list; + const char *icc_name; + struct icc_path *icc_path; struct cnss_bus_bw_cfg *cfg_table; }; +/** + * struct cnss_interconnect_cfg - CNSS platform interconnect config + * @list_head: List of interconnect path bandwidth configs + * @path_count: Count of interconnect path configured in device tree + * @current_bw_vote: WLAN driver provided bandwidth vote + * @bus_bw_cfg_count: Number of bandwidth configs for voting. It is the array + * size of struct cnss_bus_bw_info.cfg_table + */ +struct cnss_interconnect_cfg { + struct list_head list_head; + u32 path_count; + int current_bw_vote; + u32 bus_bw_cfg_count; +}; + struct cnss_fw_mem { size_t size; void *va; @@ -356,7 +386,7 @@ struct cnss_plat_data { #if IS_ENABLED(CONFIG_ESOC) struct cnss_esoc_info esoc_info; #endif - struct cnss_bus_bw_info bus_bw_info; + struct cnss_interconnect_cfg icc; struct notifier_block modem_nb; struct notifier_block reboot_nb; struct notifier_block panic_nb; diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index fc8f65845901..031ef3b98a97 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -504,42 +504,62 @@ static int cnss_pci_force_wake_put(struct cnss_pci_data *pci_priv) return ret; } -int cnss_request_bus_bandwidth(struct device *dev, int bandwidth) +/** + * cnss_setup_bus_bandwidth() - Setup interconnect vote for given bandwidth + * @plat_priv: Platform private data struct + * @bw: bandwidth + * @save: toggle flag to save bandwidth to current_bw_vote + * + * Setup bandwidth votes for configured interconnect paths + * + * Return: 0 for success + */ +static int cnss_setup_bus_bandwidth(struct cnss_plat_data *plat_priv, + u32 bw, bool save) { int ret = 0; - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct cnss_bus_bw_info *bus_bw_info; + if (!plat_priv->icc.path_count) + return -ENOTSUPP; + + if (bw >= plat_priv->icc.bus_bw_cfg_count) { + cnss_pr_err("Invalid bus bandwidth Type: %d", bw); + return -EINVAL; + } + + list_for_each_entry(bus_bw_info, &plat_priv->icc.list_head, list) { + cnss_pr_info("Set BW Cfg: %d ICC Path: %s Val: %d %d\n", + bw, bus_bw_info->icc_name, + bus_bw_info->cfg_table[bw].avg_bw, + bus_bw_info->cfg_table[bw].peak_bw); + ret = icc_set_bw(bus_bw_info->icc_path, + bus_bw_info->cfg_table[bw].avg_bw, + bus_bw_info->cfg_table[bw].peak_bw); + if (ret) { + cnss_pr_err("Could not set BW Cfg: %d, err = %d ICC Path: %s Val: %d %d\n", + bw, ret, bus_bw_info->icc_name, + bus_bw_info->cfg_table[bw].avg_bw, + bus_bw_info->cfg_table[bw].peak_bw); + break; + } + } + if (ret == 0 && save) + plat_priv->icc.current_bw_vote = bw; + return ret; +} + +int cnss_request_bus_bandwidth(struct device *dev, int bandwidth) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + if (!plat_priv) return -ENODEV; - bus_bw_info = &plat_priv->bus_bw_info; - if (!bus_bw_info->cnss_path || bandwidth > bus_bw_info->num_cfg) + if (bandwidth < 0) return -EINVAL; - switch (bandwidth) { - case CNSS_BUS_WIDTH_NONE: - case CNSS_BUS_WIDTH_IDLE: - case CNSS_BUS_WIDTH_LOW: - case CNSS_BUS_WIDTH_MEDIUM: - case CNSS_BUS_WIDTH_HIGH: - case CNSS_BUS_WIDTH_VERY_HIGH: - case CNSS_BUS_WIDTH_LOW_LATENCY: - ret = icc_set_bw(bus_bw_info->cnss_path, - bus_bw_info->cfg_table[bandwidth].ab, - bus_bw_info->cfg_table[bandwidth].ib); - if (!ret) - bus_bw_info->current_bw_vote = bandwidth; - else - cnss_pr_err("Could not set bus bandwidth: %d, err = %d\n", - bandwidth, ret); - break; - default: - cnss_pr_err("Invalid bus bandwidth: %d", bandwidth); - ret = -EINVAL; - } - - return ret; + return cnss_setup_bus_bandwidth(plat_priv, (u32)bandwidth, true); } EXPORT_SYMBOL(cnss_request_bus_bandwidth); @@ -2958,7 +2978,6 @@ int cnss_auto_suspend(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); struct cnss_plat_data *plat_priv; - struct cnss_bus_bw_info *bus_bw_info; if (!pci_priv) return -ENODEV; @@ -2979,18 +2998,11 @@ int cnss_auto_suspend(struct device *dev) cnss_pci_set_monitor_wake_intr(pci_priv, true); - bus_bw_info = &plat_priv->bus_bw_info; - if (!bus_bw_info->cnss_path) - goto out; - /* For suspend temporarily set bandwidth vote to NONE and dont save in * current_bw_vote as in resume path we should vote for last used * bandwidth vote. Also ignore error if bw voting is not setup. */ - icc_set_bw(bus_bw_info->cnss_path, - bus_bw_info->cfg_table[CNSS_BUS_WIDTH_NONE].ab, - bus_bw_info->cfg_table[CNSS_BUS_WIDTH_NONE].ib); -out: + cnss_setup_bus_bandwidth(plat_priv, CNSS_BUS_WIDTH_NONE, false); return 0; } EXPORT_SYMBOL(cnss_auto_suspend); @@ -3019,7 +3031,7 @@ int cnss_auto_resume(struct device *dev) cnss_pci_set_auto_suspended(pci_priv, 0); mutex_unlock(&pci_priv->bus_lock); - cnss_request_bus_bandwidth(dev, plat_priv->bus_bw_info.current_bw_vote); + cnss_request_bus_bandwidth(dev, plat_priv->icc.current_bw_vote); return 0; } From a7a321cca4000aeb322fe9d13043cafc8edbe40e Mon Sep 17 00:00:00 2001 From: Manikandan Mohan Date: Thu, 27 Aug 2020 21:08:15 -0700 Subject: [PATCH 2/2] cnss2: Remove unnecessary logs for Bus BW voting WLAN driver shall maintain DDR voting logs if required. Thus remove cnss platform driver side logs. Change-Id: I51fa23bd9fa6a149a581126f1e55293d819402d3 Signed-off-by: Manikandan Mohan --- drivers/net/wireless/cnss2/pci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 031ef3b98a97..5460a5244e1a 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -529,10 +529,6 @@ static int cnss_setup_bus_bandwidth(struct cnss_plat_data *plat_priv, } list_for_each_entry(bus_bw_info, &plat_priv->icc.list_head, list) { - cnss_pr_info("Set BW Cfg: %d ICC Path: %s Val: %d %d\n", - bw, bus_bw_info->icc_name, - bus_bw_info->cfg_table[bw].avg_bw, - bus_bw_info->cfg_table[bw].peak_bw); ret = icc_set_bw(bus_bw_info->icc_path, bus_bw_info->cfg_table[bw].avg_bw, bus_bw_info->cfg_table[bw].peak_bw);