예제 #1
0
static uint64_t get_avail_bw(struct msm_bus_fabric_device *fabdev)
{
	uint64_t fabclk_rate = 0;
	int i;
	uint64_t avail_bw = 0;
	uint64_t rt_bw = get_rt_bw();
	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);

	if (!rt_bw)
		goto exit_get_avail_bw;

	for (i = 0; i < NUM_CTX; i++) {
		uint64_t ctx_rate;
		ctx_rate =
			fabric->info.nodeclk[i].rate;
		fabclk_rate = max(ctx_rate, fabclk_rate);
	}

	if (!fabdev->eff_fact || !fabdev->nr_lim_thresh) {
		MSM_BUS_ERR("Error: Eff-fact %d; nr_thresh %llu",
				fabdev->eff_fact, fabdev->nr_lim_thresh);
		return 0;
	}

	avail_bw = msm_bus_div64(100,
				(GET_BIMC_BW(fabclk_rate) * fabdev->eff_fact));

	if (avail_bw >= fabdev->nr_lim_thresh)
		return 0;

	MSM_BUS_DBG("%s: Total_avail_bw %llu, rt_bw %llu\n",
		__func__, avail_bw, rt_bw);
	trace_bus_avail_bw(avail_bw, rt_bw);

	if (avail_bw < rt_bw) {
		MSM_BUS_ERR("\n%s: ERROR avail BW %llu < MDP %llu",
			__func__, avail_bw, rt_bw);
		avail_bw = 0;
		goto exit_get_avail_bw;
	}
	avail_bw -= rt_bw;

exit_get_avail_bw:
	return avail_bw;
}
예제 #2
0
static uint64_t get_mdp_bw(void)
{
	int ids[] = {MSM_BUS_MASTER_MDP_PORT0, MSM_BUS_MASTER_MDP_PORT1};
	int i;
	uint64_t mdp_ab = 0;
	uint32_t ff = 0;

	for (i = 0; i < ARRAY_SIZE(ids); i++) {
		int iid = msm_bus_board_get_iid(ids[i]);
		int fabid;
		struct msm_bus_fabric_device *fabdev;
		struct msm_bus_inode_info *info;

		fabid = GET_FABID(iid);
		fabdev = msm_bus_get_fabric_device(fabid);
		if (!fabdev) {
			MSM_BUS_ERR("Fabric not found for: %d\n", fabid);
			continue;
		}
		info = fabdev->algo->find_node(fabdev, iid);
		if (!info) {
			MSM_BUS_ERR("%s: Can't find node %d", __func__,
								ids[i]);
			continue;
		}

		mdp_ab += get_node_sumab(info);
		MSM_BUS_DBG("mdp_ab %llu", mdp_ab);
		ff = info->node_info->ff;
	}

	if (ff) {
		mdp_ab = msm_bus_div64(2 * ff, 100 * mdp_ab);
	} else {
		MSM_BUS_ERR("MDP FF is 0");
		mdp_ab = 0;
	}


	MSM_BUS_DBG("MDP BW %llu\n", mdp_ab);
	return mdp_ab;
}
/**
 * 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;
}
예제 #4
0
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);
		}
	}
}