+9
-1
drivers/gpu/drm/msm/adreno/adreno_gpu.c
+9
-1
drivers/gpu/drm/msm/adreno/adreno_gpu.c
···
124
124
125
125
/* reset completed fence seqno, just discard anything pending: */
126
126
adreno_gpu->memptrs->fence = gpu->submitted_fence;
127
+
adreno_gpu->memptrs->rptr = 0;
128
+
adreno_gpu->memptrs->wptr = 0;
127
129
128
130
gpu->funcs->pm_resume(gpu);
129
131
ret = gpu->funcs->hw_init(gpu);
···
231
229
return;
232
230
} while(time_before(jiffies, t));
233
231
234
-
DRM_ERROR("timeout waiting for %s to drain ringbuffer!\n", gpu->name);
232
+
DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
235
233
236
234
/* TODO maybe we need to reset GPU here to recover from hang? */
237
235
}
···
258
256
{
259
257
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
260
258
uint32_t freedwords;
259
+
unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
261
260
do {
262
261
uint32_t size = gpu->rb->size / 4;
263
262
uint32_t wptr = get_wptr(gpu->rb);
264
263
uint32_t rptr = adreno_gpu->memptrs->rptr;
265
264
freedwords = (rptr + (size - 1) - wptr) % size;
265
+
266
+
if (time_after(jiffies, t)) {
267
+
DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
268
+
break;
269
+
}
266
270
} while(freedwords < ndwords);
267
271
}
268
272
+32
-16
drivers/gpu/drm/msm/msm_drv.c
+32
-16
drivers/gpu/drm/msm/msm_drv.c
···
499
499
struct timespec *timeout)
500
500
{
501
501
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;
505
502
int ret;
506
503
507
-
if (time_after(start_jiffies, timeout_jiffies))
508
-
remaining_jiffies = 0;
509
-
else
510
-
remaining_jiffies = timeout_jiffies - start_jiffies;
504
+
if (!priv->gpu)
505
+
return 0;
511
506
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;
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
+
}
521
537
}
522
538
523
539
return ret;
+7
-1
drivers/gpu/drm/msm/msm_drv.h
+7
-1
drivers/gpu/drm/msm/msm_drv.h
···
153
153
int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
154
154
struct work_struct *work);
155
155
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);
157
157
void msm_gem_move_to_inactive(struct drm_gem_object *obj);
158
158
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
159
159
struct timespec *timeout);
···
190
190
191
191
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
192
192
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
193
+
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
+
}
193
199
194
200
static inline int align_pitch(int width, int bpp)
195
201
{
+24
-10
drivers/gpu/drm/msm/msm_gem.c
+24
-10
drivers/gpu/drm/msm/msm_gem.c
···
40
40
}
41
41
42
42
msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
43
-
if (!msm_obj->sgt) {
43
+
if (IS_ERR(msm_obj->sgt)) {
44
44
dev_err(dev->dev, "failed to allocate sgt\n");
45
-
return ERR_PTR(-ENOMEM);
45
+
return ERR_CAST(msm_obj->sgt);
46
46
}
47
47
48
48
msm_obj->pages = p;
···
159
159
out:
160
160
switch (ret) {
161
161
case -EAGAIN:
162
-
set_need_resched();
163
162
case 0:
164
163
case -ERESTARTSYS:
165
164
case -EINTR:
···
392
393
}
393
394
394
395
void msm_gem_move_to_active(struct drm_gem_object *obj,
395
-
struct msm_gpu *gpu, uint32_t fence)
396
+
struct msm_gpu *gpu, bool write, uint32_t fence)
396
397
{
397
398
struct msm_gem_object *msm_obj = to_msm_bo(obj);
398
399
msm_obj->gpu = gpu;
399
-
msm_obj->fence = fence;
400
+
if (write)
401
+
msm_obj->write_fence = fence;
402
+
else
403
+
msm_obj->read_fence = fence;
400
404
list_del_init(&msm_obj->mm_list);
401
405
list_add_tail(&msm_obj->mm_list, &gpu->active_list);
402
406
}
···
413
411
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
414
412
415
413
msm_obj->gpu = NULL;
416
-
msm_obj->fence = 0;
414
+
msm_obj->read_fence = 0;
415
+
msm_obj->write_fence = 0;
417
416
list_del_init(&msm_obj->mm_list);
418
417
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
419
418
···
436
433
struct msm_gem_object *msm_obj = to_msm_bo(obj);
437
434
int ret = 0;
438
435
439
-
if (is_active(msm_obj) && !(op & MSM_PREP_NOSYNC))
440
-
ret = msm_wait_fence_interruptable(dev, msm_obj->fence, timeout);
436
+
if (is_active(msm_obj)) {
437
+
uint32_t fence = 0;
438
+
439
+
if (op & MSM_PREP_READ)
440
+
fence = msm_obj->write_fence;
441
+
if (op & MSM_PREP_WRITE)
442
+
fence = max(fence, msm_obj->read_fence);
443
+
if (op & MSM_PREP_NOSYNC)
444
+
timeout = NULL;
445
+
446
+
ret = msm_wait_fence_interruptable(dev, fence, timeout);
447
+
}
441
448
442
449
/* TODO cache maintenance */
443
450
···
468
455
uint64_t off = drm_vma_node_start(&obj->vma_node);
469
456
470
457
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
471
-
seq_printf(m, "%08x: %c(%d) %2d (%2d) %08llx %p %d\n",
458
+
seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %d\n",
472
459
msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
473
-
msm_obj->fence, obj->name, obj->refcount.refcount.counter,
460
+
msm_obj->read_fence, msm_obj->write_fence,
461
+
obj->name, obj->refcount.refcount.counter,
474
462
off, msm_obj->vaddr, obj->size);
475
463
}
476
464
+1
-1
drivers/gpu/drm/msm/msm_gem.h
+1
-1
drivers/gpu/drm/msm/msm_gem.h
···
36
36
*/
37
37
struct list_head mm_list;
38
38
struct msm_gpu *gpu; /* non-null if active */
39
-
uint32_t fence;
39
+
uint32_t read_fence, write_fence;
40
40
41
41
/* Transiently in the process of submit ioctl, objects associated
42
42
* with the submit are on submit->bo_list.. this only lasts for
+13
-11
drivers/gpu/drm/msm/msm_gem_submit.c
+13
-11
drivers/gpu/drm/msm/msm_gem_submit.c
···
78
78
}
79
79
80
80
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);
82
82
ret = -EINVAL;
83
83
goto out_unlock;
84
84
}
···
92
92
*/
93
93
obj = idr_find(&file->object_idr, submit_bo.handle);
94
94
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);
96
96
ret = -EINVAL;
97
97
goto out_unlock;
98
98
}
···
100
100
msm_obj = to_msm_bo(obj);
101
101
102
102
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",
104
104
submit_bo.handle, i);
105
105
ret = -EINVAL;
106
106
goto out_unlock;
···
216
216
struct msm_gem_object **obj, uint32_t *iova, bool *valid)
217
217
{
218
218
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;
221
222
}
222
223
223
224
if (obj)
···
240
239
int ret;
241
240
242
241
if (offset % 4) {
243
-
DBG("non-aligned cmdstream buffer: %u", offset);
242
+
DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
244
243
return -EINVAL;
245
244
}
246
245
···
267
266
return -EFAULT;
268
267
269
268
if (submit_reloc.submit_offset % 4) {
270
-
DBG("non-aligned reloc offset: %u",
269
+
DRM_ERROR("non-aligned reloc offset: %u\n",
271
270
submit_reloc.submit_offset);
272
271
return -EINVAL;
273
272
}
···
277
276
278
277
if ((off >= (obj->base.size / 4)) ||
279
278
(off < last_offset)) {
280
-
DBG("invalid offset %u at reloc %u", off, i);
279
+
DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
281
280
return -EINVAL;
282
281
}
283
282
···
375
374
goto out;
376
375
377
376
if (submit_cmd.size % 4) {
378
-
DBG("non-aligned cmdstream buffer size: %u",
377
+
DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
379
378
submit_cmd.size);
380
379
ret = -EINVAL;
381
380
goto out;
382
381
}
383
382
384
-
if (submit_cmd.size >= msm_obj->base.size) {
385
-
DBG("invalid cmdstream size: %u", submit_cmd.size);
383
+
if ((submit_cmd.size + submit_cmd.submit_offset) >=
384
+
msm_obj->base.size) {
385
+
DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
386
386
ret = -EINVAL;
387
387
goto out;
388
388
}
+20
-4
drivers/gpu/drm/msm/msm_gpu.c
+20
-4
drivers/gpu/drm/msm/msm_gpu.c
···
29
29
static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev)
30
30
{
31
31
struct drm_device *dev = gpu->dev;
32
-
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
32
+
struct kgsl_device_platform_data *pdata;
33
33
34
34
if (!pdev) {
35
35
dev_err(dev->dev, "could not find dtv pdata\n");
36
36
return;
37
37
}
38
38
39
+
pdata = pdev->dev.platform_data;
39
40
if (pdata->bus_scale_table) {
40
41
gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table);
41
42
DBG("bus scale client: %08x", gpu->bsc);
···
231
230
static void hangcheck_handler(unsigned long data)
232
231
{
233
232
struct msm_gpu *gpu = (struct msm_gpu *)data;
233
+
struct drm_device *dev = gpu->dev;
234
+
struct msm_drm_private *priv = dev->dev_private;
234
235
uint32_t fence = gpu->funcs->last_fence(gpu);
235
236
236
237
if (fence != gpu->hangcheck_fence) {
···
240
237
gpu->hangcheck_fence = fence;
241
238
} else if (fence < gpu->submitted_fence) {
242
239
/* no progress and not done.. hung! */
243
-
struct msm_drm_private *priv = gpu->dev->dev_private;
244
240
gpu->hangcheck_fence = fence;
241
+
dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n",
242
+
gpu->name);
243
+
dev_err(dev->dev, "%s: completed fence: %u\n",
244
+
gpu->name, fence);
245
+
dev_err(dev->dev, "%s: submitted fence: %u\n",
246
+
gpu->name, gpu->submitted_fence);
245
247
queue_work(priv->wq, &gpu->recover_work);
246
248
}
247
249
248
250
/* if still more pending work, reset the hangcheck timer: */
249
251
if (gpu->submitted_fence > gpu->hangcheck_fence)
250
252
hangcheck_timer_reset(gpu);
253
+
254
+
/* workaround for missing irq: */
255
+
queue_work(priv->wq, &gpu->retire_work);
251
256
}
252
257
253
258
/*
···
276
265
obj = list_first_entry(&gpu->active_list,
277
266
struct msm_gem_object, mm_list);
278
267
279
-
if (obj->fence <= fence) {
268
+
if ((obj->read_fence <= fence) &&
269
+
(obj->write_fence <= fence)) {
280
270
/* move to inactive: */
281
271
msm_gem_move_to_inactive(&obj->base);
282
272
msm_gem_put_iova(&obj->base, gpu->id);
···
333
321
submit->gpu->id, &iova);
334
322
}
335
323
336
-
msm_gem_move_to_active(&msm_obj->base, gpu, submit->fence);
324
+
if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
325
+
msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence);
326
+
327
+
if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
328
+
msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
337
329
}
338
330
hangcheck_timer_reset(gpu);
339
331
mutex_unlock(&dev->struct_mutex);