aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_dma.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-03-11 15:30:04 -0400
committerEric Anholt <eric@anholt.net>2009-03-27 17:47:34 -0400
commit201361a54ed187d8595a283e3a4ddb213bc8323b (patch)
tree12a5d23a45f72f8bd917161735d55985654b52e0 /drivers/gpu/drm/i915/i915_dma.c
parenteb01459fbbccb4ca0b879cbfc97e33ac6eabf975 (diff)
drm/i915: Fix lock order reversal with cliprects and cmdbuf in non-DRI2 paths.
This introduces allocation in the batch submission path that wasn't there previously, but these are compatibility paths so we care about simplicity more than performance. kernel.org bug #12419. Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Keith Packard <keithp@keithp.com> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_dma.c')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c107
1 files changed, 73 insertions, 34 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 6d21b9e48b89..ae83fe0ab374 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -356,7 +356,7 @@ static int validate_cmd(int cmd)
356 return ret; 356 return ret;
357} 357}
358 358
359static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwords) 359static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
360{ 360{
361 drm_i915_private_t *dev_priv = dev->dev_private; 361 drm_i915_private_t *dev_priv = dev->dev_private;
362 int i; 362 int i;
@@ -370,8 +370,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
370 for (i = 0; i < dwords;) { 370 for (i = 0; i < dwords;) {
371 int cmd, sz; 371 int cmd, sz;
372 372
373 if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) 373 cmd = buffer[i];
374 return -EINVAL;
375 374
376 if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) 375 if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
377 return -EINVAL; 376 return -EINVAL;
@@ -379,11 +378,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
379 OUT_RING(cmd); 378 OUT_RING(cmd);
380 379
381 while (++i, --sz) { 380 while (++i, --sz) {
382 if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], 381 OUT_RING(buffer[i]);
383 sizeof(cmd))) {
384 return -EINVAL;
385 }
386 OUT_RING(cmd);
387 } 382 }
388 } 383 }
389 384
@@ -397,17 +392,13 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
397 392
398int 393int
399i915_emit_box(struct drm_device *dev, 394i915_emit_box(struct drm_device *dev,
400 struct drm_clip_rect __user *boxes, 395 struct drm_clip_rect *boxes,
401 int i, int DR1, int DR4) 396 int i, int DR1, int DR4)
402{ 397{
403 drm_i915_private_t *dev_priv = dev->dev_private; 398 drm_i915_private_t *dev_priv = dev->dev_private;
404 struct drm_clip_rect box; 399 struct drm_clip_rect box = boxes[i];
405 RING_LOCALS; 400 RING_LOCALS;
406 401
407 if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
408 return -EFAULT;
409 }
410
411 if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { 402 if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
412 DRM_ERROR("Bad box %d,%d..%d,%d\n", 403 DRM_ERROR("Bad box %d,%d..%d,%d\n",
413 box.x1, box.y1, box.x2, box.y2); 404 box.x1, box.y1, box.x2, box.y2);
@@ -460,7 +451,9 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
460} 451}
461 452
462static int i915_dispatch_cmdbuffer(struct drm_device * dev, 453static int i915_dispatch_cmdbuffer(struct drm_device * dev,
463 drm_i915_cmdbuffer_t * cmd) 454 drm_i915_cmdbuffer_t *cmd,
455 struct drm_clip_rect *cliprects,
456 void *cmdbuf)
464{ 457{
465 int nbox = cmd->num_cliprects; 458 int nbox = cmd->num_cliprects;
466 int i = 0, count, ret; 459 int i = 0, count, ret;
@@ -476,13 +469,13 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
476 469
477 for (i = 0; i < count; i++) { 470 for (i = 0; i < count; i++) {
478 if (i < nbox) { 471 if (i < nbox) {
479 ret = i915_emit_box(dev, cmd->cliprects, i, 472 ret = i915_emit_box(dev, cliprects, i,
480 cmd->DR1, cmd->DR4); 473 cmd->DR1, cmd->DR4);
481 if (ret) 474 if (ret)
482 return ret; 475 return ret;
483 } 476 }
484 477
485 ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4); 478 ret = i915_emit_cmds(dev, cmdbuf, cmd->sz / 4);
486 if (ret) 479 if (ret)
487 return ret; 480 return ret;
488 } 481 }
@@ -492,10 +485,10 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
492} 485}
493 486
494static int i915_dispatch_batchbuffer(struct drm_device * dev, 487static int i915_dispatch_batchbuffer(struct drm_device * dev,
495 drm_i915_batchbuffer_t * batch) 488 drm_i915_batchbuffer_t * batch,
489 struct drm_clip_rect *cliprects)
496{ 490{
497 drm_i915_private_t *dev_priv = dev->dev_private; 491 drm_i915_private_t *dev_priv = dev->dev_private;
498 struct drm_clip_rect __user *boxes = batch->cliprects;
499 int nbox = batch->num_cliprects; 492 int nbox = batch->num_cliprects;
500 int i = 0, count; 493 int i = 0, count;
501 RING_LOCALS; 494 RING_LOCALS;
@@ -511,7 +504,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
511 504
512 for (i = 0; i < count; i++) { 505 for (i = 0; i < count; i++) {
513 if (i < nbox) { 506 if (i < nbox) {
514 int ret = i915_emit_box(dev, boxes, i, 507 int ret = i915_emit_box(dev, cliprects, i,
515 batch->DR1, batch->DR4); 508 batch->DR1, batch->DR4);
516 if (ret) 509 if (ret)
517 return ret; 510 return ret;
@@ -626,6 +619,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
626 master_priv->sarea_priv; 619 master_priv->sarea_priv;
627 drm_i915_batchbuffer_t *batch = data; 620 drm_i915_batchbuffer_t *batch = data;
628 int ret; 621 int ret;
622 struct drm_clip_rect *cliprects = NULL;
629 623
630 if (!dev_priv->allow_batchbuffer) { 624 if (!dev_priv->allow_batchbuffer) {
631 DRM_ERROR("Batchbuffer ioctl disabled\n"); 625 DRM_ERROR("Batchbuffer ioctl disabled\n");
@@ -637,17 +631,35 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
637 631
638 RING_LOCK_TEST_WITH_RETURN(dev, file_priv); 632 RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
639 633
640 if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects, 634 if (batch->num_cliprects < 0)
641 batch->num_cliprects * 635 return -EINVAL;
642 sizeof(struct drm_clip_rect))) 636
643 return -EFAULT; 637 if (batch->num_cliprects) {
638 cliprects = drm_calloc(batch->num_cliprects,
639 sizeof(struct drm_clip_rect),
640 DRM_MEM_DRIVER);
641 if (cliprects == NULL)
642 return -ENOMEM;
643
644 ret = copy_from_user(cliprects, batch->cliprects,
645 batch->num_cliprects *
646 sizeof(struct drm_clip_rect));
647 if (ret != 0)
648 goto fail_free;
649 }
644 650
645 mutex_lock(&dev->struct_mutex); 651 mutex_lock(&dev->struct_mutex);
646 ret = i915_dispatch_batchbuffer(dev, batch); 652 ret = i915_dispatch_batchbuffer(dev, batch, cliprects);
647 mutex_unlock(&dev->struct_mutex); 653 mutex_unlock(&dev->struct_mutex);
648 654
649 if (sarea_priv) 655 if (sarea_priv)
650 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 656 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
657
658fail_free:
659 drm_free(cliprects,
660 batch->num_cliprects * sizeof(struct drm_clip_rect),
661 DRM_MEM_DRIVER);
662
651 return ret; 663 return ret;
652} 664}
653 665
@@ -659,6 +671,8 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
659 drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) 671 drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
660 master_priv->sarea_priv; 672 master_priv->sarea_priv;
661 drm_i915_cmdbuffer_t *cmdbuf = data; 673 drm_i915_cmdbuffer_t *cmdbuf = data;
674 struct drm_clip_rect *cliprects = NULL;
675 void *batch_data;
662 int ret; 676 int ret;
663 677
664 DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", 678 DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
@@ -666,25 +680,50 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
666 680
667 RING_LOCK_TEST_WITH_RETURN(dev, file_priv); 681 RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
668 682
669 if (cmdbuf->num_cliprects && 683 if (cmdbuf->num_cliprects < 0)
670 DRM_VERIFYAREA_READ(cmdbuf->cliprects, 684 return -EINVAL;
671 cmdbuf->num_cliprects * 685
672 sizeof(struct drm_clip_rect))) { 686 batch_data = drm_alloc(cmdbuf->sz, DRM_MEM_DRIVER);
673 DRM_ERROR("Fault accessing cliprects\n"); 687 if (batch_data == NULL)
674 return -EFAULT; 688 return -ENOMEM;
689
690 ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz);
691 if (ret != 0)
692 goto fail_batch_free;
693
694 if (cmdbuf->num_cliprects) {
695 cliprects = drm_calloc(cmdbuf->num_cliprects,
696 sizeof(struct drm_clip_rect),
697 DRM_MEM_DRIVER);
698 if (cliprects == NULL)
699 goto fail_batch_free;
700
701 ret = copy_from_user(cliprects, cmdbuf->cliprects,
702 cmdbuf->num_cliprects *
703 sizeof(struct drm_clip_rect));
704 if (ret != 0)
705 goto fail_clip_free;
675 } 706 }
676 707
677 mutex_lock(&dev->struct_mutex); 708 mutex_lock(&dev->struct_mutex);
678 ret = i915_dispatch_cmdbuffer(dev, cmdbuf); 709 ret = i915_dispatch_cmdbuffer(dev, cmdbuf, cliprects, batch_data);
679 mutex_unlock(&dev->struct_mutex); 710 mutex_unlock(&dev->struct_mutex);
680 if (ret) { 711 if (ret) {
681 DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); 712 DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
682 return ret; 713 goto fail_batch_free;
683 } 714 }
684 715
685 if (sarea_priv) 716 if (sarea_priv)
686 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 717 sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
687 return 0; 718
719fail_batch_free:
720 drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER);
721fail_clip_free:
722 drm_free(cliprects,
723 cmdbuf->num_cliprects * sizeof(struct drm_clip_rect),
724 DRM_MEM_DRIVER);
725
726 return ret;
688} 727}
689 728
690static int i915_flip_bufs(struct drm_device *dev, void *data, 729static int i915_flip_bufs(struct drm_device *dev, void *data,