/** * update_path() - Update the path with the bandwidth and clock values, as * requested by the client. * * @curr: Current source node, as specified in the client vector (master) * @pnode: The first-hop node on the path, stored in the internal client struct * @req_clk: Requested clock value from the vector * @req_bw: Requested bandwidth value from the vector * @curr_clk: Current clock frequency * @curr_bw: Currently allocated bandwidth * * This function updates the nodes on the path calculated using getpath(), with * clock and bandwidth values. The sum of bandwidths, and the max of clock * frequencies is calculated at each node on the path. Commit data to be sent * to RPM for each master and slave is also calculated here. */ static int update_path(int curr, int pnode, uint64_t req_clk, uint64_t req_bw, uint64_t curr_clk, uint64_t curr_bw, unsigned int ctx, unsigned int cl_active_flag) { int index, ret = 0; struct msm_bus_inode_info *info; int next_pnode; int64_t add_bw = req_bw - curr_bw; uint64_t bwsum = 0; uint64_t req_clk_hz, curr_clk_hz, bwsum_hz; int *master_tiers; struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device (GET_FABID(curr)); if (!fabdev) { MSM_BUS_ERR("Bus device for bus ID: %d not found!\n", GET_FABID(curr)); return -ENXIO; } MSM_BUS_DBG("args: %d %d %d %llu %llu %llu %llu %u\n", curr, GET_NODE(pnode), GET_INDEX(pnode), req_clk, req_bw, curr_clk, curr_bw, ctx); index = GET_INDEX(pnode); MSM_BUS_DBG("Client passed index :%d\n", index); info = fabdev->algo->find_node(fabdev, curr); if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); return -ENXIO; } #ifndef CONFIG_BW_LIMITER_FIX /** * If master supports dual configuration, check if * the configuration needs to be changed based on * incoming requests */ if (info->node_info->dual_conf) fabdev->algo->config_master(fabdev, info, req_clk, req_bw); #endif info->link_info.sel_bw = &info->link_info.bw[ctx]; info->link_info.sel_clk = &info->link_info.clk[ctx]; *info->link_info.sel_bw += add_bw; info->pnode[index].sel_bw = &info->pnode[index].bw[ctx]; /** * To select the right clock, AND the context with * client active flag. */ info->pnode[index].sel_clk = &info->pnode[index].clk[ctx & cl_active_flag]; *info->pnode[index].sel_bw += add_bw; #ifdef CONFIG_BW_LIMITER_FIX *info->pnode[index].sel_clk = req_clk; /** * If master supports dual configuration, check if * the configuration needs to be changed based on * incoming requests */ if (info->node_info->dual_conf) { uint64_t node_maxib = 0; node_maxib = get_node_maxib(info); fabdev->algo->config_master(fabdev, info, node_maxib, req_bw); } #endif info->link_info.num_tiers = info->node_info->num_tiers; info->link_info.tier = info->node_info->tier; master_tiers = info->node_info->tier; do { struct msm_bus_inode_info *hop; fabdev = msm_bus_get_fabric_device(GET_FABID(curr)); if (!fabdev) { MSM_BUS_ERR("Fabric not found\n"); return -ENXIO; } MSM_BUS_DBG("id: %d\n", info->node_info->priv_id); /* find next node and index */ next_pnode = info->pnode[index].next; curr = GET_NODE(next_pnode); index = GET_INDEX(next_pnode); MSM_BUS_DBG("id:%d, next: %d\n", info-> node_info->priv_id, curr); /* Get hop */ /* check if we are here as gateway, or does the hop belong to * this fabric */ if (IS_NODE(curr)) hop = fabdev->algo->find_node(fabdev, curr); else hop = fabdev->algo->find_gw_node(fabdev, curr); if (!hop) { MSM_BUS_ERR("Null Info found for hop\n"); return -ENXIO; } hop->link_info.sel_bw = &hop->link_info.bw[ctx]; hop->link_info.sel_clk = &hop->link_info.clk[ctx]; *hop->link_info.sel_bw += add_bw; hop->pnode[index].sel_bw = &hop->pnode[index].bw[ctx]; hop->pnode[index].sel_clk = &hop->pnode[index].clk[ctx & cl_active_flag]; if (!hop->node_info->buswidth) { MSM_BUS_WARN("No bus width found. Using default\n"); hop->node_info->buswidth = 8; } *hop->pnode[index].sel_clk = BW_TO_CLK_FREQ_HZ(hop->node_info-> buswidth, req_clk); *hop->pnode[index].sel_bw += add_bw; MSM_BUS_DBG("fabric: %d slave: %d, slave-width: %d info: %d\n", fabdev->id, hop->node_info->priv_id, hop->node_info-> buswidth, info->node_info->priv_id); /* Update Bandwidth */ fabdev->algo->update_bw(fabdev, hop, info, add_bw, master_tiers, ctx); bwsum = *hop->link_info.sel_bw; /* Update Fabric clocks */ curr_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, curr_clk); req_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, req_clk); bwsum_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, bwsum); /* Account for multiple channels if any */ if (hop->node_info->num_sports > 1) bwsum_hz = msm_bus_div64(hop->node_info->num_sports, bwsum_hz); MSM_BUS_DBG("AXI: Hop: %d, ports: %d, bwsum_hz: %llu\n", hop->node_info->id, hop->node_info->num_sports, bwsum_hz); MSM_BUS_DBG("up-clk: curr_hz: %llu, req_hz: %llu, bw_hz %llu\n", curr_clk, req_clk, bwsum_hz); ret = fabdev->algo->update_clks(fabdev, hop, index, curr_clk_hz, req_clk_hz, bwsum_hz, SEL_FAB_CLK, ctx, cl_active_flag); if (ret) MSM_BUS_WARN("Failed to update clk\n"); info = hop; } while (GET_NODE(info->pnode[index].next) != info->node_info->priv_id); /* Update BW, clk after exiting the loop for the last one */ if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); return -ENXIO; } /* Update slave clocks */ ret = fabdev->algo->update_clks(fabdev, info, index, curr_clk_hz, req_clk_hz, bwsum_hz, SEL_SLAVE_CLK, ctx, cl_active_flag); if (ret) MSM_BUS_ERR("Failed to update clk\n"); return ret; }
static void compute_nr_limits(struct msm_bus_fabric_device *fabdev, int pnode) { uint64_t total_ib = 0; int num_nr_lim = 0; uint64_t avail_bw = 0; struct msm_bus_inode_info *info[fabdev->num_nr_lim]; struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev); int i; num_nr_lim = radix_tree_gang_lookup_tag(&fabric->fab_tree, (void **)&info, fabric->fabdev.id, fabdev->num_nr_lim, MASTER_NODE); MSM_BUS_DBG("%s: Found %d NR LIM nodes", __func__, num_nr_lim); for (i = 0; i < num_nr_lim; i++) total_ib += get_node_maxib(info[i]); avail_bw = get_avail_bw(fabdev); MSM_BUS_DBG("\n %s: Avail BW %llu", __func__, avail_bw); for (i = 0; i < num_nr_lim; i++) { uint32_t node_pct = 0; uint64_t new_lim_bw = 0; uint64_t node_max_ib = 0; uint32_t node_max_ib_kB = 0; uint32_t total_ib_kB = 0; uint64_t bw_node; node_max_ib = get_node_maxib(info[i]); node_max_ib_kB = msm_bus_div64(1024, node_max_ib); total_ib_kB = msm_bus_div64(1024, total_ib); node_pct = (node_max_ib_kB * 100) / total_ib_kB; bw_node = node_pct * avail_bw; new_lim_bw = msm_bus_div64(100, bw_node); /* * if limiter bw is more than the requested IB clip to requested IB. */ if (new_lim_bw >= node_max_ib) new_lim_bw = node_max_ib; /* * if there is a floor bw for this nr lim node and * if there is available bw to divy up among the nr masters * and if the nr lim masters have a non zero vote and * if the limited bw is below the floor for this node. * then limit this node to the floor bw. */ if (info[i]->node_info->floor_bw && node_max_ib && avail_bw && (new_lim_bw <= info[i]->node_info->floor_bw)) { MSM_BUS_ERR("\nNode %d:Limiting BW:%llu < floor:%llu", info[i]->node_info->id, new_lim_bw, info[i]->node_info->floor_bw); new_lim_bw = info[i]->node_info->floor_bw; } if (new_lim_bw != info[i]->cur_lim_bw) { info[i]->cur_lim_bw = new_lim_bw; MSM_BUS_DBG("NodeId %d: Requested IB %llu", info[i]->node_info->id, node_max_ib); MSM_BUS_DBG("Limited to %llu(%d pct of Avail %llu )\n", new_lim_bw, node_pct, avail_bw); } else { MSM_BUS_DBG("NodeId %d: No change Limited to %llu\n", info[i]->node_info->id, info[i]->cur_lim_bw); } } }