Home | History | Annotate | Line # | Download | only in vmwgfx
      1  1.2  riastrad /*	$NetBSD: vmwgfx_fb.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $	*/
      2  1.2  riastrad 
      3  1.1  riastrad /**************************************************************************
      4  1.1  riastrad  *
      5  1.1  riastrad  * Copyright  2007 David Airlie
      6  1.2  riastrad  * Copyright  2009-2015 VMware, Inc., Palo Alto, CA., USA
      7  1.1  riastrad  * All Rights Reserved.
      8  1.1  riastrad  *
      9  1.1  riastrad  * Permission is hereby granted, free of charge, to any person obtaining a
     10  1.1  riastrad  * copy of this software and associated documentation files (the
     11  1.1  riastrad  * "Software"), to deal in the Software without restriction, including
     12  1.1  riastrad  * without limitation the rights to use, copy, modify, merge, publish,
     13  1.1  riastrad  * distribute, sub license, and/or sell copies of the Software, and to
     14  1.1  riastrad  * permit persons to whom the Software is furnished to do so, subject to
     15  1.1  riastrad  * the following conditions:
     16  1.1  riastrad  *
     17  1.1  riastrad  * The above copyright notice and this permission notice (including the
     18  1.1  riastrad  * next paragraph) shall be included in all copies or substantial portions
     19  1.1  riastrad  * of the Software.
     20  1.1  riastrad  *
     21  1.1  riastrad  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     22  1.1  riastrad  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     23  1.1  riastrad  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     24  1.1  riastrad  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     25  1.1  riastrad  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     26  1.1  riastrad  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     27  1.1  riastrad  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     28  1.1  riastrad  *
     29  1.1  riastrad  **************************************************************************/
     30  1.1  riastrad 
     31  1.2  riastrad #include <sys/cdefs.h>
     32  1.2  riastrad __KERNEL_RCSID(0, "$NetBSD: vmwgfx_fb.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $");
     33  1.2  riastrad 
     34  1.3  riastrad #include <linux/pci.h>
     35  1.3  riastrad 
     36  1.3  riastrad #include <drm/drm_fourcc.h>
     37  1.3  riastrad #include <drm/ttm/ttm_placement.h>
     38  1.1  riastrad 
     39  1.1  riastrad #include "vmwgfx_drv.h"
     40  1.2  riastrad #include "vmwgfx_kms.h"
     41  1.1  riastrad 
     42  1.1  riastrad #define VMW_DIRTY_DELAY (HZ / 30)
     43  1.1  riastrad 
     44  1.1  riastrad struct vmw_fb_par {
     45  1.1  riastrad 	struct vmw_private *vmw_priv;
     46  1.1  riastrad 
     47  1.1  riastrad 	void *vmalloc;
     48  1.1  riastrad 
     49  1.2  riastrad 	struct mutex bo_mutex;
     50  1.3  riastrad 	struct vmw_buffer_object *vmw_bo;
     51  1.2  riastrad 	unsigned bo_size;
     52  1.2  riastrad 	struct drm_framebuffer *set_fb;
     53  1.2  riastrad 	struct drm_display_mode *set_mode;
     54  1.2  riastrad 	u32 fb_x;
     55  1.2  riastrad 	u32 fb_y;
     56  1.2  riastrad 	bool bo_iowrite;
     57  1.1  riastrad 
     58  1.1  riastrad 	u32 pseudo_palette[17];
     59  1.1  riastrad 
     60  1.1  riastrad 	unsigned max_width;
     61  1.1  riastrad 	unsigned max_height;
     62  1.1  riastrad 
     63  1.1  riastrad 	struct {
     64  1.1  riastrad 		spinlock_t lock;
     65  1.1  riastrad 		bool active;
     66  1.1  riastrad 		unsigned x1;
     67  1.1  riastrad 		unsigned y1;
     68  1.1  riastrad 		unsigned x2;
     69  1.1  riastrad 		unsigned y2;
     70  1.1  riastrad 	} dirty;
     71  1.2  riastrad 
     72  1.2  riastrad 	struct drm_crtc *crtc;
     73  1.2  riastrad 	struct drm_connector *con;
     74  1.2  riastrad 	struct delayed_work local_work;
     75  1.1  riastrad };
     76  1.1  riastrad 
     77  1.1  riastrad static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
     78  1.1  riastrad 			    unsigned blue, unsigned transp,
     79  1.1  riastrad 			    struct fb_info *info)
     80  1.1  riastrad {
     81  1.1  riastrad 	struct vmw_fb_par *par = info->par;
     82  1.1  riastrad 	u32 *pal = par->pseudo_palette;
     83  1.1  riastrad 
     84  1.1  riastrad 	if (regno > 15) {
     85  1.1  riastrad 		DRM_ERROR("Bad regno %u.\n", regno);
     86  1.1  riastrad 		return 1;
     87  1.1  riastrad 	}
     88  1.1  riastrad 
     89  1.3  riastrad 	switch (par->set_fb->format->depth) {
     90  1.1  riastrad 	case 24:
     91  1.1  riastrad 	case 32:
     92  1.1  riastrad 		pal[regno] = ((red & 0xff00) << 8) |
     93  1.1  riastrad 			      (green & 0xff00) |
     94  1.1  riastrad 			     ((blue  & 0xff00) >> 8);
     95  1.1  riastrad 		break;
     96  1.1  riastrad 	default:
     97  1.3  riastrad 		DRM_ERROR("Bad depth %u, bpp %u.\n",
     98  1.3  riastrad 			  par->set_fb->format->depth,
     99  1.3  riastrad 			  par->set_fb->format->cpp[0] * 8);
    100  1.1  riastrad 		return 1;
    101  1.1  riastrad 	}
    102  1.1  riastrad 
    103  1.1  riastrad 	return 0;
    104  1.1  riastrad }
    105  1.1  riastrad 
    106  1.1  riastrad static int vmw_fb_check_var(struct fb_var_screeninfo *var,
    107  1.1  riastrad 			    struct fb_info *info)
    108  1.1  riastrad {
    109  1.1  riastrad 	int depth = var->bits_per_pixel;
    110  1.1  riastrad 	struct vmw_fb_par *par = info->par;
    111  1.1  riastrad 	struct vmw_private *vmw_priv = par->vmw_priv;
    112  1.1  riastrad 
    113  1.1  riastrad 	switch (var->bits_per_pixel) {
    114  1.1  riastrad 	case 32:
    115  1.1  riastrad 		depth = (var->transp.length > 0) ? 32 : 24;
    116  1.1  riastrad 		break;
    117  1.1  riastrad 	default:
    118  1.1  riastrad 		DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel);
    119  1.1  riastrad 		return -EINVAL;
    120  1.1  riastrad 	}
    121  1.1  riastrad 
    122  1.1  riastrad 	switch (depth) {
    123  1.1  riastrad 	case 24:
    124  1.1  riastrad 		var->red.offset = 16;
    125  1.1  riastrad 		var->green.offset = 8;
    126  1.1  riastrad 		var->blue.offset = 0;
    127  1.1  riastrad 		var->red.length = 8;
    128  1.1  riastrad 		var->green.length = 8;
    129  1.1  riastrad 		var->blue.length = 8;
    130  1.1  riastrad 		var->transp.length = 0;
    131  1.1  riastrad 		var->transp.offset = 0;
    132  1.1  riastrad 		break;
    133  1.1  riastrad 	case 32:
    134  1.1  riastrad 		var->red.offset = 16;
    135  1.1  riastrad 		var->green.offset = 8;
    136  1.1  riastrad 		var->blue.offset = 0;
    137  1.1  riastrad 		var->red.length = 8;
    138  1.1  riastrad 		var->green.length = 8;
    139  1.1  riastrad 		var->blue.length = 8;
    140  1.1  riastrad 		var->transp.length = 8;
    141  1.1  riastrad 		var->transp.offset = 24;
    142  1.1  riastrad 		break;
    143  1.1  riastrad 	default:
    144  1.1  riastrad 		DRM_ERROR("Bad depth %u.\n", depth);
    145  1.1  riastrad 		return -EINVAL;
    146  1.1  riastrad 	}
    147  1.1  riastrad 
    148  1.1  riastrad 	if ((var->xoffset + var->xres) > par->max_width ||
    149  1.1  riastrad 	    (var->yoffset + var->yres) > par->max_height) {
    150  1.1  riastrad 		DRM_ERROR("Requested geom can not fit in framebuffer\n");
    151  1.1  riastrad 		return -EINVAL;
    152  1.1  riastrad 	}
    153  1.1  riastrad 
    154  1.1  riastrad 	if (!vmw_kms_validate_mode_vram(vmw_priv,
    155  1.2  riastrad 					var->xres * var->bits_per_pixel/8,
    156  1.1  riastrad 					var->yoffset + var->yres)) {
    157  1.1  riastrad 		DRM_ERROR("Requested geom can not fit in framebuffer\n");
    158  1.1  riastrad 		return -EINVAL;
    159  1.1  riastrad 	}
    160  1.1  riastrad 
    161  1.1  riastrad 	return 0;
    162  1.1  riastrad }
    163  1.1  riastrad 
    164  1.1  riastrad static int vmw_fb_blank(int blank, struct fb_info *info)
    165  1.1  riastrad {
    166  1.1  riastrad 	return 0;
    167  1.1  riastrad }
    168  1.1  riastrad 
    169  1.3  riastrad /**
    170  1.3  riastrad  * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer
    171  1.3  riastrad  *
    172  1.3  riastrad  * @work: The struct work_struct associated with this task.
    173  1.3  riastrad  *
    174  1.3  riastrad  * This function flushes the dirty regions of the vmalloc framebuffer to the
    175  1.3  riastrad  * kms framebuffer, and if the kms framebuffer is visible, also updated the
    176  1.3  riastrad  * corresponding displays. Note that this function runs even if the kms
    177  1.3  riastrad  * framebuffer is not bound to a crtc and thus not visible, but it's turned
    178  1.3  riastrad  * off during hibernation using the par->dirty.active bool.
    179  1.1  riastrad  */
    180  1.2  riastrad static void vmw_fb_dirty_flush(struct work_struct *work)
    181  1.1  riastrad {
    182  1.2  riastrad 	struct vmw_fb_par *par = container_of(work, struct vmw_fb_par,
    183  1.2  riastrad 					      local_work.work);
    184  1.1  riastrad 	struct vmw_private *vmw_priv = par->vmw_priv;
    185  1.1  riastrad 	struct fb_info *info = vmw_priv->fb_info;
    186  1.2  riastrad 	unsigned long irq_flags;
    187  1.3  riastrad 	s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0;
    188  1.2  riastrad 	u32 cpp, max_x, max_y;
    189  1.2  riastrad 	struct drm_clip_rect clip;
    190  1.2  riastrad 	struct drm_framebuffer *cur_fb;
    191  1.2  riastrad 	u8 *src_ptr, *dst_ptr;
    192  1.3  riastrad 	struct vmw_buffer_object *vbo = par->vmw_bo;
    193  1.3  riastrad 	void *virtual;
    194  1.1  riastrad 
    195  1.3  riastrad 	if (!READ_ONCE(par->dirty.active))
    196  1.1  riastrad 		return;
    197  1.1  riastrad 
    198  1.2  riastrad 	mutex_lock(&par->bo_mutex);
    199  1.2  riastrad 	cur_fb = par->set_fb;
    200  1.2  riastrad 	if (!cur_fb)
    201  1.2  riastrad 		goto out_unlock;
    202  1.2  riastrad 
    203  1.3  riastrad 	(void) ttm_read_lock(&vmw_priv->reservation_sem, false);
    204  1.3  riastrad 	(void) ttm_bo_reserve(&vbo->base, false, false, NULL);
    205  1.3  riastrad 	virtual = vmw_bo_map_and_cache(vbo);
    206  1.3  riastrad 	if (!virtual)
    207  1.3  riastrad 		goto out_unreserve;
    208  1.3  riastrad 
    209  1.2  riastrad 	spin_lock_irqsave(&par->dirty.lock, irq_flags);
    210  1.1  riastrad 	if (!par->dirty.active) {
    211  1.2  riastrad 		spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
    212  1.3  riastrad 		goto out_unreserve;
    213  1.1  riastrad 	}
    214  1.2  riastrad 
    215  1.2  riastrad 	/*
    216  1.2  riastrad 	 * Handle panning when copying from vmalloc to framebuffer.
    217  1.2  riastrad 	 * Clip dirty area to framebuffer.
    218  1.2  riastrad 	 */
    219  1.3  riastrad 	cpp = cur_fb->format->cpp[0];
    220  1.2  riastrad 	max_x = par->fb_x + cur_fb->width;
    221  1.2  riastrad 	max_y = par->fb_y + cur_fb->height;
    222  1.2  riastrad 
    223  1.2  riastrad 	dst_x1 = par->dirty.x1 - par->fb_x;
    224  1.2  riastrad 	dst_y1 = par->dirty.y1 - par->fb_y;
    225  1.2  riastrad 	dst_x1 = max_t(s32, dst_x1, 0);
    226  1.2  riastrad 	dst_y1 = max_t(s32, dst_y1, 0);
    227  1.2  riastrad 
    228  1.2  riastrad 	dst_x2 = par->dirty.x2 - par->fb_x;
    229  1.2  riastrad 	dst_y2 = par->dirty.y2 - par->fb_y;
    230  1.2  riastrad 	dst_x2 = min_t(s32, dst_x2, max_x);
    231  1.2  riastrad 	dst_y2 = min_t(s32, dst_y2, max_y);
    232  1.2  riastrad 	w = dst_x2 - dst_x1;
    233  1.2  riastrad 	h = dst_y2 - dst_y1;
    234  1.2  riastrad 	w = max_t(s32, 0, w);
    235  1.2  riastrad 	h = max_t(s32, 0, h);
    236  1.2  riastrad 
    237  1.1  riastrad 	par->dirty.x1 = par->dirty.x2 = 0;
    238  1.1  riastrad 	par->dirty.y1 = par->dirty.y2 = 0;
    239  1.2  riastrad 	spin_unlock_irqrestore(&par->dirty.lock, irq_flags);
    240  1.1  riastrad 
    241  1.2  riastrad 	if (w && h) {
    242  1.3  riastrad 		dst_ptr = (u8 *)virtual  +
    243  1.2  riastrad 			(dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp);
    244  1.2  riastrad 		src_ptr = (u8 *)par->vmalloc +
    245  1.2  riastrad 			((dst_y1 + par->fb_y) * info->fix.line_length +
    246  1.2  riastrad 			 (dst_x1 + par->fb_x) * cpp);
    247  1.2  riastrad 
    248  1.2  riastrad 		while (h-- > 0) {
    249  1.2  riastrad 			memcpy(dst_ptr, src_ptr, w*cpp);
    250  1.2  riastrad 			dst_ptr += par->set_fb->pitches[0];
    251  1.2  riastrad 			src_ptr += info->fix.line_length;
    252  1.2  riastrad 		}
    253  1.2  riastrad 
    254  1.2  riastrad 		clip.x1 = dst_x1;
    255  1.2  riastrad 		clip.x2 = dst_x2;
    256  1.2  riastrad 		clip.y1 = dst_y1;
    257  1.2  riastrad 		clip.y2 = dst_y2;
    258  1.3  riastrad 	}
    259  1.2  riastrad 
    260  1.3  riastrad out_unreserve:
    261  1.3  riastrad 	ttm_bo_unreserve(&vbo->base);
    262  1.3  riastrad 	ttm_read_unlock(&vmw_priv->reservation_sem);
    263  1.3  riastrad 	if (w && h) {
    264  1.2  riastrad 		WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0,
    265  1.2  riastrad 						       &clip, 1));
    266  1.2  riastrad 		vmw_fifo_flush(vmw_priv, false);
    267  1.1  riastrad 	}
    268  1.2  riastrad out_unlock:
    269  1.2  riastrad 	mutex_unlock(&par->bo_mutex);
    270  1.1  riastrad }
    271  1.1  riastrad 
    272  1.1  riastrad static void vmw_fb_dirty_mark(struct vmw_fb_par *par,
    273  1.1  riastrad 			      unsigned x1, unsigned y1,
    274  1.1  riastrad 			      unsigned width, unsigned height)
    275  1.1  riastrad {
    276  1.1  riastrad 	unsigned long flags;
    277  1.1  riastrad 	unsigned x2 = x1 + width;
    278  1.1  riastrad 	unsigned y2 = y1 + height;
    279  1.1  riastrad 
    280  1.1  riastrad 	spin_lock_irqsave(&par->dirty.lock, flags);
    281  1.1  riastrad 	if (par->dirty.x1 == par->dirty.x2) {
    282  1.1  riastrad 		par->dirty.x1 = x1;
    283  1.1  riastrad 		par->dirty.y1 = y1;
    284  1.1  riastrad 		par->dirty.x2 = x2;
    285  1.1  riastrad 		par->dirty.y2 = y2;
    286  1.1  riastrad 		/* if we are active start the dirty work
    287  1.1  riastrad 		 * we share the work with the defio system */
    288  1.1  riastrad 		if (par->dirty.active)
    289  1.2  riastrad 			schedule_delayed_work(&par->local_work,
    290  1.2  riastrad 					      VMW_DIRTY_DELAY);
    291  1.1  riastrad 	} else {
    292  1.1  riastrad 		if (x1 < par->dirty.x1)
    293  1.1  riastrad 			par->dirty.x1 = x1;
    294  1.1  riastrad 		if (y1 < par->dirty.y1)
    295  1.1  riastrad 			par->dirty.y1 = y1;
    296  1.1  riastrad 		if (x2 > par->dirty.x2)
    297  1.1  riastrad 			par->dirty.x2 = x2;
    298  1.1  riastrad 		if (y2 > par->dirty.y2)
    299  1.1  riastrad 			par->dirty.y2 = y2;
    300  1.1  riastrad 	}
    301  1.1  riastrad 	spin_unlock_irqrestore(&par->dirty.lock, flags);
    302  1.1  riastrad }
    303  1.1  riastrad 
    304  1.2  riastrad static int vmw_fb_pan_display(struct fb_var_screeninfo *var,
    305  1.2  riastrad 			      struct fb_info *info)
    306  1.2  riastrad {
    307  1.2  riastrad 	struct vmw_fb_par *par = info->par;
    308  1.2  riastrad 
    309  1.2  riastrad 	if ((var->xoffset + var->xres) > var->xres_virtual ||
    310  1.2  riastrad 	    (var->yoffset + var->yres) > var->yres_virtual) {
    311  1.2  riastrad 		DRM_ERROR("Requested panning can not fit in framebuffer\n");
    312  1.2  riastrad 		return -EINVAL;
    313  1.2  riastrad 	}
    314  1.2  riastrad 
    315  1.2  riastrad 	mutex_lock(&par->bo_mutex);
    316  1.2  riastrad 	par->fb_x = var->xoffset;
    317  1.2  riastrad 	par->fb_y = var->yoffset;
    318  1.2  riastrad 	if (par->set_fb)
    319  1.2  riastrad 		vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width,
    320  1.2  riastrad 				  par->set_fb->height);
    321  1.2  riastrad 	mutex_unlock(&par->bo_mutex);
    322  1.2  riastrad 
    323  1.2  riastrad 	return 0;
    324  1.2  riastrad }
    325  1.2  riastrad 
    326  1.1  riastrad static void vmw_deferred_io(struct fb_info *info,
    327  1.1  riastrad 			    struct list_head *pagelist)
    328  1.1  riastrad {
    329  1.1  riastrad 	struct vmw_fb_par *par = info->par;
    330  1.1  riastrad 	unsigned long start, end, min, max;
    331  1.1  riastrad 	unsigned long flags;
    332  1.1  riastrad 	struct page *page;
    333  1.1  riastrad 	int y1, y2;
    334  1.1  riastrad 
    335  1.1  riastrad 	min = ULONG_MAX;
    336  1.1  riastrad 	max = 0;
    337  1.1  riastrad 	list_for_each_entry(page, pagelist, lru) {
    338  1.1  riastrad 		start = page->index << PAGE_SHIFT;
    339  1.1  riastrad 		end = start + PAGE_SIZE - 1;
    340  1.1  riastrad 		min = min(min, start);
    341  1.1  riastrad 		max = max(max, end);
    342  1.1  riastrad 	}
    343  1.1  riastrad 
    344  1.1  riastrad 	if (min < max) {
    345  1.1  riastrad 		y1 = min / info->fix.line_length;
    346  1.1  riastrad 		y2 = (max / info->fix.line_length) + 1;
    347  1.1  riastrad 
    348  1.1  riastrad 		spin_lock_irqsave(&par->dirty.lock, flags);
    349  1.1  riastrad 		par->dirty.x1 = 0;
    350  1.1  riastrad 		par->dirty.y1 = y1;
    351  1.1  riastrad 		par->dirty.x2 = info->var.xres;
    352  1.1  riastrad 		par->dirty.y2 = y2;
    353  1.1  riastrad 		spin_unlock_irqrestore(&par->dirty.lock, flags);
    354  1.2  riastrad 
    355  1.2  riastrad 		/*
    356  1.2  riastrad 		 * Since we've already waited on this work once, try to
    357  1.2  riastrad 		 * execute asap.
    358  1.2  riastrad 		 */
    359  1.2  riastrad 		cancel_delayed_work(&par->local_work);
    360  1.2  riastrad 		schedule_delayed_work(&par->local_work, 0);
    361  1.1  riastrad 	}
    362  1.1  riastrad };
    363  1.1  riastrad 
    364  1.2  riastrad static struct fb_deferred_io vmw_defio = {
    365  1.1  riastrad 	.delay		= VMW_DIRTY_DELAY,
    366  1.1  riastrad 	.deferred_io	= vmw_deferred_io,
    367  1.1  riastrad };
    368  1.1  riastrad 
    369  1.1  riastrad /*
    370  1.1  riastrad  * Draw code
    371  1.1  riastrad  */
    372  1.1  riastrad 
    373  1.1  riastrad static void vmw_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
    374  1.1  riastrad {
    375  1.1  riastrad 	cfb_fillrect(info, rect);
    376  1.1  riastrad 	vmw_fb_dirty_mark(info->par, rect->dx, rect->dy,
    377  1.1  riastrad 			  rect->width, rect->height);
    378  1.1  riastrad }
    379  1.1  riastrad 
    380  1.1  riastrad static void vmw_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
    381  1.1  riastrad {
    382  1.1  riastrad 	cfb_copyarea(info, region);
    383  1.1  riastrad 	vmw_fb_dirty_mark(info->par, region->dx, region->dy,
    384  1.1  riastrad 			  region->width, region->height);
    385  1.1  riastrad }
    386  1.1  riastrad 
    387  1.1  riastrad static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image)
    388  1.1  riastrad {
    389  1.1  riastrad 	cfb_imageblit(info, image);
    390  1.1  riastrad 	vmw_fb_dirty_mark(info->par, image->dx, image->dy,
    391  1.1  riastrad 			  image->width, image->height);
    392  1.1  riastrad }
    393  1.1  riastrad 
    394  1.1  riastrad /*
    395  1.1  riastrad  * Bring up code
    396  1.1  riastrad  */
    397  1.1  riastrad 
    398  1.1  riastrad static int vmw_fb_create_bo(struct vmw_private *vmw_priv,
    399  1.3  riastrad 			    size_t size, struct vmw_buffer_object **out)
    400  1.1  riastrad {
    401  1.3  riastrad 	struct vmw_buffer_object *vmw_bo;
    402  1.1  riastrad 	int ret;
    403  1.1  riastrad 
    404  1.2  riastrad 	(void) ttm_write_lock(&vmw_priv->reservation_sem, false);
    405  1.1  riastrad 
    406  1.1  riastrad 	vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL);
    407  1.2  riastrad 	if (!vmw_bo) {
    408  1.2  riastrad 		ret = -ENOMEM;
    409  1.1  riastrad 		goto err_unlock;
    410  1.2  riastrad 	}
    411  1.1  riastrad 
    412  1.3  riastrad 	ret = vmw_bo_init(vmw_priv, vmw_bo, size,
    413  1.2  riastrad 			      &vmw_sys_placement,
    414  1.1  riastrad 			      false,
    415  1.3  riastrad 			      &vmw_bo_bo_free);
    416  1.1  riastrad 	if (unlikely(ret != 0))
    417  1.1  riastrad 		goto err_unlock; /* init frees the buffer on failure */
    418  1.1  riastrad 
    419  1.1  riastrad 	*out = vmw_bo;
    420  1.2  riastrad 	ttm_write_unlock(&vmw_priv->reservation_sem);
    421  1.2  riastrad 
    422  1.2  riastrad 	return 0;
    423  1.2  riastrad 
    424  1.2  riastrad err_unlock:
    425  1.2  riastrad 	ttm_write_unlock(&vmw_priv->reservation_sem);
    426  1.2  riastrad 	return ret;
    427  1.2  riastrad }
    428  1.2  riastrad 
    429  1.2  riastrad static int vmw_fb_compute_depth(struct fb_var_screeninfo *var,
    430  1.2  riastrad 				int *depth)
    431  1.2  riastrad {
    432  1.2  riastrad 	switch (var->bits_per_pixel) {
    433  1.2  riastrad 	case 32:
    434  1.2  riastrad 		*depth = (var->transp.length > 0) ? 32 : 24;
    435  1.2  riastrad 		break;
    436  1.2  riastrad 	default:
    437  1.2  riastrad 		DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel);
    438  1.2  riastrad 		return -EINVAL;
    439  1.2  riastrad 	}
    440  1.1  riastrad 
    441  1.2  riastrad 	return 0;
    442  1.2  riastrad }
    443  1.2  riastrad 
    444  1.3  riastrad static int vmwgfx_set_config_internal(struct drm_mode_set *set)
    445  1.3  riastrad {
    446  1.3  riastrad 	struct drm_crtc *crtc = set->crtc;
    447  1.3  riastrad 	struct drm_modeset_acquire_ctx ctx;
    448  1.3  riastrad 	int ret;
    449  1.3  riastrad 
    450  1.3  riastrad 	drm_modeset_acquire_init(&ctx, 0);
    451  1.3  riastrad 
    452  1.3  riastrad restart:
    453  1.3  riastrad 	ret = crtc->funcs->set_config(set, &ctx);
    454  1.3  riastrad 
    455  1.3  riastrad 	if (ret == -EDEADLK) {
    456  1.3  riastrad 		drm_modeset_backoff(&ctx);
    457  1.3  riastrad 		goto restart;
    458  1.3  riastrad 	}
    459  1.3  riastrad 
    460  1.3  riastrad 	drm_modeset_drop_locks(&ctx);
    461  1.3  riastrad 	drm_modeset_acquire_fini(&ctx);
    462  1.3  riastrad 
    463  1.3  riastrad 	return ret;
    464  1.3  riastrad }
    465  1.3  riastrad 
    466  1.2  riastrad static int vmw_fb_kms_detach(struct vmw_fb_par *par,
    467  1.2  riastrad 			     bool detach_bo,
    468  1.2  riastrad 			     bool unref_bo)
    469  1.2  riastrad {
    470  1.2  riastrad 	struct drm_framebuffer *cur_fb = par->set_fb;
    471  1.2  riastrad 	int ret;
    472  1.2  riastrad 
    473  1.2  riastrad 	/* Detach the KMS framebuffer from crtcs */
    474  1.2  riastrad 	if (par->set_mode) {
    475  1.2  riastrad 		struct drm_mode_set set;
    476  1.2  riastrad 
    477  1.2  riastrad 		set.crtc = par->crtc;
    478  1.2  riastrad 		set.x = 0;
    479  1.2  riastrad 		set.y = 0;
    480  1.2  riastrad 		set.mode = NULL;
    481  1.2  riastrad 		set.fb = NULL;
    482  1.2  riastrad 		set.num_connectors = 0;
    483  1.2  riastrad 		set.connectors = &par->con;
    484  1.3  riastrad 		ret = vmwgfx_set_config_internal(&set);
    485  1.2  riastrad 		if (ret) {
    486  1.2  riastrad 			DRM_ERROR("Could not unset a mode.\n");
    487  1.2  riastrad 			return ret;
    488  1.2  riastrad 		}
    489  1.2  riastrad 		drm_mode_destroy(par->vmw_priv->dev, par->set_mode);
    490  1.2  riastrad 		par->set_mode = NULL;
    491  1.2  riastrad 	}
    492  1.2  riastrad 
    493  1.2  riastrad 	if (cur_fb) {
    494  1.3  riastrad 		drm_framebuffer_put(cur_fb);
    495  1.2  riastrad 		par->set_fb = NULL;
    496  1.2  riastrad 	}
    497  1.2  riastrad 
    498  1.3  riastrad 	if (par->vmw_bo && detach_bo && unref_bo)
    499  1.3  riastrad 		vmw_bo_unreference(&par->vmw_bo);
    500  1.1  riastrad 
    501  1.1  riastrad 	return 0;
    502  1.2  riastrad }
    503  1.2  riastrad 
    504  1.2  riastrad static int vmw_fb_kms_framebuffer(struct fb_info *info)
    505  1.2  riastrad {
    506  1.3  riastrad 	struct drm_mode_fb_cmd2 mode_cmd;
    507  1.2  riastrad 	struct vmw_fb_par *par = info->par;
    508  1.2  riastrad 	struct fb_var_screeninfo *var = &info->var;
    509  1.2  riastrad 	struct drm_framebuffer *cur_fb;
    510  1.2  riastrad 	struct vmw_framebuffer *vfb;
    511  1.3  riastrad 	int ret = 0, depth;
    512  1.2  riastrad 	size_t new_bo_size;
    513  1.2  riastrad 
    514  1.3  riastrad 	ret = vmw_fb_compute_depth(var, &depth);
    515  1.2  riastrad 	if (ret)
    516  1.2  riastrad 		return ret;
    517  1.2  riastrad 
    518  1.2  riastrad 	mode_cmd.width = var->xres;
    519  1.2  riastrad 	mode_cmd.height = var->yres;
    520  1.3  riastrad 	mode_cmd.pitches[0] = ((var->bits_per_pixel + 7) / 8) * mode_cmd.width;
    521  1.3  riastrad 	mode_cmd.pixel_format =
    522  1.3  riastrad 		drm_mode_legacy_fb_format(var->bits_per_pixel, depth);
    523  1.2  riastrad 
    524  1.2  riastrad 	cur_fb = par->set_fb;
    525  1.2  riastrad 	if (cur_fb && cur_fb->width == mode_cmd.width &&
    526  1.2  riastrad 	    cur_fb->height == mode_cmd.height &&
    527  1.3  riastrad 	    cur_fb->format->format == mode_cmd.pixel_format &&
    528  1.3  riastrad 	    cur_fb->pitches[0] == mode_cmd.pitches[0])
    529  1.2  riastrad 		return 0;
    530  1.2  riastrad 
    531  1.2  riastrad 	/* Need new buffer object ? */
    532  1.3  riastrad 	new_bo_size = (size_t) mode_cmd.pitches[0] * (size_t) mode_cmd.height;
    533  1.2  riastrad 	ret = vmw_fb_kms_detach(par,
    534  1.2  riastrad 				par->bo_size < new_bo_size ||
    535  1.2  riastrad 				par->bo_size > 2*new_bo_size,
    536  1.2  riastrad 				true);
    537  1.2  riastrad 	if (ret)
    538  1.2  riastrad 		return ret;
    539  1.2  riastrad 
    540  1.2  riastrad 	if (!par->vmw_bo) {
    541  1.2  riastrad 		ret = vmw_fb_create_bo(par->vmw_priv, new_bo_size,
    542  1.2  riastrad 				       &par->vmw_bo);
    543  1.2  riastrad 		if (ret) {
    544  1.2  riastrad 			DRM_ERROR("Failed creating a buffer object for "
    545  1.2  riastrad 				  "fbdev.\n");
    546  1.2  riastrad 			return ret;
    547  1.2  riastrad 		}
    548  1.2  riastrad 		par->bo_size = new_bo_size;
    549  1.2  riastrad 	}
    550  1.2  riastrad 
    551  1.2  riastrad 	vfb = vmw_kms_new_framebuffer(par->vmw_priv, par->vmw_bo, NULL,
    552  1.2  riastrad 				      true, &mode_cmd);
    553  1.2  riastrad 	if (IS_ERR(vfb))
    554  1.2  riastrad 		return PTR_ERR(vfb);
    555  1.2  riastrad 
    556  1.2  riastrad 	par->set_fb = &vfb->base;
    557  1.2  riastrad 
    558  1.2  riastrad 	return 0;
    559  1.2  riastrad }
    560  1.2  riastrad 
    561  1.2  riastrad static int vmw_fb_set_par(struct fb_info *info)
    562  1.2  riastrad {
    563  1.2  riastrad 	struct vmw_fb_par *par = info->par;
    564  1.2  riastrad 	struct vmw_private *vmw_priv = par->vmw_priv;
    565  1.2  riastrad 	struct drm_mode_set set;
    566  1.2  riastrad 	struct fb_var_screeninfo *var = &info->var;
    567  1.2  riastrad 	struct drm_display_mode new_mode = { DRM_MODE("fb_mode",
    568  1.2  riastrad 		DRM_MODE_TYPE_DRIVER,
    569  1.2  riastrad 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    570  1.2  riastrad 		DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
    571  1.2  riastrad 	};
    572  1.2  riastrad 	struct drm_display_mode *mode;
    573  1.2  riastrad 	int ret;
    574  1.2  riastrad 
    575  1.2  riastrad 	mode = drm_mode_duplicate(vmw_priv->dev, &new_mode);
    576  1.2  riastrad 	if (!mode) {
    577  1.2  riastrad 		DRM_ERROR("Could not create new fb mode.\n");
    578  1.2  riastrad 		return -ENOMEM;
    579  1.2  riastrad 	}
    580  1.2  riastrad 
    581  1.2  riastrad 	mode->hdisplay = var->xres;
    582  1.2  riastrad 	mode->vdisplay = var->yres;
    583  1.2  riastrad 	vmw_guess_mode_timing(mode);
    584  1.2  riastrad 
    585  1.3  riastrad 	if (!vmw_kms_validate_mode_vram(vmw_priv,
    586  1.2  riastrad 					mode->hdisplay *
    587  1.2  riastrad 					DIV_ROUND_UP(var->bits_per_pixel, 8),
    588  1.2  riastrad 					mode->vdisplay)) {
    589  1.2  riastrad 		drm_mode_destroy(vmw_priv->dev, mode);
    590  1.2  riastrad 		return -EINVAL;
    591  1.2  riastrad 	}
    592  1.2  riastrad 
    593  1.2  riastrad 	mutex_lock(&par->bo_mutex);
    594  1.2  riastrad 	ret = vmw_fb_kms_framebuffer(info);
    595  1.2  riastrad 	if (ret)
    596  1.2  riastrad 		goto out_unlock;
    597  1.2  riastrad 
    598  1.2  riastrad 	par->fb_x = var->xoffset;
    599  1.2  riastrad 	par->fb_y = var->yoffset;
    600  1.2  riastrad 
    601  1.2  riastrad 	set.crtc = par->crtc;
    602  1.2  riastrad 	set.x = 0;
    603  1.2  riastrad 	set.y = 0;
    604  1.2  riastrad 	set.mode = mode;
    605  1.2  riastrad 	set.fb = par->set_fb;
    606  1.2  riastrad 	set.num_connectors = 1;
    607  1.2  riastrad 	set.connectors = &par->con;
    608  1.2  riastrad 
    609  1.3  riastrad 	ret = vmwgfx_set_config_internal(&set);
    610  1.2  riastrad 	if (ret)
    611  1.2  riastrad 		goto out_unlock;
    612  1.2  riastrad 
    613  1.2  riastrad 	vmw_fb_dirty_mark(par, par->fb_x, par->fb_y,
    614  1.2  riastrad 			  par->set_fb->width, par->set_fb->height);
    615  1.2  riastrad 
    616  1.2  riastrad 	/* If there already was stuff dirty we wont
    617  1.2  riastrad 	 * schedule a new work, so lets do it now */
    618  1.2  riastrad 
    619  1.2  riastrad 	schedule_delayed_work(&par->local_work, 0);
    620  1.2  riastrad 
    621  1.2  riastrad out_unlock:
    622  1.3  riastrad 	if (par->set_mode)
    623  1.3  riastrad 		drm_mode_destroy(vmw_priv->dev, par->set_mode);
    624  1.2  riastrad 	par->set_mode = mode;
    625  1.2  riastrad 
    626  1.2  riastrad 	mutex_unlock(&par->bo_mutex);
    627  1.1  riastrad 
    628  1.1  riastrad 	return ret;
    629  1.1  riastrad }
    630  1.1  riastrad 
    631  1.2  riastrad 
    632  1.3  riastrad static const struct fb_ops vmw_fb_ops = {
    633  1.2  riastrad 	.owner = THIS_MODULE,
    634  1.2  riastrad 	.fb_check_var = vmw_fb_check_var,
    635  1.2  riastrad 	.fb_set_par = vmw_fb_set_par,
    636  1.2  riastrad 	.fb_setcolreg = vmw_fb_setcolreg,
    637  1.2  riastrad 	.fb_fillrect = vmw_fb_fillrect,
    638  1.2  riastrad 	.fb_copyarea = vmw_fb_copyarea,
    639  1.2  riastrad 	.fb_imageblit = vmw_fb_imageblit,
    640  1.2  riastrad 	.fb_pan_display = vmw_fb_pan_display,
    641  1.2  riastrad 	.fb_blank = vmw_fb_blank,
    642  1.2  riastrad };
    643  1.2  riastrad 
    644  1.1  riastrad int vmw_fb_init(struct vmw_private *vmw_priv)
    645  1.1  riastrad {
    646  1.1  riastrad 	struct device *device = &vmw_priv->dev->pdev->dev;
    647  1.1  riastrad 	struct vmw_fb_par *par;
    648  1.1  riastrad 	struct fb_info *info;
    649  1.1  riastrad 	unsigned fb_width, fb_height;
    650  1.3  riastrad 	unsigned int fb_bpp, fb_pitch, fb_size;
    651  1.2  riastrad 	struct drm_display_mode *init_mode;
    652  1.1  riastrad 	int ret;
    653  1.1  riastrad 
    654  1.1  riastrad 	fb_bpp = 32;
    655  1.1  riastrad 
    656  1.1  riastrad 	/* XXX As shouldn't these be as well. */
    657  1.1  riastrad 	fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
    658  1.1  riastrad 	fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
    659  1.1  riastrad 
    660  1.1  riastrad 	fb_pitch = fb_width * fb_bpp / 8;
    661  1.1  riastrad 	fb_size = fb_pitch * fb_height;
    662  1.1  riastrad 
    663  1.1  riastrad 	info = framebuffer_alloc(sizeof(*par), device);
    664  1.1  riastrad 	if (!info)
    665  1.1  riastrad 		return -ENOMEM;
    666  1.1  riastrad 
    667  1.1  riastrad 	/*
    668  1.1  riastrad 	 * Par
    669  1.1  riastrad 	 */
    670  1.1  riastrad 	vmw_priv->fb_info = info;
    671  1.1  riastrad 	par = info->par;
    672  1.2  riastrad 	memset(par, 0, sizeof(*par));
    673  1.2  riastrad 	INIT_DELAYED_WORK(&par->local_work, &vmw_fb_dirty_flush);
    674  1.1  riastrad 	par->vmw_priv = vmw_priv;
    675  1.1  riastrad 	par->vmalloc = NULL;
    676  1.1  riastrad 	par->max_width = fb_width;
    677  1.1  riastrad 	par->max_height = fb_height;
    678  1.1  riastrad 
    679  1.2  riastrad 	ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width,
    680  1.2  riastrad 				      par->max_height, &par->con,
    681  1.2  riastrad 				      &par->crtc, &init_mode);
    682  1.3  riastrad 	if (ret)
    683  1.2  riastrad 		goto err_kms;
    684  1.2  riastrad 
    685  1.2  riastrad 	info->var.xres = init_mode->hdisplay;
    686  1.2  riastrad 	info->var.yres = init_mode->vdisplay;
    687  1.2  riastrad 
    688  1.1  riastrad 	/*
    689  1.1  riastrad 	 * Create buffers and alloc memory
    690  1.1  riastrad 	 */
    691  1.2  riastrad 	par->vmalloc = vzalloc(fb_size);
    692  1.1  riastrad 	if (unlikely(par->vmalloc == NULL)) {
    693  1.1  riastrad 		ret = -ENOMEM;
    694  1.1  riastrad 		goto err_free;
    695  1.1  riastrad 	}
    696  1.1  riastrad 
    697  1.1  riastrad 	/*
    698  1.1  riastrad 	 * Fixed and var
    699  1.1  riastrad 	 */
    700  1.1  riastrad 	strcpy(info->fix.id, "svgadrmfb");
    701  1.1  riastrad 	info->fix.type = FB_TYPE_PACKED_PIXELS;
    702  1.1  riastrad 	info->fix.visual = FB_VISUAL_TRUECOLOR;
    703  1.1  riastrad 	info->fix.type_aux = 0;
    704  1.1  riastrad 	info->fix.xpanstep = 1; /* doing it in hw */
    705  1.1  riastrad 	info->fix.ypanstep = 1; /* doing it in hw */
    706  1.1  riastrad 	info->fix.ywrapstep = 0;
    707  1.1  riastrad 	info->fix.accel = FB_ACCEL_NONE;
    708  1.1  riastrad 	info->fix.line_length = fb_pitch;
    709  1.1  riastrad 
    710  1.1  riastrad 	info->fix.smem_start = 0;
    711  1.1  riastrad 	info->fix.smem_len = fb_size;
    712  1.1  riastrad 
    713  1.1  riastrad 	info->pseudo_palette = par->pseudo_palette;
    714  1.2  riastrad 	info->screen_base = (char __iomem *)par->vmalloc;
    715  1.1  riastrad 	info->screen_size = fb_size;
    716  1.1  riastrad 
    717  1.1  riastrad 	info->fbops = &vmw_fb_ops;
    718  1.1  riastrad 
    719  1.1  riastrad 	/* 24 depth per default */
    720  1.1  riastrad 	info->var.red.offset = 16;
    721  1.1  riastrad 	info->var.green.offset = 8;
    722  1.1  riastrad 	info->var.blue.offset = 0;
    723  1.1  riastrad 	info->var.red.length = 8;
    724  1.1  riastrad 	info->var.green.length = 8;
    725  1.1  riastrad 	info->var.blue.length = 8;
    726  1.1  riastrad 	info->var.transp.offset = 0;
    727  1.1  riastrad 	info->var.transp.length = 0;
    728  1.1  riastrad 
    729  1.1  riastrad 	info->var.xres_virtual = fb_width;
    730  1.1  riastrad 	info->var.yres_virtual = fb_height;
    731  1.2  riastrad 	info->var.bits_per_pixel = fb_bpp;
    732  1.1  riastrad 	info->var.xoffset = 0;
    733  1.1  riastrad 	info->var.yoffset = 0;
    734  1.1  riastrad 	info->var.activate = FB_ACTIVATE_NOW;
    735  1.1  riastrad 	info->var.height = -1;
    736  1.1  riastrad 	info->var.width = -1;
    737  1.1  riastrad 
    738  1.1  riastrad 	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
    739  1.1  riastrad 	info->apertures = alloc_apertures(1);
    740  1.1  riastrad 	if (!info->apertures) {
    741  1.1  riastrad 		ret = -ENOMEM;
    742  1.1  riastrad 		goto err_aper;
    743  1.1  riastrad 	}
    744  1.1  riastrad 	info->apertures->ranges[0].base = vmw_priv->vram_start;
    745  1.1  riastrad 	info->apertures->ranges[0].size = vmw_priv->vram_size;
    746  1.1  riastrad 
    747  1.1  riastrad 	/*
    748  1.1  riastrad 	 * Dirty & Deferred IO
    749  1.1  riastrad 	 */
    750  1.1  riastrad 	par->dirty.x1 = par->dirty.x2 = 0;
    751  1.1  riastrad 	par->dirty.y1 = par->dirty.y2 = 0;
    752  1.1  riastrad 	par->dirty.active = true;
    753  1.1  riastrad 	spin_lock_init(&par->dirty.lock);
    754  1.2  riastrad 	mutex_init(&par->bo_mutex);
    755  1.1  riastrad 	info->fbdefio = &vmw_defio;
    756  1.1  riastrad 	fb_deferred_io_init(info);
    757  1.1  riastrad 
    758  1.1  riastrad 	ret = register_framebuffer(info);
    759  1.1  riastrad 	if (unlikely(ret != 0))
    760  1.1  riastrad 		goto err_defio;
    761  1.1  riastrad 
    762  1.2  riastrad 	vmw_fb_set_par(info);
    763  1.2  riastrad 
    764  1.1  riastrad 	return 0;
    765  1.1  riastrad 
    766  1.1  riastrad err_defio:
    767  1.1  riastrad 	fb_deferred_io_cleanup(info);
    768  1.1  riastrad err_aper:
    769  1.1  riastrad err_free:
    770  1.1  riastrad 	vfree(par->vmalloc);
    771  1.2  riastrad err_kms:
    772  1.1  riastrad 	framebuffer_release(info);
    773  1.1  riastrad 	vmw_priv->fb_info = NULL;
    774  1.1  riastrad 
    775  1.1  riastrad 	return ret;
    776  1.1  riastrad }
    777  1.1  riastrad 
    778  1.1  riastrad int vmw_fb_close(struct vmw_private *vmw_priv)
    779  1.1  riastrad {
    780  1.1  riastrad 	struct fb_info *info;
    781  1.1  riastrad 	struct vmw_fb_par *par;
    782  1.1  riastrad 
    783  1.1  riastrad 	if (!vmw_priv->fb_info)
    784  1.1  riastrad 		return 0;
    785  1.1  riastrad 
    786  1.1  riastrad 	info = vmw_priv->fb_info;
    787  1.1  riastrad 	par = info->par;
    788  1.1  riastrad 
    789  1.1  riastrad 	/* ??? order */
    790  1.1  riastrad 	fb_deferred_io_cleanup(info);
    791  1.2  riastrad 	cancel_delayed_work_sync(&par->local_work);
    792  1.1  riastrad 	unregister_framebuffer(info);
    793  1.1  riastrad 
    794  1.3  riastrad 	mutex_lock(&par->bo_mutex);
    795  1.2  riastrad 	(void) vmw_fb_kms_detach(par, true, true);
    796  1.3  riastrad 	mutex_unlock(&par->bo_mutex);
    797  1.1  riastrad 
    798  1.1  riastrad 	vfree(par->vmalloc);
    799  1.1  riastrad 	framebuffer_release(info);
    800  1.1  riastrad 
    801  1.1  riastrad 	return 0;
    802  1.1  riastrad }
    803  1.1  riastrad 
    804  1.1  riastrad int vmw_fb_off(struct vmw_private *vmw_priv)
    805  1.1  riastrad {
    806  1.1  riastrad 	struct fb_info *info;
    807  1.1  riastrad 	struct vmw_fb_par *par;
    808  1.1  riastrad 	unsigned long flags;
    809  1.1  riastrad 
    810  1.1  riastrad 	if (!vmw_priv->fb_info)
    811  1.1  riastrad 		return -EINVAL;
    812  1.1  riastrad 
    813  1.1  riastrad 	info = vmw_priv->fb_info;
    814  1.1  riastrad 	par = info->par;
    815  1.1  riastrad 
    816  1.1  riastrad 	spin_lock_irqsave(&par->dirty.lock, flags);
    817  1.1  riastrad 	par->dirty.active = false;
    818  1.1  riastrad 	spin_unlock_irqrestore(&par->dirty.lock, flags);
    819  1.1  riastrad 
    820  1.1  riastrad 	flush_delayed_work(&info->deferred_work);
    821  1.2  riastrad 	flush_delayed_work(&par->local_work);
    822  1.1  riastrad 
    823  1.1  riastrad 	return 0;
    824  1.1  riastrad }
    825  1.1  riastrad 
    826  1.1  riastrad int vmw_fb_on(struct vmw_private *vmw_priv)
    827  1.1  riastrad {
    828  1.1  riastrad 	struct fb_info *info;
    829  1.1  riastrad 	struct vmw_fb_par *par;
    830  1.1  riastrad 	unsigned long flags;
    831  1.1  riastrad 
    832  1.1  riastrad 	if (!vmw_priv->fb_info)
    833  1.1  riastrad 		return -EINVAL;
    834  1.1  riastrad 
    835  1.1  riastrad 	info = vmw_priv->fb_info;
    836  1.1  riastrad 	par = info->par;
    837  1.1  riastrad 
    838  1.1  riastrad 	spin_lock_irqsave(&par->dirty.lock, flags);
    839  1.1  riastrad 	par->dirty.active = true;
    840  1.1  riastrad 	spin_unlock_irqrestore(&par->dirty.lock, flags);
    841  1.3  riastrad 
    842  1.3  riastrad 	/*
    843  1.3  riastrad 	 * Need to reschedule a dirty update, because otherwise that's
    844  1.3  riastrad 	 * only done in dirty_mark() if the previous coalesced
    845  1.3  riastrad 	 * dirty region was empty.
    846  1.3  riastrad 	 */
    847  1.3  riastrad 	schedule_delayed_work(&par->local_work, 0);
    848  1.3  riastrad 
    849  1.1  riastrad 	return 0;
    850  1.1  riastrad }
    851