diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_fb.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 104 |
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 | |||
170 | static void vmw_fb_dirty_flush(struct work_struct *work) | 175 | static 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 | ||
255 | out_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 | */ | ||
891 | void 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 | } | ||