diff options
| author | 2014-06-03 16:00:12 -0600 | |
|---|---|---|
| committer | 2014-06-03 16:04:11 -0600 | |
| commit | b3b5629aebe98d3eb5ec22e8321c3cd3fc70f59c (patch) | |
| tree | 9d5f00355781c97ebd46a4989154146986bd9aac /drivers/gpu/msm/adreno.c | |
| parent | 49621277ba34e73b1b50b1f06abd8a9f6519e56b (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.c | 81 |
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: |
