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

Commit 69a22b2d 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: Add support for multiple ops in rules engine"

parents 826b2541 d6617258
Loading
Loading
Loading
Loading
+18 −13
Original line number Diff line number Diff line
@@ -16,17 +16,18 @@ conditions to be monitored. The mandatory properties for the rules are

- qcom,src-nodes:		An array of phandles denoting the source nodes
				whose bandwidth votes need to be monitored.
- qcom,src-field:		This field represents the voted field of the
				source node to be monitored. Possible values
				are FLD_IB/FLD_AB/FLD_CLK
- qcom,src-op:			The operand to be used when evaluating a node's
				bandwidth vote with a threshold.Possible values
				are OP_LE/OP_LT/OP_GT/OP_GE.
- qcom,thresh:			The threshold in Kbytes/s to be used in vote
				evaluation.
- qcom,src-field:		An array of fields represents the voted field
				of the source node to be monitored. Possible
				values are FLD_IB/FLD_AB/FLD_CLK.
- qcom,src-op:			An array of operands to be used when evaluating
				a node's bandwidth vote with a threshold.
				Possible values are OP_LE/OP_LT/OP_GT/OP_GE.
- qcom,thresh:			An array of thresholds in Kbytes/s
				(in FLD_IB/FLD_AB case) or KHz (in FLD_CLK case)
				to be used in vote evaluation.
- qcom,mode:			The QoS mode to be applied when this rule's
				criterion are satisfied. Possible values are
				THROTTLE_ON/THROTTLE_OFF
				THROTTLE_ON/THROTTLE_OFF.
- qcom,dest-node:		An array of phandles representing the nodes to
				which the QoS mode is to be applied.

@@ -34,6 +35,9 @@ The optional properties for the rule node are:
- qcom,dest-bw:			The destination bandwidth value in Kbytes/s to
				be used toward the QoS mode for the destination
				node.
- qcom,combo-op:		A property that is only required when there
				are multiple comparison operands to multiple
				thresholds, can be OP_AND or OP_OR.

