diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 49 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 173 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 203 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 189 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 8 |
13 files changed, 620 insertions, 171 deletions
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 1a3cb6816d1c..4505e17df3f5 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile | |||
@@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm | |||
4 | vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ | 4 | vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ |
5 | vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ | 5 | vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ |
6 | vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ | 6 | vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ |
7 | vmwgfx_overlay.o | 7 | vmwgfx_overlay.o vmwgfx_fence.o |
8 | 8 | ||
9 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o | 9 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 0c9c0811f42d..b793c8c9acb3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -88,6 +88,9 @@ | |||
88 | #define DRM_IOCTL_VMW_FENCE_WAIT \ | 88 | #define DRM_IOCTL_VMW_FENCE_WAIT \ |
89 | DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \ | 89 | DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \ |
90 | struct drm_vmw_fence_wait_arg) | 90 | struct drm_vmw_fence_wait_arg) |
91 | #define DRM_IOCTL_VMW_UPDATE_LAYOUT \ | ||
92 | DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \ | ||
93 | struct drm_vmw_update_layout_arg) | ||
91 | 94 | ||
92 | 95 | ||
93 | /** | 96 | /** |
@@ -135,7 +138,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = { | |||
135 | VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, | 138 | VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, |
136 | DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED), | 139 | DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED), |
137 | VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl, | 140 | VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl, |
138 | DRM_AUTH | DRM_UNLOCKED) | 141 | DRM_AUTH | DRM_UNLOCKED), |
142 | VMW_IOCTL_DEF(DRM_IOCTL_VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, | ||
143 | DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED) | ||
139 | }; | 144 | }; |
140 | 145 | ||
141 | static struct pci_device_id vmw_pci_id_list[] = { | 146 | static struct pci_device_id vmw_pci_id_list[] = { |
@@ -318,6 +323,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
318 | goto out_err3; | 323 | goto out_err3; |
319 | } | 324 | } |
320 | 325 | ||
326 | /* Need mmio memory to check for fifo pitchlock cap. */ | ||
327 | if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && | ||
328 | !(dev_priv->capabilities & SVGA_CAP_PITCHLOCK) && | ||
329 | !vmw_fifo_have_pitchlock(dev_priv)) { | ||
330 | ret = -ENOSYS; | ||
331 | DRM_ERROR("Hardware has no pitchlock\n"); | ||
332 | goto out_err4; | ||
333 | } | ||
334 | |||
321 | dev_priv->tdev = ttm_object_device_init | 335 | dev_priv->tdev = ttm_object_device_init |
322 | (dev_priv->mem_global_ref.object, 12); | 336 | (dev_priv->mem_global_ref.object, 12); |
323 | 337 | ||
@@ -399,8 +413,6 @@ static int vmw_driver_unload(struct drm_device *dev) | |||
399 | { | 413 | { |
400 | struct vmw_private *dev_priv = vmw_priv(dev); | 414 | struct vmw_private *dev_priv = vmw_priv(dev); |
401 | 415 | ||
402 | DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); | ||
403 | |||
404 | unregister_pm_notifier(&dev_priv->pm_nb); | 416 | unregister_pm_notifier(&dev_priv->pm_nb); |
405 | 417 | ||
406 | vmw_fb_close(dev_priv); | 418 | vmw_fb_close(dev_priv); |
@@ -546,7 +558,6 @@ static int vmw_master_create(struct drm_device *dev, | |||
546 | { | 558 | { |
547 | struct vmw_master *vmaster; | 559 | struct vmw_master *vmaster; |
548 | 560 | ||
549 | DRM_INFO("Master create.\n"); | ||
550 | vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL); | 561 | vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL); |
551 | if (unlikely(vmaster == NULL)) | 562 | if (unlikely(vmaster == NULL)) |
552 | return -ENOMEM; | 563 | return -ENOMEM; |
@@ -563,7 +574,6 @@ static void vmw_master_destroy(struct drm_device *dev, | |||
563 | { | 574 | { |
564 | struct vmw_master *vmaster = vmw_master(master); | 575 | struct vmw_master *vmaster = vmw_master(master); |
565 | 576 | ||
566 | DRM_INFO("Master destroy.\n"); | ||
567 | master->driver_priv = NULL; | 577 | master->driver_priv = NULL; |
568 | kfree(vmaster); | 578 | kfree(vmaster); |
569 | } | 579 | } |
@@ -579,8 +589,6 @@ static int vmw_master_set(struct drm_device *dev, | |||
579 | struct vmw_master *vmaster = vmw_master(file_priv->master); | 589 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
580 | int ret = 0; | 590 | int ret = 0; |
581 | 591 | ||
582 | DRM_INFO("Master set.\n"); | ||
583 | |||
584 | if (active) { | 592 | if (active) { |
585 | BUG_ON(active != &dev_priv->fbdev_master); | 593 | BUG_ON(active != &dev_priv->fbdev_master); |
586 | ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile); | 594 | ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile); |
@@ -622,8 +630,6 @@ static void vmw_master_drop(struct drm_device *dev, | |||
622 | struct vmw_master *vmaster = vmw_master(file_priv->master); | 630 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
623 | int ret; | 631 | int ret; |
624 | 632 | ||
625 | DRM_INFO("Master drop.\n"); | ||
626 | |||
627 | /** | 633 | /** |
628 | * Make sure the master doesn't disappear while we have | 634 | * Make sure the master doesn't disappear while we have |
629 | * it locked. | 635 | * it locked. |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 356dc935ec13..eaad52095339 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
@@ -41,12 +41,13 @@ | |||
41 | 41 | ||
42 | #define VMWGFX_DRIVER_DATE "20100209" | 42 | #define VMWGFX_DRIVER_DATE "20100209" |
43 | #define VMWGFX_DRIVER_MAJOR 1 | 43 | #define VMWGFX_DRIVER_MAJOR 1 |
44 | #define VMWGFX_DRIVER_MINOR 0 | 44 | #define VMWGFX_DRIVER_MINOR 2 |
45 | #define VMWGFX_DRIVER_PATCHLEVEL 0 | 45 | #define VMWGFX_DRIVER_PATCHLEVEL 0 |
46 | #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 | 46 | #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 |
47 | #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) | 47 | #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) |
48 | #define VMWGFX_MAX_RELOCATIONS 2048 | 48 | #define VMWGFX_MAX_RELOCATIONS 2048 |
49 | #define VMWGFX_MAX_GMRS 2048 | 49 | #define VMWGFX_MAX_GMRS 2048 |
50 | #define VMWGFX_MAX_DISPLAYS 16 | ||
50 | 51 | ||
51 | struct vmw_fpriv { | 52 | struct vmw_fpriv { |
52 | struct drm_master *locked_master; | 53 | struct drm_master *locked_master; |
@@ -102,6 +103,13 @@ struct vmw_surface { | |||
102 | struct vmw_cursor_snooper snooper; | 103 | struct vmw_cursor_snooper snooper; |
103 | }; | 104 | }; |
104 | 105 | ||
106 | struct vmw_fence_queue { | ||
107 | struct list_head head; | ||
108 | struct timespec lag; | ||
109 | struct timespec lag_time; | ||
110 | spinlock_t lock; | ||
111 | }; | ||
112 | |||
105 | struct vmw_fifo_state { | 113 | struct vmw_fifo_state { |
106 | unsigned long reserved_size; | 114 | unsigned long reserved_size; |
107 | __le32 *dynamic_buffer; | 115 | __le32 *dynamic_buffer; |
@@ -115,6 +123,7 @@ struct vmw_fifo_state { | |||
115 | uint32_t capabilities; | 123 | uint32_t capabilities; |
116 | struct mutex fifo_mutex; | 124 | struct mutex fifo_mutex; |
117 | struct rw_semaphore rwsem; | 125 | struct rw_semaphore rwsem; |
126 | struct vmw_fence_queue fence_queue; | ||
118 | }; | 127 | }; |
119 | 128 | ||
120 | struct vmw_relocation { | 129 | struct vmw_relocation { |
@@ -144,6 +153,14 @@ struct vmw_master { | |||
144 | struct ttm_lock lock; | 153 | struct ttm_lock lock; |
145 | }; | 154 | }; |
146 | 155 | ||
156 | struct vmw_vga_topology_state { | ||
157 | uint32_t width; | ||
158 | uint32_t height; | ||
159 | uint32_t primary; | ||
160 | uint32_t pos_x; | ||
161 | uint32_t pos_y; | ||
162 | }; | ||
163 | |||
147 | struct vmw_private { | 164 | struct vmw_private { |
148 | struct ttm_bo_device bdev; | 165 | struct ttm_bo_device bdev; |
149 | struct ttm_bo_global_ref bo_global_ref; | 166 | struct ttm_bo_global_ref bo_global_ref; |
@@ -171,14 +188,19 @@ struct vmw_private { | |||
171 | * VGA registers. | 188 | * VGA registers. |
172 | */ | 189 | */ |
173 | 190 | ||
191 | struct vmw_vga_topology_state vga_save[VMWGFX_MAX_DISPLAYS]; | ||
174 | uint32_t vga_width; | 192 | uint32_t vga_width; |
175 | uint32_t vga_height; | 193 | uint32_t vga_height; |
176 | uint32_t vga_depth; | 194 | uint32_t vga_depth; |
177 | uint32_t vga_bpp; | 195 | uint32_t vga_bpp; |
178 | uint32_t vga_pseudo; | 196 | uint32_t vga_pseudo; |
179 | uint32_t vga_red_mask; | 197 | uint32_t vga_red_mask; |
180 | uint32_t vga_blue_mask; | ||
181 | uint32_t vga_green_mask; | 198 | uint32_t vga_green_mask; |
199 | uint32_t vga_blue_mask; | ||
200 | uint32_t vga_bpl; | ||
201 | uint32_t vga_pitchlock; | ||
202 | |||
203 | uint32_t num_displays; | ||
182 | 204 | ||
183 | /* | 205 | /* |
184 | * Framebuffer info. | 206 | * Framebuffer info. |
@@ -393,6 +415,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, | |||
393 | extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); | 415 | extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); |
394 | extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma); | 416 | extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma); |
395 | extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); | 417 | extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); |
418 | extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv); | ||
396 | 419 | ||
397 | /** | 420 | /** |
398 | * TTM glue - vmwgfx_ttm_glue.c | 421 | * TTM glue - vmwgfx_ttm_glue.c |
@@ -441,6 +464,23 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv, | |||
441 | uint32_t sequence, | 464 | uint32_t sequence, |
442 | bool interruptible, | 465 | bool interruptible, |
443 | unsigned long timeout); | 466 | unsigned long timeout); |
467 | extern void vmw_update_sequence(struct vmw_private *dev_priv, | ||
468 | struct vmw_fifo_state *fifo_state); | ||
469 | |||
470 | |||
471 | /** | ||
472 | * Rudimentary fence objects currently used only for throttling - | ||
473 | * vmwgfx_fence.c | ||
474 | */ | ||
475 | |||
476 | extern void vmw_fence_queue_init(struct vmw_fence_queue *queue); | ||
477 | extern void vmw_fence_queue_takedown(struct vmw_fence_queue *queue); | ||
478 | extern int vmw_fence_push(struct vmw_fence_queue *queue, | ||
479 | uint32_t sequence); | ||
480 | extern int vmw_fence_pull(struct vmw_fence_queue *queue, | ||
481 | uint32_t signaled_sequence); | ||
482 | extern int vmw_wait_lag(struct vmw_private *dev_priv, | ||
483 | struct vmw_fence_queue *queue, uint32_t us); | ||
444 | 484 | ||
445 | /** | 485 | /** |
446 | * Kernel framebuffer - vmwgfx_fb.c | 486 | * Kernel framebuffer - vmwgfx_fb.c |
@@ -466,6 +506,11 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, | |||
466 | struct ttm_object_file *tfile, | 506 | struct ttm_object_file *tfile, |
467 | struct ttm_buffer_object *bo, | 507 | struct ttm_buffer_object *bo, |
468 | SVGA3dCmdHeader *header); | 508 | SVGA3dCmdHeader *header); |
509 | void vmw_kms_write_svga(struct vmw_private *vmw_priv, | ||
510 | unsigned width, unsigned height, unsigned pitch, | ||
511 | unsigned bbp, unsigned depth); | ||
512 | int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, | ||
513 | struct drm_file *file_priv); | ||
469 | 514 | ||
470 | /** | 515 | /** |
471 | * Overlay control - vmwgfx_overlay.c | 516 | * Overlay control - vmwgfx_overlay.c |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index dbd36b8910cf..8e396850513c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | |||
@@ -644,6 +644,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, | |||
644 | ret = copy_from_user(cmd, user_cmd, arg->command_size); | 644 | ret = copy_from_user(cmd, user_cmd, arg->command_size); |
645 | 645 | ||
646 | if (unlikely(ret != 0)) { | 646 | if (unlikely(ret != 0)) { |
647 | ret = -EFAULT; | ||
647 | DRM_ERROR("Failed copying commands.\n"); | 648 | DRM_ERROR("Failed copying commands.\n"); |
648 | goto out_commit; | 649 | goto out_commit; |
649 | } | 650 | } |
@@ -669,6 +670,15 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, | |||
669 | goto out_err; | 670 | goto out_err; |
670 | 671 | ||
671 | vmw_apply_relocations(sw_context); | 672 | vmw_apply_relocations(sw_context); |
673 | |||
674 | if (arg->throttle_us) { | ||
675 | ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.fence_queue, | ||
676 | arg->throttle_us); | ||
677 | |||
678 | if (unlikely(ret != 0)) | ||
679 | goto out_err; | ||
680 | } | ||
681 | |||
672 | vmw_fifo_commit(dev_priv, arg->command_size); | 682 | vmw_fifo_commit(dev_priv, arg->command_size); |
673 | 683 | ||
674 | ret = vmw_fifo_send_fence(dev_priv, &sequence); | 684 | ret = vmw_fifo_send_fence(dev_priv, &sequence); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 7421aaad8d09..b0866f04ec76 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | |||
@@ -132,16 +132,14 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var, | |||
132 | return -EINVAL; | 132 | return -EINVAL; |
133 | } | 133 | } |
134 | 134 | ||
135 | /* without multimon its hard to resize */ | 135 | if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && |
136 | if (!(vmw_priv->capabilities & SVGA_CAP_MULTIMON) && | 136 | (var->xoffset != 0 || var->yoffset != 0)) { |
137 | (var->xres != par->max_width || | 137 | DRM_ERROR("Can not handle panning without display topology\n"); |
138 | var->yres != par->max_height)) { | ||
139 | DRM_ERROR("Tried to resize, but we don't have multimon\n"); | ||
140 | return -EINVAL; | 138 | return -EINVAL; |
141 | } | 139 | } |
142 | 140 | ||
143 | if (var->xres > par->max_width || | 141 | if ((var->xoffset + var->xres) > par->max_width || |
144 | var->yres > par->max_height) { | 142 | (var->yoffset + var->yres) > par->max_height) { |
145 | DRM_ERROR("Requested geom can not fit in framebuffer\n"); | 143 | DRM_ERROR("Requested geom can not fit in framebuffer\n"); |
146 | return -EINVAL; | 144 | return -EINVAL; |
147 | } | 145 | } |
@@ -154,27 +152,11 @@ static int vmw_fb_set_par(struct fb_info *info) | |||
154 | struct vmw_fb_par *par = info->par; | 152 | struct vmw_fb_par *par = info->par; |
155 | struct vmw_private *vmw_priv = par->vmw_priv; | 153 | struct vmw_private *vmw_priv = par->vmw_priv; |
156 | 154 | ||
157 | if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { | 155 | vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, |
158 | vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); | 156 | info->fix.line_length, |
159 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); | 157 | par->bpp, par->depth); |
160 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); | 158 | if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { |
161 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); | ||
162 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); | ||
163 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0); | ||
164 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); | ||
165 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); | ||
166 | |||
167 | vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); | ||
168 | vmw_write(vmw_priv, SVGA_REG_WIDTH, par->max_width); | ||
169 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, par->max_height); | ||
170 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, par->bpp); | ||
171 | vmw_write(vmw_priv, SVGA_REG_DEPTH, par->depth); | ||
172 | vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); | ||
173 | vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); | ||
174 | vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); | ||
175 | |||
176 | /* TODO check if pitch and offset changes */ | 159 | /* TODO check if pitch and offset changes */ |
177 | |||
178 | vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); | 160 | vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); |
179 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); | 161 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); |
180 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); | 162 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); |
@@ -183,13 +165,13 @@ static int vmw_fb_set_par(struct fb_info *info) | |||
183 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); | 165 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); |
184 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); | 166 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); |
185 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); | 167 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); |
186 | } else { | ||
187 | vmw_write(vmw_priv, SVGA_REG_WIDTH, info->var.xres); | ||
188 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, info->var.yres); | ||
189 | |||
190 | /* TODO check if pitch and offset changes */ | ||
191 | } | 168 | } |
192 | 169 | ||
170 | /* This is really helpful since if this fails the user | ||
171 | * can probably not see anything on the screen. | ||
172 | */ | ||
173 | WARN_ON(vmw_read(vmw_priv, SVGA_REG_FB_OFFSET) != 0); | ||
174 | |||
193 | return 0; | 175 | return 0; |
194 | } | 176 | } |
195 | 177 | ||
@@ -416,48 +398,23 @@ int vmw_fb_init(struct vmw_private *vmw_priv) | |||
416 | unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size; | 398 | unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size; |
417 | int ret; | 399 | int ret; |
418 | 400 | ||
401 | /* XXX These shouldn't be hardcoded. */ | ||
419 | initial_width = 800; | 402 | initial_width = 800; |
420 | initial_height = 600; | 403 | initial_height = 600; |
421 | 404 | ||
422 | fb_bbp = 32; | 405 | fb_bbp = 32; |
423 | fb_depth = 24; | 406 | fb_depth = 24; |
424 | 407 | ||
425 | if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { | 408 | /* XXX As shouldn't these be as well. */ |
426 | fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); | 409 | fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); |
427 | fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); | 410 | fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); |
428 | } else { | ||
429 | fb_width = min(vmw_priv->fb_max_width, initial_width); | ||
430 | fb_height = min(vmw_priv->fb_max_height, initial_height); | ||
431 | } | ||
432 | 411 | ||
433 | initial_width = min(fb_width, initial_width); | 412 | initial_width = min(fb_width, initial_width); |
434 | initial_height = min(fb_height, initial_height); | 413 | initial_height = min(fb_height, initial_height); |
435 | 414 | ||
436 | vmw_write(vmw_priv, SVGA_REG_WIDTH, fb_width); | 415 | fb_pitch = fb_width * fb_bbp / 8; |
437 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, fb_height); | 416 | fb_size = fb_pitch * fb_height; |
438 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, fb_bbp); | ||
439 | vmw_write(vmw_priv, SVGA_REG_DEPTH, fb_depth); | ||
440 | vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); | ||
441 | vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); | ||
442 | vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); | ||
443 | |||
444 | fb_size = vmw_read(vmw_priv, SVGA_REG_FB_SIZE); | ||
445 | fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET); | 417 | fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET); |
446 | fb_pitch = vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE); | ||
447 | |||
448 | DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_WIDTH)); | ||
449 | DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_HEIGHT)); | ||
450 | DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_WIDTH)); | ||
451 | DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_HEIGHT)); | ||
452 | DRM_DEBUG("bpp %u\n", vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL)); | ||
453 | DRM_DEBUG("depth %u\n", vmw_read(vmw_priv, SVGA_REG_DEPTH)); | ||
454 | DRM_DEBUG("bpl %u\n", vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE)); | ||
455 | DRM_DEBUG("r mask %08x\n", vmw_read(vmw_priv, SVGA_REG_RED_MASK)); | ||
456 | DRM_DEBUG("g mask %08x\n", vmw_read(vmw_priv, SVGA_REG_GREEN_MASK)); | ||
457 | DRM_DEBUG("b mask %08x\n", vmw_read(vmw_priv, SVGA_REG_BLUE_MASK)); | ||
458 | DRM_DEBUG("fb_offset 0x%08x\n", fb_offset); | ||
459 | DRM_DEBUG("fb_pitch %u\n", fb_pitch); | ||
460 | DRM_DEBUG("fb_size %u kiB\n", fb_size / 1024); | ||
461 | 418 | ||
462 | info = framebuffer_alloc(sizeof(*par), device); | 419 | info = framebuffer_alloc(sizeof(*par), device); |
463 | if (!info) | 420 | if (!info) |
@@ -659,6 +616,10 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, | |||
659 | goto err_unlock; | 616 | goto err_unlock; |
660 | 617 | ||
661 | ret = ttm_bo_validate(bo, &ne_placement, false, false, false); | 618 | ret = ttm_bo_validate(bo, &ne_placement, false, false, false); |
619 | |||
620 | /* Could probably bug on */ | ||
621 | WARN_ON(bo->offset != 0); | ||
622 | |||
662 | ttm_bo_unreserve(bo); | 623 | ttm_bo_unreserve(bo); |
663 | err_unlock: | 624 | err_unlock: |
664 | ttm_write_unlock(&vmw_priv->active_master->lock); | 625 | ttm_write_unlock(&vmw_priv->active_master->lock); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c new file mode 100644 index 000000000000..61eacc1b5ca3 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright (C) 2010 VMware, Inc., Palo Alto, CA., USA | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | **************************************************************************/ | ||
27 | |||
28 | |||
29 | #include "vmwgfx_drv.h" | ||
30 | |||
31 | struct vmw_fence { | ||
32 | struct list_head head; | ||
33 | uint32_t sequence; | ||
34 | struct timespec submitted; | ||
35 | }; | ||
36 | |||
37 | void vmw_fence_queue_init(struct vmw_fence_queue *queue) | ||
38 | { | ||
39 | INIT_LIST_HEAD(&queue->head); | ||
40 | queue->lag = ns_to_timespec(0); | ||
41 | getrawmonotonic(&queue->lag_time); | ||
42 | spin_lock_init(&queue->lock); | ||
43 | } | ||
44 | |||
45 | void vmw_fence_queue_takedown(struct vmw_fence_queue *queue) | ||
46 | { | ||
47 | struct vmw_fence *fence, *next; | ||
48 | |||
49 | spin_lock(&queue->lock); | ||
50 | list_for_each_entry_safe(fence, next, &queue->head, head) { | ||
51 | kfree(fence); | ||
52 | } | ||
53 | spin_unlock(&queue->lock); | ||
54 | } | ||
55 | |||
56 | int vmw_fence_push(struct vmw_fence_queue *queue, | ||
57 | uint32_t sequence) | ||
58 | { | ||
59 | struct vmw_fence *fence = kmalloc(sizeof(*fence), GFP_KERNEL); | ||
60 | |||
61 | if (unlikely(!fence)) | ||
62 | return -ENOMEM; | ||
63 | |||
64 | fence->sequence = sequence; | ||
65 | getrawmonotonic(&fence->submitted); | ||
66 | spin_lock(&queue->lock); | ||
67 | list_add_tail(&fence->head, &queue->head); | ||
68 | spin_unlock(&queue->lock); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | int vmw_fence_pull(struct vmw_fence_queue *queue, | ||
74 | uint32_t signaled_sequence) | ||
75 | { | ||
76 | struct vmw_fence *fence, *next; | ||
77 | struct timespec now; | ||
78 | bool updated = false; | ||
79 | |||
80 | spin_lock(&queue->lock); | ||
81 | getrawmonotonic(&now); | ||
82 | |||
83 | if (list_empty(&queue->head)) { | ||
84 | queue->lag = ns_to_timespec(0); | ||
85 | queue->lag_time = now; | ||
86 | updated = true; | ||
87 | goto out_unlock; | ||
88 | } | ||
89 | |||
90 | list_for_each_entry_safe(fence, next, &queue->head, head) { | ||
91 | if (signaled_sequence - fence->sequence > (1 << 30)) | ||
92 | continue; | ||
93 | |||
94 | queue->lag = timespec_sub(now, fence->submitted); | ||
95 | queue->lag_time = now; | ||
96 | updated = true; | ||
97 | list_del(&fence->head); | ||
98 | kfree(fence); | ||
99 | } | ||
100 | |||
101 | out_unlock: | ||
102 | spin_unlock(&queue->lock); | ||
103 | |||
104 | return (updated) ? 0 : -EBUSY; | ||
105 | } | ||
106 | |||
107 | static struct timespec vmw_timespec_add(struct timespec t1, | ||
108 | struct timespec t2) | ||
109 | { | ||
110 | t1.tv_sec += t2.tv_sec; | ||
111 | t1.tv_nsec += t2.tv_nsec; | ||
112 | if (t1.tv_nsec >= 1000000000L) { | ||
113 | t1.tv_sec += 1; | ||
114 | t1.tv_nsec -= 1000000000L; | ||
115 | } | ||
116 | |||
117 | return t1; | ||
118 | } | ||
119 | |||
120 | static struct timespec vmw_fifo_lag(struct vmw_fence_queue *queue) | ||
121 | { | ||
122 | struct timespec now; | ||
123 | |||
124 | spin_lock(&queue->lock); | ||
125 | getrawmonotonic(&now); | ||
126 | queue->lag = vmw_timespec_add(queue->lag, | ||
127 | timespec_sub(now, queue->lag_time)); | ||
128 | queue->lag_time = now; | ||
129 | spin_unlock(&queue->lock); | ||
130 | return queue->lag; | ||
131 | } | ||
132 | |||
133 | |||
134 | static bool vmw_lag_lt(struct vmw_fence_queue *queue, | ||
135 | uint32_t us) | ||
136 | { | ||
137 | struct timespec lag, cond; | ||
138 | |||
139 | cond = ns_to_timespec((s64) us * 1000); | ||
140 | lag = vmw_fifo_lag(queue); | ||
141 | return (timespec_compare(&lag, &cond) < 1); | ||
142 | } | ||
143 | |||
144 | int vmw_wait_lag(struct vmw_private *dev_priv, | ||
145 | struct vmw_fence_queue *queue, uint32_t us) | ||
146 | { | ||
147 | struct vmw_fence *fence; | ||
148 | uint32_t sequence; | ||
149 | int ret; | ||
150 | |||
151 | while (!vmw_lag_lt(queue, us)) { | ||
152 | spin_lock(&queue->lock); | ||
153 | if (list_empty(&queue->head)) | ||
154 | sequence = atomic_read(&dev_priv->fence_seq); | ||
155 | else { | ||
156 | fence = list_first_entry(&queue->head, | ||
157 | struct vmw_fence, head); | ||
158 | sequence = fence->sequence; | ||
159 | } | ||
160 | spin_unlock(&queue->lock); | ||
161 | |||
162 | ret = vmw_wait_fence(dev_priv, false, sequence, true, | ||
163 | 3*HZ); | ||
164 | |||
165 | if (unlikely(ret != 0)) | ||
166 | return ret; | ||
167 | |||
168 | (void) vmw_fence_pull(queue, sequence); | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | |||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 39d43a01d846..e6a1eb7ea954 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | |||
@@ -34,6 +34,9 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) | |||
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 | 36 | ||
37 | if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) | ||
38 | return false; | ||
39 | |||
37 | fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN); | 40 | fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN); |
38 | if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) | 41 | if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) |
39 | return false; | 42 | return false; |
@@ -48,6 +51,21 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) | |||
48 | return true; | 51 | return true; |
49 | } | 52 | } |
50 | 53 | ||
54 | bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv) | ||
55 | { | ||
56 | __le32 __iomem *fifo_mem = dev_priv->mmio_virt; | ||
57 | uint32_t caps; | ||
58 | |||
59 | if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) | ||
60 | return false; | ||
61 | |||
62 | caps = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES); | ||
63 | if (caps & SVGA_FIFO_CAP_PITCHLOCK) | ||
64 | return true; | ||
65 | |||
66 | return false; | ||
67 | } | ||
68 | |||
51 | int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) | 69 | int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) |
52 | { | 70 | { |
53 | __le32 __iomem *fifo_mem = dev_priv->mmio_virt; | 71 | __le32 __iomem *fifo_mem = dev_priv->mmio_virt; |
@@ -120,7 +138,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) | |||
120 | 138 | ||
121 | atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence); | 139 | atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence); |
122 | iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); | 140 | iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); |
123 | 141 | vmw_fence_queue_init(&fifo->fence_queue); | |
124 | return vmw_fifo_send_fence(dev_priv, &dummy); | 142 | return vmw_fifo_send_fence(dev_priv, &dummy); |
125 | out_err: | 143 | out_err: |
126 | vfree(fifo->static_buffer); | 144 | vfree(fifo->static_buffer); |
@@ -159,6 +177,7 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) | |||
159 | dev_priv->enable_state); | 177 | dev_priv->enable_state); |
160 | 178 | ||
161 | mutex_unlock(&dev_priv->hw_mutex); | 179 | mutex_unlock(&dev_priv->hw_mutex); |
180 | vmw_fence_queue_takedown(&fifo->fence_queue); | ||
162 | 181 | ||
163 | if (likely(fifo->last_buffer != NULL)) { | 182 | if (likely(fifo->last_buffer != NULL)) { |
164 | vfree(fifo->last_buffer); | 183 | vfree(fifo->last_buffer); |
@@ -484,6 +503,8 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) | |||
484 | fifo_state->last_buffer_add = true; | 503 | fifo_state->last_buffer_add = true; |
485 | vmw_fifo_commit(dev_priv, bytes); | 504 | vmw_fifo_commit(dev_priv, bytes); |
486 | fifo_state->last_buffer_add = false; | 505 | fifo_state->last_buffer_add = false; |
506 | (void) vmw_fence_push(&fifo_state->fence_queue, *sequence); | ||
507 | vmw_update_sequence(dev_priv, fifo_state); | ||
487 | 508 | ||
488 | out_err: | 509 | out_err: |
489 | return ret; | 510 | return ret; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 4d7cb5393860..e92298a6a383 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | |||
@@ -64,22 +64,33 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence) | |||
64 | return (busy == 0); | 64 | return (busy == 0); |
65 | } | 65 | } |
66 | 66 | ||
67 | void vmw_update_sequence(struct vmw_private *dev_priv, | ||
68 | struct vmw_fifo_state *fifo_state) | ||
69 | { | ||
70 | __le32 __iomem *fifo_mem = dev_priv->mmio_virt; | ||
71 | |||
72 | uint32_t sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); | ||
73 | |||
74 | if (dev_priv->last_read_sequence != sequence) { | ||
75 | dev_priv->last_read_sequence = sequence; | ||
76 | vmw_fence_pull(&fifo_state->fence_queue, sequence); | ||
77 | } | ||
78 | } | ||
67 | 79 | ||
68 | bool vmw_fence_signaled(struct vmw_private *dev_priv, | 80 | bool vmw_fence_signaled(struct vmw_private *dev_priv, |
69 | uint32_t sequence) | 81 | uint32_t sequence) |
70 | { | 82 | { |
71 | __le32 __iomem *fifo_mem = dev_priv->mmio_virt; | ||
72 | struct vmw_fifo_state *fifo_state; | 83 | struct vmw_fifo_state *fifo_state; |
73 | bool ret; | 84 | bool ret; |
74 | 85 | ||
75 | if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) | 86 | if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) |
76 | return true; | 87 | return true; |
77 | 88 | ||
78 | dev_priv->last_read_sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); | 89 | fifo_state = &dev_priv->fifo; |
90 | vmw_update_sequence(dev_priv, fifo_state); | ||
79 | if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) | 91 | if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) |
80 | return true; | 92 | return true; |
81 | 93 | ||
82 | fifo_state = &dev_priv->fifo; | ||
83 | if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && | 94 | if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && |
84 | vmw_fifo_idle(dev_priv, sequence)) | 95 | vmw_fifo_idle(dev_priv, sequence)) |
85 | return true; | 96 | return true; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bbc7c4c30bc7..f1d626112415 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -30,6 +30,8 @@ | |||
30 | /* Might need a hrtimer here? */ | 30 | /* Might need a hrtimer here? */ |
31 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) | 31 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) |
32 | 32 | ||
33 | static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb); | ||
34 | static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb); | ||
33 | 35 | ||
34 | void vmw_display_unit_cleanup(struct vmw_display_unit *du) | 36 | void vmw_display_unit_cleanup(struct vmw_display_unit *du) |
35 | { | 37 | { |
@@ -326,6 +328,7 @@ int vmw_framebuffer_create_handle(struct drm_framebuffer *fb, | |||
326 | struct vmw_framebuffer_surface { | 328 | struct vmw_framebuffer_surface { |
327 | struct vmw_framebuffer base; | 329 | struct vmw_framebuffer base; |
328 | struct vmw_surface *surface; | 330 | struct vmw_surface *surface; |
331 | struct vmw_dma_buffer *buffer; | ||
329 | struct delayed_work d_work; | 332 | struct delayed_work d_work; |
330 | struct mutex work_lock; | 333 | struct mutex work_lock; |
331 | bool present_fs; | 334 | bool present_fs; |
@@ -500,8 +503,8 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, | |||
500 | vfbs->base.base.depth = 24; | 503 | vfbs->base.base.depth = 24; |
501 | vfbs->base.base.width = width; | 504 | vfbs->base.base.width = width; |
502 | vfbs->base.base.height = height; | 505 | vfbs->base.base.height = height; |
503 | vfbs->base.pin = NULL; | 506 | vfbs->base.pin = &vmw_surface_dmabuf_pin; |
504 | vfbs->base.unpin = NULL; | 507 | vfbs->base.unpin = &vmw_surface_dmabuf_unpin; |
505 | vfbs->surface = surface; | 508 | vfbs->surface = surface; |
506 | mutex_init(&vfbs->work_lock); | 509 | mutex_init(&vfbs->work_lock); |
507 | INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback); | 510 | INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback); |
@@ -589,6 +592,40 @@ static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { | |||
589 | .create_handle = vmw_framebuffer_create_handle, | 592 | .create_handle = vmw_framebuffer_create_handle, |
590 | }; | 593 | }; |
591 | 594 | ||
595 | static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb) | ||
596 | { | ||
597 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); | ||
598 | struct vmw_framebuffer_surface *vfbs = | ||
599 | vmw_framebuffer_to_vfbs(&vfb->base); | ||
600 | unsigned long size = vfbs->base.base.pitch * vfbs->base.base.height; | ||
601 | int ret; | ||
602 | |||
603 | vfbs->buffer = kzalloc(sizeof(*vfbs->buffer), GFP_KERNEL); | ||
604 | if (unlikely(vfbs->buffer == NULL)) | ||
605 | return -ENOMEM; | ||
606 | |||
607 | vmw_overlay_pause_all(dev_priv); | ||
608 | ret = vmw_dmabuf_init(dev_priv, vfbs->buffer, size, | ||
609 | &vmw_vram_ne_placement, | ||
610 | false, &vmw_dmabuf_bo_free); | ||
611 | vmw_overlay_resume_all(dev_priv); | ||
612 | |||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb) | ||
617 | { | ||
618 | struct ttm_buffer_object *bo; | ||
619 | struct vmw_framebuffer_surface *vfbs = | ||
620 | vmw_framebuffer_to_vfbs(&vfb->base); | ||
621 | |||
622 | bo = &vfbs->buffer->base; | ||
623 | ttm_bo_unref(&bo); | ||
624 | vfbs->buffer = NULL; | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
592 | static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) | 629 | static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) |
593 | { | 630 | { |
594 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); | 631 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); |
@@ -596,33 +633,15 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) | |||
596 | vmw_framebuffer_to_vfbd(&vfb->base); | 633 | vmw_framebuffer_to_vfbd(&vfb->base); |
597 | int ret; | 634 | int ret; |
598 | 635 | ||
636 | |||
599 | vmw_overlay_pause_all(dev_priv); | 637 | vmw_overlay_pause_all(dev_priv); |
600 | 638 | ||
601 | ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer); | 639 | ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer); |
602 | 640 | ||
603 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { | ||
604 | vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); | ||
605 | vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, 0); | ||
606 | vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); | ||
607 | vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); | ||
608 | vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); | ||
609 | vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0); | ||
610 | vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0); | ||
611 | vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); | ||
612 | |||
613 | vmw_write(dev_priv, SVGA_REG_ENABLE, 1); | ||
614 | vmw_write(dev_priv, SVGA_REG_WIDTH, vfb->base.width); | ||
615 | vmw_write(dev_priv, SVGA_REG_HEIGHT, vfb->base.height); | ||
616 | vmw_write(dev_priv, SVGA_REG_BITS_PER_PIXEL, vfb->base.bits_per_pixel); | ||
617 | vmw_write(dev_priv, SVGA_REG_DEPTH, vfb->base.depth); | ||
618 | vmw_write(dev_priv, SVGA_REG_RED_MASK, 0x00ff0000); | ||
619 | vmw_write(dev_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); | ||
620 | vmw_write(dev_priv, SVGA_REG_BLUE_MASK, 0x000000ff); | ||
621 | } else | ||
622 | WARN_ON(true); | ||
623 | |||
624 | vmw_overlay_resume_all(dev_priv); | 641 | vmw_overlay_resume_all(dev_priv); |
625 | 642 | ||
643 | WARN_ON(ret != 0); | ||
644 | |||
626 | return 0; | 645 | return 0; |
627 | } | 646 | } |
628 | 647 | ||
@@ -668,7 +687,7 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, | |||
668 | 687 | ||
669 | /* XXX get the first 3 from the surface info */ | 688 | /* XXX get the first 3 from the surface info */ |
670 | vfbd->base.base.bits_per_pixel = 32; | 689 | vfbd->base.base.bits_per_pixel = 32; |
671 | vfbd->base.base.pitch = width * 32 / 4; | 690 | vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8; |
672 | vfbd->base.base.depth = 24; | 691 | vfbd->base.base.depth = 24; |
673 | vfbd->base.base.width = width; | 692 | vfbd->base.base.width = width; |
674 | vfbd->base.base.height = height; | 693 | vfbd->base.base.height = height; |
@@ -765,8 +784,9 @@ int vmw_kms_init(struct vmw_private *dev_priv) | |||
765 | dev->mode_config.funcs = &vmw_kms_funcs; | 784 | dev->mode_config.funcs = &vmw_kms_funcs; |
766 | dev->mode_config.min_width = 1; | 785 | dev->mode_config.min_width = 1; |
767 | dev->mode_config.min_height = 1; | 786 | dev->mode_config.min_height = 1; |
768 | dev->mode_config.max_width = dev_priv->fb_max_width; | 787 | /* assumed largest fb size */ |
769 | dev->mode_config.max_height = dev_priv->fb_max_height; | 788 | dev->mode_config.max_width = 8192; |
789 | dev->mode_config.max_height = 8192; | ||
770 | 790 | ||
771 | ret = vmw_kms_init_legacy_display_system(dev_priv); | 791 | ret = vmw_kms_init_legacy_display_system(dev_priv); |
772 | 792 | ||
@@ -826,49 +846,140 @@ out: | |||
826 | return ret; | 846 | return ret; |
827 | } | 847 | } |
828 | 848 | ||
849 | void vmw_kms_write_svga(struct vmw_private *vmw_priv, | ||
850 | unsigned width, unsigned height, unsigned pitch, | ||
851 | unsigned bbp, unsigned depth) | ||
852 | { | ||
853 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) | ||
854 | vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch); | ||
855 | else if (vmw_fifo_have_pitchlock(vmw_priv)) | ||
856 | iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); | ||
857 | vmw_write(vmw_priv, SVGA_REG_WIDTH, width); | ||
858 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); | ||
859 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp); | ||
860 | vmw_write(vmw_priv, SVGA_REG_DEPTH, depth); | ||
861 | vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); | ||
862 | vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); | ||
863 | vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); | ||
864 | } | ||
865 | |||
829 | int vmw_kms_save_vga(struct vmw_private *vmw_priv) | 866 | int vmw_kms_save_vga(struct vmw_private *vmw_priv) |
830 | { | 867 | { |
831 | /* | 868 | struct vmw_vga_topology_state *save; |
832 | * setup a single multimon monitor with the size | 869 | uint32_t i; |
833 | * of 0x0, this stops the UI from resizing when we | ||
834 | * change the framebuffer size | ||
835 | */ | ||
836 | if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { | ||
837 | vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); | ||
838 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); | ||
839 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); | ||
840 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); | ||
841 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); | ||
842 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0); | ||
843 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); | ||
844 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); | ||
845 | } | ||
846 | 870 | ||
847 | vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); | 871 | vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); |
848 | vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); | 872 | vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); |
849 | vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); | ||
850 | vmw_priv->vga_depth = vmw_read(vmw_priv, SVGA_REG_DEPTH); | 873 | vmw_priv->vga_depth = vmw_read(vmw_priv, SVGA_REG_DEPTH); |
874 | vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); | ||
851 | vmw_priv->vga_pseudo = vmw_read(vmw_priv, SVGA_REG_PSEUDOCOLOR); | 875 | vmw_priv->vga_pseudo = vmw_read(vmw_priv, SVGA_REG_PSEUDOCOLOR); |
852 | vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK); | 876 | vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK); |
853 | vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); | ||
854 | vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK); | 877 | vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK); |
878 | vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); | ||
879 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) | ||
880 | vmw_priv->vga_pitchlock = | ||
881 | vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); | ||
882 | else if (vmw_fifo_have_pitchlock(vmw_priv)) | ||
883 | vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt + | ||
884 | SVGA_FIFO_PITCHLOCK); | ||
885 | |||
886 | if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) | ||
887 | return 0; | ||
855 | 888 | ||
889 | vmw_priv->num_displays = vmw_read(vmw_priv, | ||
890 | SVGA_REG_NUM_GUEST_DISPLAYS); | ||
891 | |||
892 | for (i = 0; i < vmw_priv->num_displays; ++i) { | ||
893 | save = &vmw_priv->vga_save[i]; | ||
894 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); | ||
895 | save->primary = vmw_read(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY); | ||
896 | save->pos_x = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_X); | ||
897 | save->pos_y = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y); | ||
898 | save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH); | ||
899 | save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT); | ||
900 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); | ||
901 | } | ||
856 | return 0; | 902 | return 0; |
857 | } | 903 | } |
858 | 904 | ||
859 | int vmw_kms_restore_vga(struct vmw_private *vmw_priv) | 905 | int vmw_kms_restore_vga(struct vmw_private *vmw_priv) |
860 | { | 906 | { |
907 | struct vmw_vga_topology_state *save; | ||
908 | uint32_t i; | ||
909 | |||
861 | vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width); | 910 | vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width); |
862 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height); | 911 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height); |
863 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); | ||
864 | vmw_write(vmw_priv, SVGA_REG_DEPTH, vmw_priv->vga_depth); | 912 | vmw_write(vmw_priv, SVGA_REG_DEPTH, vmw_priv->vga_depth); |
913 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); | ||
865 | vmw_write(vmw_priv, SVGA_REG_PSEUDOCOLOR, vmw_priv->vga_pseudo); | 914 | vmw_write(vmw_priv, SVGA_REG_PSEUDOCOLOR, vmw_priv->vga_pseudo); |
866 | vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask); | 915 | vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask); |
867 | vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask); | 916 | vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask); |
868 | vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask); | 917 | vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask); |
918 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) | ||
919 | vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, | ||
920 | vmw_priv->vga_pitchlock); | ||
921 | else if (vmw_fifo_have_pitchlock(vmw_priv)) | ||
922 | iowrite32(vmw_priv->vga_pitchlock, | ||
923 | vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); | ||
924 | |||
925 | if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) | ||
926 | return 0; | ||
869 | 927 | ||
870 | /* TODO check for multimon */ | 928 | for (i = 0; i < vmw_priv->num_displays; ++i) { |
871 | vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); | 929 | save = &vmw_priv->vga_save[i]; |
930 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); | ||
931 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, save->primary); | ||
932 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, save->pos_x); | ||
933 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, save->pos_y); | ||
934 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, save->width); | ||
935 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, save->height); | ||
936 | vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); | ||
937 | } | ||
872 | 938 | ||
873 | return 0; | 939 | return 0; |
874 | } | 940 | } |
941 | |||
942 | int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, | ||
943 | struct drm_file *file_priv) | ||
944 | { | ||
945 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
946 | struct drm_vmw_update_layout_arg *arg = | ||
947 | (struct drm_vmw_update_layout_arg *)data; | ||
948 | struct vmw_master *vmaster = vmw_master(file_priv->master); | ||
949 | void __user *user_rects; | ||
950 | struct drm_vmw_rect *rects; | ||
951 | unsigned rects_size; | ||
952 | int ret; | ||
953 | |||
954 | ret = ttm_read_lock(&vmaster->lock, true); | ||
955 | if (unlikely(ret != 0)) | ||
956 | return ret; | ||
957 | |||
958 | if (!arg->num_outputs) { | ||
959 | struct drm_vmw_rect def_rect = {0, 0, 800, 600}; | ||
960 | vmw_kms_ldu_update_layout(dev_priv, 1, &def_rect); | ||
961 | goto out_unlock; | ||
962 | } | ||
963 | |||
964 | rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); | ||
965 | rects = kzalloc(rects_size, GFP_KERNEL); | ||
966 | if (unlikely(!rects)) { | ||
967 | ret = -ENOMEM; | ||
968 | goto out_unlock; | ||
969 | } | ||
970 | |||
971 | user_rects = (void __user *)(unsigned long)arg->rects; | ||
972 | ret = copy_from_user(rects, user_rects, rects_size); | ||
973 | if (unlikely(ret != 0)) { | ||
974 | DRM_ERROR("Failed to get rects.\n"); | ||
975 | goto out_free; | ||
976 | } | ||
977 | |||
978 | vmw_kms_ldu_update_layout(dev_priv, arg->num_outputs, rects); | ||
979 | |||
980 | out_free: | ||
981 | kfree(rects); | ||
982 | out_unlock: | ||
983 | ttm_read_unlock(&vmaster->lock); | ||
984 | return ret; | ||
985 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8b95249f0531..8a398a0339b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | |||
@@ -94,9 +94,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | |||
94 | int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); | 94 | int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); |
95 | 95 | ||
96 | /* | 96 | /* |
97 | * Legacy display unit functions - vmwgfx_ldu.h | 97 | * Legacy display unit functions - vmwgfx_ldu.c |
98 | */ | 98 | */ |
99 | int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); | 99 | int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); |
100 | int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); | 100 | int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); |
101 | int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num, | ||
102 | struct drm_vmw_rect *rects); | ||
101 | 103 | ||
102 | #endif | 104 | #endif |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 90891593bf6c..cfaf690a5b2f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | |||
@@ -38,6 +38,7 @@ struct vmw_legacy_display { | |||
38 | struct list_head active; | 38 | struct list_head active; |
39 | 39 | ||
40 | unsigned num_active; | 40 | unsigned num_active; |
41 | unsigned last_num_active; | ||
41 | 42 | ||
42 | struct vmw_framebuffer *fb; | 43 | struct vmw_framebuffer *fb; |
43 | }; | 44 | }; |
@@ -48,9 +49,12 @@ struct vmw_legacy_display { | |||
48 | struct vmw_legacy_display_unit { | 49 | struct vmw_legacy_display_unit { |
49 | struct vmw_display_unit base; | 50 | struct vmw_display_unit base; |
50 | 51 | ||
51 | struct list_head active; | 52 | unsigned pref_width; |
53 | unsigned pref_height; | ||
54 | bool pref_active; | ||
55 | struct drm_display_mode *pref_mode; | ||
52 | 56 | ||
53 | unsigned unit; | 57 | struct list_head active; |
54 | }; | 58 | }; |
55 | 59 | ||
56 | static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) | 60 | static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) |
@@ -88,23 +92,44 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) | |||
88 | { | 92 | { |
89 | struct vmw_legacy_display *lds = dev_priv->ldu_priv; | 93 | struct vmw_legacy_display *lds = dev_priv->ldu_priv; |
90 | struct vmw_legacy_display_unit *entry; | 94 | struct vmw_legacy_display_unit *entry; |
91 | struct drm_crtc *crtc; | 95 | struct drm_framebuffer *fb = NULL; |
96 | struct drm_crtc *crtc = NULL; | ||
92 | int i = 0; | 97 | int i = 0; |
93 | 98 | ||
94 | /* to stop the screen from changing size on resize */ | 99 | /* If there is no display topology the host just assumes |
95 | vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); | 100 | * that the guest will set the same layout as the host. |
96 | for (i = 0; i < lds->num_active; i++) { | 101 | */ |
97 | vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); | 102 | if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) { |
98 | vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); | 103 | int w = 0, h = 0; |
99 | vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); | 104 | list_for_each_entry(entry, &lds->active, active) { |
100 | vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); | 105 | crtc = &entry->base.crtc; |
101 | vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0); | 106 | w = max(w, crtc->x + crtc->mode.hdisplay); |
102 | vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0); | 107 | h = max(h, crtc->y + crtc->mode.vdisplay); |
103 | vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); | 108 | i++; |
109 | } | ||
110 | |||
111 | if (crtc == NULL) | ||
112 | return 0; | ||
113 | fb = entry->base.crtc.fb; | ||
114 | |||
115 | vmw_kms_write_svga(dev_priv, w, h, fb->pitch, | ||
116 | fb->bits_per_pixel, fb->depth); | ||
117 | |||
118 | return 0; | ||
104 | } | 119 | } |
105 | 120 | ||
106 | /* Now set the mode */ | 121 | if (!list_empty(&lds->active)) { |
107 | vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, lds->num_active); | 122 | entry = list_entry(lds->active.next, typeof(*entry), active); |
123 | fb = entry->base.crtc.fb; | ||
124 | |||
125 | vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitch, | ||
126 | fb->bits_per_pixel, fb->depth); | ||
127 | } | ||
128 | |||
129 | /* Make sure we always show something. */ | ||
130 | vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, | ||
131 | lds->num_active ? lds->num_active : 1); | ||
132 | |||
108 | i = 0; | 133 | i = 0; |
109 | list_for_each_entry(entry, &lds->active, active) { | 134 | list_for_each_entry(entry, &lds->active, active) { |
110 | crtc = &entry->base.crtc; | 135 | crtc = &entry->base.crtc; |
@@ -120,6 +145,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) | |||
120 | i++; | 145 | i++; |
121 | } | 146 | } |
122 | 147 | ||
148 | BUG_ON(i != lds->num_active); | ||
149 | |||
150 | lds->last_num_active = lds->num_active; | ||
151 | |||
123 | return 0; | 152 | return 0; |
124 | } | 153 | } |
125 | 154 | ||
@@ -130,6 +159,7 @@ static int vmw_ldu_del_active(struct vmw_private *vmw_priv, | |||
130 | if (list_empty(&ldu->active)) | 159 | if (list_empty(&ldu->active)) |
131 | return 0; | 160 | return 0; |
132 | 161 | ||
162 | /* Must init otherwise list_empty(&ldu->active) will not work. */ | ||
133 | list_del_init(&ldu->active); | 163 | list_del_init(&ldu->active); |
134 | if (--(ld->num_active) == 0) { | 164 | if (--(ld->num_active) == 0) { |
135 | BUG_ON(!ld->fb); | 165 | BUG_ON(!ld->fb); |
@@ -149,24 +179,29 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, | |||
149 | struct vmw_legacy_display_unit *entry; | 179 | struct vmw_legacy_display_unit *entry; |
150 | struct list_head *at; | 180 | struct list_head *at; |
151 | 181 | ||
182 | BUG_ON(!ld->num_active && ld->fb); | ||
183 | if (vfb != ld->fb) { | ||
184 | if (ld->fb && ld->fb->unpin) | ||
185 | ld->fb->unpin(ld->fb); | ||
186 | if (vfb->pin) | ||
187 | vfb->pin(vfb); | ||
188 | ld->fb = vfb; | ||
189 | } | ||
190 | |||
152 | if (!list_empty(&ldu->active)) | 191 | if (!list_empty(&ldu->active)) |
153 | return 0; | 192 | return 0; |
154 | 193 | ||
155 | at = &ld->active; | 194 | at = &ld->active; |
156 | list_for_each_entry(entry, &ld->active, active) { | 195 | list_for_each_entry(entry, &ld->active, active) { |
157 | if (entry->unit > ldu->unit) | 196 | if (entry->base.unit > ldu->base.unit) |
158 | break; | 197 | break; |
159 | 198 | ||
160 | at = &entry->active; | 199 | at = &entry->active; |
161 | } | 200 | } |
162 | 201 | ||
163 | list_add(&ldu->active, at); | 202 | list_add(&ldu->active, at); |
164 | if (ld->num_active++ == 0) { | 203 | |
165 | BUG_ON(ld->fb); | 204 | ld->num_active++; |
166 | if (vfb->pin) | ||
167 | vfb->pin(vfb); | ||
168 | ld->fb = vfb; | ||
169 | } | ||
170 | 205 | ||
171 | return 0; | 206 | return 0; |
172 | } | 207 | } |
@@ -208,6 +243,8 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) | |||
208 | 243 | ||
209 | /* ldu only supports one fb active at the time */ | 244 | /* ldu only supports one fb active at the time */ |
210 | if (dev_priv->ldu_priv->fb && vfb && | 245 | if (dev_priv->ldu_priv->fb && vfb && |
246 | !(dev_priv->ldu_priv->num_active == 1 && | ||
247 | !list_empty(&ldu->active)) && | ||
211 | dev_priv->ldu_priv->fb != vfb) { | 248 | dev_priv->ldu_priv->fb != vfb) { |
212 | DRM_ERROR("Multiple framebuffers not supported\n"); | 249 | DRM_ERROR("Multiple framebuffers not supported\n"); |
213 | return -EINVAL; | 250 | return -EINVAL; |
@@ -300,8 +337,7 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector) | |||
300 | static enum drm_connector_status | 337 | static enum drm_connector_status |
301 | vmw_ldu_connector_detect(struct drm_connector *connector) | 338 | vmw_ldu_connector_detect(struct drm_connector *connector) |
302 | { | 339 | { |
303 | /* XXX vmwctrl should control connection status */ | 340 | if (vmw_connector_to_ldu(connector)->pref_active) |
304 | if (vmw_connector_to_ldu(connector)->base.unit == 0) | ||
305 | return connector_status_connected; | 341 | return connector_status_connected; |
306 | return connector_status_disconnected; | 342 | return connector_status_disconnected; |
307 | } | 343 | } |
@@ -312,10 +348,9 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = { | |||
312 | 752, 800, 0, 480, 489, 492, 525, 0, | 348 | 752, 800, 0, 480, 489, 492, 525, 0, |
313 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 349 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
314 | /* 800x600@60Hz */ | 350 | /* 800x600@60Hz */ |
315 | { DRM_MODE("800x600", | 351 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, |
316 | DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, | 352 | 968, 1056, 0, 600, 601, 605, 628, 0, |
317 | 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, | 353 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
318 | 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
319 | /* 1024x768@60Hz */ | 354 | /* 1024x768@60Hz */ |
320 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, | 355 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, |
321 | 1184, 1344, 0, 768, 771, 777, 806, 0, | 356 | 1184, 1344, 0, 768, 771, 777, 806, 0, |
@@ -387,10 +422,34 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = { | |||
387 | static int vmw_ldu_connector_fill_modes(struct drm_connector *connector, | 422 | static int vmw_ldu_connector_fill_modes(struct drm_connector *connector, |
388 | uint32_t max_width, uint32_t max_height) | 423 | uint32_t max_width, uint32_t max_height) |
389 | { | 424 | { |
425 | struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector); | ||
390 | struct drm_device *dev = connector->dev; | 426 | struct drm_device *dev = connector->dev; |
391 | struct drm_display_mode *mode = NULL; | 427 | struct drm_display_mode *mode = NULL; |
428 | struct drm_display_mode prefmode = { DRM_MODE("preferred", | ||
429 | DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, | ||
430 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
431 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) | ||
432 | }; | ||
392 | int i; | 433 | int i; |
393 | 434 | ||
435 | /* Add preferred mode */ | ||
436 | { | ||
437 | mode = drm_mode_duplicate(dev, &prefmode); | ||
438 | if (!mode) | ||
439 | return 0; | ||
440 | mode->hdisplay = ldu->pref_width; | ||
441 | mode->vdisplay = ldu->pref_height; | ||
442 | mode->vrefresh = drm_mode_vrefresh(mode); | ||
443 | drm_mode_probed_add(connector, mode); | ||
444 | |||
445 | if (ldu->pref_mode) { | ||
446 | list_del_init(&ldu->pref_mode->head); | ||
447 | drm_mode_destroy(dev, ldu->pref_mode); | ||
448 | } | ||
449 | |||
450 | ldu->pref_mode = mode; | ||
451 | } | ||
452 | |||
394 | for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) { | 453 | for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) { |
395 | if (vmw_ldu_connector_builtin[i].hdisplay > max_width || | 454 | if (vmw_ldu_connector_builtin[i].hdisplay > max_width || |
396 | vmw_ldu_connector_builtin[i].vdisplay > max_height) | 455 | vmw_ldu_connector_builtin[i].vdisplay > max_height) |
@@ -443,18 +502,21 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) | |||
443 | if (!ldu) | 502 | if (!ldu) |
444 | return -ENOMEM; | 503 | return -ENOMEM; |
445 | 504 | ||
446 | ldu->unit = unit; | 505 | ldu->base.unit = unit; |
447 | crtc = &ldu->base.crtc; | 506 | crtc = &ldu->base.crtc; |
448 | encoder = &ldu->base.encoder; | 507 | encoder = &ldu->base.encoder; |
449 | connector = &ldu->base.connector; | 508 | connector = &ldu->base.connector; |
450 | 509 | ||
510 | INIT_LIST_HEAD(&ldu->active); | ||
511 | |||
512 | ldu->pref_active = (unit == 0); | ||
513 | ldu->pref_width = 800; | ||
514 | ldu->pref_height = 600; | ||
515 | ldu->pref_mode = NULL; | ||
516 | |||
451 | drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, | 517 | drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, |
452 | DRM_MODE_CONNECTOR_LVDS); | 518 | DRM_MODE_CONNECTOR_LVDS); |
453 | /* Initial status */ | 519 | connector->status = vmw_ldu_connector_detect(connector); |
454 | if (unit == 0) | ||
455 | connector->status = connector_status_connected; | ||
456 | else | ||
457 | connector->status = connector_status_disconnected; | ||
458 | 520 | ||
459 | drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, | 521 | drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, |
460 | DRM_MODE_ENCODER_LVDS); | 522 | DRM_MODE_ENCODER_LVDS); |
@@ -462,8 +524,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) | |||
462 | encoder->possible_crtcs = (1 << unit); | 524 | encoder->possible_crtcs = (1 << unit); |
463 | encoder->possible_clones = 0; | 525 | encoder->possible_clones = 0; |
464 | 526 | ||
465 | INIT_LIST_HEAD(&ldu->active); | ||
466 | |||
467 | drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs); | 527 | drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs); |
468 | 528 | ||
469 | drm_connector_attach_property(connector, | 529 | drm_connector_attach_property(connector, |
@@ -487,18 +547,22 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) | |||
487 | 547 | ||
488 | INIT_LIST_HEAD(&dev_priv->ldu_priv->active); | 548 | INIT_LIST_HEAD(&dev_priv->ldu_priv->active); |
489 | dev_priv->ldu_priv->num_active = 0; | 549 | dev_priv->ldu_priv->num_active = 0; |
550 | dev_priv->ldu_priv->last_num_active = 0; | ||
490 | dev_priv->ldu_priv->fb = NULL; | 551 | dev_priv->ldu_priv->fb = NULL; |
491 | 552 | ||
492 | drm_mode_create_dirty_info_property(dev_priv->dev); | 553 | drm_mode_create_dirty_info_property(dev_priv->dev); |
493 | 554 | ||
494 | vmw_ldu_init(dev_priv, 0); | 555 | vmw_ldu_init(dev_priv, 0); |
495 | vmw_ldu_init(dev_priv, 1); | 556 | /* for old hardware without multimon only enable one display */ |
496 | vmw_ldu_init(dev_priv, 2); | 557 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { |
497 | vmw_ldu_init(dev_priv, 3); | 558 | vmw_ldu_init(dev_priv, 1); |
498 | vmw_ldu_init(dev_priv, 4); | 559 | vmw_ldu_init(dev_priv, 2); |
499 | vmw_ldu_init(dev_priv, 5); | 560 | vmw_ldu_init(dev_priv, 3); |
500 | vmw_ldu_init(dev_priv, 6); | 561 | vmw_ldu_init(dev_priv, 4); |
501 | vmw_ldu_init(dev_priv, 7); | 562 | vmw_ldu_init(dev_priv, 5); |
563 | vmw_ldu_init(dev_priv, 6); | ||
564 | vmw_ldu_init(dev_priv, 7); | ||
565 | } | ||
502 | 566 | ||
503 | return 0; | 567 | return 0; |
504 | } | 568 | } |
@@ -514,3 +578,42 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv) | |||
514 | 578 | ||
515 | return 0; | 579 | return 0; |
516 | } | 580 | } |
581 | |||
582 | int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num, | ||
583 | struct drm_vmw_rect *rects) | ||
584 | { | ||
585 | struct drm_device *dev = dev_priv->dev; | ||
586 | struct vmw_legacy_display_unit *ldu; | ||
587 | struct drm_connector *con; | ||
588 | int i; | ||
589 | |||
590 | mutex_lock(&dev->mode_config.mutex); | ||
591 | |||
592 | #if 0 | ||
593 | DRM_INFO("%s: new layout ", __func__); | ||
594 | for (i = 0; i < (int)num; i++) | ||
595 | DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y, | ||
596 | rects[i].w, rects[i].h); | ||
597 | DRM_INFO("\n"); | ||
598 | #else | ||
599 | (void)i; | ||
600 | #endif | ||
601 | |||
602 | list_for_each_entry(con, &dev->mode_config.connector_list, head) { | ||
603 | ldu = vmw_connector_to_ldu(con); | ||
604 | if (num > ldu->base.unit) { | ||
605 | ldu->pref_width = rects[ldu->base.unit].w; | ||
606 | ldu->pref_height = rects[ldu->base.unit].h; | ||
607 | ldu->pref_active = true; | ||
608 | } else { | ||
609 | ldu->pref_width = 800; | ||
610 | ldu->pref_height = 600; | ||
611 | ldu->pref_active = false; | ||
612 | } | ||
613 | con->status = vmw_ldu_connector_detect(con); | ||
614 | } | ||
615 | |||
616 | mutex_unlock(&dev->mode_config.mutex); | ||
617 | |||
618 | return 0; | ||
619 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index ad566c85b075..df2036ed18d5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | |||
@@ -358,6 +358,8 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv, | |||
358 | if (stream->buf != buf) | 358 | if (stream->buf != buf) |
359 | stream->buf = vmw_dmabuf_reference(buf); | 359 | stream->buf = vmw_dmabuf_reference(buf); |
360 | stream->saved = *arg; | 360 | stream->saved = *arg; |
361 | /* stream is no longer stopped/paused */ | ||
362 | stream->paused = false; | ||
361 | 363 | ||
362 | return 0; | 364 | return 0; |
363 | } | 365 | } |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index f8fbbc67a406..8612378b131e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
@@ -597,8 +597,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | |||
597 | 597 | ||
598 | ret = copy_from_user(srf->sizes, user_sizes, | 598 | ret = copy_from_user(srf->sizes, user_sizes, |
599 | srf->num_sizes * sizeof(*srf->sizes)); | 599 | srf->num_sizes * sizeof(*srf->sizes)); |
600 | if (unlikely(ret != 0)) | 600 | if (unlikely(ret != 0)) { |
601 | ret = -EFAULT; | ||
601 | goto out_err1; | 602 | goto out_err1; |
603 | } | ||
602 | 604 | ||
603 | if (srf->scanout && | 605 | if (srf->scanout && |
604 | srf->num_sizes == 1 && | 606 | srf->num_sizes == 1 && |
@@ -697,9 +699,11 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
697 | if (user_sizes) | 699 | if (user_sizes) |
698 | ret = copy_to_user(user_sizes, srf->sizes, | 700 | ret = copy_to_user(user_sizes, srf->sizes, |
699 | srf->num_sizes * sizeof(*srf->sizes)); | 701 | srf->num_sizes * sizeof(*srf->sizes)); |
700 | if (unlikely(ret != 0)) | 702 | if (unlikely(ret != 0)) { |
701 | DRM_ERROR("copy_to_user failed %p %u\n", | 703 | DRM_ERROR("copy_to_user failed %p %u\n", |
702 | user_sizes, srf->num_sizes); | 704 | user_sizes, srf->num_sizes); |
705 | ret = -EFAULT; | ||
706 | } | ||
703 | out_bad_resource: | 707 | out_bad_resource: |
704 | out_no_reference: | 708 | out_no_reference: |
705 | ttm_base_object_unref(&base); | 709 | ttm_base_object_unref(&base); |