Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ba0a27d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: msm_bus: Introduce ALC voting" into msm-4.9

parents 34f8e211 bee66230
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -218,7 +218,16 @@ using the following properties:
				master-id, slave-id, arbitrated bandwidth
				in KBps, instantaneous bandwidth in KBps

Example:
The following are optional properties for client's device nodes:

- qcom,msm-bus,alc-voter:	Boolean alc_voter flag to indicate that client
				will vote as an Active Latency Client.
- qcom,msm-bus,vectors-alc:	Arrays of unsigned integers representing:
				first access latency, idle time in ns, this
				property is required if qcom,msm-bus,alc-voter
				is present.

Example for default client:

	qcom,msm-bus,name = "client-name";
	qcom,msm-bus,num-cases = <3>;
@@ -229,3 +238,12 @@ Example:
			<22 512 320000 3200000>, <26 512 3200000 3200000>,
			<22 512 160000 1600000>, <26 512 1600000 1600000>;

Example for ALC client:

	qcom,msm-bus,name = "client-name";
	qcom,msm-bus,num-cases = <2>;
	qcom,msm-bus,active-only;
	qcom,msm-bus,alc-voter;
	qcom,msm-bus,vectors-alc =
			<0 0>,
			<500 1600>;
+198 −9
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@
#define NUM_LNODES	3
#define MAX_STR_CL	50

#define MSM_BUS_MAS_ALC	144

struct bus_search_type {
	struct list_head link;
	struct list_head node_list;
@@ -123,6 +125,9 @@ static void bcm_add_bus_req(struct device *dev)
		goto exit_bcm_add_bus_req;
	}

	if (cur_dev->node_info->bcm_req_idx != -1)
		goto exit_bcm_add_bus_req;

	if (!cur_dev->node_info->num_bcm_devs)
		goto exit_bcm_add_bus_req;

@@ -179,8 +184,6 @@ static void bcm_add_bus_req(struct device *dev)
		cur_dev->node_info->bcm_req_idx = lnode_idx;
		memset(lnode->lnode_ib, 0, sizeof(uint64_t) * NUM_CTX);
		memset(lnode->lnode_ab, 0, sizeof(uint64_t) * NUM_CTX);
		MSM_BUS_ERR("%s: Added %d entry to bcm %d @ %d\n", __func__,
			lnode->bus_dev_id, bcm_dev->node_info->id, lnode_idx);
	}

exit_bcm_add_bus_req:
@@ -316,7 +319,6 @@ static int prune_path(struct list_head *route_list, int dest, int src,
		MSM_BUS_ERR("%s: Can't find dest dev %d", __func__, dest);
		goto exit_prune_path;
	}
	MSM_BUS_ERR("%s: dest dev %d", __func__, dest);

	lnode_hop = gen_lnode(dest_dev, search_dev_id, lnode_hop, cl_name);
	bcm_add_bus_req(dest_dev);
@@ -520,7 +522,6 @@ static void bcm_update_bus_req(struct device *dev, int ctx)
				max_ib = max(max_ib,
				max(bcm_dev->lnode_list[i].lnode_ib[ACTIVE_CTX],
				bcm_dev->lnode_list[i].lnode_ib[DUAL_CTX]));

				max_ab = max(max_ab,
				bcm_dev->lnode_list[i].lnode_ab[ACTIVE_CTX] +
				bcm_dev->lnode_list[i].lnode_ab[DUAL_CTX]);
@@ -531,9 +532,14 @@ static void bcm_update_bus_req(struct device *dev, int ctx)
					bcm_dev->lnode_list[i].lnode_ab[ctx]);
			}
		}

		bcm_dev->node_bw[ctx].max_ab = max_ab;
		bcm_dev->node_bw[ctx].max_ib = max_ib;

		max_ab = msm_bus_div64(max_ab, bcm_dev->bcmdev->unit_size);
		max_ib = msm_bus_div64(max_ib, bcm_dev->bcmdev->unit_size);

		bcm_dev->node_vec[ctx].vec_a = max_ab;
		bcm_dev->node_vec[ctx].vec_b = max_ib;
	}
