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

Changed files
+106 -44
drivers
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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);