Skip to content

Commit

Permalink
msm: msm_bus: Add support for multi-level util factor
Browse files Browse the repository at this point in the history
The util factor is used to account for ineffeciencies at the slave
device when computing the bus clk needed based on bandwidth vote. Allow
for a SOC to have different util factors based on the bandwidth load at
a given bus node.

Change-Id: I934a359f22e460e1aba5e3614feacfe32e1ba9cc
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
  • Loading branch information
Girish Mahadevan committed Jul 1, 2015
1 parent d3846f3 commit bf7a898
Show file tree
Hide file tree
Showing 7 changed files with 344 additions and 130 deletions.
18 changes: 14 additions & 4 deletions Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,16 @@ qcom,qos-off: Parameter that represents the delta between QoS register address
space for different devices.
Typically these optional properties are used for
devices that represent fabric devices.
qcom,util-fact: Parameter that represents the DDR utilization factor. It is
represented as actual util-factor * 100.
qcom,agg-scheme: Parameter that represents the aggregation scheme to be used for the
node. This parameter defaults to LEGACY scheme. The valid options
are LEGACY/SCHEME_1.
qcom,util-fact: Parameter that represents the DDR utilization factor to be used in
LEGACY scheme. It is represented as actual util-factor * 100.
qcom,vrail-comp: Parameter that represents the voltage rail compensation to push
the bus to the next level if needed. It is represented as actual
vrail-comp * 100.
the bus to the next level if needed in LEGACY and SCHEME 1 aggregation
schemes. It is represented as actual vrail-comp * 100.
qcom,util-levels: Array of tuples that represent a bandwidth threshold and util factor
to be used uptil the given threshold.
qcom,bus-type: Parameter that represents the bus type such as BIMC or NOC.
Typically these optional properties are used for
devices that represent fabric devices.
Expand Down Expand Up @@ -148,6 +153,9 @@ Example:
label = "fab-snoc";
qcom,fab-dev;
qcom,bypass-qos-prg;
qcom,agg-scheme = <SCHEME_1>;
qcom,util-levels = <450000 133>,
<750000 154>;
qcom,base-name = "snoc-base";
qcom,base-offset = <0x7000>;
qcom,qos-off = <0x1000>;
Expand All @@ -166,6 +174,8 @@ Example:
mm_int_bimc: mm-int-bimc {
cell-id = <10003>;
label = "mm-int-bimc";
qcom,util-fact = <154>;
qcom,vrail-comp = <100>;
qcom,ap-owned;
qcom,connections = <&snoc_bimc_1_mas>;
qcom,bus-dev = <&fab_snoc>;
Expand Down
23 changes: 17 additions & 6 deletions drivers/platform/msm/msm_bus/msm_bus_adhoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ struct nodebw {
uint64_t last_sum_ab;
uint64_t max_ib;
uint64_t cur_clk_hz;
uint32_t util_used;
uint32_t vrail_used;
};

struct msm_bus_fab_device_type {
Expand All @@ -60,8 +62,6 @@ struct msm_bus_fab_device_type {
uint32_t base_offset;
uint32_t qos_freq;
uint32_t qos_off;
uint32_t util_fact;
uint32_t vrail_comp;
struct msm_bus_noc_ops noc_ops;
enum msm_bus_hw_sel bus_type;
bool bypass_qos_prg;
Expand All @@ -83,6 +83,20 @@ struct qos_params_type {
u64 bw_buffer;
};

struct node_util_levels_type {
uint64_t threshold;
uint32_t util_fact;
};

struct node_agg_params_type {
uint32_t agg_scheme;
uint32_t num_aggports;
unsigned int buswidth;
uint32_t vrail_comp;
uint32_t num_util_levels;
struct node_util_levels_type *util_levels;
};

struct msm_bus_node_info_type {
const char *name;
unsigned int id;
Expand All @@ -103,13 +117,10 @@ struct msm_bus_node_info_type {
struct device **black_connections;
unsigned int bus_device_id;
struct device *bus_device;
unsigned int buswidth;
struct rule_update_path_info rule;
uint64_t lim_bw;
uint32_t util_fact;
uint32_t vrail_comp;
uint32_t num_aggports;
bool defer_qos;
struct node_agg_params_type agg_params;
};

struct msm_bus_node_device_type {
Expand Down
201 changes: 166 additions & 35 deletions drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,68 +395,197 @@ static int getpath(int src, int dest, const char *cl_name)
return first_hop;
}

static uint64_t arbitrate_bus_req(struct msm_bus_node_device_type *bus_dev,
int ctx)
static uint64_t scheme1_agg_scheme(struct msm_bus_node_device_type *bus_dev,
struct msm_bus_node_device_type *fab_dev, int ctx)
{
int i;
uint64_t max_ib = 0;
uint64_t sum_ab = 0;
uint64_t max_ib;
uint64_t sum_ab;
uint64_t bw_max_hz;
struct msm_bus_node_device_type *fab_dev = NULL;
uint32_t util_fact = 0;
uint32_t vrail_comp = 0;
struct node_util_levels_type *utils;
int i;
int num_util_levels;

/* Find max ib */
for (i = 0; i < bus_dev->num_lnodes; i++) {
max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]);
sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx];
/*
* Account for Util factor and vrail comp.
* Util factor is picked according to the current sum(AB) for this
* node and for this context.
* Vrail comp is fixed for the entire performance range.
* They default to 100 if absent.
*
* The aggregated clock is computed as:
* Freq_hz = max((sum(ab) * util_fact)/num_chan, max(ib)/vrail_comp)
* / bus-width
*/
if (bus_dev->node_info->agg_params.num_util_levels) {
utils = bus_dev->node_info->agg_params.util_levels;
num_util_levels =
bus_dev->node_info->agg_params.num_util_levels;
} else {
utils = fab_dev->node_info->agg_params.util_levels;
num_util_levels =
fab_dev->node_info->agg_params.num_util_levels;
}

bus_dev->node_bw[ctx].sum_ab = sum_ab;
bus_dev->node_bw[ctx].max_ib = max_ib;
sum_ab = bus_dev->node_bw[ctx].sum_ab;
max_ib = bus_dev->node_bw[ctx].max_ib;

for (i = 0; i < num_util_levels; i++) {
if (sum_ab < utils[i].threshold) {
util_fact = utils[i].util_fact;
break;
}
}
if (i == num_util_levels)
util_fact = utils[(num_util_levels - 1)].util_fact;

vrail_comp = bus_dev->node_info->agg_params.vrail_comp ?
bus_dev->node_info->agg_params.vrail_comp :
fab_dev->node_info->agg_params.vrail_comp;

bus_dev->node_bw[ctx].vrail_used = vrail_comp;
bus_dev->node_bw[ctx].util_used = util_fact;

if (util_fact && (util_fact != 100)) {
sum_ab *= util_fact;
sum_ab = msm_bus_div64(100, sum_ab);
}

if (vrail_comp && (vrail_comp != 100)) {
max_ib *= 100;
max_ib = msm_bus_div64(vrail_comp, max_ib);
}

/* Account for multiple channels if any */
if (bus_dev->node_info->agg_params.num_aggports > 1)
sum_ab = msm_bus_div64(
bus_dev->node_info->agg_params.num_aggports,
sum_ab);

if (!bus_dev->node_info->agg_params.buswidth) {
MSM_BUS_WARN("No bus width found for %d. Using default\n",
bus_dev->node_info->id);
bus_dev->node_info->agg_params.buswidth = 8;
}

bw_max_hz = max(max_ib, sum_ab);
bw_max_hz = msm_bus_div64(bus_dev->node_info->agg_params.buswidth,
bw_max_hz);

return bw_max_hz;
}

static uint64_t legacy_agg_scheme(struct msm_bus_node_device_type *bus_dev,
struct msm_bus_node_device_type *fab_dev, int ctx)
{
uint64_t max_ib;
uint64_t sum_ab;
uint64_t bw_max_hz;
uint32_t util_fact = 0;
uint32_t vrail_comp = 0;

/*
* Account for Util factor and vrail comp. The new aggregation
* formula is:
* Util_fact and vrail comp are obtained from fabric/Node's dts
* properties and are fixed for the entire performance range.
* They default to 100 if absent.
*
* The clock frequency is computed as:
* Freq_hz = max((sum(ab) * util_fact)/num_chan, max(ib)/vrail_comp)
* / bus-width
* util_fact and vrail comp are obtained from fabric/Node's dts
* properties.
* They default to 100 if absent.
*/
fab_dev = bus_dev->node_info->bus_device->platform_data;
/* Don't do this for virtual fabrics */
if (fab_dev && fab_dev->fabdev) {
util_fact = bus_dev->node_info->util_fact ?
bus_dev->node_info->util_fact :
fab_dev->fabdev->util_fact;
vrail_comp = bus_dev->node_info->vrail_comp ?
bus_dev->node_info->vrail_comp :
fab_dev->fabdev->vrail_comp;
util_fact = fab_dev->node_info->agg_params.util_levels[0].util_fact;
vrail_comp = fab_dev->node_info->agg_params.vrail_comp;

if (bus_dev->node_info->agg_params.num_util_levels)
util_fact =
bus_dev->node_info->agg_params.util_levels[0].util_fact ?
bus_dev->node_info->agg_params.util_levels[0].util_fact :
util_fact;

vrail_comp = bus_dev->node_info->agg_params.vrail_comp ?
bus_dev->node_info->agg_params.vrail_comp :
vrail_comp;

bus_dev->node_bw[ctx].vrail_used = vrail_comp;
bus_dev->node_bw[ctx].util_used = util_fact;
sum_ab = bus_dev->node_bw[ctx].sum_ab;
max_ib = bus_dev->node_bw[ctx].max_ib;

if (util_fact && (util_fact != 100)) {
sum_ab *= util_fact;
sum_ab = msm_bus_div64(100, sum_ab);
}

if (vrail_comp && (vrail_comp != 100)) {
max_ib *= 100;
max_ib = msm_bus_div64(vrail_comp, max_ib);
}

/* Account for multiple channels if any */
if (bus_dev->node_info->num_aggports > 1)
sum_ab = msm_bus_div64(bus_dev->node_info->num_aggports,
if (bus_dev->node_info->agg_params.num_aggports > 1)
sum_ab = msm_bus_div64(
bus_dev->node_info->agg_params.num_aggports,
sum_ab);

if (!bus_dev->node_info->buswidth) {
if (!bus_dev->node_info->agg_params.buswidth) {
MSM_BUS_WARN("No bus width found for %d. Using default\n",
bus_dev->node_info->id);
bus_dev->node_info->buswidth = 8;
bus_dev->node_info->agg_params.buswidth = 8;
}

bw_max_hz = max(max_ib, sum_ab);
bw_max_hz = msm_bus_div64(bus_dev->node_info->buswidth,
bw_max_hz = msm_bus_div64(bus_dev->node_info->agg_params.buswidth,
bw_max_hz);

return bw_max_hz;
}

static uint64_t aggregate_bus_req(struct msm_bus_node_device_type *bus_dev,
int ctx)
{
uint64_t bw_hz = 0;
int i;
struct msm_bus_node_device_type *fab_dev = NULL;
uint32_t agg_scheme;
uint64_t max_ib = 0;
uint64_t sum_ab = 0;

if (!bus_dev || !bus_dev->node_info->bus_device->platform_data) {
MSM_BUS_ERR("Bus node pointer is Invalid");
goto exit_agg_bus_req;
}

fab_dev = bus_dev->node_info->bus_device->platform_data;
for (i = 0; i < bus_dev->num_lnodes; i++) {
max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]);
sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx];
}

bus_dev->node_bw[ctx].sum_ab = sum_ab;
bus_dev->node_bw[ctx].max_ib = max_ib;

if (bus_dev->node_info->agg_params.agg_scheme != AGG_SCHEME_NONE)
agg_scheme = bus_dev->node_info->agg_params.agg_scheme;
else
agg_scheme = fab_dev->node_info->agg_params.agg_scheme;

switch (agg_scheme) {
case AGG_SCHEME_1:
bw_hz = scheme1_agg_scheme(bus_dev, fab_dev, ctx);
break;
case AGG_SCHEME_LEG:
bw_hz = legacy_agg_scheme(bus_dev, fab_dev, ctx);
break;
default:
panic("Invalid Bus aggregation scheme");
}

exit_agg_bus_req:
return bw_hz;
}


static void del_inp_list(struct list_head *list)
{
struct rule_update_path_info *rule_node;
Expand Down Expand Up @@ -519,9 +648,11 @@ static uint64_t get_node_aggab(struct msm_bus_node_device_type *bus_dev)
for (i = 0; i < bus_dev->num_lnodes; i++)
agg_ab += bus_dev->lnode_list[i].lnode_ab[ctx];

if (bus_dev->node_info->num_aggports > 1)
agg_ab = msm_bus_div64(bus_dev->node_info->num_aggports,
agg_ab);
if (bus_dev->node_info->agg_params.num_aggports > 1)
agg_ab =
msm_bus_div64(
bus_dev->node_info->agg_params.num_aggports,
agg_ab);

max_agg_ab = max(max_agg_ab, agg_ab);
}
Expand Down Expand Up @@ -606,7 +737,7 @@ static int update_path(int src, int dest, uint64_t act_req_ib,

for (i = 0; i < NUM_CTX; i++)
dev_info->node_bw[i].cur_clk_hz =
arbitrate_bus_req(dev_info, i);
aggregate_bus_req(dev_info, i);

/* Start updating the clocks at the first hop.
* Its ok to figure out the aggregated
Expand Down
4 changes: 2 additions & 2 deletions drivers/platform/msm/msm_bus/msm_bus_dbg_voter.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*
* This program is Mree software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
Expand Down Expand Up @@ -198,7 +198,7 @@ static int msm_bus_floor_init_dev(struct device *fab_dev,
bus_node->node_info = node_info;
bus_node->ap_owned = true;
bus_node->node_info->bus_device = fab_dev;
bus_node->node_info->buswidth = 8;
bus_node->node_info->agg_params.buswidth = 8;
dev->platform_data = bus_node;
dev->bus = &msm_bus_type;

Expand Down
Loading

0 comments on commit bf7a898

Please sign in to comment.