exit_bcm_update_bus_req:
	return;
@@ -598,15 +604,51 @@ static void bcm_query_bus_req(struct device *dev, int ctx)
			}
		}

		max_query_ab = msm_bus_div64(max_query_ab,
						bcm_dev->bcmdev->unit_size);
		max_query_ib = msm_bus_div64(max_query_ib,
						bcm_dev->bcmdev->unit_size);

		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;
}

static void bcm_update_alc_req(struct msm_bus_node_device_type *dev, int ctx)
{
	struct msm_bus_node_device_type *bcm_dev = NULL;
	int i;
	uint64_t max_alc = 0;

	if (!dev || !to_msm_bus_node(dev->node_info->bus_device)) {
		MSM_BUS_ERR("Bus node pointer is Invalid");
		goto exit_bcm_update_alc_req;
	}

	for (i = 0; i < dev->num_lnodes; i++)
		max_alc = max(max_alc, dev->lnode_list[i].alc_idx[ctx]);

	dev->node_bw[ctx].max_alc = max_alc;

	bcm_dev = to_msm_bus_node(dev->node_info->bcm_devs[0]);

	if (ctx == ACTIVE_CTX) {
		max_alc = max(max_alc,
				max(dev->node_bw[ACTIVE_CTX].max_alc,
				dev->node_bw[DUAL_CTX].max_alc));
	} else {
		max_alc = dev->node_bw[ctx].max_alc;
	}

	bcm_dev->node_bw[ctx].max_alc = max_alc;
	bcm_dev->node_vec[ctx].vec_a = max_alc;
	bcm_dev->node_vec[ctx].vec_b = 0;

exit_bcm_update_alc_req:
	return;
}

int bcm_remove_handoff_req(struct device *dev, void *data)
{
@@ -684,7 +726,6 @@ static void aggregate_bus_query_req(struct msm_bus_node_device_type *bus_dev,
		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;

@@ -870,6 +911,63 @@ static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib,
	return ret;
}

static int update_alc_vote(struct device *alc_dev, uint64_t act_req_fa_lat,
			uint64_t act_req_idle_time, uint64_t slp_req_fa_lat,
			uint64_t slp_req_idle_time, uint64_t cur_fa_lat,
			uint64_t cur_idle_time, int idx, int ctx)
{
	struct link_node *lnode = NULL;
	struct msm_bus_node_device_type *dev_info = NULL;
	int curr_idx, i;
	int ret = 0;

	if (IS_ERR_OR_NULL(alc_dev)) {
		MSM_BUS_ERR("%s: No source device", __func__);
		ret = -ENODEV;
		goto exit_update_alc_vote;
	}

	if (idx < 0) {
		MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, idx);
		ret = -ENXIO;
		goto exit_update_alc_vote;
	}

	dev_info = to_msm_bus_node(alc_dev);
	curr_idx = idx;

	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_update_alc_vote;
	}

	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_update_alc_vote;
	}

	/*
	 * Add aggregation and mapping logic once LUT is avail.
	 * Use default values for time being.
	 */
	lnode->alc_idx[ACTIVE_CTX] = 12;
	lnode->alc_idx[DUAL_CTX] = 0;

	for (i = 0; i < NUM_CTX; i++)
		bcm_update_alc_req(dev_info, i);

	add_node_to_clist(dev_info);

exit_update_alc_vote:
	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,
