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

Commit 04bb677f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Add L3 performance hint"

parents 4ab436db 53245658
Loading
Loading
Loading
Loading
+5 −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,10 @@ IOMMU Data:
GPU Power levels:
- qcom,gpu-pwrlevel-bins:	Container for sets of GPU power levels (see
				adreno-pwrlevels.txt)

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.
DCVS Core info
- qcom,dcvs-core-info		Container for the DCVS core info (see
				dcvs-core-info.txt)
+52 −0
Original line number Diff line number Diff line
@@ -2525,7 +2525,39 @@ 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, (void __user *)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;
@@ -2607,7 +2639,27 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,

			status = adreno_set_constraint(device, context,
								&constraint);
			kgsl_context_put(context);
		}
		break;
	case KGSL_PROP_L3_PWR_CONSTRAINT: {
			struct kgsl_device_constraint constraint;
			struct kgsl_context *context;

			if (sizebytes != sizeof(constraint))
				break;
			if (copy_from_user(&constraint, value,
				sizeof(constraint))) {
				status = -EFAULT;
				break;
			}
			context = kgsl_context_get_owner(dev_priv,
							constraint.context_id);

			if (context == NULL)
				break;
			status = adreno_set_constraint(device, context,
							&constraint);
			kgsl_context_put(context);
		}
		break;
+32 −1
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
@@ -187,6 +187,37 @@ int adreno_setproperty_compat(struct kgsl_device_private *dev_priv,
			kgsl_context_put(context);
		}
		break;
	case KGSL_PROP_L3_PWR_CONSTRAINT: {
			struct kgsl_device_constraint_compat constraint32;
			struct kgsl_device_constraint constraint;
			struct kgsl_context *context;

			if (sizebytes != sizeof(constraint32))
				break;

			if (copy_from_user(&constraint32, value,
				sizeof(constraint32))) {
				status = -EFAULT;
				break;
			}

			constraint.type = constraint32.type;
			constraint.context_id = constraint32.context_id;
			constraint.data = compat_ptr(constraint32.data);
			constraint.size = (size_t)constraint32.size;

			context = kgsl_context_get_owner(dev_priv,
							constraint.context_id);

			if (context == NULL)
				break;

			status = adreno_set_constraint(device, context,
							&constraint);
			kgsl_context_put(context);

		}
		break;
	default:
		/*
		 * Call adreno_setproperty in case the property type was
+84 −0
Original line number Diff line number Diff line
@@ -762,10 +762,55 @@ adreno_ringbuffer_issue_internal_cmds(struct adreno_ringbuffer *rb,
		sizedwords, 0, NULL);
}

static int
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) {
		dev_err_once(&device->pdev->dev, "Unable to find 'qcom,l3-pwrlevels'\n");
		return -EINVAL;
	}

	device->num_l3_pwrlevels = 0;

	for_each_child_of_node(pwrlevel_node, child) {
		unsigned int index;

		if (of_property_read_u32(child, "reg", &index))
			return -EINVAL;
		if (index >= MAX_L3_LEVELS) {
			dev_err(&device->pdev->dev, "L3 pwrlevel %d is out of range\n",
					index);
			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]))
		return -EINVAL;

	}

	return 0;

}

static void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
			struct kgsl_drawobj *drawobj)
{
	struct kgsl_context *context = drawobj->context;
	struct device *dev = &device->pdev->dev;
	unsigned long flags = drawobj->flags;
	struct device_node *node;

	node = device->pdev->dev.of_node;

	/*
	 * Check if the context has a constraint and constraint flags are
	 * set.
@@ -775,6 +820,45 @@ 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 (IS_ERR_OR_NULL(device->l3_clk))
		device->l3_clk = devm_clk_get(dev, "l3_vote");

	if (IS_ERR_OR_NULL(device->l3_clk)) {
		KGSL_DEV_ERR_ONCE(device, "Unable to get the l3_vote clock. Cannot set the L3 constraint\n");
		return;
	}

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

		int ret =  l3_pwrlevel_probe(device, node);

		if (ret)
			return;

		switch (context->l3_pwr_constraint.type) {

		case KGSL_CONSTRAINT_L3_PWRLEVEL: {
			unsigned int sub_type;

			sub_type = context->l3_pwr_constraint.sub_type;

			if (sub_type == KGSL_CONSTRAINT_L3_PWR_MED)
				clk_set_rate(device->l3_clk,
						device->l3_freq[1]);

			if (sub_type == KGSL_CONSTRAINT_L3_PWR_MAX)
				clk_set_rate(device->l3_clk,
						device->l3_freq[2]);
			}
			break;
		case KGSL_CONSTRAINT_L3_NONE:
			clk_set_rate(device->l3_clk, device->l3_freq[0]);
			break;
		}
	}
}

static inline int _get_alwayson_counter(struct adreno_device *adreno_dev,
+5 −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;
@@ -332,6 +333,9 @@ 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;
};

#define KGSL_MMU_DEVICE(_mmu) \
@@ -410,6 +414,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