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

Commit c087b71f authored by Urvashi Agrawal's avatar Urvashi Agrawal Committed by Lynus Vaz
Browse files

msm: kgsl: Add L3 performance hint



Add software path to bump the l3 frequency using a
performance hint from user space in I/O coherence cases.

Change-Id: I559fecf0dbbf79ebe3972db2a65bde6b69063fc9
Signed-off-by: default avatarUrvashi Agrawal <urvaagra@codeaurora.org>
Signed-off-by: default avatarLynus Vaz <lvaz@codeaurora.org>
parent 5ebcda44
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ Required properties:
				Current values of clock-names are:
				"src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk",
				"alt_mem_iface_clk", "rbbmtimer_clk",  "alwayson_clk",
				"iref_clk"
				"iref_clk", "l3_vote"
				"core_clk" and "iface_clk" are required and others are optional

- qcom,base-leakage-coefficient: Dynamic leakage coefficient.
@@ -78,7 +78,6 @@ IOMMU Data:
GPU Power levels:
- qcom,gpu-pwrlevel-bins:	Container for sets of GPU power levels (see
				adreno-pwrlevels.txt)

DCVS Core info
- qcom,dcvs-core-info		Container for the DCVS core info (see
				dcvs-core-info.txt)
@@ -262,6 +261,21 @@ GPU LLC slice info:
				and pagetable walk.
- cache-slices:			phandle to the system LLC driver, cache slice index.

L3 Power levels:
- qcom,l3-pwrlevels:		Container for sets of L3 power levels, the
				L3 frequency is adjusted according to the
				performance hint received from userspace.

Properties:
- compatible:			Must be qcom,l3-pwrlevels
- qcom,l3-pwrlevel:		A single L3 powerlevel

Properties:
- reg:				Index of the L3 powerlevel
				0 = powerlevel for no L3 vote
				1 = powerlevel for medium L3 vote
				2 = powerlevel for maximum L3 vote
- qcom,l3-freq:			The L3 frequency for the powerlevel (in Hz)

GPU coresight info:
The following properties are optional as collecting data via coresight might
+70 −1
Original line number Diff line number Diff line
@@ -1037,6 +1037,41 @@ static int adreno_of_get_pwrlevels(struct adreno_device *adreno_dev,
	return -ENODEV;
}

static void
l3_pwrlevel_probe(struct kgsl_device *device, struct device_node *node)
{
	struct device_node *pwrlevel_node, *child;

	pwrlevel_node = of_find_node_by_name(node, "qcom,l3-pwrlevels");

	if (pwrlevel_node == NULL)
		return;

	for_each_available_child_of_node(pwrlevel_node, child) {
		unsigned int index;

		if (of_property_read_u32(child, "reg", &index))
			return;
		if (index >= MAX_L3_LEVELS)
			continue;

		if (index >= device->num_l3_pwrlevels)
			device->num_l3_pwrlevels = index + 1;

		if (of_property_read_u32(child, "qcom,l3-freq",
				&device->l3_freq[index]))
			continue;
	}

	device->l3_clk = devm_clk_get(&device->pdev->dev, "l3_vote");

	if (IS_ERR_OR_NULL(device->l3_clk)) {
		dev_err(&device->pdev->dev,
			"Unable to get the l3_vote clock\n");
		device->l3_clk = NULL;
	}
}