@@ -1160,6 +1258,40 @@ static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata)
	}
	client->pdata = pdata;

	if (pdata->alc) {
		client->curr = -1;
		lnode = kzalloc(sizeof(int), GFP_KERNEL);

		if (ZERO_OR_NULL_PTR(lnode)) {
			MSM_BUS_ERR("%s: Error allocating lnode!", __func__);
			goto exit_lnode_malloc_fail;
		}
		client->src_pnode = lnode;

		client->src_devs = kzalloc(sizeof(struct device *),
							GFP_KERNEL);
		if (IS_ERR_OR_NULL(client->src_devs)) {
			MSM_BUS_ERR("%s: Error allocating src_dev!", __func__);
			goto exit_src_dev_malloc_fail;
		}
		src = MSM_BUS_MAS_ALC;
		dev = bus_find_device(&msm_bus_type, NULL,
				(void *) &src,
				msm_bus_device_match_adhoc);
		if (IS_ERR_OR_NULL(dev)) {
			MSM_BUS_ERR("%s:Failed to find alc device",
				__func__);
			goto exit_invalid_data;
		}
		gen_lnode(dev, MSM_BUS_MAS_ALC, 0, pdata->name);
		bcm_add_bus_req(dev);

		client->src_devs[0] = dev;

		handle = gen_handle(client);
		goto exit_register_client;
	}

	lnode = kcalloc(pdata->usecase->num_paths, sizeof(int), GFP_KERNEL);
	if (ZERO_OR_NULL_PTR(lnode)) {
		MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
@@ -1293,6 +1425,58 @@ static int update_client_paths(struct msm_bus_client *client, bool log_trns,
	return ret;
}

static int update_client_alc(struct msm_bus_client *client, bool log_trns,
							unsigned int idx)
{
	int lnode, cur_idx;
	uint64_t req_idle_time, req_fal, dual_idle_time, dual_fal,
	cur_idle_time, cur_fal;
	int 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_alc;
	}

	pdata = client->pdata;
	if (!pdata) {
		MSM_BUS_ERR("Client pdata Null");
		ret = -ENXIO;
		goto exit_update_client_alc;
	}

	cur_idx = client->curr;
	client->curr = idx;
	req_fal = pdata->usecase_lat[idx].fal_ns;
	req_idle_time = pdata->usecase_lat[idx].idle_t_ns;
	lnode = client->src_pnode[0];
	src_dev = client->src_devs[0];

	if (pdata->active_only) {
		dual_fal = 0;
		dual_idle_time = 0;
	} else {
		dual_fal = req_fal;
		dual_idle_time = req_idle_time;
	}

	ret = update_alc_vote(src_dev, req_fal, req_idle_time, dual_fal,
		dual_idle_time, cur_fal, cur_idle_time, 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_alc;
	}
	commit_data();
exit_update_client_alc:
	return ret;
}

static int query_usecase(struct msm_bus_client *client, bool log_trns,
					unsigned int idx,
					struct msm_bus_tcs_usecase *tcs_usecase)
