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

Commit 435903c1 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 multi-level util factor"

parents b5d90584 bf7a8985
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -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.
@@ -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>;
@@ -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>;
+17 −6
Original line number Diff line number Diff line
@@ -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 {
@@ -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;
@@ -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;
@@ -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 {
+166 −35
Original line number Diff line number Diff line
@@ -395,68 +395,197 @@ exit_getpath:
	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;
@@ -519,8 +648,10 @@ 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,
		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);
@@ -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
+2 −2
Original line number Diff line number Diff line
/* 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
@@ -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;

+39 −47
Original line number Diff line number Diff line
@@ -25,41 +25,6 @@

static int msm_bus_dev_init_qos(struct device *dev, void *data);


ssize_t vrail_show(struct device *dev, struct device_attribute *attr,
			  char *buf)
{
	struct msm_bus_node_info_type *node_info = NULL;
	struct msm_bus_node_device_type *bus_node = NULL;

	bus_node = dev->platform_data;
	if (!bus_node)
		return -EINVAL;
	node_info = bus_node->node_info;

	return snprintf(buf, PAGE_SIZE, "%u", node_info->vrail_comp);
}

ssize_t vrail_store(struct device *dev, struct device_attribute *attr,
			   const char *buf, size_t count)
{
	struct msm_bus_node_info_type *node_info = NULL;
	struct msm_bus_node_device_type *bus_node = NULL;
	int ret = 0;

	bus_node = dev->platform_data;
	if (!bus_node)
		return -EINVAL;
	node_info = bus_node->node_info;

	ret = sscanf(buf, "%u", &node_info->vrail_comp);
	if (ret != 1)
		return -EINVAL;
	return count;
}

DEVICE_ATTR(vrail, 0600, vrail_show, vrail_store);

ssize_t bw_show(struct device *dev, struct device_attribute *attr,
			  char *buf)
{
@@ -92,17 +57,29 @@ ssize_t bw_show(struct device *dev, struct device_attribute *attr,
			bus_node->lnode_list[i].lnode_ab[DUAL_CTX]);
	}
	off += scnprintf((buf + off), PAGE_SIZE,
	"Max_Act_IB %llu Sum_Act_AB %llu\nMax_Slp_IB %llu Sum_Slp_AB %llu\n",
	"Max_Act_IB %llu Sum_Act_AB %llu Act_Util_fact %d Act_Vrail_comp %d\n",
		bus_node->node_bw[ACTIVE_CTX].max_ib,
		bus_node->node_bw[ACTIVE_CTX].sum_ab,
		bus_node->node_bw[ACTIVE_CTX].util_used,
		bus_node->node_bw[ACTIVE_CTX].vrail_used);
	off += scnprintf((buf + off), PAGE_SIZE,
	"Max_Slp_IB %llu Sum_Slp_AB %llu Slp_Util_fact %d Slp_Vrail_comp %d\n",
		bus_node->node_bw[DUAL_CTX].max_ib,
		bus_node->node_bw[DUAL_CTX].sum_ab);
		bus_node->node_bw[DUAL_CTX].sum_ab,
		bus_node->node_bw[DUAL_CTX].util_used,
		bus_node->node_bw[DUAL_CTX].vrail_used);
	trace_printk(
	"Max_Act_IB %llu Sum_Act_AB %llu\nMax_Slp_IB %llu Sum_Slp_AB %llu\n",
	"Max_Act_IB %llu Sum_Act_AB %llu Act_Util_fact %d Act_Vrail_comp %d\n",
		bus_node->node_bw[ACTIVE_CTX].max_ib,
		bus_node->node_bw[ACTIVE_CTX].sum_ab,
		bus_node->node_bw[ACTIVE_CTX].util_used,
		bus_node->node_bw[ACTIVE_CTX].vrail_used);
	trace_printk(
	"Max_Slp_IB %llu Sum_Slp_AB %lluSlp_Util_fact %d Slp_Vrail_comp %d\n",
		bus_node->node_bw[DUAL_CTX].max_ib,
		bus_node->node_bw[DUAL_CTX].sum_ab);
		bus_node->node_bw[DUAL_CTX].sum_ab,
		bus_node->node_bw[DUAL_CTX].util_used,
		bus_node->node_bw[DUAL_CTX].vrail_used);
	return off;
}

@@ -909,8 +886,6 @@ static int msm_bus_fabric_init(struct device *dev,
	fabdev->qos_freq = pdata->fabdev->qos_freq;
	fabdev->bus_type = pdata->fabdev->bus_type;
	fabdev->bypass_qos_prg = pdata->fabdev->bypass_qos_prg;
	fabdev->util_fact = pdata->fabdev->util_fact;
	fabdev->vrail_comp = pdata->fabdev->vrail_comp;
	msm_bus_fab_init_noc_ops(node_dev);

	fabdev->qos_base = devm_ioremap(dev,
@@ -1020,8 +995,6 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata,
	node_info->num_connections = pdata_node_info->num_connections;
	node_info->num_blist = pdata_node_info->num_blist;
	node_info->num_qports = pdata_node_info->num_qports;
	node_info->num_aggports = pdata_node_info->num_aggports;
	node_info->buswidth = pdata_node_info->buswidth;
	node_info->virt_dev = pdata_node_info->virt_dev;
	node_info->is_fab_dev = pdata_node_info->is_fab_dev;
	node_info->qos_params.mode = pdata_node_info->qos_params.mode;
@@ -1036,8 +1009,28 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata,
	node_info->qos_params.thmp = pdata_node_info->qos_params.thmp;
	node_info->qos_params.ws = pdata_node_info->qos_params.ws;
	node_info->qos_params.bw_buffer = pdata_node_info->qos_params.bw_buffer;
	node_info->util_fact = pdata_node_info->util_fact;
	node_info->vrail_comp = pdata_node_info->vrail_comp;
	node_info->agg_params.buswidth = pdata_node_info->agg_params.buswidth;
	node_info->agg_params.agg_scheme =
					pdata_node_info->agg_params.agg_scheme;
	node_info->agg_params.vrail_comp =
					pdata_node_info->agg_params.vrail_comp;
	node_info->agg_params.num_aggports =
				pdata_node_info->agg_params.num_aggports;
	node_info->agg_params.num_util_levels =
				pdata_node_info->agg_params.num_util_levels;
	node_info->agg_params.util_levels = devm_kzalloc(bus_dev,
			sizeof(struct node_util_levels_type) *
			node_info->agg_params.num_util_levels,
			GFP_KERNEL);
	if (!node_info->agg_params.util_levels) {
		MSM_BUS_ERR("%s: Agg util level alloc failed\n", __func__);
		ret = -ENOMEM;
		goto exit_copy_node_info;
	}
	memcpy(node_info->agg_params.util_levels,
		pdata_node_info->agg_params.util_levels,
		sizeof(struct node_util_levels_type) *
			pdata_node_info->agg_params.num_util_levels);

	node_info->dev_connections = devm_kzalloc(bus_dev,
			sizeof(struct device *) *
@@ -1181,7 +1174,6 @@ static struct device *msm_bus_device_init(
		bus_dev = NULL;
		goto exit_device_init;
	}
	device_create_file(bus_dev, &dev_attr_vrail);
	device_create_file(bus_dev, &dev_attr_bw);

exit_device_init:
@@ -1271,7 +1263,7 @@ static int msm_bus_node_debug(struct device *bus_dev, void *data)
	}

	MSM_BUS_DBG("Device = %d buswidth %u", bus_node->node_info->id,
				bus_node->node_info->buswidth);
				bus_node->node_info->agg_params.buswidth);
	for (j = 0; j < bus_node->node_info->num_connections; j++) {
		struct msm_bus_node_device_type *bdev =
			(struct msm_bus_node_device_type *)
Loading