Skip to content

Commit 6ddf2ed

Browse files
committed
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
2 parents 9808cc9 + 7e60353 commit 6ddf2ed

File tree

7 files changed

+107
-45
lines changed

7 files changed

+107
-45
lines changed

drivers/gpu/drm/msm/adreno/adreno_gpu.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ void adreno_recover(struct msm_gpu *gpu)
124124

125125
/* reset completed fence seqno, just discard anything pending: */
126126
adreno_gpu->memptrs->fence = gpu->submitted_fence;
127+
adreno_gpu->memptrs->rptr = 0;
128+
adreno_gpu->memptrs->wptr = 0;
127129

128130
gpu->funcs->pm_resume(gpu);
129131
ret = gpu->funcs->hw_init(gpu);
@@ -229,7 +231,7 @@ void adreno_idle(struct msm_gpu *gpu)
229231
return;
230232
} while(time_before(jiffies, t));
231233

232-
DRM_ERROR("timeout waiting for %s to drain ringbuffer!\n", gpu->name);
234+
DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
233235

234236
/* TODO maybe we need to reset GPU here to recover from hang? */
235237
}
@@ -256,11 +258,17 @@ void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
256258
{
257259
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
258260
uint32_t freedwords;
261+
unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
259262
do {
260263
uint32_t size = gpu->rb->size / 4;
261264
uint32_t wptr = get_wptr(gpu->rb);
262265
uint32_t rptr = adreno_gpu->memptrs->rptr;
263266
freedwords = (rptr + (size - 1) - wptr) % size;
267+
268+
if (time_after(jiffies, t)) {
269+
DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
270+
break;
271+
}
264272
} while(freedwords < ndwords);
265273
}
266274

drivers/gpu/drm/msm/msm_drv.c

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -499,25 +499,41 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
499499
struct timespec *timeout)
500500
{
501501
struct msm_drm_private *priv = dev->dev_private;
502-
unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
503-
unsigned long start_jiffies = jiffies;
504-
unsigned long remaining_jiffies;
505502
int ret;
506503

507-
if (time_after(start_jiffies, timeout_jiffies))
508-
remaining_jiffies = 0;
509-
else
510-
remaining_jiffies = timeout_jiffies - start_jiffies;
511-
512-
ret = wait_event_interruptible_timeout(priv->fence_event,
513-
priv->completed_fence >= fence,
514-
remaining_jiffies);
515-
if (ret == 0) {
516-
DBG("timeout waiting for fence: %u (completed: %u)",
517-
fence, priv->completed_fence);
518-
ret = -ETIMEDOUT;
519-
} else if (ret != -ERESTARTSYS) {
520-
ret = 0;
504+
if (!priv->gpu)
505+
return 0;
506+
507+
if (fence > priv->gpu->submitted_fence) {
508+
DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
509+
fence, priv->gpu->submitted_fence);
510+
return -EINVAL;
511+
}
512+
513+
if (!timeout) {
514+
/* no-wait: */
515+
ret = fence_completed(dev, fence) ? 0 : -EBUSY;
516+
} else {
517+
unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
518+
unsigned long start_jiffies = jiffies;
519+
unsigned long remaining_jiffies;
520+
521+
if (time_after(start_jiffies, timeout_jiffies))
522+
remaining_jiffies = 0;
523+
else
524+
remaining_jiffies = timeout_jiffies - start_jiffies;
525+
526+
ret = wait_event_interruptible_timeout(priv->fence_event,
527+
fence_completed(dev, fence),
528+
remaining_jiffies);
529+
530+
if (ret == 0) {
531+
DBG("timeout waiting for fence: %u (completed: %u)",
532+
fence, priv->completed_fence);
533+
ret = -ETIMEDOUT;
534+
} else if (ret != -ERESTARTSYS) {
535+
ret = 0;
536+
}
521537
}
522538

523539
return ret;

drivers/gpu/drm/msm/msm_drv.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ void *msm_gem_vaddr(struct drm_gem_object *obj);
153153
int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
154154
struct work_struct *work);
155155
void msm_gem_move_to_active(struct drm_gem_object *obj,
156-
struct msm_gpu *gpu, uint32_t fence);
156+
struct msm_gpu *gpu, bool write, uint32_t fence);
157157
void msm_gem_move_to_inactive(struct drm_gem_object *obj);
158158
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
159159
struct timespec *timeout);
@@ -191,6 +191,12 @@ u32 msm_readl(const void __iomem *addr);
191191
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
192192
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
193193

194+
static inline bool fence_completed(struct drm_device *dev, uint32_t fence)
195+
{
196+
struct msm_drm_private *priv = dev->dev_private;
197+
return priv->completed_fence >= fence;
198+
}
199+
194200
static inline int align_pitch(int width, int bpp)
195201
{
196202
int bytespp = (bpp + 7) / 8;

drivers/gpu/drm/msm/msm_gem.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ static struct page **get_pages(struct drm_gem_object *obj)
4040
}
4141

