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

Commit f61e3b54 authored by Harshdeep Dhatt's avatar Harshdeep Dhatt Committed by Lynus Vaz
Browse files

msm: kgsl: Keep a list of perfcounters per file descriptor



We need a list of perfcounters for each kgsl file descriptor, in
order to gracefully release any perfcounter allocated using that fd
in the event that the process dies unexpectedly or doesn't release
the perfcounters properly. This prevents possible leakage of
perfcounters referenced by a process.

Change-Id: Ib443282f26a0cbdad656fa0f82fb62c6de871fb0
Signed-off-by: default avatarHarshdeep Dhatt <hdhatt@codeaurora.org>
Signed-off-by: default avatarLynus Vaz <lvaz@codeaurora.org>
parent d98d6971
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -3424,6 +3424,47 @@ static int adreno_readtimestamp(struct kgsl_device *device,
	return status;
}

/**
 * adreno_device_private_create(): Allocate an adreno_device_private structure
 */
static struct kgsl_device_private *adreno_device_private_create(void)
{
	struct adreno_device_private *adreno_priv =
			kzalloc(sizeof(*adreno_priv), GFP_KERNEL);

	if (adreno_priv) {
		INIT_LIST_HEAD(&adreno_priv->perfcounter_list);
		return &adreno_priv->dev_priv;
	}
	return NULL;
}

/**
 * adreno_device_private_destroy(): Destroy an adreno_device_private structure
 * and release the perfcounters held by the kgsl fd.
 * @dev_priv: The kgsl device private structure
 */
static void adreno_device_private_destroy(struct kgsl_device_private *dev_priv)
{
	struct kgsl_device *device = dev_priv->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_device_private *adreno_priv =
		container_of(dev_priv, struct adreno_device_private,
		dev_priv);
	struct adreno_perfcounter_list_node *p, *tmp;

	mutex_lock(&device->mutex);
	list_for_each_entry_safe(p, tmp, &adreno_priv->perfcounter_list, node) {
		adreno_perfcounter_put(adreno_dev, p->groupid,
					p->countable, PERFCOUNTER_FLAG_NONE);
		list_del(&p->node);
		kfree(p);
	}
	mutex_unlock(&device->mutex);

	kfree(adreno_priv);
}

static inline s64 adreno_ticks_to_us(u32 ticks, u32 freq)
{
	freq /= 1000000;
@@ -3705,6 +3746,8 @@ static const struct kgsl_functable adreno_functable = {
	.snapshot = adreno_snapshot,
	.irq_handler = adreno_irq_handler,
	.drain = adreno_drain,
	.device_private_create = adreno_device_private_create,
	.device_private_destroy = adreno_device_private_destroy,
	/* Optional functions */
	.snapshot_gmu = adreno_snapshot_gmu,
	.drawctxt_create = adreno_drawctxt_create,
+23 −0
Original line number Diff line number Diff line
@@ -326,6 +326,29 @@ struct adreno_firmware {
	struct kgsl_memdesc memdesc;
};

/**
 * struct adreno_perfcounter_list_node - struct to store perfcounters
 * allocated by a process on a kgsl fd.
 * @groupid: groupid of the allocated perfcounter
 * @countable: countable assigned to the allocated perfcounter
 * @node: list node for perfcounter_list of a process
 */
struct adreno_perfcounter_list_node {
	unsigned int groupid;
	unsigned int countable;
	struct list_head node;
};

/**
 * struct adreno_device_private - Adreno private structure per fd
 * @dev_priv: the kgsl device private structure
 * @perfcounter_list: list of perfcounters used by the process
 */
struct adreno_device_private {
	struct kgsl_device_private dev_priv;
	struct list_head perfcounter_list;
};

/**
 * struct adreno_gpu_core - A specific GPU core definition
 * @gpurev: Unique GPU revision identifier
+63 −3
Original line number Diff line number Diff line
/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2002,2007-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
@@ -16,6 +16,50 @@
#include "adreno.h"
#include "adreno_a5xx.h"

/*
 * Add a perfcounter to the per-fd list.
 * Call with the device mutex held
 */
static int adreno_process_perfcounter_add(struct kgsl_device_private *dev_priv,
	unsigned int groupid, unsigned int countable)
{
	struct adreno_device_private *adreno_priv = container_of(dev_priv,
		struct adreno_device_private, dev_priv);
	struct adreno_perfcounter_list_node *perfctr;

	perfctr = kmalloc(sizeof(*perfctr), GFP_KERNEL);
	if (!perfctr)
		return -ENOMEM;

	perfctr->groupid = groupid;
	perfctr->countable = countable;

	/* add the pair to process perfcounter list */
	list_add(&perfctr->node, &adreno_priv->perfcounter_list);
	return 0;
}

/*
 * Remove a perfcounter from the per-fd list.
 * Call with the device mutex held
 */
static int adreno_process_perfcounter_del(struct kgsl_device_private *dev_priv,
	unsigned int groupid, unsigned int countable)
{
	struct adreno_device_private *adreno_priv = container_of(dev_priv,
		struct adreno_device_private, dev_priv);
	struct adreno_perfcounter_list_node *p;

	list_for_each_entry(p, &adreno_priv->perfcounter_list, node) {
		if (p->groupid == groupid && p->countable == countable) {
			list_del(&p->node);
			kfree(p);
			return 0;
		}
	}
	return -ENODEV;
}

long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv,
	unsigned int cmd, void *data)
{
@@ -42,6 +86,15 @@ long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv,
			get->groupid, get->countable, &get->offset,
			&get->offset_hi, PERFCOUNTER_FLAG_NONE);

	/* Add the perfcounter into the list */
	if (!result) {
		result = adreno_process_perfcounter_add(dev_priv, get->groupid,
				get->countable);
		if (result)
			adreno_perfcounter_put(adreno_dev, get->groupid,
				get->countable, PERFCOUNTER_FLAG_NONE);
	}

	adreno_perfcntr_active_oob_put(adreno_dev);

	mutex_unlock(&device->mutex);
@@ -58,7 +111,14 @@ long adreno_ioctl_perfcounter_put(struct kgsl_device_private *dev_priv,
	int result;

	mutex_lock(&device->mutex);
	result = adreno_perfcounter_put(adreno_dev, put->groupid,

	/* Delete the perfcounter from the process list */
	result = adreno_process_perfcounter_del(dev_priv, put->groupid,
		put->countable);

	/* Put the perfcounter refcount */
	if (!result)
		adreno_perfcounter_put(adreno_dev, put->groupid,
			put->countable, PERFCOUNTER_FLAG_NONE);
	mutex_unlock(&device->mutex);

+3 −2
Original line number Diff line number Diff line
@@ -1119,7 +1119,8 @@ static int kgsl_release(struct inode *inodep, struct file *filep)
	/* Close down the process wide resources for the file */
	kgsl_process_private_close(dev_priv, dev_priv->process_priv);

	kfree(dev_priv);
	/* Destroy the device-specific structure */
	device->ftbl->device_private_destroy(dev_priv);

	result = kgsl_close_device(device);
	pm_runtime_put(&device->pdev->dev);
@@ -1187,7 +1188,7 @@ static int kgsl_open(struct inode *inodep, struct file *filep)
	}
	result = 0;

	dev_priv = kzalloc(sizeof(struct kgsl_device_private), GFP_KERNEL);
	dev_priv = device->ftbl->device_private_create();
	if (dev_priv == NULL) {
		result = -ENOMEM;
		goto err;
+2 −0
Original line number Diff line number Diff line
@@ -156,6 +156,8 @@ struct kgsl_functable {
		struct kgsl_snapshot *snapshot);
	irqreturn_t (*irq_handler)(struct kgsl_device *device);
	int (*drain)(struct kgsl_device *device);
	struct kgsl_device_private * (*device_private_create)(void);
	void (*device_private_destroy)(struct kgsl_device_private *dev_priv);
	/*
	 * Optional functions - these functions are not mandatory.  The
	 * driver will check that the function pointer is not NULL before