Loading drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c +69 −0 Original line number Diff line number Diff line Loading @@ -1111,6 +1111,75 @@ static int update_client_paths(struct msm_bus_client *client, bool log_trns, return ret; } static int query_client_paths(struct msm_bus_client *client, bool log_trns, unsigned int idx) { int lnode, src, dest, cur_idx; uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw; int i, ret = 0; struct msm_bus_scale_pdata *pdata; struct device *src_dev; if (!client) { MSM_BUS_ERR("Client handle Null"); ret = -ENXIO; goto exit_update_client_paths; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("Client pdata Null"); ret = -ENXIO; goto exit_update_client_paths; } cur_idx = client->curr; client->curr = idx; for (i = 0; i < pdata->usecase->num_paths; i++) { src = pdata->usecase[idx].vectors[i].src; dest = pdata->usecase[idx].vectors[i].dst; lnode = client->src_pnode[i]; src_dev = client->src_devs[i]; req_clk = client->pdata->usecase[idx].vectors[i].ib; req_bw = client->pdata->usecase[idx].vectors[i].ab; if (cur_idx < 0) { curr_clk = 0; curr_bw = 0; } else { curr_clk = client->pdata->usecase[cur_idx].vectors[i].ib; curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab; MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__, curr_bw, curr_clk); } if (pdata->active_only) { slp_clk = 0; slp_bw = 0; } else { slp_clk = req_clk; slp_bw = req_bw; } ret = update_path(src_dev, dest, req_clk, req_bw, slp_clk, slp_bw, curr_clk, curr_bw, lnode, pdata->active_only); if (ret) { MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n", __func__, ret, pdata->active_only); goto exit_update_client_paths; } if (log_trns) getpath_debug(src, lnode, pdata->active_only); } commit_data(); exit_update_client_paths: return ret; } static int update_context(uint32_t cl, bool active_only, unsigned int ctx_idx) { Loading drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c +366 −2 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ static struct handle_type handle_list; static LIST_HEAD(input_list); static LIST_HEAD(apply_list); static LIST_HEAD(commit_list); static LIST_HEAD(query_list); DEFINE_RT_MUTEX(msm_bus_adhoc_lock); Loading Loading @@ -537,6 +538,74 @@ static void bcm_update_bus_req(struct device *dev, int ctx) return; } static void bcm_query_bus_req(struct device *dev, int ctx) { struct msm_bus_node_device_type *cur_dev = NULL; struct msm_bus_node_device_type *bcm_dev = NULL; int i; uint64_t max_query_ib = 0; uint64_t max_query_ab = 0; int lnode_idx = 0; cur_dev = to_msm_bus_node(dev); if (!cur_dev) { MSM_BUS_ERR("%s: Null device ptr", __func__); goto exit_bcm_query_bus_req; } if (!cur_dev->node_info->num_bcm_devs) goto exit_bcm_query_bus_req; for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) { bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]); if (!bcm_dev) goto exit_bcm_query_bus_req; lnode_idx = cur_dev->node_info->bcm_req_idx; bcm_dev->lnode_list[lnode_idx].lnode_query_ib[ctx] = msm_bus_div64(cur_dev->node_info->agg_params.buswidth, cur_dev->node_bw[ctx].max_query_ib * (uint64_t)bcm_dev->bcmdev->width); bcm_dev->lnode_list[lnode_idx].lnode_query_ab[ctx] = msm_bus_div64(cur_dev->node_info->agg_params.buswidth, cur_dev->node_bw[ctx].sum_query_ab * (uint64_t)bcm_dev->bcmdev->width); for (i = 0; i < bcm_dev->num_lnodes; i++) { if (ctx == ACTIVE_CTX) { max_query_ib = max(max_query_ib, max(bcm_dev->lnode_list[i]. lnode_query_ib[ACTIVE_CTX], bcm_dev->lnode_list[i]. lnode_query_ib[DUAL_CTX])); max_query_ab = max(max_query_ab, bcm_dev->lnode_list[i]. lnode_query_ab[ACTIVE_CTX] + bcm_dev->lnode_list[i]. lnode_query_ab[DUAL_CTX]); } else { max_query_ib = max(max_query_ib, bcm_dev->lnode_list[i]. lnode_query_ib[ctx]); max_query_ab = max(max_query_ab, bcm_dev->lnode_list[i]. lnode_query_ab[ctx]); } } bcm_dev->node_bw[ctx].max_query_ab = max_query_ab; bcm_dev->node_bw[ctx].max_query_ib = max_query_ib; } exit_bcm_query_bus_req: return; } int bcm_remove_handoff_req(struct device *dev, void *data) { struct msm_bus_node_device_type *bcm_dev = NULL; Loading Loading @@ -571,8 +640,6 @@ int bcm_remove_handoff_req(struct device *dev, void *data) return ret; } static void aggregate_bus_req(struct msm_bus_node_device_type *bus_dev, int ctx) { Loading @@ -597,6 +664,31 @@ static void aggregate_bus_req(struct msm_bus_node_device_type *bus_dev, return; } static void aggregate_bus_query_req(struct msm_bus_node_device_type *bus_dev, int ctx) { int i; uint64_t max_ib = 0; uint64_t sum_ab = 0; if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) { MSM_BUS_ERR("Bus node pointer is Invalid"); goto exit_agg_bus_req; } for (i = 0; i < bus_dev->num_lnodes; i++) { max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_query_ib[ctx]); sum_ab += bus_dev->lnode_list[i].lnode_query_ab[ctx]; } MSM_BUS_ERR("aggregate: query_ab:%llu\n", sum_ab); bus_dev->node_bw[ctx].sum_query_ab = sum_ab; bus_dev->node_bw[ctx].max_query_ib = max_ib; exit_agg_bus_req: return; } static void del_inp_list(struct list_head *list) { Loading Loading @@ -688,6 +780,14 @@ static void add_node_to_clist(struct msm_bus_node_device_type *node) } } static void add_node_to_query_list(struct msm_bus_node_device_type *node) { if (!node->query_dirty) { list_add_tail(&node->query_link, &query_list); node->query_dirty = true; } } static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib, uint64_t act_req_bw, uint64_t slp_req_ib, uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw, Loading Loading @@ -768,6 +868,71 @@ static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib, return ret; } static int query_path(struct device *src_dev, int dest, uint64_t act_req_ib, uint64_t act_req_bw, uint64_t slp_req_ib, uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw, int src_idx) { struct device *next_dev = NULL; struct link_node *lnode = NULL; struct msm_bus_node_device_type *dev_info = NULL; int curr_idx; int ret = 0; if (IS_ERR_OR_NULL(src_dev)) { MSM_BUS_ERR("%s: No source device", __func__); ret = -ENODEV; goto exit_query_path; } next_dev = src_dev; if (src_idx < 0) { MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx); ret = -ENXIO; goto exit_query_path; } curr_idx = src_idx; while (next_dev) { int i; dev_info = to_msm_bus_node(next_dev); if (curr_idx >= dev_info->num_lnodes) { MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d", __func__, curr_idx, dev_info->num_lnodes); ret = -ENXIO; goto exit_query_path; } lnode = &dev_info->lnode_list[curr_idx]; if (!lnode) { MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d", __func__, curr_idx); ret = -ENXIO; goto exit_query_path; } lnode->lnode_query_ib[ACTIVE_CTX] = act_req_ib; lnode->lnode_query_ab[ACTIVE_CTX] = act_req_bw; lnode->lnode_query_ib[DUAL_CTX] = slp_req_ib; lnode->lnode_query_ab[DUAL_CTX] = slp_req_bw; for (i = 0; i < NUM_CTX; i++) { aggregate_bus_query_req(dev_info, i); bcm_query_bus_req(next_dev, i); } add_node_to_query_list(dev_info); next_dev = lnode->next_dev; curr_idx = lnode->next; } exit_query_path: return ret; } static int remove_path(struct device *src_dev, int dst, uint64_t cur_ib, uint64_t cur_ab, int src_idx, int active_only) { Loading Loading @@ -1126,6 +1291,92 @@ static int update_client_paths(struct msm_bus_client *client, bool log_trns, return ret; } static int query_usecase(struct msm_bus_client *client, bool log_trns, unsigned int idx, struct msm_bus_tcs_usecase *tcs_usecase) { int lnode, src, dest, cur_idx; uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw; int i, ret = 0; struct msm_bus_scale_pdata *pdata; struct device *src_dev; struct msm_bus_node_device_type *node = NULL; struct msm_bus_node_device_type *node_tmp = NULL; if (!client) { MSM_BUS_ERR("Client handle Null"); ret = -ENXIO; goto exit_query_usecase; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("Client pdata Null"); ret = -ENXIO; goto exit_query_usecase; } cur_idx = client->curr; client->curr = idx; for (i = 0; i < pdata->usecase->num_paths; i++) { src = pdata->usecase[idx].vectors[i].src; dest = pdata->usecase[idx].vectors[i].dst; lnode = client->src_pnode[i]; src_dev = client->src_devs[i]; req_clk = client->pdata->usecase[idx].vectors[i].ib; req_bw = client->pdata->usecase[idx].vectors[i].ab; if (cur_idx < 0) { curr_clk = 0; curr_bw = 0; } else { curr_clk = client->pdata->usecase[cur_idx].vectors[i].ib; curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab; MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__, curr_bw, curr_clk); } ret = query_path(src_dev, dest, req_clk, req_bw, slp_clk, slp_bw, curr_clk, curr_bw, lnode); if (ret) { MSM_BUS_ERR("%s: Query path failed! %d ctx %d\n", __func__, ret, pdata->active_only); goto exit_query_usecase; } } msm_bus_query_gen(&query_list, tcs_usecase); INIT_LIST_HEAD(&query_list); for (i = 0; i < pdata->usecase->num_paths; i++) { src = pdata->usecase[idx].vectors[i].src; dest = pdata->usecase[idx].vectors[i].dst; lnode = client->src_pnode[i]; src_dev = client->src_devs[i]; ret = query_path(src_dev, dest, 0, 0, 0, 0, curr_clk, curr_bw, lnode); if (ret) { MSM_BUS_ERR("%s: Clear query path failed! %d ctx %d\n", __func__, ret, pdata->active_only); goto exit_query_usecase; } } list_for_each_entry_safe(node, node_tmp, &query_list, query_link) { node->query_dirty = false; list_del_init(&node->query_link); } INIT_LIST_HEAD(&query_list); exit_query_usecase: return ret; } static int update_context(uint32_t cl, bool active_only, unsigned int ctx_idx) { Loading Loading @@ -1244,6 +1495,117 @@ static int update_request_adhoc(uint32_t cl, unsigned int index) return ret; } static int query_client_usecase(struct msm_bus_tcs_usecase *tcs_usecase, uint32_t cl, unsigned int index) { int ret = 0; struct msm_bus_scale_pdata *pdata; struct msm_bus_client *client; const char *test_cl = "Null"; bool log_transaction = false; rt_mutex_lock(&msm_bus_adhoc_lock); if (!cl) { MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl); ret = -ENXIO; goto exit_query_client_usecase; } client = handle_list.cl_list[cl]; if (!client) { MSM_BUS_ERR("%s: Invalid client pointer ", __func__); ret = -ENXIO; goto exit_query_client_usecase; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("%s: Client data Null.[client didn't register]", __func__); ret = -ENXIO; goto exit_query_client_usecase; } if (index >= pdata->num_usecases) { MSM_BUS_ERR("Client %u passed invalid index: %d\n", cl, index); ret = -ENXIO; goto exit_query_client_usecase; } if (!strcmp(test_cl, pdata->name)) log_transaction = true; MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__, cl, index, client->curr, client->pdata->usecase->num_paths); ret = query_usecase(client, log_transaction, index, tcs_usecase); if (ret) { pr_err("%s: Err updating path\n", __func__); goto exit_query_client_usecase; } // trace_bus_update_request_end(pdata->name); exit_query_client_usecase: rt_mutex_unlock(&msm_bus_adhoc_lock); return ret; } static int query_client_usecase_all(struct msm_bus_tcs_handle *tcs_handle, uint32_t cl) { int ret = 0; struct msm_bus_scale_pdata *pdata; struct msm_bus_client *client; const char *test_cl = "Null"; bool log_transaction = false; int i = 0; rt_mutex_lock(&msm_bus_adhoc_lock); if (!cl) { MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl); ret = -ENXIO; goto exit_query_client_usecase_all; } client = handle_list.cl_list[cl]; if (!client) { MSM_BUS_ERR("%s: Invalid client pointer ", __func__); ret = -ENXIO; goto exit_query_client_usecase_all; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("%s: Client data Null.[client didn't register]", __func__); ret = -ENXIO; goto exit_query_client_usecase_all; } if (!strcmp(test_cl, pdata->name)) log_transaction = true; MSM_BUS_ERR("%s: query_start", __func__); for (i = 0; i < pdata->num_usecases; i++) query_usecase(client, log_transaction, i, &tcs_handle->usecases[i]); tcs_handle->num_usecases = pdata->num_usecases; if (ret) { pr_err("%s: Err updating path\n", __func__); goto exit_query_client_usecase_all; } // trace_bus_update_request_end(pdata->name); exit_query_client_usecase_all: rt_mutex_unlock(&msm_bus_adhoc_lock); return ret; } static void free_cl_mem(struct msm_bus_client_handle *cl) { if (cl) { Loading Loading @@ -1446,4 +1808,6 @@ void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops) arb_ops->unregister = unregister_adhoc; arb_ops->update_bw = update_bw_adhoc; arb_ops->update_bw_context = update_bw_context; arb_ops->query_usecase = query_client_usecase; arb_ops->query_usecase_all = query_client_usecase_all; } drivers/soc/qcom/msm_bus/msm_bus_client_api.c +39 −0 Original line number Diff line number Diff line Loading @@ -173,3 +173,42 @@ void msm_bus_scale_unregister(struct msm_bus_client_handle *cl) __func__); } EXPORT_SYMBOL(msm_bus_scale_unregister); /** * msm_bus_scale_query_tcs_cmd() - Query for a list of TCS commands for * an aggregated votes of paths from a single usecase. * * tcs_usecase: pointer to client allocated memory blob * cl: Handle to the client * index: Index into the vector, to which the bw and clock values need to be * updated */ int msm_bus_scale_query_tcs_cmd(struct msm_bus_tcs_usecase *tcs_usecase, uint32_t cl, unsigned int index) { if (arb_ops.query_usecase) return arb_ops.query_usecase(tcs_usecase, cl, index); pr_err("%s: Bus driver not ready.", __func__); return -EPROBE_DEFER; } EXPORT_SYMBOL(msm_bus_scale_query_tcs_cmd); /** * msm_bus_scale_query_tcs_cmd_all() - Query for a list of TCS commands for * an aggregated vote of paths for all usecases registered by client * * tcs_handle: pointer to client allocated memory blob * cl: Handle to the client * */ int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle *tcs_handle, uint32_t cl) { if (arb_ops.query_usecase) return arb_ops.query_usecase_all(tcs_handle, cl); pr_err("%s: Bus driver not ready.", __func__); return -EPROBE_DEFER; } EXPORT_SYMBOL(msm_bus_scale_query_tcs_cmd_all); drivers/soc/qcom/msm_bus/msm_bus_core.h +5 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,11 @@ struct msm_bus_arb_ops { void (*unregister)(struct msm_bus_client_handle *cl); int (*update_bw_context)(struct msm_bus_client_handle *cl, u64 act_ab, u64 act_ib, u64 slp_ib, u64 slp_ab); int (*query_usecase)(struct msm_bus_tcs_usecase *tcs_usecase, uint32_t cl, unsigned int index); int (*query_usecase_all)(struct msm_bus_tcs_handle *tcs_handle, uint32_t cl); }; enum { Loading drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c +117 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data); struct list_head bcm_clist_inorder[VCD_MAX_CNT]; struct list_head bcm_query_list_inorder[VCD_MAX_CNT]; static struct rpmh_client *mbox_apps; struct bcm_db { Loading Loading @@ -393,6 +394,41 @@ static int tcs_cmd_list_gen(int *n_active, return k; } static int tcs_cmd_query_list_gen(struct tcs_cmd *cmdlist_active) { struct msm_bus_node_device_type *cur_bcm = NULL; struct list_head *bcm_list_inorder = NULL; int i = 0; int k = 0; bool commit = false; int ret = 0; if (!cmdlist_active) goto exit_tcs_cmd_list_gen; bcm_list_inorder = bcm_query_list_inorder; for (i = 0; i < VCD_MAX_CNT; i++) { if (list_empty(&bcm_list_inorder[i])) continue; list_for_each_entry(cur_bcm, &bcm_list_inorder[i], query_link) { commit = false; if (list_is_last(&cur_bcm->query_link, &bcm_list_inorder[i])) { commit = true; } tcs_cmd_gen(cur_bcm, &cmdlist_active[k], cur_bcm->node_bw[ACTIVE_CTX].max_query_ib, cur_bcm->node_bw[ACTIVE_CTX].max_query_ab, commit); k++; } } exit_tcs_cmd_list_gen: return ret; } static int bcm_clist_add(struct msm_bus_node_device_type *cur_dev) { int ret = 0; Loading @@ -414,6 +450,26 @@ static int bcm_clist_add(struct msm_bus_node_device_type *cur_dev) return ret; } static int bcm_query_list_add(struct msm_bus_node_device_type *cur_dev) { int ret = 0; int cur_vcd = 0; struct msm_bus_node_device_type *cur_bcm = NULL; if (!cur_dev->node_info->num_bcm_devs) goto exit_bcm_query_list_add; cur_bcm = to_msm_bus_node(cur_dev->node_info->bcm_devs[0]); cur_vcd = cur_bcm->bcmdev->clk_domain; if (!cur_bcm->query_dirty) list_add_tail(&cur_bcm->query_link, &bcm_query_list_inorder[cur_vcd]); exit_bcm_query_list_add: return ret; } static int bcm_clist_clean(struct msm_bus_node_device_type *cur_dev) { int ret = 0; Loading @@ -436,6 +492,24 @@ static int bcm_clist_clean(struct msm_bus_node_device_type *cur_dev) return ret; } static int bcm_query_list_clean(struct msm_bus_node_device_type *cur_dev) { int ret = 0; struct msm_bus_node_device_type *cur_bcm = NULL; if (!cur_dev->node_info->num_bcm_devs) goto exit_bcm_clist_add; cur_bcm = to_msm_bus_node(cur_dev->node_info->bcm_devs[0]); MSM_BUS_ERR("%s: removing bcm %d\n", __func__, cur_bcm->node_info->id); cur_bcm->query_dirty = false; list_del_init(&cur_bcm->query_link); exit_bcm_clist_add: return ret; } int msm_bus_commit_data(struct list_head *clist) { int ret = 0; Loading Loading @@ -518,6 +592,46 @@ int msm_bus_commit_data(struct list_head *clist) return ret; } int msm_bus_query_gen(struct list_head *query_list, struct msm_bus_tcs_usecase *tcs_usecase) { int ret = 0; struct msm_bus_node_device_type *node = NULL; struct msm_bus_node_device_type *node_tmp = NULL; struct msm_bus_node_device_type *cur_bcm = NULL; int *n_active = NULL; int cnt_vcd = 0; int cnt_active = 0; int i = 0; list_for_each_entry_safe(node, node_tmp, query_list, query_link) bcm_query_list_add(node); for (i = 0; i < VCD_MAX_CNT; i++) { if (list_empty(&bcm_query_list_inorder[i])) continue; list_for_each_entry(cur_bcm, &bcm_query_list_inorder[i], query_link) { cnt_active++; } cnt_vcd++; } tcs_usecase->num_cmds = cnt_active; ret = tcs_cmd_query_list_gen(tcs_usecase->cmds); list_for_each_entry_safe(node, node_tmp, query_list, query_link) { bcm_query_list_clean(node); node->query_dirty = false; list_del_init(&node->query_link); } kfree(n_active); return ret; } void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size, size_t new_size, gfp_t flags) { Loading Loading @@ -817,8 +931,10 @@ static int msm_bus_bcm_init(struct device *dev, bcmdev->num_bus_devs = 0; // Add way to count # of VCDs, initialize LL for (i = 0; i < VCD_MAX_CNT; i++) for (i = 0; i < VCD_MAX_CNT; i++) { INIT_LIST_HEAD(&bcm_clist_inorder[i]); INIT_LIST_HEAD(&bcm_query_list_inorder[i]); } exit_bcm_init: return ret; Loading Loading
drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c +69 −0 Original line number Diff line number Diff line Loading @@ -1111,6 +1111,75 @@ static int update_client_paths(struct msm_bus_client *client, bool log_trns, return ret; } static int query_client_paths(struct msm_bus_client *client, bool log_trns, unsigned int idx) { int lnode, src, dest, cur_idx; uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw; int i, ret = 0; struct msm_bus_scale_pdata *pdata; struct device *src_dev; if (!client) { MSM_BUS_ERR("Client handle Null"); ret = -ENXIO; goto exit_update_client_paths; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("Client pdata Null"); ret = -ENXIO; goto exit_update_client_paths; } cur_idx = client->curr; client->curr = idx; for (i = 0; i < pdata->usecase->num_paths; i++) { src = pdata->usecase[idx].vectors[i].src; dest = pdata->usecase[idx].vectors[i].dst; lnode = client->src_pnode[i]; src_dev = client->src_devs[i]; req_clk = client->pdata->usecase[idx].vectors[i].ib; req_bw = client->pdata->usecase[idx].vectors[i].ab; if (cur_idx < 0) { curr_clk = 0; curr_bw = 0; } else { curr_clk = client->pdata->usecase[cur_idx].vectors[i].ib; curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab; MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__, curr_bw, curr_clk); } if (pdata->active_only) { slp_clk = 0; slp_bw = 0; } else { slp_clk = req_clk; slp_bw = req_bw; } ret = update_path(src_dev, dest, req_clk, req_bw, slp_clk, slp_bw, curr_clk, curr_bw, lnode, pdata->active_only); if (ret) { MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n", __func__, ret, pdata->active_only); goto exit_update_client_paths; } if (log_trns) getpath_debug(src, lnode, pdata->active_only); } commit_data(); exit_update_client_paths: return ret; } static int update_context(uint32_t cl, bool active_only, unsigned int ctx_idx) { Loading
drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c +366 −2 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ static struct handle_type handle_list; static LIST_HEAD(input_list); static LIST_HEAD(apply_list); static LIST_HEAD(commit_list); static LIST_HEAD(query_list); DEFINE_RT_MUTEX(msm_bus_adhoc_lock); Loading Loading @@ -537,6 +538,74 @@ static void bcm_update_bus_req(struct device *dev, int ctx) return; } static void bcm_query_bus_req(struct device *dev, int ctx) { struct msm_bus_node_device_type *cur_dev = NULL; struct msm_bus_node_device_type *bcm_dev = NULL; int i; uint64_t max_query_ib = 0; uint64_t max_query_ab = 0; int lnode_idx = 0; cur_dev = to_msm_bus_node(dev); if (!cur_dev) { MSM_BUS_ERR("%s: Null device ptr", __func__); goto exit_bcm_query_bus_req; } if (!cur_dev->node_info->num_bcm_devs) goto exit_bcm_query_bus_req; for (i = 0; i < cur_dev->node_info->num_bcm_devs; i++) { bcm_dev = to_msm_bus_node(cur_dev->node_info->bcm_devs[i]); if (!bcm_dev) goto exit_bcm_query_bus_req; lnode_idx = cur_dev->node_info->bcm_req_idx; bcm_dev->lnode_list[lnode_idx].lnode_query_ib[ctx] = msm_bus_div64(cur_dev->node_info->agg_params.buswidth, cur_dev->node_bw[ctx].max_query_ib * (uint64_t)bcm_dev->bcmdev->width); bcm_dev->lnode_list[lnode_idx].lnode_query_ab[ctx] = msm_bus_div64(cur_dev->node_info->agg_params.buswidth, cur_dev->node_bw[ctx].sum_query_ab * (uint64_t)bcm_dev->bcmdev->width); for (i = 0; i < bcm_dev->num_lnodes; i++) { if (ctx == ACTIVE_CTX) { max_query_ib = max(max_query_ib, max(bcm_dev->lnode_list[i]. lnode_query_ib[ACTIVE_CTX], bcm_dev->lnode_list[i]. lnode_query_ib[DUAL_CTX])); max_query_ab = max(max_query_ab, bcm_dev->lnode_list[i]. lnode_query_ab[ACTIVE_CTX] + bcm_dev->lnode_list[i]. lnode_query_ab[DUAL_CTX]); } else { max_query_ib = max(max_query_ib, bcm_dev->lnode_list[i]. lnode_query_ib[ctx]); max_query_ab = max(max_query_ab, bcm_dev->lnode_list[i]. lnode_query_ab[ctx]); } } bcm_dev->node_bw[ctx].max_query_ab = max_query_ab; bcm_dev->node_bw[ctx].max_query_ib = max_query_ib; } exit_bcm_query_bus_req: return; } int bcm_remove_handoff_req(struct device *dev, void *data) { struct msm_bus_node_device_type *bcm_dev = NULL; Loading Loading @@ -571,8 +640,6 @@ int bcm_remove_handoff_req(struct device *dev, void *data) return ret; } static void aggregate_bus_req(struct msm_bus_node_device_type *bus_dev, int ctx) { Loading @@ -597,6 +664,31 @@ static void aggregate_bus_req(struct msm_bus_node_device_type *bus_dev, return; } static void aggregate_bus_query_req(struct msm_bus_node_device_type *bus_dev, int ctx) { int i; uint64_t max_ib = 0; uint64_t sum_ab = 0; if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) { MSM_BUS_ERR("Bus node pointer is Invalid"); goto exit_agg_bus_req; } for (i = 0; i < bus_dev->num_lnodes; i++) { max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_query_ib[ctx]); sum_ab += bus_dev->lnode_list[i].lnode_query_ab[ctx]; } MSM_BUS_ERR("aggregate: query_ab:%llu\n", sum_ab); bus_dev->node_bw[ctx].sum_query_ab = sum_ab; bus_dev->node_bw[ctx].max_query_ib = max_ib; exit_agg_bus_req: return; } static void del_inp_list(struct list_head *list) { Loading Loading @@ -688,6 +780,14 @@ static void add_node_to_clist(struct msm_bus_node_device_type *node) } } static void add_node_to_query_list(struct msm_bus_node_device_type *node) { if (!node->query_dirty) { list_add_tail(&node->query_link, &query_list); node->query_dirty = true; } } static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib, uint64_t act_req_bw, uint64_t slp_req_ib, uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw, Loading Loading @@ -768,6 +868,71 @@ static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib, return ret; } static int query_path(struct device *src_dev, int dest, uint64_t act_req_ib, uint64_t act_req_bw, uint64_t slp_req_ib, uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw, int src_idx) { struct device *next_dev = NULL; struct link_node *lnode = NULL; struct msm_bus_node_device_type *dev_info = NULL; int curr_idx; int ret = 0; if (IS_ERR_OR_NULL(src_dev)) { MSM_BUS_ERR("%s: No source device", __func__); ret = -ENODEV; goto exit_query_path; } next_dev = src_dev; if (src_idx < 0) { MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx); ret = -ENXIO; goto exit_query_path; } curr_idx = src_idx; while (next_dev) { int i; dev_info = to_msm_bus_node(next_dev); if (curr_idx >= dev_info->num_lnodes) { MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d", __func__, curr_idx, dev_info->num_lnodes); ret = -ENXIO; goto exit_query_path; } lnode = &dev_info->lnode_list[curr_idx]; if (!lnode) { MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d", __func__, curr_idx); ret = -ENXIO; goto exit_query_path; } lnode->lnode_query_ib[ACTIVE_CTX] = act_req_ib; lnode->lnode_query_ab[ACTIVE_CTX] = act_req_bw; lnode->lnode_query_ib[DUAL_CTX] = slp_req_ib; lnode->lnode_query_ab[DUAL_CTX] = slp_req_bw; for (i = 0; i < NUM_CTX; i++) { aggregate_bus_query_req(dev_info, i); bcm_query_bus_req(next_dev, i); } add_node_to_query_list(dev_info); next_dev = lnode->next_dev; curr_idx = lnode->next; } exit_query_path: return ret; } static int remove_path(struct device *src_dev, int dst, uint64_t cur_ib, uint64_t cur_ab, int src_idx, int active_only) { Loading Loading @@ -1126,6 +1291,92 @@ static int update_client_paths(struct msm_bus_client *client, bool log_trns, return ret; } static int query_usecase(struct msm_bus_client *client, bool log_trns, unsigned int idx, struct msm_bus_tcs_usecase *tcs_usecase) { int lnode, src, dest, cur_idx; uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw; int i, ret = 0; struct msm_bus_scale_pdata *pdata; struct device *src_dev; struct msm_bus_node_device_type *node = NULL; struct msm_bus_node_device_type *node_tmp = NULL; if (!client) { MSM_BUS_ERR("Client handle Null"); ret = -ENXIO; goto exit_query_usecase; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("Client pdata Null"); ret = -ENXIO; goto exit_query_usecase; } cur_idx = client->curr; client->curr = idx; for (i = 0; i < pdata->usecase->num_paths; i++) { src = pdata->usecase[idx].vectors[i].src; dest = pdata->usecase[idx].vectors[i].dst; lnode = client->src_pnode[i]; src_dev = client->src_devs[i]; req_clk = client->pdata->usecase[idx].vectors[i].ib; req_bw = client->pdata->usecase[idx].vectors[i].ab; if (cur_idx < 0) { curr_clk = 0; curr_bw = 0; } else { curr_clk = client->pdata->usecase[cur_idx].vectors[i].ib; curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab; MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__, curr_bw, curr_clk); } ret = query_path(src_dev, dest, req_clk, req_bw, slp_clk, slp_bw, curr_clk, curr_bw, lnode); if (ret) { MSM_BUS_ERR("%s: Query path failed! %d ctx %d\n", __func__, ret, pdata->active_only); goto exit_query_usecase; } } msm_bus_query_gen(&query_list, tcs_usecase); INIT_LIST_HEAD(&query_list); for (i = 0; i < pdata->usecase->num_paths; i++) { src = pdata->usecase[idx].vectors[i].src; dest = pdata->usecase[idx].vectors[i].dst; lnode = client->src_pnode[i]; src_dev = client->src_devs[i]; ret = query_path(src_dev, dest, 0, 0, 0, 0, curr_clk, curr_bw, lnode); if (ret) { MSM_BUS_ERR("%s: Clear query path failed! %d ctx %d\n", __func__, ret, pdata->active_only); goto exit_query_usecase; } } list_for_each_entry_safe(node, node_tmp, &query_list, query_link) { node->query_dirty = false; list_del_init(&node->query_link); } INIT_LIST_HEAD(&query_list); exit_query_usecase: return ret; } static int update_context(uint32_t cl, bool active_only, unsigned int ctx_idx) { Loading Loading @@ -1244,6 +1495,117 @@ static int update_request_adhoc(uint32_t cl, unsigned int index) return ret; } static int query_client_usecase(struct msm_bus_tcs_usecase *tcs_usecase, uint32_t cl, unsigned int index) { int ret = 0; struct msm_bus_scale_pdata *pdata; struct msm_bus_client *client; const char *test_cl = "Null"; bool log_transaction = false; rt_mutex_lock(&msm_bus_adhoc_lock); if (!cl) { MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl); ret = -ENXIO; goto exit_query_client_usecase; } client = handle_list.cl_list[cl]; if (!client) { MSM_BUS_ERR("%s: Invalid client pointer ", __func__); ret = -ENXIO; goto exit_query_client_usecase; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("%s: Client data Null.[client didn't register]", __func__); ret = -ENXIO; goto exit_query_client_usecase; } if (index >= pdata->num_usecases) { MSM_BUS_ERR("Client %u passed invalid index: %d\n", cl, index); ret = -ENXIO; goto exit_query_client_usecase; } if (!strcmp(test_cl, pdata->name)) log_transaction = true; MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__, cl, index, client->curr, client->pdata->usecase->num_paths); ret = query_usecase(client, log_transaction, index, tcs_usecase); if (ret) { pr_err("%s: Err updating path\n", __func__); goto exit_query_client_usecase; } // trace_bus_update_request_end(pdata->name); exit_query_client_usecase: rt_mutex_unlock(&msm_bus_adhoc_lock); return ret; } static int query_client_usecase_all(struct msm_bus_tcs_handle *tcs_handle, uint32_t cl) { int ret = 0; struct msm_bus_scale_pdata *pdata; struct msm_bus_client *client; const char *test_cl = "Null"; bool log_transaction = false; int i = 0; rt_mutex_lock(&msm_bus_adhoc_lock); if (!cl) { MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl); ret = -ENXIO; goto exit_query_client_usecase_all; } client = handle_list.cl_list[cl]; if (!client) { MSM_BUS_ERR("%s: Invalid client pointer ", __func__); ret = -ENXIO; goto exit_query_client_usecase_all; } pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("%s: Client data Null.[client didn't register]", __func__); ret = -ENXIO; goto exit_query_client_usecase_all; } if (!strcmp(test_cl, pdata->name)) log_transaction = true; MSM_BUS_ERR("%s: query_start", __func__); for (i = 0; i < pdata->num_usecases; i++) query_usecase(client, log_transaction, i, &tcs_handle->usecases[i]); tcs_handle->num_usecases = pdata->num_usecases; if (ret) { pr_err("%s: Err updating path\n", __func__); goto exit_query_client_usecase_all; } // trace_bus_update_request_end(pdata->name); exit_query_client_usecase_all: rt_mutex_unlock(&msm_bus_adhoc_lock); return ret; } static void free_cl_mem(struct msm_bus_client_handle *cl) { if (cl) { Loading Loading @@ -1446,4 +1808,6 @@ void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops) arb_ops->unregister = unregister_adhoc; arb_ops->update_bw = update_bw_adhoc; arb_ops->update_bw_context = update_bw_context; arb_ops->query_usecase = query_client_usecase; arb_ops->query_usecase_all = query_client_usecase_all; }
drivers/soc/qcom/msm_bus/msm_bus_client_api.c +39 −0 Original line number Diff line number Diff line Loading @@ -173,3 +173,42 @@ void msm_bus_scale_unregister(struct msm_bus_client_handle *cl) __func__); } EXPORT_SYMBOL(msm_bus_scale_unregister); /** * msm_bus_scale_query_tcs_cmd() - Query for a list of TCS commands for * an aggregated votes of paths from a single usecase. * * tcs_usecase: pointer to client allocated memory blob * cl: Handle to the client * index: Index into the vector, to which the bw and clock values need to be * updated */ int msm_bus_scale_query_tcs_cmd(struct msm_bus_tcs_usecase *tcs_usecase, uint32_t cl, unsigned int index) { if (arb_ops.query_usecase) return arb_ops.query_usecase(tcs_usecase, cl, index); pr_err("%s: Bus driver not ready.", __func__); return -EPROBE_DEFER; } EXPORT_SYMBOL(msm_bus_scale_query_tcs_cmd); /** * msm_bus_scale_query_tcs_cmd_all() - Query for a list of TCS commands for * an aggregated vote of paths for all usecases registered by client * * tcs_handle: pointer to client allocated memory blob * cl: Handle to the client * */ int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle *tcs_handle, uint32_t cl) { if (arb_ops.query_usecase) return arb_ops.query_usecase_all(tcs_handle, cl); pr_err("%s: Bus driver not ready.", __func__); return -EPROBE_DEFER; } EXPORT_SYMBOL(msm_bus_scale_query_tcs_cmd_all);
drivers/soc/qcom/msm_bus/msm_bus_core.h +5 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,11 @@ struct msm_bus_arb_ops { void (*unregister)(struct msm_bus_client_handle *cl); int (*update_bw_context)(struct msm_bus_client_handle *cl, u64 act_ab, u64 act_ib, u64 slp_ib, u64 slp_ab); int (*query_usecase)(struct msm_bus_tcs_usecase *tcs_usecase, uint32_t cl, unsigned int index); int (*query_usecase_all)(struct msm_bus_tcs_handle *tcs_handle, uint32_t cl); }; enum { Loading
drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c +117 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data); struct list_head bcm_clist_inorder[VCD_MAX_CNT]; struct list_head bcm_query_list_inorder[VCD_MAX_CNT]; static struct rpmh_client *mbox_apps; struct bcm_db { Loading Loading @@ -393,6 +394,41 @@ static int tcs_cmd_list_gen(int *n_active, return k; } static int tcs_cmd_query_list_gen(struct tcs_cmd *cmdlist_active) { struct msm_bus_node_device_type *cur_bcm = NULL; struct list_head *bcm_list_inorder = NULL; int i = 0; int k = 0; bool commit = false; int ret = 0; if (!cmdlist_active) goto exit_tcs_cmd_list_gen; bcm_list_inorder = bcm_query_list_inorder; for (i = 0; i < VCD_MAX_CNT; i++) { if (list_empty(&bcm_list_inorder[i])) continue; list_for_each_entry(cur_bcm, &bcm_list_inorder[i], query_link) { commit = false; if (list_is_last(&cur_bcm->query_link, &bcm_list_inorder[i])) { commit = true; } tcs_cmd_gen(cur_bcm, &cmdlist_active[k], cur_bcm->node_bw[ACTIVE_CTX].max_query_ib, cur_bcm->node_bw[ACTIVE_CTX].max_query_ab, commit); k++; } } exit_tcs_cmd_list_gen: return ret; } static int bcm_clist_add(struct msm_bus_node_device_type *cur_dev) { int ret = 0; Loading @@ -414,6 +450,26 @@ static int bcm_clist_add(struct msm_bus_node_device_type *cur_dev) return ret; } static int bcm_query_list_add(struct msm_bus_node_device_type *cur_dev) { int ret = 0; int cur_vcd = 0; struct msm_bus_node_device_type *cur_bcm = NULL; if (!cur_dev->node_info->num_bcm_devs) goto exit_bcm_query_list_add; cur_bcm = to_msm_bus_node(cur_dev->node_info->bcm_devs[0]); cur_vcd = cur_bcm->bcmdev->clk_domain; if (!cur_bcm->query_dirty) list_add_tail(&cur_bcm->query_link, &bcm_query_list_inorder[cur_vcd]); exit_bcm_query_list_add: return ret; } static int bcm_clist_clean(struct msm_bus_node_device_type *cur_dev) { int ret = 0; Loading @@ -436,6 +492,24 @@ static int bcm_clist_clean(struct msm_bus_node_device_type *cur_dev) return ret; } static int bcm_query_list_clean(struct msm_bus_node_device_type *cur_dev) { int ret = 0; struct msm_bus_node_device_type *cur_bcm = NULL; if (!cur_dev->node_info->num_bcm_devs) goto exit_bcm_clist_add; cur_bcm = to_msm_bus_node(cur_dev->node_info->bcm_devs[0]); MSM_BUS_ERR("%s: removing bcm %d\n", __func__, cur_bcm->node_info->id); cur_bcm->query_dirty = false; list_del_init(&cur_bcm->query_link); exit_bcm_clist_add: return ret; } int msm_bus_commit_data(struct list_head *clist) { int ret = 0; Loading Loading @@ -518,6 +592,46 @@ int msm_bus_commit_data(struct list_head *clist) return ret; } int msm_bus_query_gen(struct list_head *query_list, struct msm_bus_tcs_usecase *tcs_usecase) { int ret = 0; struct msm_bus_node_device_type *node = NULL; struct msm_bus_node_device_type *node_tmp = NULL; struct msm_bus_node_device_type *cur_bcm = NULL; int *n_active = NULL; int cnt_vcd = 0; int cnt_active = 0; int i = 0; list_for_each_entry_safe(node, node_tmp, query_list, query_link) bcm_query_list_add(node); for (i = 0; i < VCD_MAX_CNT; i++) { if (list_empty(&bcm_query_list_inorder[i])) continue; list_for_each_entry(cur_bcm, &bcm_query_list_inorder[i], query_link) { cnt_active++; } cnt_vcd++; } tcs_usecase->num_cmds = cnt_active; ret = tcs_cmd_query_list_gen(tcs_usecase->cmds); list_for_each_entry_safe(node, node_tmp, query_list, query_link) { bcm_query_list_clean(node); node->query_dirty = false; list_del_init(&node->query_link); } kfree(n_active); return ret; } void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size, size_t new_size, gfp_t flags) { Loading Loading @@ -817,8 +931,10 @@ static int msm_bus_bcm_init(struct device *dev, bcmdev->num_bus_devs = 0; // Add way to count # of VCDs, initialize LL for (i = 0; i < VCD_MAX_CNT; i++) for (i = 0; i < VCD_MAX_CNT; i++) { INIT_LIST_HEAD(&bcm_clist_inorder[i]); INIT_LIST_HEAD(&bcm_query_list_inorder[i]); } exit_bcm_init: return ret; Loading