diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 394 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 23 |
7 files changed, 318 insertions, 155 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); |
393 | extern 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); | ||
393 | extern void vmw_surface_res_free(struct vmw_resource *res); | 398 | extern void vmw_surface_res_free(struct vmw_resource *res); |
394 | extern int vmw_surface_init(struct vmw_private *dev_priv, | 399 | extern 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 37d40545ed77..8aa1dbb45c67 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 | |||
35 | struct 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 | */ | ||
43 | void 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 | |||
34 | void vmw_display_unit_cleanup(struct vmw_display_unit *du) | 72 | void 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 | ||
123 | int 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); | ||
153 | err_unreserve: | ||
154 | ttm_bo_unreserve(&dmabuf->base); | ||
155 | |||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | |||
85 | void vmw_cursor_update_position(struct vmw_private *dev_priv, | 160 | void 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); | ||
176 | err_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); |
558 | out_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++; |
@@ -1033,46 +1123,29 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, | |||
1033 | return ERR_PTR(-ENOENT); | 1123 | return ERR_PTR(-ENOENT); |
1034 | } | 1124 | } |
1035 | 1125 | ||
1036 | /** | 1126 | /* returns either a dmabuf or surface */ |
1037 | * End conditioned code. | 1127 | ret = vmw_user_lookup_handle(dev_priv, tfile, |
1038 | */ | 1128 | mode_cmd->handle, |
1039 | 1129 | &surface, &bo); | |
1040 | ret = vmw_user_surface_lookup_handle(dev_priv, tfile, | ||
1041 | mode_cmd->handle, &surface); | ||
1042 | if (ret) | 1130 | if (ret) |
1043 | goto try_dmabuf; | 1131 | goto err_out; |
1044 | 1132 | ||
1045 | if (!surface->scanout) | 1133 | /* Create the new framebuffer depending one what we got back */ |
1046 | goto err_not_scanout; | 1134 | if (bo) |
1047 | 1135 | ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, | |
1048 | ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface, | 1136 | mode_cmd); |
1049 | &vfb, mode_cmd); | 1137 | else if (surface) |
1050 | 1138 | ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, | |
1051 | /* vmw_user_surface_lookup takes one ref so does new_fb */ | 1139 | surface, &vfb, mode_cmd); |
1052 | vmw_surface_unreference(&surface); | 1140 | else |
1053 | 1141 | BUG(); | |
1054 | if (ret) { | ||
1055 | DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); | ||
1056 | ttm_base_object_unref(&user_obj); | ||
1057 | return ERR_PTR(ret); | ||
1058 | } else | ||
1059 | vfb->user_obj = user_obj; | ||
1060 | return &vfb->base; | ||
1061 | |||
1062 | try_dmabuf: | ||
1063 | DRM_INFO("%s: trying buffer\n", __func__); | ||
1064 | |||
1065 | ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo); | ||
1066 | if (ret) { | ||
1067 | DRM_ERROR("failed to find buffer: %i\n", ret); | ||
1068 | return ERR_PTR(-ENOENT); | ||
1069 | } | ||
1070 | |||
1071 | ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, | ||
1072 | mode_cmd); | ||
1073 | 1142 | ||
1074 | /* vmw_user_dmabuf_lookup takes one ref so does new_fb */ | 1143 | err_out: |
1075 | vmw_dmabuf_unreference(&bo); | 1144 | /* vmw_user_lookup_handle takes one ref so does new_fb */ |
1145 | if (bo) | ||
1146 | vmw_dmabuf_unreference(&bo); | ||
1147 | if (surface) | ||
1148 | vmw_surface_unreference(&surface); | ||
1076 | 1149 | ||
1077 | if (ret) { | 1150 | if (ret) { |
1078 | DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); | 1151 | DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); |
@@ -1082,14 +1155,6 @@ try_dmabuf: | |||
1082 | vfb->user_obj = user_obj; | 1155 | vfb->user_obj = user_obj; |
1083 | 1156 | ||
1084 | return &vfb->base; | 1157 | return &vfb->base; |
1085 | |||
1086 | err_not_scanout: | ||
1087 | DRM_ERROR("surface not marked as scanout\n"); | ||
1088 | /* vmw_user_surface_lookup takes one ref */ | ||
1089 | vmw_surface_unreference(&surface); | ||
1090 | ttm_base_object_unref(&user_obj); | ||
1091 | |||
1092 | return ERR_PTR(-EINVAL); | ||
1093 | } | 1158 | } |
1094 | 1159 | ||
1095 | static struct drm_mode_config_funcs vmw_kms_funcs = { | 1160 | static struct drm_mode_config_funcs vmw_kms_funcs = { |
@@ -1106,10 +1171,12 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1106 | uint32_t num_clips) | 1171 | uint32_t num_clips) |
1107 | { | 1172 | { |
1108 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; | 1173 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
1174 | struct drm_clip_rect *tmp; | ||
1109 | struct drm_crtc *crtc; | 1175 | struct drm_crtc *crtc; |
1110 | size_t fifo_size; | 1176 | size_t fifo_size; |
1111 | int i, k, num_units; | 1177 | int i, k, num_units; |
1112 | int ret = 0; /* silence warning */ | 1178 | int ret = 0; /* silence warning */ |
1179 | int left, right, top, bottom; | ||
1113 | 1180 | ||
1114 | struct { | 1181 | struct { |
1115 | SVGA3dCmdHeader header; | 1182 | SVGA3dCmdHeader header; |
@@ -1127,60 +1194,95 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1127 | BUG_ON(surface == NULL); | 1194 | BUG_ON(surface == NULL); |
1128 | BUG_ON(!clips || !num_clips); | 1195 | BUG_ON(!clips || !num_clips); |
1129 | 1196 | ||
1197 | tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); | ||
1198 | if (unlikely(tmp == NULL)) { | ||
1199 | DRM_ERROR("Temporary cliprect memory alloc failed.\n"); | ||
1200 | return -ENOMEM; | ||
1201 | } | ||
1202 | |||
1130 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; | 1203 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; |
1131 | cmd = kmalloc(fifo_size, GFP_KERNEL); | 1204 | cmd = kmalloc(fifo_size, GFP_KERNEL); |
1132 | if (unlikely(cmd == NULL)) { | 1205 | if (unlikely(cmd == NULL)) { |
1133 | DRM_ERROR("Failed to allocate temporary fifo memory.\n"); | 1206 | DRM_ERROR("Failed to allocate temporary fifo memory.\n"); |
1134 | return -ENOMEM; | 1207 | ret = -ENOMEM; |
1208 | goto out_free_tmp; | ||
1209 | } | ||
1210 | |||
1211 | left = clips->x; | ||
1212 | right = clips->x + clips->w; | ||
1213 | top = clips->y; | ||
1214 | bottom = clips->y + clips->h; | ||
1215 | |||
1216 | for (i = 1; i < num_clips; i++) { | ||
1217 | left = min_t(int, left, (int)clips[i].x); | ||
1218 | right = max_t(int, right, (int)clips[i].x + clips[i].w); | ||
1219 | top = min_t(int, top, (int)clips[i].y); | ||
1220 | bottom = max_t(int, bottom, (int)clips[i].y + clips[i].h); | ||
1135 | } | 1221 | } |
1136 | 1222 | ||
1137 | /* only need to do this once */ | 1223 | /* only need to do this once */ |
1138 | memset(cmd, 0, fifo_size); | 1224 | memset(cmd, 0, fifo_size); |
1139 | cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); | 1225 | cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); |
1140 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); | ||
1141 | |||
1142 | cmd->body.srcRect.left = 0; | ||
1143 | cmd->body.srcRect.right = surface->sizes[0].width; | ||
1144 | cmd->body.srcRect.top = 0; | ||
1145 | cmd->body.srcRect.bottom = surface->sizes[0].height; | ||
1146 | 1226 | ||
1147 | blits = (SVGASignedRect *)&cmd[1]; | 1227 | blits = (SVGASignedRect *)&cmd[1]; |
1228 | |||
1229 | cmd->body.srcRect.left = left; | ||
1230 | cmd->body.srcRect.right = right; | ||
1231 | cmd->body.srcRect.top = top; | ||
1232 | cmd->body.srcRect.bottom = bottom; | ||
1233 | |||
1148 | for (i = 0; i < num_clips; i++) { | 1234 | for (i = 0; i < num_clips; i++) { |
1149 | blits[i].left = clips[i].x; | 1235 | tmp[i].x1 = clips[i].x - left; |
1150 | blits[i].right = clips[i].x + clips[i].w; | 1236 | tmp[i].x2 = clips[i].x + clips[i].w - left; |
1151 | blits[i].top = clips[i].y; | 1237 | tmp[i].y1 = clips[i].y - top; |
1152 | blits[i].bottom = clips[i].y + clips[i].h; | 1238 | tmp[i].y2 = clips[i].y + clips[i].h - top; |
1153 | } | 1239 | } |
1154 | 1240 | ||
1155 | for (k = 0; k < num_units; k++) { | 1241 | for (k = 0; k < num_units; k++) { |
1156 | struct vmw_display_unit *unit = units[k]; | 1242 | struct vmw_display_unit *unit = units[k]; |
1157 | int clip_x1 = destX - unit->crtc.x; | 1243 | struct vmw_clip_rect clip; |
1158 | int clip_y1 = destY - unit->crtc.y; | 1244 | int num; |
1159 | int clip_x2 = clip_x1 + surface->sizes[0].width; | 1245 | |
1160 | int clip_y2 = clip_y1 + surface->sizes[0].height; | 1246 | clip.x1 = left + destX - unit->crtc.x; |
1247 | clip.y1 = top + destY - unit->crtc.y; | ||
1248 | clip.x2 = right + destX - unit->crtc.x; | ||
1249 | clip.y2 = bottom + destY - unit->crtc.y; | ||
1161 | 1250 | ||
1162 | /* skip any crtcs that misses the clip region */ | 1251 | /* skip any crtcs that misses the clip region */ |
1163 | if (clip_x1 >= unit->crtc.mode.hdisplay || | 1252 | if (clip.x1 >= unit->crtc.mode.hdisplay || |
1164 | clip_y1 >= unit->crtc.mode.vdisplay || | 1253 | clip.y1 >= unit->crtc.mode.vdisplay || |
1165 | clip_x2 <= 0 || clip_y2 <= 0) | 1254 | clip.x2 <= 0 || clip.y2 <= 0) |
1166 | continue; | 1255 | continue; |
1167 | 1256 | ||
1257 | /* | ||
1258 | * In order for the clip rects to be correctly scaled | ||
1259 | * the src and dest rects needs to be the same size. | ||
1260 | */ | ||
1261 | cmd->body.destRect.left = clip.x1; | ||
1262 | cmd->body.destRect.right = clip.x2; | ||
1263 | cmd->body.destRect.top = clip.y1; | ||
1264 | cmd->body.destRect.bottom = clip.y2; | ||
1265 | |||
1266 | /* create a clip rect of the crtc in dest coords */ | ||
1267 | clip.x2 = unit->crtc.mode.hdisplay - clip.x1; | ||
1268 | clip.y2 = unit->crtc.mode.vdisplay - clip.y1; | ||
1269 | clip.x1 = 0 - clip.x1; | ||
1270 | clip.y1 = 0 - clip.y1; | ||
1271 | |||
1168 | /* need to reset sid as it is changed by execbuf */ | 1272 | /* need to reset sid as it is changed by execbuf */ |
1169 | cmd->body.srcImage.sid = sid; | 1273 | cmd->body.srcImage.sid = sid; |
1170 | |||
1171 | cmd->body.destScreenId = unit->unit; | 1274 | cmd->body.destScreenId = unit->unit; |
1172 | 1275 | ||
1173 | /* | 1276 | /* clip and write blits to cmd stream */ |
1174 | * The blit command is a lot more resilient then the | 1277 | vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); |
1175 | * readback command when it comes to clip rects. So its | ||
1176 | * okay to go out of bounds. | ||
1177 | */ | ||
1178 | 1278 | ||
1179 | cmd->body.destRect.left = clip_x1; | 1279 | /* if no cliprects hit skip this */ |
1180 | cmd->body.destRect.right = clip_x2; | 1280 | if (num == 0) |
1181 | cmd->body.destRect.top = clip_y1; | 1281 | continue; |
1182 | cmd->body.destRect.bottom = clip_y2; | ||
1183 | 1282 | ||
1283 | /* recalculate package length */ | ||
1284 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; | ||
1285 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); | ||
1184 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, | 1286 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, |
1185 | fifo_size, 0, NULL); | 1287 | fifo_size, 0, NULL); |
1186 | 1288 | ||
@@ -1189,6 +1291,8 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1189 | } | 1291 | } |
1190 | 1292 | ||
1191 | kfree(cmd); | 1293 | kfree(cmd); |
1294 | out_free_tmp: | ||
1295 | kfree(tmp); | ||
1192 | 1296 | ||
1193 | return ret; | 1297 | return ret; |
1194 | } | 1298 | } |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index af8e6e5bd964..e1cb8556355f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | |||
@@ -62,9 +62,14 @@ struct vmw_framebuffer { | |||
62 | int vmw_cursor_update_image(struct vmw_private *dev_priv, | 62 | int vmw_cursor_update_image(struct vmw_private *dev_priv, |
63 | u32 *image, u32 width, u32 height, | 63 | u32 *image, u32 width, u32 height, |
64 | u32 hotspotX, u32 hotspotY); | 64 | u32 hotspotX, u32 hotspotY); |
65 | int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, | ||
66 | struct vmw_dma_buffer *dmabuf, | ||
67 | u32 width, u32 height, | ||
68 | u32 hotspotX, u32 hotspotY); | ||
65 | void vmw_cursor_update_position(struct vmw_private *dev_priv, | 69 | void vmw_cursor_update_position(struct vmw_private *dev_priv, |
66 | bool show, int x, int y); | 70 | bool show, int x, int y); |
67 | 71 | ||
72 | |||
68 | /** | 73 | /** |
69 | * Base class display unit. | 74 | * Base class display unit. |
70 | * | 75 | * |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 90c5e3928491..8f8dbd43c33d 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 86c5e4cceb31..1c7f09e26819 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 | */ | ||
1198 | int 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 | ||
1194 | int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, | 1217 | int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, |
1195 | struct ttm_object_file *tfile, | 1218 | struct ttm_object_file *tfile, |