@@ -1483,8 +1667,13 @@ static int update_request_adhoc(uint32_t cl, unsigned int index)

	MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
		cl, index, client->curr, client->pdata->usecase->num_paths);

	if (pdata->alc)
		ret = update_client_alc(client, log_transaction, index);
	else {
		msm_bus_dbg_client_data(client->pdata, index, cl);
		ret = update_client_paths(client, log_transaction, index);
	}
	if (ret) {
		pr_err("%s: Err updating path\n", __func__);
		goto exit_update_request;
+1 −2
Original line number Diff line number Diff line
/* Copyright (c) 2010-2012, 2014-2016, The Linux Foundation. All rights
/* Copyright (c) 2010-2012, 2014-2017, The Linux Foundation. All rights
 * reserved.
 *
 * This program is free software; you can redistribute it and/or modify
@@ -439,7 +439,6 @@ static void msm_bus_dbg_free_client(uint32_t clid)

	list_for_each_entry(cldata, &cl_list, list) {
		if (cldata->clid == clid) {
			debugfs_remove(cldata->file);
			list_del(&cldata->list);
			kfree(cldata);
			break;
+27 −31
Original line number Diff line number Diff line
@@ -265,27 +265,23 @@ static int setrate_nodeclk(struct nodeclk *nclk, long rate)
}

static int tcs_cmd_gen(struct msm_bus_node_device_type *cur_bcm,
				struct tcs_cmd *cmd, uint64_t ib,
					uint64_t ab, bool commit)
				struct tcs_cmd *cmd, uint64_t vec_a,
					uint64_t vec_b, bool commit)
{
	int ret = 0;
	bool valid = true;

	if (ib == 0 && ab == 0) {
	if (vec_a == 0 && vec_b == 0)
		valid = false;
	} else {
		do_div(ib, cur_bcm->bcmdev->unit_size);
		do_div(ab, cur_bcm->bcmdev->unit_size);
	}

	if (ib > BCM_TCS_CMD_VOTE_MASK)
		ib = BCM_TCS_CMD_VOTE_MASK;
	if (vec_a > BCM_TCS_CMD_VOTE_MASK)
		vec_a = BCM_TCS_CMD_VOTE_MASK;

	if (ab > BCM_TCS_CMD_VOTE_MASK)
		ab = BCM_TCS_CMD_VOTE_MASK;
	if (vec_b > BCM_TCS_CMD_VOTE_MASK)
		vec_b = BCM_TCS_CMD_VOTE_MASK;

	cmd->addr = cur_bcm->bcmdev->addr;
	cmd->data = BCM_TCS_CMD(commit, valid, ab, ib);
	cmd->data = BCM_TCS_CMD(commit, valid, vec_a, vec_b);
	cmd->complete = commit;

	return ret;
@@ -333,8 +329,8 @@ static int tcs_cmd_list_gen(int *n_active,
				idx++;
			}
			tcs_cmd_gen(cur_bcm, &cmdlist_active[k],
				cur_bcm->node_bw[ACTIVE_CTX].max_ib,
				cur_bcm->node_bw[ACTIVE_CTX].max_ab, commit);
				cur_bcm->node_vec[ACTIVE_CTX].vec_a,
				cur_bcm->node_vec[ACTIVE_CTX].vec_b, commit);
			k++;
			last_tcs = k;
			cur_bcm->updated = true;
@@ -352,10 +348,10 @@ static int tcs_cmd_list_gen(int *n_active,
			continue;
		list_for_each_entry(cur_bcm, &cur_bcm_clist[i], link) {
			commit = false;
			if ((cur_bcm->node_bw[DUAL_CTX].max_ab ==
				cur_bcm->node_bw[ACTIVE_CTX].max_ab) &&
				(cur_bcm->node_bw[DUAL_CTX].max_ib ==
				cur_bcm->node_bw[ACTIVE_CTX].max_ib)) {
			if ((cur_bcm->node_vec[DUAL_CTX].vec_a ==
				cur_bcm->node_vec[ACTIVE_CTX].vec_a) &&
				(cur_bcm->node_vec[DUAL_CTX].vec_b ==
				cur_bcm->node_vec[ACTIVE_CTX].vec_b)) {
				if (last_tcs != -1 &&
					list_is_last(&cur_bcm->link,
					&cur_bcm_clist[i])) {
@@ -378,11 +374,11 @@ static int tcs_cmd_list_gen(int *n_active,
			}

			tcs_cmd_gen(cur_bcm, &cmdlist_wake[k],
				cur_bcm->node_bw[ACTIVE_CTX].max_ib,
				cur_bcm->node_bw[ACTIVE_CTX].max_ab, commit);
				cur_bcm->node_vec[ACTIVE_CTX].vec_a,
				cur_bcm->node_vec[ACTIVE_CTX].vec_b, commit);
			tcs_cmd_gen(cur_bcm, &cmdlist_sleep[k],
				cur_bcm->node_bw[DUAL_CTX].max_ib,
				cur_bcm->node_bw[DUAL_CTX].max_ab, commit);
				cur_bcm->node_vec[DUAL_CTX].vec_a,
				cur_bcm->node_vec[DUAL_CTX].vec_b, commit);
			k++;
		}
	}
@@ -485,10 +481,10 @@ static int bcm_clist_clean(struct msm_bus_node_device_type *cur_dev)

	cur_bcm = to_msm_bus_node(cur_dev->node_info->bcm_devs[0]);

	if (cur_bcm->node_bw[DUAL_CTX].max_ab == 0 &&
			cur_bcm->node_bw[ACTIVE_CTX].max_ab == 0 &&
			cur_bcm->node_bw[DUAL_CTX].max_ib == 0 &&
			cur_bcm->node_bw[ACTIVE_CTX].max_ib == 0) {
	if (cur_bcm->node_vec[DUAL_CTX].vec_a == 0 &&
			cur_bcm->node_vec[ACTIVE_CTX].vec_a == 0 &&
			cur_bcm->node_vec[DUAL_CTX].vec_b == 0 &&
			cur_bcm->node_vec[ACTIVE_CTX].vec_b == 0) {
		cur_bcm->dirty = false;
		list_del_init(&cur_bcm->link);
	}
@@ -550,10 +546,10 @@ int msm_bus_commit_data(struct list_head *clist)
		if (list_empty(&cur_bcm_clist[i]))
			continue;
		list_for_each_entry(cur_bcm, &cur_bcm_clist[i], link) {
			if ((cur_bcm->node_bw[DUAL_CTX].max_ab !=
				cur_bcm->node_bw[ACTIVE_CTX].max_ab) ||
				(cur_bcm->node_bw[DUAL_CTX].max_ib !=
				cur_bcm->node_bw[ACTIVE_CTX].max_ib)) {
			if ((cur_bcm->node_vec[DUAL_CTX].vec_a !=
				cur_bcm->node_vec[ACTIVE_CTX].vec_a) ||
				(cur_bcm->node_vec[DUAL_CTX].vec_b !=
				cur_bcm->node_vec[ACTIVE_CTX].vec_b)) {
				cnt_sleep++;
				cnt_wake++;
			}
@@ -563,7 +559,6 @@ int msm_bus_commit_data(struct list_head *clist)
		cnt_vcd++;
	}

	MSM_BUS_ERR("%s: cmd_gen\n", __func__);
	n_active = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
	n_wake = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
	n_sleep = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
@@ -1086,6 +1081,7 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata,

	node_info->name = pdata_node_info->name;
	node_info->id =  pdata_node_info->id;
	node_info->bcm_req_idx = -1;
	node_info->bus_device_id = pdata_node_info->bus_device_id;
	node_info->mas_rpm_id = pdata_node_info->mas_rpm_id;
	node_info->slv_rpm_id = pdata_node_info->slv_rpm_id;
+38 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -46,6 +46,7 @@ static struct msm_bus_scale_pdata *get_pdata(struct platform_device *pdev,
{
	struct msm_bus_scale_pdata *pdata = NULL;
	struct msm_bus_paths *usecase = NULL;
	struct msm_bus_lat_vectors *usecase_lat = NULL;
	int i = 0, j, ret, num_usecases = 0, num_paths, len;
	const uint32_t *vec_arr = NULL;
	bool mem_err = false;
@@ -85,6 +86,42 @@ static struct msm_bus_scale_pdata *get_pdata(struct platform_device *pdev,
		pr_debug("Using dual context by default\n");
	}

	pdata->alc = of_property_read_bool(of_node, "qcom,msm-bus,alc-voter");

	if (pdata->alc) {
		usecase_lat = devm_kzalloc(&pdev->dev,
				(sizeof(struct msm_bus_lat_vectors) *
				pdata->num_usecases), GFP_KERNEL);
		if (!usecase_lat) {
			mem_err = true;
			goto err;
		}

		vec_arr = of_get_property(of_node,
					"qcom,msm-bus,vectors-alc", &len);
		if (vec_arr == NULL) {
			pr_err("Error: Lat vector array not found\n");
			goto err;
		}

		if (len != num_usecases * sizeof(uint32_t) * 2) {
			pr_err("Error: Length-error on getting vectors\n");
			goto err;
		}

		for (i = 0; i < num_usecases; i++) {
			int index = i * 2;

			usecase_lat[i].fal_ns = (uint64_t)
				KBTOB(be32_to_cpu(vec_arr[index]));
			usecase_lat[i].idle_t_ns = (uint64_t)
				KBTOB(be32_to_cpu(vec_arr[index + 1]));
		}

		pdata->usecase_lat = usecase_lat;
		return pdata;
	}

	usecase = devm_kzalloc(&pdev->dev, (sizeof(struct msm_bus_paths) *
		pdata->num_usecases), GFP_KERNEL);
	if (!usecase) {
Loading