aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2011-12-21 04:50:56 -0500
committerDave Airlie <airlied@redhat.com>2011-12-21 04:50:56 -0500
commit4cf73129cbe001b41be2f8b56f763fbf3acaa4ce (patch)
tree2cdde82f48800ae1746775bab7e4f3c5f1fc3b88 /drivers/gpu/drm/vmwgfx
parent3e54f5b72b44a5b905dc56442b147b0ee0475a1d (diff)
parent6abff3c78051e40130a1c653f874fb12b9d40254 (diff)
Merge remote-tracking branch 'pfdo/drm-fixes' into drm-core-next
-next reported a messy merge, so I've merged my upstream pull into my -next tree. Conflicts: drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
Diffstat (limited to 'drivers/gpu/drm/vmwgfx')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c16
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c390
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c22
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c23
7 files changed, 318 insertions, 151 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 8cca91a93bde..dc279706ca70 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -390,6 +390,11 @@ extern int vmw_context_check(struct vmw_private *dev_priv,
390 struct ttm_object_file *tfile, 390 struct ttm_object_file *tfile,
391 int id, 391 int id,
392 struct vmw_resource **p_res); 392 struct vmw_resource **p_res);
393extern int vmw_user_lookup_handle(struct vmw_private *dev_priv,
394 struct ttm_object_file *tfile,
395 uint32_t handle,
396 struct vmw_surface **out_surf,
397 struct vmw_dma_buffer **out_buf);
393extern void vmw_surface_res_free(struct vmw_resource *res); 398extern void vmw_surface_res_free(struct vmw_resource *res);
394extern int vmw_surface_init(struct vmw_private *dev_priv, 399extern int vmw_surface_init(struct vmw_private *dev_priv,
395 struct vmw_surface *srf, 400 struct vmw_surface *srf,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index 03bbc2a6f9a7..a0c2f12b1e1b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -33,6 +33,7 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
33{ 33{
34 __le32 __iomem *fifo_mem = dev_priv->mmio_virt; 34 __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
35 uint32_t fifo_min, hwversion; 35 uint32_t fifo_min, hwversion;
36 const struct vmw_fifo_state *fifo = &dev_priv->fifo;
36 37
37 if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) 38 if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
38 return false; 39 return false;
@@ -41,7 +42,12 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
41 if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) 42 if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int))
42 return false; 43 return false;
43 44
44 hwversion = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); 45 hwversion = ioread32(fifo_mem +
46 ((fifo->capabilities &
47 SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
48 SVGA_FIFO_3D_HWVERSION_REVISED :
49 SVGA_FIFO_3D_HWVERSION));
50
45 if (hwversion == 0) 51 if (hwversion == 0)
46 return false; 52 return false;
47 53
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 5ff561d4e0b4..66917c6c3813 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -58,8 +58,14 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
58 case DRM_VMW_PARAM_FIFO_HW_VERSION: 58 case DRM_VMW_PARAM_FIFO_HW_VERSION:
59 { 59 {
60 __le32 __iomem *fifo_mem = dev_priv->mmio_virt; 60 __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
61 61 const struct vmw_fifo_state *fifo = &dev_priv->fifo;
62 param->value = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); 62
63 param->value =
64 ioread32(fifo_mem +
65 ((fifo->capabilities &
66 SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?
67 SVGA_FIFO_3D_HWVERSION_REVISED :
68 SVGA_FIFO_3D_HWVERSION));
63 break; 69 break;
64 } 70 }
65 default: 71 default:
@@ -166,13 +172,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
166 ret = -EINVAL; 172 ret = -EINVAL;
167 goto out_no_fb; 173 goto out_no_fb;
168 } 174 }
169
170 vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); 175 vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
171 if (!vfb->dmabuf) {
172 DRM_ERROR("Framebuffer not dmabuf backed.\n");
173 ret = -EINVAL;
174 goto out_no_fb;
175 }
176 176
177 ret = ttm_read_lock(&vmaster->lock, true); 177 ret = ttm_read_lock(&vmaster->lock, true);
178 if (unlikely(ret != 0)) 178 if (unlikely(ret != 0))
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 1748a7142aca..c4bdef3062c7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -31,6 +31,44 @@
31/* Might need a hrtimer here? */ 31/* Might need a hrtimer here? */
32#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) 32#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
33 33
34
35struct vmw_clip_rect {
36 int x1, x2, y1, y2;
37};
38
39/**
40 * Clip @num_rects number of @rects against @clip storing the
41 * results in @out_rects and the number of passed rects in @out_num.
42 */
43void vmw_clip_cliprects(struct drm_clip_rect *rects,
44 int num_rects,
45 struct vmw_clip_rect clip,
46 SVGASignedRect *out_rects,
47 int *out_num)
48{
49 int i, k;
50
51 for (i = 0, k = 0; i < num_rects; i++) {
52 int x1 = max_t(int, clip.x1, rects[i].x1);
53 int y1 = max_t(int, clip.y1, rects[i].y1);
54 int x2 = min_t(int, clip.x2, rects[i].x2);
55 int y2 = min_t(int, clip.y2, rects[i].y2);
56
57 if (x1 >= x2)
58 continue;
59 if (y1 >= y2)
60 continue;
61
62 out_rects[k].left = x1;
63 out_rects[k].top = y1;
64 out_rects[k].right = x2;
65 out_rects[k].bottom = y2;
66 k++;
67 }
68
69 *out_num = k;
70}
71
34void vmw_display_unit_cleanup(struct vmw_display_unit *du) 72void vmw_display_unit_cleanup(struct vmw_display_unit *du)
35{ 73{
36 if (du->cursor_surface) 74 if (du->cursor_surface)
@@ -82,6 +120,43 @@ int vmw_cursor_update_image(struct vmw_private *dev_priv,
82 return 0; 120 return 0;
83} 121}
84 122
123int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv,
124 struct vmw_dma_buffer *dmabuf,
125 u32 width, u32 height,
126 u32 hotspotX, u32 hotspotY)
127{
128 struct ttm_bo_kmap_obj map;
129 unsigned long kmap_offset;
130 unsigned long kmap_num;
131 void *virtual;
132 bool dummy;
133 int ret;
134
135 kmap_offset = 0;
136 kmap_num = (width*height*4 + PAGE_SIZE - 1) >> PAGE_SHIFT;
137
138 ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0);
139 if (unlikely(ret != 0)) {
140 DRM_ERROR("reserve failed\n");
141 return -EINVAL;
142 }
143
144 ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map);
145 if (unlikely(ret != 0))
146 goto err_unreserve;
147
148 virtual = ttm_kmap_obj_virtual(&map, &dummy);
149 ret = vmw_cursor_update_image(dev_priv, virtual, width, height,
150 hotspotX, hotspotY);
151
152 ttm_bo_kunmap(&map);
153err_unreserve:
154 ttm_bo_unreserve(&dmabuf->base);
155
156 return ret;
157}
158
159
85void vmw_cursor_update_position(struct vmw_private *dev_priv, 160void vmw_cursor_update_position(struct vmw_private *dev_priv,
86 bool show, int x, int y) 161 bool show, int x, int y)
87{ 162{
@@ -110,24 +185,21 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
110 return -EINVAL; 185 return -EINVAL;
111 186
112 if (handle) { 187 if (handle) {
113 ret = vmw_user_surface_lookup_handle(dev_priv, tfile, 188 ret = vmw_user_lookup_handle(dev_priv, tfile,
114 handle, &surface); 189 handle, &surface, &dmabuf);
115 if (!ret) { 190 if (ret) {
116 if (!surface->snooper.image) { 191 DRM_ERROR("failed to find surface or dmabuf: %i\n", ret);
117 DRM_ERROR("surface not suitable for cursor\n"); 192 return -EINVAL;
118 vmw_surface_unreference(&surface);
119 return -EINVAL;
120 }
121 } else {
122 ret = vmw_user_dmabuf_lookup(tfile,
123 handle, &dmabuf);
124 if (ret) {
125 DRM_ERROR("failed to find surface or dmabuf: %i\n", ret);
126 return -EINVAL;
127 }
128 } 193 }
129 } 194 }
130 195
196 /* need to do this before taking down old image */
197 if (surface && !surface->snooper.image) {
198 DRM_ERROR("surface not suitable for cursor\n");
199 vmw_surface_unreference(&surface);
200 return -EINVAL;
201 }
202
131 /* takedown old cursor */ 203 /* takedown old cursor */
132 if (du->cursor_surface) { 204 if (du->cursor_surface) {
133 du->cursor_surface->snooper.crtc = NULL; 205 du->cursor_surface->snooper.crtc = NULL;
@@ -146,36 +218,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
146 vmw_cursor_update_image(dev_priv, surface->snooper.image, 218 vmw_cursor_update_image(dev_priv, surface->snooper.image,
147 64, 64, du->hotspot_x, du->hotspot_y); 219 64, 64, du->hotspot_x, du->hotspot_y);
148 } else if (dmabuf) { 220 } else if (dmabuf) {
149 struct ttm_bo_kmap_obj map;
150 unsigned long kmap_offset;
151 unsigned long kmap_num;
152 void *virtual;
153 bool dummy;
154
155 /* vmw_user_surface_lookup takes one reference */ 221 /* vmw_user_surface_lookup takes one reference */
156 du->cursor_dmabuf = dmabuf; 222 du->cursor_dmabuf = dmabuf;
157 223
158 kmap_offset = 0; 224 ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height,
159 kmap_num = (64*64*4) >> PAGE_SHIFT; 225 du->hotspot_x, du->hotspot_y);
160
161 ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0);
162 if (unlikely(ret != 0)) {
163 DRM_ERROR("reserve failed\n");
164 return -EINVAL;
165 }
166
167 ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map);
168 if (unlikely(ret != 0))
169 goto err_unreserve;
170
171 virtual = ttm_kmap_obj_virtual(&map, &dummy);
172 vmw_cursor_update_image(dev_priv, virtual, 64, 64,
173 du->hotspot_x, du->hotspot_y);
174
175 ttm_bo_kunmap(&map);
176err_unreserve:
177 ttm_bo_unreserve(&dmabuf->base);
178
179 } else { 226 } else {
180 vmw_cursor_update_position(dev_priv, false, 0, 0); 227 vmw_cursor_update_position(dev_priv, false, 0, 0);
181 return 0; 228 return 0;
@@ -377,8 +424,9 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
377 struct drm_clip_rect *clips, 424 struct drm_clip_rect *clips,
378 unsigned num_clips, int inc) 425 unsigned num_clips, int inc)
379{ 426{
380 struct drm_clip_rect *clips_ptr;
381 struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; 427 struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
428 struct drm_clip_rect *clips_ptr;
429 struct drm_clip_rect *tmp;
382 struct drm_crtc *crtc; 430 struct drm_crtc *crtc;
383 size_t fifo_size; 431 size_t fifo_size;
384 int i, num_units; 432 int i, num_units;
@@ -391,7 +439,6 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
391 } *cmd; 439 } *cmd;
392 SVGASignedRect *blits; 440 SVGASignedRect *blits;
393 441
394
395 num_units = 0; 442 num_units = 0;
396 list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, 443 list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
397 head) { 444 head) {
@@ -402,13 +449,24 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
402 449
403 BUG_ON(!clips || !num_clips); 450 BUG_ON(!clips || !num_clips);
404 451
452 tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL);
453 if (unlikely(tmp == NULL)) {
454 DRM_ERROR("Temporary cliprect memory alloc failed.\n");
455 return -ENOMEM;
456 }
457
405 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; 458 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
406 cmd = kzalloc(fifo_size, GFP_KERNEL); 459 cmd = kzalloc(fifo_size, GFP_KERNEL);
407 if (unlikely(cmd == NULL)) { 460 if (unlikely(cmd == NULL)) {
408 DRM_ERROR("Temporary fifo memory alloc failed.\n"); 461 DRM_ERROR("Temporary fifo memory alloc failed.\n");
409 return -ENOMEM; 462 ret = -ENOMEM;
463 goto out_free_tmp;
410 } 464 }
411 465
466 /* setup blits pointer */
467 blits = (SVGASignedRect *)&cmd[1];
468
469 /* initial clip region */
412 left = clips->x1; 470 left = clips->x1;
413 right = clips->x2; 471 right = clips->x2;
414 top = clips->y1; 472 top = clips->y1;
@@ -434,45 +492,60 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
434 cmd->body.srcRect.bottom = bottom; 492 cmd->body.srcRect.bottom = bottom;
435 493
436 clips_ptr = clips; 494 clips_ptr = clips;
437 blits = (SVGASignedRect *)&cmd[1];
438 for (i = 0; i < num_clips; i++, clips_ptr += inc) { 495 for (i = 0; i < num_clips; i++, clips_ptr += inc) {
439 blits[i].left = clips_ptr->x1 - left; 496 tmp[i].x1 = clips_ptr->x1 - left;
440 blits[i].right = clips_ptr->x2 - left; 497 tmp[i].x2 = clips_ptr->x2 - left;
441 blits[i].top = clips_ptr->y1 - top; 498 tmp[i].y1 = clips_ptr->y1 - top;
442 blits[i].bottom = clips_ptr->y2 - top; 499 tmp[i].y2 = clips_ptr->y2 - top;
443 } 500 }
444 501
445 /* do per unit writing, reuse fifo for each */ 502 /* do per unit writing, reuse fifo for each */
446 for (i = 0; i < num_units; i++) { 503 for (i = 0; i < num_units; i++) {
447 struct vmw_display_unit *unit = units[i]; 504 struct vmw_display_unit *unit = units[i];
448 int clip_x1 = left - unit->crtc.x; 505 struct vmw_clip_rect clip;
449 int clip_y1 = top - unit->crtc.y; 506 int num;
450 int clip_x2 = right - unit->crtc.x; 507
451 int clip_y2 = bottom - unit->crtc.y; 508 clip.x1 = left - unit->crtc.x;
509 clip.y1 = top - unit->crtc.y;
510 clip.x2 = right - unit->crtc.x;
511 clip.y2 = bottom - unit->crtc.y;
452 512
453 /* skip any crtcs that misses the clip region */ 513 /* skip any crtcs that misses the clip region */
454 if (clip_x1 >= unit->crtc.mode.hdisplay || 514 if (clip.x1 >= unit->crtc.mode.hdisplay ||
455 clip_y1 >= unit->crtc.mode.vdisplay || 515 clip.y1 >= unit->crtc.mode.vdisplay ||
456 clip_x2 <= 0 || clip_y2 <= 0) 516 clip.x2 <= 0 || clip.y2 <= 0)
457 continue; 517 continue;
458 518
519 /*
520 * In order for the clip rects to be correctly scaled
521 * the src and dest rects needs to be the same size.
522 */
523 cmd->body.destRect.left = clip.x1;
524 cmd->body.destRect.right = clip.x2;
525 cmd->body.destRect.top = clip.y1;
526 cmd->body.destRect.bottom = clip.y2;
527
528 /* create a clip rect of the crtc in dest coords */
529 clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
530 clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
531 clip.x1 = 0 - clip.x1;
532 clip.y1 = 0 - clip.y1;
533
459 /* need to reset sid as it is changed by execbuf */ 534 /* need to reset sid as it is changed by execbuf */
460 cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); 535 cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle);
461
462 cmd->body.destScreenId = unit->unit; 536 cmd->body.destScreenId = unit->unit;
463 537
464 /* 538 /* clip and write blits to cmd stream */
465 * The blit command is a lot more resilient then the 539 vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
466 * readback command when it comes to clip rects. So its
467 * okay to go out of bounds.
468 */
469 540
470 cmd->body.destRect.left = clip_x1; 541 /* if no cliprects hit skip this */
471 cmd->body.destRect.right = clip_x2; 542 if (num == 0)
472 cmd->body.destRect.top = clip_y1; 543 continue;
473 cmd->body.destRect.bottom = clip_y2;
474 544
475 545
546 /* recalculate package length */
547 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
548 cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
476 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, 549 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
477 fifo_size, 0, NULL); 550 fifo_size, 0, NULL);
478 551
@@ -480,7 +553,10 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
480 break; 553 break;
481 } 554 }
482 555
556
483 kfree(cmd); 557 kfree(cmd);
558out_free_tmp:
559 kfree(tmp);
484 560
485 return ret; 561 return ret;
486} 562}
@@ -556,6 +632,10 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
556 * Sanity checks. 632 * Sanity checks.
557 */ 633 */
558 634
635 /* Surface must be marked as a scanout. */
636 if (unlikely(!surface->scanout))
637 return -EINVAL;
638
559 if (unlikely(surface->mip_levels[0] != 1 || 639 if (unlikely(surface->mip_levels[0] != 1 ||
560 surface->num_sizes != 1 || 640 surface->num_sizes != 1 ||
561 surface->sizes[0].width < mode_cmd->width || 641 surface->sizes[0].width < mode_cmd->width ||
@@ -782,6 +862,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
782 int clip_y1 = clips_ptr->y1 - unit->crtc.y; 862 int clip_y1 = clips_ptr->y1 - unit->crtc.y;
783 int clip_x2 = clips_ptr->x2 - unit->crtc.x; 863 int clip_x2 = clips_ptr->x2 - unit->crtc.x;
784 int clip_y2 = clips_ptr->y2 - unit->crtc.y; 864 int clip_y2 = clips_ptr->y2 - unit->crtc.y;
865 int move_x, move_y;
785 866
786 /* skip any crtcs that misses the clip region */ 867 /* skip any crtcs that misses the clip region */
787 if (clip_x1 >= unit->crtc.mode.hdisplay || 868 if (clip_x1 >= unit->crtc.mode.hdisplay ||
@@ -789,12 +870,21 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
789 clip_x2 <= 0 || clip_y2 <= 0) 870 clip_x2 <= 0 || clip_y2 <= 0)
790 continue; 871 continue;
791 872
873 /* clip size to crtc size */
874 clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay);
875 clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay);
876
877 /* translate both src and dest to bring clip into screen */
878 move_x = min_t(int, clip_x1, 0);
879 move_y = min_t(int, clip_y1, 0);
880
881 /* actual translate done here */
792 blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; 882 blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
793 blits[hit_num].body.destScreenId = unit->unit; 883 blits[hit_num].body.destScreenId = unit->unit;
794 blits[hit_num].body.srcOrigin.x = clips_ptr->x1; 884 blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x;
795 blits[hit_num].body.srcOrigin.y = clips_ptr->y1; 885 blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y;
796 blits[hit_num].body.destRect.left = clip_x1; 886 blits[hit_num].body.destRect.left = clip_x1 - move_x;
797 blits[hit_num].body.destRect.top = clip_y1; 887 blits[hit_num].body.destRect.top = clip_y1 - move_y;
798 blits[hit_num].body.destRect.right = clip_x2; 888 blits[hit_num].body.destRect.right = clip_x2;
799 blits[hit_num].body.destRect.bottom = clip_y2; 889 blits[hit_num].body.destRect.bottom = clip_y2;
800 hit_num++; 890 hit_num++;
@@ -1045,42 +1135,29 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
1045 * End conditioned code. 1135 * End conditioned code.
1046 */ 1136 */
1047 1137
1048 ret = vmw_user_surface_lookup_handle(dev_priv, tfile, 1138 /* returns either a dmabuf or surface */
1049 mode_cmd.handle, &surface); 1139 ret = vmw_user_lookup_handle(dev_priv, tfile,
1140 mode_cmd.handle,
1141 &surface, &bo);
1050 if (ret) 1142 if (ret)
1051 goto try_dmabuf; 1143 goto err_out;
1052 1144
1053 if (!surface->scanout) 1145 /* Create the new framebuffer depending one what we got back */
1054 goto err_not_scanout; 1146 if (bo)
1055 1147 ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
1056 ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface, 1148 &mode_cmd);
1057 &vfb, &mode_cmd); 1149 else if (surface)
1058 1150 ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv,
1059 /* vmw_user_surface_lookup takes one ref so does new_fb */ 1151 surface, &vfb, &mode_cmd);
1060 vmw_surface_unreference(&surface); 1152 else
1061 1153 BUG();
1062 if (ret) {
1063 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
1064 ttm_base_object_unref(&user_obj);
1065 return ERR_PTR(ret);
1066 } else
1067 vfb->user_obj = user_obj;
1068 return &vfb->base;
1069
1070try_dmabuf:
1071 DRM_INFO("%s: trying buffer\n", __func__);
1072
1073 ret = vmw_user_dmabuf_lookup(tfile, mode_cmd.handle, &bo);
1074 if (ret) {
1075 DRM_ERROR("failed to find buffer: %i\n", ret);
1076 return ERR_PTR(-ENOENT);
1077 }
1078
1079 ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
1080 &mode_cmd);
1081 1154
1082 /* vmw_user_dmabuf_lookup takes one ref so does new_fb */ 1155err_out:
1083 vmw_dmabuf_unreference(&bo); 1156 /* vmw_user_lookup_handle takes one ref so does new_fb */
1157 if (bo)
1158 vmw_dmabuf_unreference(&bo);
1159 if (surface)
1160 vmw_surface_unreference(&surface);
1084 1161
1085 if (ret) { 1162 if (ret) {
1086 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); 1163 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
@@ -1090,14 +1167,6 @@ try_dmabuf:
1090 vfb->user_obj = user_obj; 1167 vfb->user_obj = user_obj;
1091 1168
1092 return &vfb->base; 1169 return &vfb->base;
1093
1094err_not_scanout:
1095 DRM_ERROR("surface not marked as scanout\n");
1096 /* vmw_user_surface_lookup takes one ref */
1097 vmw_surface_unreference(&surface);
1098 ttm_base_object_unref(&user_obj);
1099
1100 return ERR_PTR(-EINVAL);
1101} 1170}
1102 1171
1103static struct drm_mode_config_funcs vmw_kms_funcs = { 1172static struct drm_mode_config_funcs vmw_kms_funcs = {
@@ -1114,10 +1183,12 @@ int vmw_kms_present(struct vmw_private *dev_priv,
1114 uint32_t num_clips) 1183 uint32_t num_clips)
1115{ 1184{
1116 struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; 1185 struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
1186 struct drm_clip_rect *tmp;
1117 struct drm_crtc *crtc; 1187 struct drm_crtc *crtc;
1118 size_t fifo_size; 1188 size_t fifo_size;
1119 int i, k, num_units; 1189 int i, k, num_units;
1120 int ret = 0; /* silence warning */ 1190 int ret = 0; /* silence warning */
1191 int left, right, top, bottom;
1121 1192
1122 struct { 1193 struct {
1123 SVGA3dCmdHeader header; 1194 SVGA3dCmdHeader header;
@@ -1135,60 +1206,95 @@ int vmw_kms_present(struct vmw_private *dev_priv,
1135 BUG_ON(surface == NULL); 1206 BUG_ON(surface == NULL);
1136 BUG_ON(!clips || !num_clips); 1207 BUG_ON(!clips || !num_clips);
1137 1208
1209 tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL);
1210 if (unlikely(tmp == NULL)) {
1211 DRM_ERROR("Temporary cliprect memory alloc failed.\n");
1212 return -ENOMEM;
1213 }
1214
1138 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; 1215 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
1139 cmd = kmalloc(fifo_size, GFP_KERNEL); 1216 cmd = kmalloc(fifo_size, GFP_KERNEL);
1140 if (unlikely(cmd == NULL)) { 1217 if (unlikely(cmd == NULL)) {
1141 DRM_ERROR("Failed to allocate temporary fifo memory.\n"); 1218 DRM_ERROR("Failed to allocate temporary fifo memory.\n");
1142 return -ENOMEM; 1219 ret = -ENOMEM;
1220 goto out_free_tmp;
1221 }
1222
1223 left = clips->x;
1224 right = clips->x + clips->w;
1225 top = clips->y;
1226 bottom = clips->y + clips->h;
1227
1228 for (i = 1; i < num_clips; i++) {
1229 left = min_t(int, left, (int)clips[i].x);
1230 right = max_t(int, right, (int)clips[i].x + clips[i].w);
1231 top = min_t(int, top, (int)clips[i].y);
1232 bottom = max_t(int, bottom, (int)clips[i].y + clips[i].h);
1143 } 1233 }
1144 1234
1145 /* only need to do this once */ 1235 /* only need to do this once */
1146 memset(cmd, 0, fifo_size); 1236 memset(cmd, 0, fifo_size);
1147 cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); 1237 cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN);
1148 cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
1149
1150 cmd->body.srcRect.left = 0;
1151 cmd->body.srcRect.right = surface->sizes[0].width;
1152 cmd->body.srcRect.top = 0;
1153 cmd->body.srcRect.bottom = surface->sizes[0].height;
1154 1238
1155 blits = (SVGASignedRect *)&cmd[1]; 1239 blits = (SVGASignedRect *)&cmd[1];
1240
1241 cmd->body.srcRect.left = left;
1242 cmd->body.srcRect.right = right;
1243 cmd->body.srcRect.top = top;
1244 cmd->body.srcRect.bottom = bottom;
1245
1156 for (i = 0; i < num_clips; i++) { 1246 for (i = 0; i < num_clips; i++) {
1157 blits[i].left = clips[i].x; 1247 tmp[i].x1 = clips[i].x - left;
1158 blits[i].right = clips[i].x + clips[i].w; 1248 tmp[i].x2 = clips[i].x + clips[i].w - left;
1159 blits[i].top = clips[i].y; 1249 tmp[i].y1 = clips[i].y - top;
1160 blits[i].bottom = clips[i].y + clips[i].h; 1250 tmp[i].y2 = clips[i].y + clips[i].h - top;
1161 } 1251 }
1162 1252
1163 for (k = 0; k < num_units; k++) { 1253 for (k = 0; k < num_units; k++) {
1164 struct vmw_display_unit *unit = units[k]; 1254 struct vmw_display_unit *unit = units[k];
1165 int clip_x1 = destX - unit->crtc.x; 1255 struct vmw_clip_rect clip;
1166 int clip_y1 = destY - unit->crtc.y; 1256 int num;
1167 int clip_x2 = clip_x1 + surface->sizes[0].width; 1257
1168 int clip_y2 = clip_y1 + surface->sizes[0].height; 1258 clip.x1 = left + destX - unit->crtc.x;
1259 clip.y1 = top + destY - unit->crtc.y;
1260 clip.x2 = right + destX - unit->crtc.x;
1261 clip.y2 = bottom + destY - unit->crtc.y;
1169 1262
1170 /* skip any crtcs that misses the clip region */ 1263 /* skip any crtcs that misses the clip region */
1171 if (clip_x1 >= unit->crtc.mode.hdisplay || 1264 if (clip.x1 >= unit->crtc.mode.hdisplay ||
1172 clip_y1 >= unit->crtc.mode.vdisplay || 1265 clip.y1 >= unit->crtc.mode.vdisplay ||
1173 clip_x2 <= 0 || clip_y2 <= 0) 1266 clip.x2 <= 0 || clip.y2 <= 0)
1174 continue; 1267 continue;
1175 1268
1269 /*
1270 * In order for the clip rects to be correctly scaled
1271 * the src and dest rects needs to be the same size.
1272 */
1273 cmd->body.destRect.left = clip.x1;
1274 cmd->body.destRect.right = clip.x2;
1275 cmd->body.destRect.top = clip.y1;
1276 cmd->body.destRect.bottom = clip.y2;
1277
1278 /* create a clip rect of the crtc in dest coords */
1279 clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
1280 clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
1281 clip.x1 = 0 - clip.x1;
1282 clip.y1 = 0 - clip.y1;
1283
1176 /* need to reset sid as it is changed by execbuf */ 1284 /* need to reset sid as it is changed by execbuf */
1177 cmd->body.srcImage.sid = sid; 1285 cmd->body.srcImage.sid = sid;
1178
1179 cmd->body.destScreenId = unit->unit; 1286 cmd->body.destScreenId = unit->unit;
1180 1287
1181 /* 1288 /* clip and write blits to cmd stream */
1182 * The blit command is a lot more resilient then the 1289 vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
1183 * readback command when it comes to clip rects. So its
1184 * okay to go out of bounds.
1185 */
1186 1290
1187 cmd->body.destRect.left = clip_x1; 1291 /* if no cliprects hit skip this */
1188 cmd->body.destRect.right = clip_x2; 1292 if (num == 0)
1189 cmd->body.destRect.top = clip_y1; 1293 continue;
1190 cmd->body.destRect.bottom = clip_y2;
1191 1294
1295 /* recalculate package length */
1296 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
1297 cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
1192 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, 1298 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
1193 fifo_size, 0, NULL); 1299 fifo_size, 0, NULL);
1194 1300
@@ -1197,6 +1303,8 @@ int vmw_kms_present(struct vmw_private *dev_priv,
1197 } 1303 }
1198 1304
1199 kfree(cmd); 1305 kfree(cmd);
1306out_free_tmp:
1307 kfree(tmp);
1200 1308
1201 return ret; 1309 return ret;
1202} 1310}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 055b844bd80f..a4f7f034996a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -63,9 +63,14 @@ struct vmw_framebuffer {
63int vmw_cursor_update_image(struct vmw_private *dev_priv, 63int vmw_cursor_update_image(struct vmw_private *dev_priv,
64 u32 *image, u32 width, u32 height, 64 u32 *image, u32 width, u32 height,
65 u32 hotspotX, u32 hotspotY); 65 u32 hotspotX, u32 hotspotY);
66int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv,
67 struct vmw_dma_buffer *dmabuf,
68 u32 width, u32 height,
69 u32 hotspotX, u32 hotspotY);
66void vmw_cursor_update_position(struct vmw_private *dev_priv, 70void vmw_cursor_update_position(struct vmw_private *dev_priv,
67 bool show, int x, int y); 71 bool show, int x, int y);
68 72
73
69/** 74/**
70 * Base class display unit. 75 * Base class display unit.
71 * 76 *
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 15a6805e48b0..f77b184be807 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -74,9 +74,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
74{ 74{
75 struct vmw_legacy_display *lds = dev_priv->ldu_priv; 75 struct vmw_legacy_display *lds = dev_priv->ldu_priv;
76 struct vmw_legacy_display_unit *entry; 76 struct vmw_legacy_display_unit *entry;
77 struct vmw_display_unit *du = NULL;
77 struct drm_framebuffer *fb = NULL; 78 struct drm_framebuffer *fb = NULL;
78 struct drm_crtc *crtc = NULL; 79 struct drm_crtc *crtc = NULL;
79 int i = 0; 80 int i = 0, ret;
80 81
81 /* If there is no display topology the host just assumes 82 /* If there is no display topology the host just assumes
82 * that the guest will set the same layout as the host. 83 * that the guest will set the same layout as the host.
@@ -129,6 +130,25 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
129 130
130 lds->last_num_active = lds->num_active; 131 lds->last_num_active = lds->num_active;
131 132
133
134 /* Find the first du with a cursor. */
135 list_for_each_entry(entry, &lds->active, active) {
136 du = &entry->base;
137
138 if (!du->cursor_dmabuf)
139 continue;
140
141 ret = vmw_cursor_update_dmabuf(dev_priv,
142 du->cursor_dmabuf,
143 64, 64,
144 du->hotspot_x,
145 du->hotspot_y);
146 if (ret == 0)
147 break;
148
149 DRM_ERROR("Could not update cursor image\n");
150 }
151
132 return 0; 152 return 0;
133} 153}
134 154
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 2eb84a55aee7..a37abb581cbb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -1190,6 +1190,29 @@ void vmw_resource_unreserve(struct list_head *list)
1190 write_unlock(lock); 1190 write_unlock(lock);
1191} 1191}
1192 1192
1193/**
1194 * Helper function that looks either a surface or dmabuf.
1195 *
1196 * The pointer this pointed at by out_surf and out_buf needs to be null.
1197 */
1198int vmw_user_lookup_handle(struct vmw_private *dev_priv,
1199 struct ttm_object_file *tfile,
1200 uint32_t handle,
1201 struct vmw_surface **out_surf,
1202 struct vmw_dma_buffer **out_buf)
1203{
1204 int ret;
1205
1206 BUG_ON(*out_surf || *out_buf);
1207
1208 ret = vmw_user_surface_lookup_handle(dev_priv, tfile, handle, out_surf);
1209 if (!ret)
1210 return 0;
1211
1212 ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf);
1213 return ret;
1214}
1215
1193 1216
1194int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, 1217int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
1195 struct ttm_object_file *tfile, 1218 struct ttm_object_file *tfile,