4242
msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
43-
if (!msm_obj->sgt) {
43+
if (IS_ERR(msm_obj->sgt)) {
4444
dev_err(dev->dev, "failed to allocate sgt\n");
45-
return ERR_PTR(-ENOMEM);
45+
return ERR_CAST(msm_obj->sgt);
4646
}
4747

4848
msm_obj->pages = p;
@@ -159,7 +159,6 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
159159
out:
160160
switch (ret) {
161161
case -EAGAIN:
162-
set_need_resched();
163162
case 0:
164163
case -ERESTARTSYS:
165164
case -EINTR:
@@ -393,11 +392,14 @@ int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
393392
}
394393

395394
void msm_gem_move_to_active(struct drm_gem_object *obj,
396-
struct msm_gpu *gpu, uint32_t fence)
395+
struct msm_gpu *gpu, bool write, uint32_t fence)
397396
{
398397
struct msm_gem_object *msm_obj = to_msm_bo(obj);
399398
msm_obj->gpu = gpu;
400-
msm_obj->fence = fence;
399+
if (write)
400+
msm_obj->write_fence = fence;
401+
else
402+
msm_obj->read_fence = fence;
401403
list_del_init(&msm_obj->mm_list);
402404
list_add_tail(&msm_obj->mm_list, &gpu->active_list);
403405
}
@@ -411,7 +413,8 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj)
411413
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
412414

413415
msm_obj->gpu = NULL;
414-
msm_obj->fence = 0;
416+
msm_obj->read_fence = 0;
417+
msm_obj->write_fence = 0;
415418
list_del_init(&msm_obj->mm_list);
416419
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
417420

@@ -433,8 +436,18 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
433436
struct msm_gem_object *msm_obj = to_msm_bo(obj);
434437
int ret = 0;
435438

436-
if (is_active(msm_obj) && !(op & MSM_PREP_NOSYNC))
437-
ret = msm_wait_fence_interruptable(dev, msm_obj->fence, timeout);
439+
if (is_active(msm_obj)) {
440+
uint32_t fence = 0;
441+
442+
if (op & MSM_PREP_READ)
443+
fence = msm_obj->write_fence;
444+
if (op & MSM_PREP_WRITE)
445+
fence = max(fence, msm_obj->read_fence);
446+
if (op & MSM_PREP_NOSYNC)
447+
timeout = NULL;
448+
449+
ret = msm_wait_fence_interruptable(dev, fence, timeout);
450+
}
438451

439452
/* TODO cache maintenance */
440453

@@ -455,9 +468,10 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
455468
uint64_t off = drm_vma_node_start(&obj->vma_node);
456469

457470
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
458-
seq_printf(m, "%08x: %c(%d) %2d (%2d) %08llx %p %d\n",
471+
seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %d\n",
459472
msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
460-
msm_obj->fence, obj->name, obj->refcount.refcount.counter,
473+
msm_obj->read_fence, msm_obj->write_fence,
474+
obj->name, obj->refcount.refcount.counter,
461475
off, msm_obj->vaddr, obj->size);
462476
}
463477

