aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_fb.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c104
1 files changed, 44 insertions, 60 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index be7d7fb1b44b..2582ffd36bb5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -43,8 +43,6 @@ struct vmw_fb_par {
43 43
44 struct mutex bo_mutex; 44 struct mutex bo_mutex;
45 struct vmw_dma_buffer *vmw_bo; 45 struct vmw_dma_buffer *vmw_bo;
46 struct ttm_bo_kmap_obj map;
47 void *bo_ptr;
48 unsigned bo_size; 46 unsigned bo_size;
49 struct drm_framebuffer *set_fb; 47 struct drm_framebuffer *set_fb;
50 struct drm_display_mode *set_mode; 48 struct drm_display_mode *set_mode;
@@ -163,10 +161,17 @@ static int vmw_fb_blank(int blank, struct fb_info *info)
163 return 0; 161 return 0;
164} 162}
165 163
166/* 164/**
167 * Dirty code 165 * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer
166 *
167 * @work: The struct work_struct associated with this task.
168 *
169 * This function flushes the dirty regions of the vmalloc framebuffer to the
170 * kms framebuffer, and if the kms framebuffer is visible, also updated the
171 * corresponding displays. Note that this function runs even if the kms
172 * framebuffer is not bound to a crtc and thus not visible, but it's turned
173 * off during hibernation using the par->dirty.active bool.
168 */ 174 */
169
170static void vmw_fb_dirty_flush(struct work_struct *work) 175static void vmw_fb_dirty_flush(struct work_struct *work)
171{ 176{
172 struct vmw_fb_par *par = container_of(work, struct vmw_fb_par, 177 struct vmw_fb_par *par = container_of(work, struct vmw_fb_par,
@@ -174,13 +179,15 @@ static void vmw_fb_dirty_flush(struct work_struct *work)
174 struct vmw_private *vmw_priv = par->vmw_priv; 179 struct vmw_private *vmw_priv = par->vmw_priv;
175 struct fb_info *info = vmw_priv->fb_info; 180 struct fb_info *info = vmw_priv->fb_info;
176 unsigned long irq_flags; 181 unsigned long irq_flags;
177 s32 dst_x1, dst_x2, dst_y1, dst_y2, w, h; 182 s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0;
178 u32 cpp, max_x, max_y; 183 u32 cpp, max_x, max_y;
179 struct drm_clip_rect clip; 184 struct drm_clip_rect clip;
180 struct drm_framebuffer *cur_fb; 185 struct drm_framebuffer *cur_fb;
181 u8 *src_ptr, *dst_ptr; 186 u8 *src_ptr, *dst_ptr;
187 struct vmw_dma_buffer *vbo = par->vmw_bo;
188 void *virtual;
182 189
183 if (vmw_priv->suspended) 190 if (!READ_ONCE(par->dirty.active))
184 return; 191 return;
185 192
186 mutex_lock(&par->bo_mutex); 193 mutex_lock(&par->bo_mutex);
@@ -188,10 +195,16 @@ static void vmw_fb_dirty_flush(struct work_struct *work)
188 if (!cur_fb) 195 if (!cur_fb)
189 goto out_unlock; 196 goto out_unlock;
190 197
198 (void) ttm_read_lock(&vmw_priv->reservation_sem, false);
199 (void) ttm_bo_reserve(&vbo->base, false, false, NULL);
200 virtual = vmw_dma_buffer_map_and_cache(vbo);
201 if (!virtual)
202 goto out_unreserve;
203
191 spin_lock_irqsave(&par->dirty.lock, irq_flags); 204 spin_lock_irqsave(&par->dirty.lock, irq_flags);
192 if (!par->dirty.active) { 205 if (!par->dirty.active) {
193 spin_unlock_irqrestore(&par->dirty.lock, irq_flags); 206 spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
194 goto out_unlock; 207 goto out_unreserve;
195 } 208 }
196 209
197 /* 210 /*
@@ -221,7 +234,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work)
221 spin_unlock_irqrestore(&par->dirty.lock, irq_flags); 234 spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
222 235
223 if (w && h) { 236 if (w && h) {
224 dst_ptr = (u8 *)par->bo_ptr + 237 dst_ptr = (u8 *)virtual +
225 (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); 238 (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp);
226 src_ptr = (u8 *)par->vmalloc + 239 src_ptr = (u8 *)par->vmalloc +
227 ((dst_y1 + par->fb_y) * info->fix.line_length + 240 ((dst_y1 + par->fb_y) * info->fix.line_length +
@@ -237,7 +250,12 @@ static void vmw_fb_dirty_flush(struct work_struct *work)
237 clip.x2 = dst_x2; 250 clip.x2 = dst_x2;
238 clip.y1 = dst_y1; 251 clip.y1 = dst_y1;
239 clip.y2 = dst_y2; 252 clip.y2 = dst_y2;
253 }
240 254
255out_unreserve:
256 ttm_bo_unreserve(&vbo->base);
257 ttm_read_unlock(&vmw_priv->reservation_sem);
258 if (w && h) {
241 WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, 259 WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0,
242 &clip, 1)); 260 &clip, 1));
243 vmw_fifo_flush(vmw_priv, false); 261 vmw_fifo_flush(vmw_priv, false);
@@ -504,18 +522,8 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
504 par->set_fb = NULL; 522 par->set_fb = NULL;
505 } 523 }
506 524
507 if (par->vmw_bo && detach_bo) { 525 if (par->vmw_bo && detach_bo && unref_bo)
508 struct vmw_private *vmw_priv = par->vmw_priv; 526 vmw_dmabuf_unreference(&par->vmw_bo);
509
510 if (par->bo_ptr) {
511 ttm_bo_kunmap(&par->map);
512 par->bo_ptr = NULL;
513 }
514 if (unref_bo)
515 vmw_dmabuf_unreference(&par->vmw_bo);
516 else if (vmw_priv->active_display_unit != vmw_du_legacy)
517 vmw_dmabuf_unpin(par->vmw_priv, par->vmw_bo, false);
518 }
519 527
520 return 0; 528 return 0;
521} 529}
@@ -636,38 +644,6 @@ static int vmw_fb_set_par(struct fb_info *info)
636 if (ret) 644 if (ret)
637 goto out_unlock; 645 goto out_unlock;
638 646
639 if (!par->bo_ptr) {
640 struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(set.fb);
641
642 /*
643 * Pin before mapping. Since we don't know in what placement
644 * to pin, call into KMS to do it for us. LDU doesn't require
645 * additional pinning because set_config() would've pinned
646 * it already
647 */
648 if (vmw_priv->active_display_unit != vmw_du_legacy) {
649 ret = vfb->pin(vfb);
650 if (ret) {
651 DRM_ERROR("Could not pin the fbdev "
652 "framebuffer.\n");
653 goto out_unlock;
654 }
655 }
656
657 ret = ttm_bo_kmap(&par->vmw_bo->base, 0,
658 par->vmw_bo->base.num_pages, &par->map);
659 if (ret) {
660 if (vmw_priv->active_display_unit != vmw_du_legacy)
661 vfb->unpin(vfb);
662
663 DRM_ERROR("Could not map the fbdev framebuffer.\n");
664 goto out_unlock;
665 }
666
667 par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite);
668 }
669
670
671 vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, 647 vmw_fb_dirty_mark(par, par->fb_x, par->fb_y,
672 par->set_fb->width, par->set_fb->height); 648 par->set_fb->width, par->set_fb->height);
673 649
@@ -883,12 +859,6 @@ int vmw_fb_off(struct vmw_private *vmw_priv)
883 flush_delayed_work(&info->deferred_work); 859 flush_delayed_work(&info->deferred_work);
884 flush_delayed_work(&par->local_work); 860 flush_delayed_work(&par->local_work);
885 861
886 mutex_lock(&par->bo_mutex);
887 drm_modeset_lock_all(vmw_priv->dev);
888 (void) vmw_fb_kms_detach(par, true, false);
889 drm_modeset_unlock_all(vmw_priv->dev);
890 mutex_unlock(&par->bo_mutex);
891
892 return 0; 862 return 0;
893} 863}
894 864
@@ -904,10 +874,24 @@ int vmw_fb_on(struct vmw_private *vmw_priv)
904 info = vmw_priv->fb_info; 874 info = vmw_priv->fb_info;
905 par = info->par; 875 par = info->par;
906 876
907 vmw_fb_set_par(info);
908 spin_lock_irqsave(&par->dirty.lock, flags); 877 spin_lock_irqsave(&par->dirty.lock, flags);
909 par->dirty.active = true; 878 par->dirty.active = true;
910 spin_unlock_irqrestore(&par->dirty.lock, flags); 879 spin_unlock_irqrestore(&par->dirty.lock, flags);
911 880
912 return 0; 881 return 0;
913} 882}
883
884/**
885 * vmw_fb_refresh - Refresh fb display
886 *
887 * @vmw_priv: Pointer to device private
888 *
889 * Call into kms to show the fbdev display(s).
890 */
891void vmw_fb_refresh(struct vmw_private *vmw_priv)
892{
893 if (!vmw_priv->fb_info)
894 return;
895
896 vmw_fb_set_par(vmw_priv->fb_info);
897}