Example:
	static-rules {
@@ -42,13 +46,14 @@ Example:
		#size-cells = <0>;

		rule@0 {
			qcom,src-nodes = <&mas_apss>;
			qcom,src-field = <FLD_IB>;
			qcom,src-op = <OP_LE>;
			qcom,thresh = <1599078>;
			qcom,src-nodes = <&mas_apss &mas_mdp>;
			qcom,src-field = <FLD_IB FLD_AB>;
			qcom,src-op = <OP_LE OP_GT>;
			qcom,thresh = <1599078 0>;
			qcom,mode = <THROTTLE_ON>;
			qcom,dest-node = <&mas_apss>;
			qcom,dest-bw = <1599078>;
			qcom,combo-op = <OP_AND>;
		};

		rule@1 {
+69 −20
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, 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
@@ -808,6 +808,9 @@ int msm_bus_of_get_static_rules(struct platform_device *pdev,
	int bw_fld = 0;
	int i;
	struct bus_rule_type *local_rule = NULL;
	int *thresh_arr = NULL;
	int num_op = 0;
	int num_fld = 0;

	of_node = pdev->dev.of_node;
	num_rules = of_get_child_count(of_node);
@@ -832,37 +835,58 @@ int msm_bus_of_get_static_rules(struct platform_device *pdev,
			&local_rule[rule_idx].num_dst,
			"qcom,dest-node");

		ret = of_property_read_u32(child_node, "qcom,src-field",
				&local_rule[rule_idx].src_field);
		if (ret) {
			dev_err(&pdev->dev, "src-field missing");
		if (local_rule[rule_idx].num_dst > 1) {
			dev_err(&pdev->dev, "Only 1 dest node supported\n");
			ret = -ENXIO;
			goto err_static_rules;
		}

		ret = of_property_read_u32(child_node, "qcom,src-op",
				&local_rule[rule_idx].op);
		if (ret) {
			dev_err(&pdev->dev, "src-op missing");
		thresh_arr = get_arr(pdev, child_node,
				"qcom,thresh",
				&local_rule[rule_idx].num_thresh);

		if (!local_rule[rule_idx].num_thresh ||
				((local_rule[rule_idx].num_thresh > 1) &&
				 local_rule[rule_idx].num_thresh !=
				 local_rule[rule_idx].num_src)) {
			dev_err(&pdev->dev, "thresholds missing");
			ret = -ENXIO;
			goto err_static_rules;
		} else {
			int i;

			local_rule[rule_idx].thresh =
				devm_kzalloc(&pdev->dev,
				sizeof(u64) * local_rule[rule_idx].num_thresh,
				GFP_KERNEL);
			if (!IS_ERR_OR_NULL(thresh_arr)) {
				for (i = 0;
				    i < local_rule[rule_idx].num_thresh; ++i)
					local_rule[rule_idx].thresh[i] =
						KBTOB(thresh_arr[i]);
			}
		}

		ret = of_property_read_u32(child_node, "qcom,mode",
				&local_rule[rule_idx].mode);
		if (ret) {
			dev_err(&pdev->dev, "mode missing");
		local_rule[rule_idx].src_field = get_arr(pdev, child_node,
				"qcom,src-field", &num_fld);
		if (!num_fld || (num_fld != local_rule[rule_idx].num_thresh)) {
			dev_err(&pdev->dev, "src-field missing");
			ret = -ENXIO;
			goto err_static_rules;
		}

		ret = of_property_read_u32(child_node, "qcom,thresh", &bw_fld);
		if (ret) {
			dev_err(&pdev->dev, "thresh missing");
		local_rule[rule_idx].op = get_arr(pdev, child_node,
				"qcom,src-op", &num_op);
		if (!num_op || (num_op != local_rule[rule_idx].num_thresh)) {
			dev_err(&pdev->dev, "src-op missing");
			ret = -ENXIO;
			goto err_static_rules;
		} else
			local_rule[rule_idx].thresh = KBTOB(bw_fld);
		}

		ret = of_property_read_u32(child_node, "qcom,mode",
				&local_rule[rule_idx].mode);
		if (ret)
			local_rule[rule_idx].mode = THROTTLE_OFF;

		ret = of_property_read_u32(child_node, "qcom,dest-bw",
								&bw_fld);
@@ -871,9 +895,21 @@ int msm_bus_of_get_static_rules(struct platform_device *pdev,
		else
			local_rule[rule_idx].dst_bw = KBTOB(bw_fld);

		rule_idx++;
		ret = of_property_read_u32(child_node, "qcom,combo-op",
				&local_rule[rule_idx].combo_op);
		if (ret) {
			if (local_rule[rule_idx].num_thresh > 1) {
				dev_err(&pdev->dev, "combo-op missing");
				ret = -ENXIO;
				goto err_static_rules;
			} else
				local_rule[rule_idx].combo_op = 0;
		}

		++rule_idx;
	}
	ret = rule_idx;

exit_static_rules:
	return ret;
err_static_rules:
@@ -885,9 +921,22 @@ err_static_rules:
			if (!IS_ERR_OR_NULL(local_rule[i].dst_node))
				devm_kfree(&pdev->dev,
						local_rule[i].dst_node);
			devm_kfree(&pdev->dev, local_rule);
			if (!IS_ERR_OR_NULL(thresh_arr))
				devm_kfree(&pdev->dev, thresh_arr);
			if (!IS_ERR_OR_NULL(local_rule[i].thresh))
				devm_kfree(&pdev->dev,
						local_rule[i].thresh);
			if (!IS_ERR_OR_NULL(local_rule[i].op))
				devm_kfree(&pdev->dev,
						local_rule[i].op);
			if (!IS_ERR_OR_NULL(local_rule[i].src_field))
				devm_kfree(&pdev->dev,
						local_rule[i].src_field);
			if (!IS_ERR_OR_NULL(thresh_arr))
				devm_kfree(&pdev->dev, thresh_arr);
		}
	}
	devm_kfree(&pdev->dev, local_rule);
	*static_rules = NULL;
	return ret;
}
+114 −77
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, 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
@@ -128,9 +128,6 @@ static bool do_compare_op(u64 op1, u64 op2, int op)
	case OP_GE:
		ret = GE(op1, op2);
		break;
	case OP_NOOP:
		ret = true;
		break;
	default:
		pr_info("Invalid OP %d", op);
		break;
@@ -155,13 +152,13 @@ static void update_src_id_vote(struct rule_update_path_info *inp_node,
	}
}

static u64 get_field(struct rules_def *rule, int src_id)
static u64 get_sum_field(struct rules_def *rule)
{
	u64 field = 0;
	int i;

	for (i = 0; i < rule->num_src; i++) {
		switch (rule->rule_ops.src_field) {
		switch (rule->rule_ops.src_field[0]) {
		case FLD_IB:
			field += rule->src_info[i].ib;
			break;
@@ -177,28 +174,58 @@ static u64 get_field(struct rules_def *rule, int src_id)
	return field;
}

static bool check_rule(struct rules_def *rule,
			struct rule_update_path_info *inp)
static u64 get_field(struct rules_def *rule, int src_id)
{
	u64 field = 0;
	int i;

	for (i = 0; i < rule->num_src; i++) {
		if (rule->src_info[i].id == src_id) {
			switch (rule->rule_ops.src_field[i]) {
			case FLD_IB:
				field = rule->src_info[i].ib;
				break;
			case FLD_AB:
				field = rule->src_info[i].ab;
				break;
			case FLD_CLK:
				field = rule->src_info[i].clk;
				break;
			}
			break;
		}
	}
	return field;
}

static bool check_rule(struct rules_def *rule)
{
	bool ret = false;
	u64 src_field = 0;
	int i;

	if (!rule)
		return ret;

	switch (rule->rule_ops.op) {
	case OP_LE:
	case OP_LT:
	case OP_GT:
	case OP_GE:
	{
		u64 src_field = get_field(rule, inp->id);
		ret = do_compare_op(src_field, rule->rule_ops.thresh,
							rule->rule_ops.op);
		break;
	for (i = 0; i < rule->rule_ops.num_thresh; i++) {
		if (rule->rule_ops.op[i] > OP_GT) {
			pr_err("Unsupported op %d", rule->rule_ops.op[i]);
			continue;
		}
		if (rule->rule_ops.num_thresh > 1)
			src_field = get_field(rule, rule->src_info[i].id);
		else
			src_field = get_sum_field(rule);

		ret = do_compare_op(src_field, rule->rule_ops.thresh[i],
						rule->rule_ops.op[i]);
		if (rule->rule_ops.combo_op == OP_AND) {
			if (!ret)
				return ret;
		} else if (rule->rule_ops.combo_op == OP_OR) {
			if (ret)
				return ret;
		}
	default:
		pr_err("Unsupported op %d", rule->rule_ops.op);
		break;
	}
	return ret;
}
@@ -212,7 +239,7 @@ static void match_rule(struct rule_update_path_info *inp_node,
	list_for_each_entry(rule, &node->node_rules, link) {
		for (i = 0; i < rule->num_src; i++) {
			if (rule->src_info[i].id == inp_node->id) {
				if (check_rule(rule, inp_node)) {
				if (check_rule(rule)) {
					trace_bus_rules_matches(
						(node->cur_rule ?
						 node->cur_rule->rule_id : -1),
@@ -298,33 +325,38 @@ int msm_rules_update_path(struct list_head *input_list,
	return ret;
}

static bool ops_equal(int op1, int op2)
static bool is_throttle_rule(int mode)
{
	bool ret = false;
	bool ret = true;

	switch (op1) {
	case OP_GT:
	case OP_GE:
	case OP_LT:
	case OP_LE:
		if (abs(op1 - op2) <= 1)
			ret = true;
		break;
	default:
		ret = (op1 == op2);
	}
	if (mode == THROTTLE_OFF)
		ret = false;

	return ret;
}

static bool is_throttle_rule(int mode)
static int64_t get_th_diff(struct rules_def *ra, struct rules_def *rb)
{
	bool ret = true;
	int64_t th_diff = 0;
	int num_thresh = 1;

	if (mode == THROTTLE_OFF)
		ret = false;
	if (!(ra && rb))
		return -ENXIO;

	return ret;
	num_thresh = ra->rule_ops.num_thresh;
	if (num_thresh > 1) {
		th_diff = ra->rule_ops.dst_bw -
					rb->rule_ops.dst_bw;
	} else {
		if ((ra->rule_ops.op[0] == OP_LE) ||
				(ra->rule_ops.op[0] == OP_LT))
			th_diff = ra->rule_ops.thresh[0] -
					rb->rule_ops.thresh[0];
		else
			th_diff = rb->rule_ops.thresh[0] -
					ra->rule_ops.thresh[0];
	}
	return th_diff;
}

static int node_rules_compare(void *priv, struct list_head *a,
@@ -337,26 +369,17 @@ static int node_rules_compare(void *priv, struct list_head *a,


	if (ra->rule_ops.mode == rb->rule_ops.mode) {
		if (ops_equal(ra->rule_ops.op, rb->rule_ops.op)) {
			if ((ra->rule_ops.op == OP_LT) ||
				(ra->rule_ops.op == OP_LE)) {
				th_diff = ra->rule_ops.thresh -
						rb->rule_ops.thresh;
				if (th_diff > 0)
					ret = 1;
				 else
					ret = -1;
			} else if ((ra->rule_ops.op == OP_GT) ||
					(ra->rule_ops.op == OP_GE)) {
				th_diff = rb->rule_ops.thresh -
							ra->rule_ops.thresh;
		if ((ra->rule_ops.num_thresh == 1) &&
			(ra->rule_ops.op[0] - rb->rule_ops.op[0]))
			ret = ra->rule_ops.op - rb->rule_ops.op;
		else {
			th_diff = get_th_diff(ra, rb);

			if (th_diff > 0)
				ret = 1;
			 else
				ret = -1;
		}
		} else
			ret = ra->rule_ops.op - rb->rule_ops.op;
	} else if (is_throttle_rule(ra->rule_ops.mode) &&
				is_throttle_rule(rb->rule_ops.mode)) {
		if (ra->rule_ops.mode == THROTTLE_ON)
@@ -390,7 +413,8 @@ static void print_rules(struct rule_node_info *node_it)
	list_for_each_entry(node_rule, &node_it->node_rules, link) {
		pr_info("\n num Rules %d  rule Id %d\n",
				node_it->num_rules, node_rule->rule_id);
		pr_info("Rule: src_field %d\n", node_rule->rule_ops.src_field);
		pr_info("Rule: src_field %d\n",
					node_rule->rule_ops.src_field[0]);
		for (i = 0; i < node_rule->rule_ops.num_src; i++)
			pr_info("Rule: src %d\n",
					node_rule->rule_ops.src_id[i]);
@@ -399,8 +423,8 @@ static void print_rules(struct rule_node_info *node_it)
						node_rule->rule_ops.dst_node[i],
						node_rule->rule_ops.dst_bw);
		pr_info("Rule: thresh %llu op %d mode %d State %d\n",
					node_rule->rule_ops.thresh,
					node_rule->rule_ops.op,
					node_rule->rule_ops.thresh[0],
					node_rule->rule_ops.op[0],
					node_rule->rule_ops.mode,
					node_rule->state);
	}
@@ -431,25 +455,31 @@ void print_rules_buf(char *buf, int max_buf)
				"\nNum Rules:%d ruleId %d STATE:%d change:%d\n",
				node_it->num_rules, node_rule->rule_id,
				node_rule->state, node_rule->state_change);
			for (i = 0; i < node_rule->rule_ops.num_thresh; i++)
				cnt += scnprintf(buf + cnt, max_buf - cnt,
					"Src_field %d\n",
				node_rule->rule_ops.src_field);
					node_rule->rule_ops.src_field[i]);
			for (i = 0; i < node_rule->rule_ops.num_src; i++)
				cnt += scnprintf(buf + cnt, max_buf - cnt,
					"Src %d Cur Ib %llu Ab %llu\n",
					"Src %d Cur Ib %llu Ab %llu Clk %llu\n",
					node_rule->rule_ops.src_id[i],
					node_rule->src_info[i].ib,
					node_rule->src_info[i].ab);
					node_rule->src_info[i].ab,
					node_rule->src_info[i].clk);
			for (i = 0; i < node_rule->rule_ops.num_dst; i++)
				cnt += scnprintf(buf + cnt, max_buf - cnt,
					"Dst %d dst_bw %llu\n",
					node_rule->rule_ops.dst_node[0],
					node_rule->rule_ops.dst_bw);
			for (i = 0; i < node_rule->rule_ops.num_thresh; i++)
				cnt += scnprintf(buf + cnt, max_buf - cnt,
					"Thresh %llu op %d mode %d\n",
					node_rule->rule_ops.thresh,
					node_rule->rule_ops.op,
					node_rule->rule_ops.thresh[i],
					node_rule->rule_ops.op[i],
					node_rule->rule_ops.mode);
			scnprintf(buf+cnt, max_buf - cnt,
					"Combo Op %d\n",
					node_rule->rule_ops.combo_op);
		}
	}
}
@@ -573,9 +603,16 @@ static int comp_rules(struct bus_rule_type *rulea, struct bus_rule_type *ruleb)
	if (!ret && (rulea->num_dst == ruleb->num_dst))
		ret = memcmp(rulea->dst_node, ruleb->dst_node,
				(sizeof(int) * rulea->num_dst));
	if (ret || (rulea->dst_bw != ruleb->dst_bw) ||
		(rulea->op != ruleb->op) || (rulea->thresh != ruleb->thresh))
	if (!ret && (rulea->num_thresh == ruleb->num_thresh))
		ret = (memcmp(rulea->op, ruleb->op,
				(sizeof(int) * rulea->num_thresh)) &&
			memcmp(rulea->thresh, ruleb->thresh,
				(sizeof(int) * rulea->num_thresh)) &&
			memcmp(rulea->src_field, ruleb->src_field,
				(sizeof(int) * rulea->num_thresh)));
	if (ret || (rulea->dst_bw != ruleb->dst_bw))
		ret = 1;

	return ret;
}

+4 −2
Original line number Diff line number Diff line
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, 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
@@ -22,6 +22,8 @@
#define OP_GE	2
#define OP_GT	3
#define OP_NOOP 4
#define OP_AND	5
#define OP_OR	6

#define RULE_STATE_NOT_APPLIED	0
#define RULE_STATE_APPLIED	1
+6 −4
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, 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
@@ -40,9 +40,11 @@ struct rule_apply_rcm_info {
struct bus_rule_type {
	int num_src;
	int *src_id;
	int src_field;
	int op;
	u64 thresh;
	int *src_field;
	int *op;
	int combo_op;
	int num_thresh;
	u64 *thresh;
	int num_dst;
	int *dst_node;
	u64 dst_bw;