drivers/gpu/drm/msm/msm_gem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct msm_gem_object {
3636
*/
3737
struct list_head mm_list;
3838
struct msm_gpu *gpu; /* non-null if active */
39-
uint32_t fence;
39+
uint32_t read_fence, write_fence;
4040

4141
/* Transiently in the process of submit ioctl, objects associated
4242
* with the submit are on submit->bo_list.. this only lasts for

drivers/gpu/drm/msm/msm_gem_submit.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
7878
}
7979

8080
if (submit_bo.flags & BO_INVALID_FLAGS) {
81-
DBG("invalid flags: %x", submit_bo.flags);
81+
DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
8282
ret = -EINVAL;
8383
goto out_unlock;
8484
}
@@ -92,15 +92,15 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
9292
*/
9393
obj = idr_find(&file->object_idr, submit_bo.handle);
9494
if (!obj) {
95-
DBG("invalid handle %u at index %u", submit_bo.handle, i);
95+
DRM_ERROR("invalid handle %u at index %u\n", submit_bo.handle, i);
9696
ret = -EINVAL;
9797
goto out_unlock;
9898
}
9999

100100
msm_obj = to_msm_bo(obj);
101101

102102
if (!list_empty(&msm_obj->submit_entry)) {
103-
DBG("handle %u at index %u already on submit list",
103+
DRM_ERROR("handle %u at index %u already on submit list\n",
104104
submit_bo.handle, i);
105105
ret = -EINVAL;
106106
goto out_unlock;
@@ -216,8 +216,9 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
216216
struct msm_gem_object **obj, uint32_t *iova, bool *valid)
217217
{
218218
if (idx >= submit->nr_bos) {
219-
DBG("invalid buffer index: %u (out of %u)", idx, submit->nr_bos);
220-
return EINVAL;
219+
DRM_ERROR("invalid buffer index: %u (out of %u)\n",
220+
idx, submit->nr_bos);
221+
return -EINVAL;
221222
}
222223

223224
if (obj)
@@ -239,7 +240,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
239240
int ret;
240241

241242
if (offset % 4) {
242-
DBG("non-aligned cmdstream buffer: %u", offset);
243+
DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
243244
return -EINVAL;
244245
}
245246

@@ -266,7 +267,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
266267
return -EFAULT;
267268

268269
if (submit_reloc.submit_offset % 4) {
269-
DBG("non-aligned reloc offset: %u",
270+
DRM_ERROR("non-aligned reloc offset: %u\n",
270271
submit_reloc.submit_offset);
271272
return -EINVAL;
272273
}
@@ -276,7 +277,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
276277

277278
if ((off >= (obj->base.size / 4)) ||
278279
(off < last_offset)) {
279-
DBG("invalid offset %u at reloc %u", off, i);
280+
DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
280281
return -EINVAL;
281282
}
282283

@@ -374,14 +375,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
374375
goto out;
375376

376377
if (submit_cmd.size % 4) {
377-
DBG("non-aligned cmdstream buffer size: %u",
378+
DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
378379
submit_cmd.size);
379380
ret = -EINVAL;
380381
goto out;
381382
}
382383

383-
if (submit_cmd.size >= msm_obj->base.size) {
384-
DBG("invalid cmdstream size: %u", submit_cmd.size);
384+
if ((submit_cmd.size + submit_cmd.submit_offset) >=
385+
msm_obj->base.size) {
386+
DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
385387
ret = -EINVAL;
386388
goto out;
387389
}

drivers/gpu/drm/msm/msm_gpu.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@
2929
static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev)
3030
{
3131
struct drm_device *dev = gpu->dev;
32-
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
32+
struct kgsl_device_platform_data *pdata;
3333

3434
if (!pdev) {
3535
dev_err(dev->dev, "could not find dtv pdata\n");
3636
return;
3737
}
3838

39+
pdata = pdev->dev.platform_data;
3940
if (pdata->bus_scale_table) {
4041
gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table);
4142
DBG("bus scale client: %08x", gpu->bsc);
@@ -230,21 +231,31 @@ static void hangcheck_timer_reset(struct msm_gpu *gpu)
230231
static void hangcheck_handler(unsigned long data)
231232
{
232233
struct msm_gpu *gpu = (struct msm_gpu *)data;
234+
struct drm_device *dev = gpu->dev;
235+
struct msm_drm_private *priv = dev->dev_private;
233236
uint32_t fence = gpu->funcs->last_fence(gpu);
234237

235238
if (fence != gpu->hangcheck_fence) {
236239
/* some progress has been made.. ya! */
237240
gpu->hangcheck_fence = fence;
238241
} else if (fence < gpu->submitted_fence) {
239242
/* no progress and not done.. hung! */
240-
struct msm_drm_private *priv = gpu->dev->dev_private;
241243
gpu->hangcheck_fence = fence;
244+
dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n",
245+
gpu->name);
246+
dev_err(dev->dev, "%s: completed fence: %u\n",
247+
gpu->name, fence);
248+
dev_err(dev->dev, "%s: submitted fence: %u\n",
249+
gpu->name, gpu->submitted_fence);
242250
queue_work(priv->wq, &gpu->recover_work);
243251
}
244252

245253
/* if still more pending work, reset the hangcheck timer: */
246254
if (gpu->submitted_fence > gpu->hangcheck_fence)
247255
hangcheck_timer_reset(gpu);
256+
257+
/* workaround for missing irq: */
258+
queue_work(priv->wq, &gpu->retire_work);
248259
}
249260

250261
/*
@@ -265,7 +276,8 @@ static void retire_worker(struct work_struct *work)
265276
obj = list_first_entry(&gpu->active_list,
266277
struct msm_gem_object, mm_list);
267278

268-
if (obj->fence <= fence) {
279+
if ((obj->read_fence <= fence) &&
280+
(obj->write_fence <= fence)) {
269281
/* move to inactive: */
270282
msm_gem_move_to_inactive(&obj->base);
271283
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,
321333
submit->gpu->id, &iova);
322334
}
323335

324-
msm_gem_move_to_active(&msm_obj->base, gpu, submit->fence);
336+
if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
337+
msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence);
338+
339+
if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
340+
msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
325341
}
326342
hangcheck_timer_reset(gpu);
327343
mutex_unlock(&dev->struct_mutex);

0 commit comments

Comments
 (0)