Merge "cnss2: Remove unnecessary logs for Bus BW voting"

This commit is contained in:
qctecmdr 2020-09-04 13:08:04 -07:00 • committed by Gerrit - the friendly Code Review server
commit c1d17bef32
3 changed files with 184 additions and 91 deletions

View file

@ -2230,75 +2230,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,

View file

@ -140,18 +140,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;
@ -360,7 +390,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;

View file

@ -509,42 +509,58 @@ 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) {
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);
@ -2987,7 +3003,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;
@ -3008,18 +3023,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);
@ -3048,7 +3056,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;
}