static inline struct adreno_device *adreno_get_dev(struct platform_device *pdev)
{
	const struct of_device_id *of_id =
@@ -1083,6 +1118,8 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev,
	/* Get context aware DCVS properties */
	adreno_of_get_ca_aware_properties(adreno_dev, node);

	l3_pwrlevel_probe(device, node);

	/* get pm-qos-active-latency, set it to default if not found */
	if (of_property_read_u32(node, "qcom,pm-qos-active-latency",
		&device->pwrctrl.pm_qos_active_latency))
@@ -2619,7 +2656,38 @@ int adreno_set_constraint(struct kgsl_device *device,
				context->pwr_constraint.sub_type);
		context->pwr_constraint.type = KGSL_CONSTRAINT_NONE;
		break;
	case KGSL_CONSTRAINT_L3_PWRLEVEL: {
		struct kgsl_device_constraint_pwrlevel pwr;

		if (constraint->size != sizeof(pwr)) {
			status = -EINVAL;
			break;
		}

		if (copy_from_user(&pwr, constraint->data, sizeof(pwr))) {
			status = -EFAULT;
			break;
		}
		if (pwr.level >= KGSL_CONSTRAINT_PWR_MAXLEVELS)
			pwr.level = KGSL_CONSTRAINT_PWR_MAXLEVELS - 1;

		context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_PWRLEVEL;
		context->l3_pwr_constraint.sub_type = pwr.level;
		trace_kgsl_user_pwrlevel_constraint(device, context->id,
			context->l3_pwr_constraint.type,
			context->l3_pwr_constraint.sub_type);
		}
		break;
	case KGSL_CONSTRAINT_L3_NONE: {
		unsigned int type = context->l3_pwr_constraint.type;

		if (type == KGSL_CONSTRAINT_L3_PWRLEVEL)
			trace_kgsl_user_pwrlevel_constraint(device, context->id,
				KGSL_CONSTRAINT_L3_NONE,
				context->l3_pwr_constraint.sub_type);
		context->l3_pwr_constraint.type = KGSL_CONSTRAINT_L3_NONE;
		}
		break;
	default:
		status = -EINVAL;
		break;
@@ -2680,7 +2748,8 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
			status = 0;
		}
		break;
	case KGSL_PROP_PWR_CONSTRAINT: {
	case KGSL_PROP_PWR_CONSTRAINT:
	case KGSL_PROP_L3_PWR_CONSTRAINT: {
			struct kgsl_device_constraint constraint;
			struct kgsl_context *context;

+3 −2
Original line number Diff line number Diff line
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2018, 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
@@ -158,7 +158,8 @@ int adreno_setproperty_compat(struct kgsl_device_private *dev_priv,
	struct kgsl_device *device = dev_priv->device;

	switch (type) {
	case KGSL_PROP_PWR_CONSTRAINT: {
	case KGSL_PROP_PWR_CONSTRAINT:
	case KGSL_PROP_L3_PWR_CONSTRAINT: {
			struct kgsl_device_constraint_compat constraint32;
			struct kgsl_device_constraint constraint;
			struct kgsl_context *context;
+43 −0
Original line number Diff line number Diff line
@@ -767,6 +767,8 @@ static void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
			struct kgsl_drawobj *drawobj)
{
	struct kgsl_context *context = drawobj->context;
	unsigned long flags = drawobj->flags;

	/*
	 * Check if the context has a constraint and constraint flags are
	 * set.
@@ -776,6 +778,47 @@ static void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
			(drawobj->flags & KGSL_CONTEXT_PWR_CONSTRAINT)))
		kgsl_pwrctrl_set_constraint(device, &context->pwr_constraint,
						context->id);

	if (context->l3_pwr_constraint.type &&
		((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
			(flags & KGSL_CONTEXT_PWR_CONSTRAINT))) {

		if (!device->l3_clk) {
			KGSL_DEV_ERR_ONCE(device,
				"l3_vote clk not available\n");
			return;
		}

		switch (context->l3_pwr_constraint.type) {
		case KGSL_CONSTRAINT_L3_PWRLEVEL: {
			unsigned int sub_type;
			unsigned int new_l3;
			int ret = 0;

			sub_type = context->l3_pwr_constraint.sub_type;

			/*
			 * If an L3 constraint is already set, set the new
			 * one only if it is higher.
			 */
			new_l3 = max_t(unsigned int, sub_type + 1,
					device->cur_l3_pwrlevel);
			new_l3 = min_t(unsigned int, new_l3,
					device->num_l3_pwrlevels - 1);

			ret = clk_set_rate(device->l3_clk,
					device->l3_freq[new_l3]);

			if (!ret)
				device->cur_l3_pwrlevel = new_l3;
			else
				KGSL_DRV_ERR_RATELIMIT(device,
					"Could not set l3_vote: %d\n",
					ret);
			break;
			}
		}
	}
}

static inline int _get_alwayson_counter(struct adreno_device *adreno_dev,
+7 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ enum kgsl_event_results {

/* Allocate 600K for the snapshot static region*/
#define KGSL_SNAPSHOT_MEMSIZE (600 * 1024)
#define MAX_L3_LEVELS	3

struct kgsl_device;
struct platform_device;
@@ -328,6 +329,11 @@ struct kgsl_device {
	/* Number of active contexts seen globally for this device */
	int active_context_count;
	struct kobject *gpu_sysfs_kobj;
	struct clk *l3_clk;
	unsigned int l3_freq[MAX_L3_LEVELS];
	unsigned int num_l3_pwrlevels;
	/* store current L3 vote to determine if we should change our vote */
	unsigned int cur_l3_pwrlevel;
};

#define KGSL_MMU_DEVICE(_mmu) \
@@ -406,6 +412,7 @@ struct kgsl_context {
	struct kgsl_event_group events;
	unsigned int flags;
	struct kgsl_pwr_constraint pwr_constraint;
	struct kgsl_pwr_constraint l3_pwr_constraint;
	unsigned int fault_count;
	unsigned long fault_time;
	struct kgsl_mem_entry *user_ctxt_record;
Loading