Commit 6ddf2ed6 authored by Dave Airlie's avatar Dave Airlie

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
parents 9808cc94 7e60353a
...@@ -124,6 +124,8 @@ void adreno_recover(struct msm_gpu *gpu) ...@@ -124,6 +124,8 @@ void adreno_recover(struct msm_gpu *gpu)
/* reset completed fence seqno, just discard anything pending: */ /* reset completed fence seqno, just discard anything pending: */
adreno_gpu->memptrs->fence = gpu->submitted_fence; adreno_gpu->memptrs->fence = gpu->submitted_fence;
adreno_gpu->memptrs->rptr = 0;
adreno_gpu->memptrs->wptr = 0;
gpu->funcs->pm_resume(gpu); gpu->funcs->pm_resume(gpu);
ret = gpu->funcs->hw_init(gpu); ret = gpu->funcs->hw_init(gpu);
...@@ -229,7 +231,7 @@ void adreno_idle(struct msm_gpu *gpu) ...@@ -229,7 +231,7 @@ void adreno_idle(struct msm_gpu *gpu)
return; return;
} while(time_before(jiffies, t)); } 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? */ /* 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) ...@@ -256,11 +258,17 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
{ {
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
uint32_t freedwords; uint32_t freedwords;
unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
do { do {
uint32_t size = gpu->rb->size / 4; uint32_t size = gpu->rb->size / 4;
uint32_t wptr = get_wptr(gpu->rb); uint32_t wptr = get_wptr(gpu->rb);
uint32_t rptr = adreno_gpu->memptrs->rptr; uint32_t rptr = adreno_gpu->memptrs->rptr;
freedwords = (rptr + (size - 1) - wptr) % size; 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); } while(freedwords < ndwords);
} }
......
...@@ -499,10 +499,24 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, ...@@ -499,10 +499,24 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
struct timespec *timeout) struct timespec *timeout)
{ {
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
int ret;
if (!priv->gpu)
return 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 timeout_jiffies = timespec_to_jiffies(timeout);
unsigned long start_jiffies = jiffies; unsigned long start_jiffies = jiffies;
unsigned long remaining_jiffies; unsigned long remaining_jiffies;
int ret;
if (time_after(start_jiffies, timeout_jiffies)) if (time_after(start_jiffies, timeout_jiffies))
remaining_jiffies = 0; remaining_jiffies = 0;
...@@ -510,8 +524,9 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, ...@@ -510,8 +524,9 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
remaining_jiffies = timeout_jiffies - start_jiffies; remaining_jiffies = timeout_jiffies - start_jiffies;
ret = wait_event_interruptible_timeout(priv->fence_event, ret = wait_event_interruptible_timeout(priv->fence_event,
priv->completed_fence >= fence, fence_completed(dev, fence),
remaining_jiffies); remaining_jiffies);
if (ret == 0) { if (ret == 0) {
DBG("timeout waiting for fence: %u (completed: %u)", DBG("timeout waiting for fence: %u (completed: %u)",
fence, priv->completed_fence); fence, priv->completed_fence);
...@@ -519,6 +534,7 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, ...@@ -519,6 +534,7 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
} else if (ret != -ERESTARTSYS) { } else if (ret != -ERESTARTSYS) {
ret = 0; ret = 0;
} }
}
return ret; return ret;
} }
......
...@@ -153,7 +153,7 @@ void *msm_gem_vaddr(struct drm_gem_object *obj); ...@@ -153,7 +153,7 @@ void *msm_gem_vaddr(struct drm_gem_object *obj);
int msm_gem_queue_inactive_work(struct drm_gem_object *obj, int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
struct work_struct *work); struct work_struct *work);
void msm_gem_move_to_active(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);
void msm_gem_move_to_inactive(struct drm_gem_object *obj); void msm_gem_move_to_inactive(struct drm_gem_object *obj);
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
struct timespec *timeout); struct timespec *timeout);
...@@ -191,6 +191,12 @@ u32 msm_readl(const void __iomem *addr); ...@@ -191,6 +191,12 @@ u32 msm_readl(const void __iomem *addr);
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
#define VERB(fmt, ...) if (0) 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) static inline int align_pitch(int width, int bpp)
{ {
int bytespp = (bpp + 7) / 8; int bytespp = (bpp + 7) / 8;
......
...@@ -40,9 +40,9 @@ static struct page **get_pages(struct drm_gem_object *obj) ...@@ -40,9 +40,9 @@ static struct page **get_pages(struct drm_gem_object *obj)
} }
msm_obj->sgt = drm_prime_pages_to_sg(p, npages); 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"); dev_err(dev->dev, "failed to allocate sgt\n");
return ERR_PTR(-ENOMEM); return ERR_CAST(msm_obj->sgt);
} }
msm_obj->pages = p; msm_obj->pages = p;
...@@ -159,7 +159,6 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -159,7 +159,6 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
out: out:
switch (ret) { switch (ret) {
case -EAGAIN: case -EAGAIN:
set_need_resched();
case 0: case 0:
case -ERESTARTSYS: case -ERESTARTSYS:
case -EINTR: case -EINTR:
...@@ -393,11 +392,14 @@ int msm_gem_queue_inactive_work(struct drm_gem_object *obj, ...@@ -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, 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); struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_obj->gpu = gpu; 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_del_init(&msm_obj->mm_list);
list_add_tail(&msm_obj->mm_list, &gpu->active_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) ...@@ -411,7 +413,8 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj)
WARN_ON(!mutex_is_locked(&dev->struct_mutex)); WARN_ON(!mutex_is_locked(&dev->struct_mutex));
msm_obj->gpu = NULL; 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_del_init(&msm_obj->mm_list);
list_add_tail(&msm_obj->mm_list, &priv->inactive_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, ...@@ -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); struct msm_gem_object *msm_obj = to_msm_bo(obj);
int ret = 0; int ret = 0;
if (is_active(msm_obj) && !(op & MSM_PREP_NOSYNC)) if (is_active(msm_obj)) {
ret = msm_wait_fence_interruptable(dev, msm_obj->fence, timeout); 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 */ /* TODO cache maintenance */
...@@ -455,9 +468,10 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) ...@@ -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); uint64_t off = drm_vma_node_start(&obj->vma_node);
WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 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->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); off, msm_obj->vaddr, obj->size);
} }
......
...@@ -36,7 +36,7 @@ struct msm_gem_object { ...@@ -36,7 +36,7 @@ struct msm_gem_object {
*/ */
struct list_head mm_list; struct list_head mm_list;
struct msm_gpu *gpu; /* non-null if active */ 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 /* Transiently in the process of submit ioctl, objects associated
* with the submit are on submit->bo_list.. this only lasts for * 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, ...@@ -78,7 +78,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
} }
if (submit_bo.flags & BO_INVALID_FLAGS) { 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; ret = -EINVAL;
goto out_unlock; goto out_unlock;
} }
...@@ -92,7 +92,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, ...@@ -92,7 +92,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
*/ */
obj = idr_find(&file->object_idr, submit_bo.handle); obj = idr_find(&file->object_idr, submit_bo.handle);
if (!obj) { 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; ret = -EINVAL;
goto out_unlock; goto out_unlock;
} }
...@@ -100,7 +100,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, ...@@ -100,7 +100,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
msm_obj = to_msm_bo(obj); msm_obj = to_msm_bo(obj);
if (!list_empty(&msm_obj->submit_entry)) { 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); submit_bo.handle, i);
ret = -EINVAL; ret = -EINVAL;
goto out_unlock; goto out_unlock;
...@@ -216,8 +216,9 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, ...@@ -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) struct msm_gem_object **obj, uint32_t *iova, bool *valid)
{ {
if (idx >= submit->nr_bos) { if (idx >= submit->nr_bos) {
DBG("invalid buffer index: %u (out of %u)", idx, submit->nr_bos); DRM_ERROR("invalid buffer index: %u (out of %u)\n",
return EINVAL; idx, submit->nr_bos);
return -EINVAL;
} }
if (obj) if (obj)
...@@ -239,7 +240,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob ...@@ -239,7 +240,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
int ret; int ret;
if (offset % 4) { if (offset % 4) {
DBG("non-aligned cmdstream buffer: %u", offset); DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
return -EINVAL; return -EINVAL;
} }
...@@ -266,7 +267,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob ...@@ -266,7 +267,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
return -EFAULT; return -EFAULT;
if (submit_reloc.submit_offset % 4) { if (submit_reloc.submit_offset % 4) {
DBG("non-aligned reloc offset: %u", DRM_ERROR("non-aligned reloc offset: %u\n",
submit_reloc.submit_offset); submit_reloc.submit_offset);
return -EINVAL; return -EINVAL;
} }
...@@ -276,7 +277,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob ...@@ -276,7 +277,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
if ((off >= (obj->base.size / 4)) || if ((off >= (obj->base.size / 4)) ||
(off < last_offset)) { (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; return -EINVAL;
} }
...@@ -374,14 +375,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, ...@@ -374,14 +375,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
goto out; goto out;
if (submit_cmd.size % 4) { if (submit_cmd.size % 4) {
DBG("non-aligned cmdstream buffer size: %u", DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
submit_cmd.size); submit_cmd.size);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (submit_cmd.size >= msm_obj->base.size) { if ((submit_cmd.size + submit_cmd.submit_offset) >=
DBG("invalid cmdstream size: %u", submit_cmd.size); msm_obj->base.size) {
DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
......
...@@ -29,13 +29,14 @@ ...@@ -29,13 +29,14 @@
static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev) static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev)
{ {
struct drm_device *dev = gpu->dev; struct drm_device *dev = gpu->dev;
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; struct kgsl_device_platform_data *pdata;
if (!pdev) { if (!pdev) {
dev_err(dev->dev, "could not find dtv pdata\n"); dev_err(dev->dev, "could not find dtv pdata\n");
return; return;
} }
pdata = pdev->dev.platform_data;
if (pdata->bus_scale_table) { if (pdata->bus_scale_table) {
gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table); gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table);
DBG("bus scale client: %08x", gpu->bsc); DBG("bus scale client: %08x", gpu->bsc);
...@@ -230,6 +231,8 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu) ...@@ -230,6 +231,8 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu)
static void hangcheck_handler(unsigned long data) static void hangcheck_handler(unsigned long data)
{ {
struct msm_gpu *gpu = (struct msm_gpu *)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); uint32_t fence = gpu->funcs->last_fence(gpu);
if (fence != gpu->hangcheck_fence) { if (fence != gpu->hangcheck_fence) {
...@@ -237,14 +240,22 @@ static void hangcheck_handler(unsigned long data) ...@@ -237,14 +240,22 @@ static void hangcheck_handler(unsigned long data)
gpu->hangcheck_fence = fence; gpu->hangcheck_fence = fence;
} else if (fence < gpu->submitted_fence) { } else if (fence < gpu->submitted_fence) {
/* no progress and not done.. hung! */ /* no progress and not done.. hung! */
struct msm_drm_private *priv = gpu->dev->dev_private;
gpu->hangcheck_fence = fence; 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); queue_work(priv->wq, &gpu->recover_work);
} }
/* if still more pending work, reset the hangcheck timer: */ /* if still more pending work, reset the hangcheck timer: */
if (gpu->submitted_fence > gpu->hangcheck_fence) if (gpu->submitted_fence > gpu->hangcheck_fence)
hangcheck_timer_reset(gpu); 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) ...@@ -265,7 +276,8 @@ static void retire_worker(struct work_struct *work)
obj = list_first_entry(&gpu->active_list, obj = list_first_entry(&gpu->active_list,
struct msm_gem_object, mm_list); struct msm_gem_object, mm_list);
if (obj->fence <= fence) { if ((obj->read_fence <= fence) &&
(obj->write_fence <= fence)) {
/* move to inactive: */ /* move to inactive: */
msm_gem_move_to_inactive(&obj->base); msm_gem_move_to_inactive(&obj->base);
msm_gem_put_iova(&obj->base, gpu->id); 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, ...@@ -321,7 +333,11 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
submit->gpu->id, &iova); 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); hangcheck_timer_reset(gpu);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment