Loading Documentation/devicetree/bindings/arm/msm/msm_bus_rules.txt +18 −13 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 { Loading @@ -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 { Loading drivers/platform/msm/msm_bus/msm_bus_of_adhoc.c +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 Loading Loading @@ -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); Loading @@ -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); Loading @@ -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: Loading @@ -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; } drivers/platform/msm/msm_bus/msm_bus_rules.c +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 Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -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), Loading Loading @@ -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, Loading @@ -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) Loading Loading @@ -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]); Loading @@ -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); } Loading Loading @@ -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); } } } Loading Loading @@ -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; } Loading include/dt-bindings/msm/msm-bus-rule-ops.h +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 Loading @@ -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 Loading include/linux/msm_bus_rules.h +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 Loading Loading @@ -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; Loading Loading
Documentation/devicetree/bindings/arm/msm/msm_bus_rules.txt +18 −13 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 { Loading @@ -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 { Loading
drivers/platform/msm/msm_bus/msm_bus_of_adhoc.c +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 Loading Loading @@ -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); Loading @@ -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); Loading @@ -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: Loading @@ -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; }
drivers/platform/msm/msm_bus/msm_bus_rules.c +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 Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -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), Loading Loading @@ -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, Loading @@ -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) Loading Loading @@ -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]); Loading @@ -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); } Loading Loading @@ -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); } } } Loading Loading @@ -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; } Loading
include/dt-bindings/msm/msm-bus-rule-ops.h +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 Loading @@ -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 Loading
include/linux/msm_bus_rules.h +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 Loading Loading @@ -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; Loading