aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/msm/adreno.c
diff options
context:
space:
mode:
authorJordan Crouse <jcrouse@codeaurora.org>2014-06-03 16:00:12 -0600
committerJordan Crouse <jcrouse@codeaurora.org>2014-06-03 16:04:11 -0600
commitb3b5629aebe98d3eb5ec22e8321c3cd3fc70f59c (patch)
tree9d5f00355781c97ebd46a4989154146986bd9aac /drivers/gpu/msm/adreno.c
parent49621277ba34e73b1b50b1f06abd8a9f6519e56b (diff)
msm: kgsl: Remove the "global" locking from the ioctl path
Remove the lock code from the generic ioctl handler and move the mutex lock/unlock code to the places that really need it. In particular try not to hold a lock while doing user memory functions (copy_to_user/copy_from_user) to avoid the potential of a deadlock with the memory semaphore. CRs-Fixed: 671080 Change-Id: Ic0dedbad6f7325b53d71a5dbbed50f92483871c8 Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Diffstat (limited to 'drivers/gpu/msm/adreno.c')
-rw-r--r--drivers/gpu/msm/adreno.c81
1 files changed, 55 insertions, 26 deletions
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 5c6569a..39345da 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -330,6 +330,7 @@ done:
int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
struct kgsl_perfcounter_read_group __user *reads, unsigned int count)
{
+ struct kgsl_device *device = &adreno_dev->dev;
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct adreno_perfcounters *counters = gpudev->perfcounters;
struct adreno_perfcount_group *group;
@@ -359,6 +360,13 @@ int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
goto done;
}
+ kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+ ret = kgsl_active_count_get(device);
+ if (ret) {
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+ goto done;
+ }
+
/* list iterator */
for (j = 0; j < count; j++) {
@@ -367,7 +375,7 @@ int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
/* Verify that the group ID is within range */
if (list[j].groupid >= counters->group_count) {
ret = -EINVAL;
- goto done;
+ break;
}
group = &(counters->groups[list[j].groupid]);
@@ -382,11 +390,13 @@ int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
}
}
+ kgsl_active_count_put(device);
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
/* write the data */
- if (copy_to_user(reads, list,
- sizeof(struct kgsl_perfcounter_read_group) *
- count) != 0)
- ret = -EFAULT;
+ if (ret == 0)
+ ret = copy_to_user(reads, list,
+ sizeof(struct kgsl_perfcounter_read_group) * count);
done:
kfree(list);
@@ -461,15 +471,20 @@ int adreno_perfcounter_query_group(struct adreno_device *adreno_dev,
unsigned int groupid, unsigned int __user *countables,
unsigned int count, unsigned int *max_counters)
{
+ struct kgsl_device *device = &adreno_dev->dev;
struct adreno_perfcounters *counters = ADRENO_PERFCOUNTERS(adreno_dev);
struct adreno_perfcount_group *group;
- unsigned int i;
+ unsigned int i, t;
+ int ret;
+ unsigned int *buf;
*max_counters = 0;
if (counters == NULL || groupid >= counters->group_count)
return -EINVAL;
+ kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+
group = &(counters->groups[groupid]);
*max_counters = group->reg_count;
@@ -477,20 +492,28 @@ int adreno_perfcounter_query_group(struct adreno_device *adreno_dev,
* if NULL countable or *count of zero, return max reg_count in
* *max_counters and return success
*/
- if (countables == NULL || count == 0)
+ if (countables == NULL || count == 0) {
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
return 0;
+ }
- /*
- * Go through all available counters. Write upto *count * countable
- * values.
- */
- for (i = 0; i < group->reg_count && i < count; i++) {
- if (copy_to_user(&countables[i], &(group->regs[i].countable),
- sizeof(unsigned int)) != 0)
- return -EFAULT;
+ t = min_t(int, group->reg_count, count);
+
+ buf = kmalloc(t * sizeof(unsigned int), GFP_KERNEL);
+ if (buf == NULL) {
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+ return -ENOMEM;
}
- return 0;
+ for (i = 0; i < t; i++)
+ buf[i] = group->regs[i].countable;
+
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
+ ret = copy_to_user(countables, buf, sizeof(unsigned int) * t);
+ kfree(buf);
+
+ return ret;
}
static inline void refcount_group(struct adreno_perfcount_group *group,
@@ -2666,6 +2689,8 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
break;
}
+ kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+
if (enable) {
device->pwrctrl.ctrl_flags = 0;
adreno_dev->fast_hang_detect = 1;
@@ -2684,6 +2709,7 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
kgsl_pwrscale_disable(device);
}
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
status = 0;
}
break;
@@ -2702,10 +2728,13 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv,
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;
@@ -3143,24 +3172,28 @@ static long adreno_ioctl(struct kgsl_device_private *dev_priv,
switch (cmd) {
case IOCTL_KGSL_PERFCOUNTER_GET: {
struct kgsl_perfcounter_get *get = data;
+ kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
/*
* adreno_perfcounter_get() is called by kernel clients
* during start(), so it is not safe to take an
* active count inside this function.
*/
result = kgsl_active_count_get(device);
- if (result)
- break;
- result = adreno_perfcounter_get(adreno_dev, get->groupid,
- get->countable, &get->offset, &get->offset_hi,
- PERFCOUNTER_FLAG_NONE);
- kgsl_active_count_put(device);
+ if (result == 0) {
+ result = adreno_perfcounter_get(adreno_dev,
+ get->groupid, get->countable, &get->offset,
+ &get->offset_hi, PERFCOUNTER_FLAG_NONE);
+ kgsl_active_count_put(device);
+ }
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
break;
}
case IOCTL_KGSL_PERFCOUNTER_PUT: {
struct kgsl_perfcounter_put *put = data;
+ kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
result = adreno_perfcounter_put(adreno_dev, put->groupid,
put->countable, PERFCOUNTER_FLAG_NONE);
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
break;
}
case IOCTL_KGSL_PERFCOUNTER_QUERY: {
@@ -3172,12 +3205,8 @@ static long adreno_ioctl(struct kgsl_device_private *dev_priv,
}
case IOCTL_KGSL_PERFCOUNTER_READ: {
struct kgsl_perfcounter_read *read = data;
- result = kgsl_active_count_get(device);
- if (result)
- break;
result = adreno_perfcounter_read_group(adreno_dev,
read->reads, read->count);
- kgsl_active_count_put(device);
break;
}
default: