mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-23 19:14:30 +08:00
Merge branch 'msm-fixes-3.12' of git://people.freedesktop.org/~robclark/linux into drm-fixes
A couple small msm fixes. Plus drop of set_need_resched(). * 'msm-fixes-3.12' of git://people.freedesktop.org/~robclark/linux: drm/msm: drop unnecessary set_need_resched() drm/msm: fix potential NULL pointer dereference drm/msm: workaround for missing irq drm/msm: return -EBUSY if bo still active drm/msm: fix return value check in ERR_PTR() drm/msm: fix cmdstream size check drm/msm: hangcheck harder drm/msm: handle read vs write fences
This commit is contained in:
commit
6ddf2ed6e0
@ -124,6 +124,8 @@ void adreno_recover(struct msm_gpu *gpu)
|
||||
|
||||
/* reset completed fence seqno, just discard anything pending: */
|
||||
adreno_gpu->memptrs->fence = gpu->submitted_fence;
|
||||
adreno_gpu->memptrs->rptr = 0;
|
||||
adreno_gpu->memptrs->wptr = 0;
|
||||
|
||||
gpu->funcs->pm_resume(gpu);
|
||||
ret = gpu->funcs->hw_init(gpu);
|
||||
@ -229,7 +231,7 @@ void adreno_idle(struct msm_gpu *gpu)
|
||||
return;
|
||||
} while(time_before(jiffies, t));
|
||||
|
||||
DRM_ERROR("timeout waiting for %s to drain ringbuffer!\n", gpu->name);
|
||||
DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
|
||||
|
||||
/* TODO maybe we need to reset GPU here to recover from hang? */
|
||||
}
|
||||
@ -256,11 +258,17 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
|
||||
{
|
||||
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
|
||||
uint32_t freedwords;
|
||||
unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
|
||||
do {
|
||||
uint32_t size = gpu->rb->size / 4;
|
||||
uint32_t wptr = get_wptr(gpu->rb);
|
||||
uint32_t rptr = adreno_gpu->memptrs->rptr;
|
||||
freedwords = (rptr + (size - 1) - wptr) % size;
|
||||
|
||||
if (time_after(jiffies, t)) {
|
||||
DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
|
||||
break;
|
||||
}
|
||||
} while(freedwords < ndwords);
|
||||
}
|
||||
|
||||
|
@ -499,25 +499,41 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
|
||||
struct timespec *timeout)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
|
||||
unsigned long start_jiffies = jiffies;
|
||||
unsigned long remaining_jiffies;
|
||||
int ret;
|
||||
|
||||
if (time_after(start_jiffies, timeout_jiffies))
|
||||
remaining_jiffies = 0;
|
||||
else
|
||||
remaining_jiffies = timeout_jiffies - start_jiffies;
|
||||
if (!priv->gpu)
|
||||
return 0;
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->fence_event,
|
||||
priv->completed_fence >= fence,
|
||||
remaining_jiffies);
|
||||
if (ret == 0) {
|
||||
DBG("timeout waiting for fence: %u (completed: %u)",
|
||||
fence, priv->completed_fence);
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (ret != -ERESTARTSYS) {
|
||||
ret = 0;
|
||||
if (fence > priv->gpu->submitted_fence) {
|
||||
DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
|
||||
fence, priv->gpu->submitted_fence);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
/* no-wait: */
|
||||
ret = fence_completed(dev, fence) ? 0 : -EBUSY;
|
||||
} else {
|
||||
unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
|
||||
unsigned long start_jiffies = jiffies;
|
||||
unsigned long remaining_jiffies;
|
||||
|
||||
if (time_after(start_jiffies, timeout_jiffies))
|
||||
remaining_jiffies = 0;
|
||||
else
|
||||
remaining_jiffies = timeout_jiffies - start_jiffies;
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->fence_event,
|
||||
fence_completed(dev, fence),
|
||||
remaining_jiffies);
|
||||
|
||||
if (ret == 0) {
|
||||
DBG("timeout waiting for fence: %u (completed: %u)",
|
||||
fence, priv->completed_fence);
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (ret != -ERESTARTSYS) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -153,7 +153,7 @@ void *msm_gem_vaddr(struct drm_gem_object *obj);
|
||||
int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
|
||||
struct work_struct *work);
|
||||
void msm_gem_move_to_active(struct drm_gem_object *obj,
|
||||
struct msm_gpu *gpu, uint32_t fence);
|
||||
struct msm_gpu *gpu, bool write, uint32_t fence);
|
||||
void msm_gem_move_to_inactive(struct drm_gem_object *obj);
|
||||
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
|
||||
struct timespec *timeout);
|
||||
@ -191,6 +191,12 @@ u32 msm_readl(const void __iomem *addr);
|
||||
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
|
||||
static inline bool fence_completed(struct drm_device *dev, uint32_t fence)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
return priv->completed_fence >= fence;
|
||||
}
|
||||
|
||||
static inline int align_pitch(int width, int bpp)
|
||||
{
|
||||
int bytespp = (bpp + 7) / 8;
|
||||
|
@ -40,9 +40,9 @@ static struct page **get_pages(struct drm_gem_object *obj)
|
||||
}
|
||||
|
||||
msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
|
||||
if (!msm_obj->sgt) {
|
||||
if (IS_ERR(msm_obj->sgt)) {
|
||||
dev_err(dev->dev, "failed to allocate sgt\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return ERR_CAST(msm_obj->sgt);
|
||||
}
|
||||
|
||||
msm_obj->pages = p;
|
||||
@ -159,7 +159,6 @@ out_unlock:
|
||||
out:
|
||||
switch (ret) {
|
||||
case -EAGAIN:
|
||||
set_need_resched();
|
||||
case 0:
|
||||
case -ERESTARTSYS:
|
||||
case -EINTR:
|
||||
@ -393,11 +392,14 @@ int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
|
||||
}
|
||||
|
||||
void msm_gem_move_to_active(struct drm_gem_object *obj,
|
||||
struct msm_gpu *gpu, uint32_t fence)
|
||||
struct msm_gpu *gpu, bool write, uint32_t fence)
|
||||
{
|
||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||
msm_obj->gpu = gpu;
|
||||
msm_obj->fence = fence;
|
||||
if (write)
|
||||
msm_obj->write_fence = fence;
|
||||
else
|
||||
msm_obj->read_fence = fence;
|
||||
list_del_init(&msm_obj->mm_list);
|
||||
list_add_tail(&msm_obj->mm_list, &gpu->active_list);
|
||||
}
|
||||
@ -411,7 +413,8 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj)
|
||||
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||
|
||||
msm_obj->gpu = NULL;
|
||||
msm_obj->fence = 0;
|
||||
msm_obj->read_fence = 0;
|
||||
msm_obj->write_fence = 0;
|
||||
list_del_init(&msm_obj->mm_list);
|
||||
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
|
||||
|
||||
@ -433,8 +436,18 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
|
||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||
int ret = 0;
|
||||
|
||||
if (is_active(msm_obj) && !(op & MSM_PREP_NOSYNC))
|
||||
ret = msm_wait_fence_interruptable(dev, msm_obj->fence, timeout);
|
||||
if (is_active(msm_obj)) {
|
||||
uint32_t fence = 0;
|
||||
|
||||
if (op & MSM_PREP_READ)
|
||||
fence = msm_obj->write_fence;
|
||||
if (op & MSM_PREP_WRITE)
|
||||
fence = max(fence, msm_obj->read_fence);
|
||||
if (op & MSM_PREP_NOSYNC)
|
||||
timeout = NULL;
|
||||
|
||||
ret = msm_wait_fence_interruptable(dev, fence, timeout);
|
||||
}
|
||||
|
||||
/* TODO cache maintenance */
|
||||
|
||||
@ -455,9 +468,10 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
|
||||
uint64_t off = drm_vma_node_start(&obj->vma_node);
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||
seq_printf(m, "%08x: %c(%d) %2d (%2d) %08llx %p %d\n",
|
||||
seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %d\n",
|
||||
msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
|
||||
msm_obj->fence, obj->name, obj->refcount.refcount.counter,
|
||||
msm_obj->read_fence, msm_obj->write_fence,
|
||||
obj->name, obj->refcount.refcount.counter,
|
||||
off, msm_obj->vaddr, obj->size);
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ struct msm_gem_object {
|
||||
*/
|
||||
struct list_head mm_list;
|
||||
struct msm_gpu *gpu; /* non-null if active */
|
||||
uint32_t fence;
|
||||
uint32_t read_fence, write_fence;
|
||||
|
||||
/* Transiently in the process of submit ioctl, objects associated
|
||||
* with the submit are on submit->bo_list.. this only lasts for
|
||||
|
@ -78,7 +78,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
|
||||
}
|
||||
|
||||
if (submit_bo.flags & BO_INVALID_FLAGS) {
|
||||
DBG("invalid flags: %x", submit_bo.flags);
|
||||
DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
@ -92,7 +92,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
|
||||
*/
|
||||
obj = idr_find(&file->object_idr, submit_bo.handle);
|
||||
if (!obj) {
|
||||
DBG("invalid handle %u at index %u", submit_bo.handle, i);
|
||||
DRM_ERROR("invalid handle %u at index %u\n", submit_bo.handle, i);
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
@ -100,7 +100,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
|
||||
msm_obj = to_msm_bo(obj);
|
||||
|
||||
if (!list_empty(&msm_obj->submit_entry)) {
|
||||
DBG("handle %u at index %u already on submit list",
|
||||
DRM_ERROR("handle %u at index %u already on submit list\n",
|
||||
submit_bo.handle, i);
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
@ -216,8 +216,9 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
|
||||
struct msm_gem_object **obj, uint32_t *iova, bool *valid)
|
||||
{
|
||||
if (idx >= submit->nr_bos) {
|
||||
DBG("invalid buffer index: %u (out of %u)", idx, submit->nr_bos);
|
||||
return EINVAL;
|
||||
DRM_ERROR("invalid buffer index: %u (out of %u)\n",
|
||||
idx, submit->nr_bos);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj)
|
||||
@ -239,7 +240,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
|
||||
int ret;
|
||||
|
||||
if (offset % 4) {
|
||||
DBG("non-aligned cmdstream buffer: %u", offset);
|
||||
DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -266,7 +267,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
|
||||
return -EFAULT;
|
||||
|
||||
if (submit_reloc.submit_offset % 4) {
|
||||
DBG("non-aligned reloc offset: %u",
|
||||
DRM_ERROR("non-aligned reloc offset: %u\n",
|
||||
submit_reloc.submit_offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -276,7 +277,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
|
||||
|
||||
if ((off >= (obj->base.size / 4)) ||
|
||||
(off < last_offset)) {
|
||||
DBG("invalid offset %u at reloc %u", off, i);
|
||||
DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -374,14 +375,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
goto out;
|
||||
|
||||
if (submit_cmd.size % 4) {
|
||||
DBG("non-aligned cmdstream buffer size: %u",
|
||||
DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
|
||||
submit_cmd.size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (submit_cmd.size >= msm_obj->base.size) {
|
||||
DBG("invalid cmdstream size: %u", submit_cmd.size);
|
||||
if ((submit_cmd.size + submit_cmd.submit_offset) >=
|
||||
msm_obj->base.size) {
|
||||
DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -29,13 +29,14 @@
|
||||
static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev)
|
||||
{
|
||||
struct drm_device *dev = gpu->dev;
|
||||
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct kgsl_device_platform_data *pdata;
|
||||
|
||||
if (!pdev) {
|
||||
dev_err(dev->dev, "could not find dtv pdata\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata->bus_scale_table) {
|
||||
gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table);
|
||||
DBG("bus scale client: %08x", gpu->bsc);
|
||||
@ -230,6 +231,8 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu)
|
||||
static void hangcheck_handler(unsigned long data)
|
||||
{
|
||||
struct msm_gpu *gpu = (struct msm_gpu *)data;
|
||||
struct drm_device *dev = gpu->dev;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
uint32_t fence = gpu->funcs->last_fence(gpu);
|
||||
|
||||
if (fence != gpu->hangcheck_fence) {
|
||||
@ -237,14 +240,22 @@ static void hangcheck_handler(unsigned long data)
|
||||
gpu->hangcheck_fence = fence;
|
||||
} else if (fence < gpu->submitted_fence) {
|
||||
/* no progress and not done.. hung! */
|
||||
struct msm_drm_private *priv = gpu->dev->dev_private;
|
||||
gpu->hangcheck_fence = fence;
|
||||
dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n",
|
||||
gpu->name);
|
||||
dev_err(dev->dev, "%s: completed fence: %u\n",
|
||||
gpu->name, fence);
|
||||
dev_err(dev->dev, "%s: submitted fence: %u\n",
|
||||
gpu->name, gpu->submitted_fence);
|
||||
queue_work(priv->wq, &gpu->recover_work);
|
||||
}
|
||||
|
||||
/* if still more pending work, reset the hangcheck timer: */
|
||||
if (gpu->submitted_fence > gpu->hangcheck_fence)
|
||||
hangcheck_timer_reset(gpu);
|
||||
|
||||
/* workaround for missing irq: */
|
||||
queue_work(priv->wq, &gpu->retire_work);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -265,7 +276,8 @@ static void retire_worker(struct work_struct *work)
|
||||
obj = list_first_entry(&gpu->active_list,
|
||||
struct msm_gem_object, mm_list);
|
||||
|
||||
if (obj->fence <= fence) {
|
||||
if ((obj->read_fence <= fence) &&
|
||||
(obj->write_fence <= fence)) {
|
||||
/* move to inactive: */
|
||||
msm_gem_move_to_inactive(&obj->base);
|
||||
msm_gem_put_iova(&obj->base, gpu->id);
|
||||
@ -321,7 +333,11 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
|
||||
submit->gpu->id, &iova);
|
||||
}
|
||||
|
||||
msm_gem_move_to_active(&msm_obj->base, gpu, submit->fence);
|
||||
if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
|
||||
msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence);
|
||||
|
||||
if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
|
||||
msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
|
||||
}
|
||||
hangcheck_timer_reset(gpu);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
Loading…
Reference in New Issue
Block a user