1 /**************************************************************************
3 * Copyright © 2007 David Airlie
4 * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
29 #include <linux/pci.h>
31 #include <drm/drm_fourcc.h>
32 #include <drm/ttm/ttm_placement.h>
34 #include "vmwgfx_drv.h"
35 #include "vmwgfx_kms.h"
37 #define VMW_DIRTY_DELAY (HZ / 30)
40 struct vmw_private
*vmw_priv
;
44 struct mutex bo_mutex
;
45 struct vmw_buffer_object
*vmw_bo
;
47 struct drm_framebuffer
*set_fb
;
48 struct drm_display_mode
*set_mode
;
53 u32 pseudo_palette
[17];
67 struct drm_crtc
*crtc
;
68 struct drm_connector
*con
;
69 struct delayed_work local_work
;
72 static int vmw_fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
73 unsigned blue
, unsigned transp
,
76 struct vmw_fb_par
*par
= info
->par
;
77 u32
*pal
= par
->pseudo_palette
;
80 DRM_ERROR("Bad regno %u.\n", regno
);
84 switch (par
->set_fb
->format
->depth
) {
87 pal
[regno
] = ((red
& 0xff00) << 8) |
89 ((blue
& 0xff00) >> 8);
92 DRM_ERROR("Bad depth %u, bpp %u.\n",
93 par
->set_fb
->format
->depth
,
94 par
->set_fb
->format
->cpp
[0] * 8);
101 static int vmw_fb_check_var(struct fb_var_screeninfo
*var
,
102 struct fb_info
*info
)
104 int depth
= var
->bits_per_pixel
;
105 struct vmw_fb_par
*par
= info
->par
;
106 struct vmw_private
*vmw_priv
= par
->vmw_priv
;
108 switch (var
->bits_per_pixel
) {
110 depth
= (var
->transp
.length
> 0) ? 32 : 24;
113 DRM_ERROR("Bad bpp %u.\n", var
->bits_per_pixel
);
119 var
->red
.offset
= 16;
120 var
->green
.offset
= 8;
121 var
->blue
.offset
= 0;
123 var
->green
.length
= 8;
124 var
->blue
.length
= 8;
125 var
->transp
.length
= 0;
126 var
->transp
.offset
= 0;
129 var
->red
.offset
= 16;
130 var
->green
.offset
= 8;
131 var
->blue
.offset
= 0;
133 var
->green
.length
= 8;
134 var
->blue
.length
= 8;
135 var
->transp
.length
= 8;
136 var
->transp
.offset
= 24;
139 DRM_ERROR("Bad depth %u.\n", depth
);
143 if ((var
->xoffset
+ var
->xres
) > par
->max_width
||
144 (var
->yoffset
+ var
->yres
) > par
->max_height
) {
145 DRM_ERROR("Requested geom can not fit in framebuffer\n");
149 if (!vmw_kms_validate_mode_vram(vmw_priv
,
150 var
->xres
* var
->bits_per_pixel
/8,
151 var
->yoffset
+ var
->yres
)) {
152 DRM_ERROR("Requested geom can not fit in framebuffer\n");
159 static int vmw_fb_blank(int blank
, struct fb_info
*info
)
165 * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer
167 * @work: The struct work_struct associated with this task.
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.
175 static void vmw_fb_dirty_flush(struct work_struct
*work
)
177 struct vmw_fb_par
*par
= container_of(work
, struct vmw_fb_par
,
179 struct vmw_private
*vmw_priv
= par
->vmw_priv
;
180 struct fb_info
*info
= vmw_priv
->fb_info
;
181 unsigned long irq_flags
;
182 s32 dst_x1
, dst_x2
, dst_y1
, dst_y2
, w
= 0, h
= 0;
183 u32 cpp
, max_x
, max_y
;
184 struct drm_clip_rect clip
;
185 struct drm_framebuffer
*cur_fb
;
186 u8
*src_ptr
, *dst_ptr
;
187 struct vmw_buffer_object
*vbo
= par
->vmw_bo
;
190 if (!READ_ONCE(par
->dirty
.active
))
193 mutex_lock(&par
->bo_mutex
);
194 cur_fb
= par
->set_fb
;
198 (void) ttm_read_lock(&vmw_priv
->reservation_sem
, false);
199 (void) ttm_bo_reserve(&vbo
->base
, false, false, NULL
);
200 virtual = vmw_bo_map_and_cache(vbo
);
204 spin_lock_irqsave(&par
->dirty
.lock
, irq_flags
);
205 if (!par
->dirty
.active
) {
206 spin_unlock_irqrestore(&par
->dirty
.lock
, irq_flags
);
211 * Handle panning when copying from vmalloc to framebuffer.
212 * Clip dirty area to framebuffer.
214 cpp
= cur_fb
->format
->cpp
[0];
215 max_x
= par
->fb_x
+ cur_fb
->width
;
216 max_y
= par
->fb_y
+ cur_fb
->height
;
218 dst_x1
= par
->dirty
.x1
- par
->fb_x
;
219 dst_y1
= par
->dirty
.y1
- par
->fb_y
;
220 dst_x1
= max_t(s32
, dst_x1
, 0);
221 dst_y1
= max_t(s32
, dst_y1
, 0);
223 dst_x2
= par
->dirty
.x2
- par
->fb_x
;
224 dst_y2
= par
->dirty
.y2
- par
->fb_y
;
225 dst_x2
= min_t(s32
, dst_x2
, max_x
);
226 dst_y2
= min_t(s32
, dst_y2
, max_y
);
229 w
= max_t(s32
, 0, w
);
230 h
= max_t(s32
, 0, h
);
232 par
->dirty
.x1
= par
->dirty
.x2
= 0;
233 par
->dirty
.y1
= par
->dirty
.y2
= 0;
234 spin_unlock_irqrestore(&par
->dirty
.lock
, irq_flags
);
237 dst_ptr
= (u8
*)virtual +
238 (dst_y1
* par
->set_fb
->pitches
[0] + dst_x1
* cpp
);
239 src_ptr
= (u8
*)par
->vmalloc
+
240 ((dst_y1
+ par
->fb_y
) * info
->fix
.line_length
+
241 (dst_x1
+ par
->fb_x
) * cpp
);
244 memcpy(dst_ptr
, src_ptr
, w
*cpp
);
245 dst_ptr
+= par
->set_fb
->pitches
[0];
246 src_ptr
+= info
->fix
.line_length
;
256 ttm_bo_unreserve(&vbo
->base
);
257 ttm_read_unlock(&vmw_priv
->reservation_sem
);
259 WARN_ON_ONCE(par
->set_fb
->funcs
->dirty(cur_fb
, NULL
, 0, 0,
261 vmw_fifo_flush(vmw_priv
, false);
264 mutex_unlock(&par
->bo_mutex
);
267 static void vmw_fb_dirty_mark(struct vmw_fb_par
*par
,
268 unsigned x1
, unsigned y1
,
269 unsigned width
, unsigned height
)
272 unsigned x2
= x1
+ width
;
273 unsigned y2
= y1
+ height
;
275 spin_lock_irqsave(&par
->dirty
.lock
, flags
);
276 if (par
->dirty
.x1
== par
->dirty
.x2
) {
281 /* if we are active start the dirty work
282 * we share the work with the defio system */
283 if (par
->dirty
.active
)
284 schedule_delayed_work(&par
->local_work
,
287 if (x1
< par
->dirty
.x1
)
289 if (y1
< par
->dirty
.y1
)
291 if (x2
> par
->dirty
.x2
)
293 if (y2
> par
->dirty
.y2
)
296 spin_unlock_irqrestore(&par
->dirty
.lock
, flags
);
299 static int vmw_fb_pan_display(struct fb_var_screeninfo
*var
,
300 struct fb_info
*info
)
302 struct vmw_fb_par
*par
= info
->par
;
304 if ((var
->xoffset
+ var
->xres
) > var
->xres_virtual
||
305 (var
->yoffset
+ var
->yres
) > var
->yres_virtual
) {
306 DRM_ERROR("Requested panning can not fit in framebuffer\n");
310 mutex_lock(&par
->bo_mutex
);
311 par
->fb_x
= var
->xoffset
;
312 par
->fb_y
= var
->yoffset
;
314 vmw_fb_dirty_mark(par
, par
->fb_x
, par
->fb_y
, par
->set_fb
->width
,
315 par
->set_fb
->height
);
316 mutex_unlock(&par
->bo_mutex
);
321 static void vmw_deferred_io(struct fb_info
*info
,
322 struct list_head
*pagelist
)
324 struct vmw_fb_par
*par
= info
->par
;
325 unsigned long start
, end
, min
, max
;
332 list_for_each_entry(page
, pagelist
, lru
) {
333 start
= page
->index
<< PAGE_SHIFT
;
334 end
= start
+ PAGE_SIZE
- 1;
335 min
= min(min
, start
);
340 y1
= min
/ info
->fix
.line_length
;
341 y2
= (max
/ info
->fix
.line_length
) + 1;
343 spin_lock_irqsave(&par
->dirty
.lock
, flags
);
346 par
->dirty
.x2
= info
->var
.xres
;
348 spin_unlock_irqrestore(&par
->dirty
.lock
, flags
);
351 * Since we've already waited on this work once, try to
354 cancel_delayed_work(&par
->local_work
);
355 schedule_delayed_work(&par
->local_work
, 0);
359 static struct fb_deferred_io vmw_defio
= {
360 .delay
= VMW_DIRTY_DELAY
,
361 .deferred_io
= vmw_deferred_io
,
368 static void vmw_fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
370 cfb_fillrect(info
, rect
);
371 vmw_fb_dirty_mark(info
->par
, rect
->dx
, rect
->dy
,
372 rect
->width
, rect
->height
);
375 static void vmw_fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*region
)
377 cfb_copyarea(info
, region
);
378 vmw_fb_dirty_mark(info
->par
, region
->dx
, region
->dy
,
379 region
->width
, region
->height
);
382 static void vmw_fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
384 cfb_imageblit(info
, image
);
385 vmw_fb_dirty_mark(info
->par
, image
->dx
, image
->dy
,
386 image
->width
, image
->height
);
393 static int vmw_fb_create_bo(struct vmw_private
*vmw_priv
,
394 size_t size
, struct vmw_buffer_object
**out
)
396 struct vmw_buffer_object
*vmw_bo
;
399 (void) ttm_write_lock(&vmw_priv
->reservation_sem
, false);
401 vmw_bo
= kmalloc(sizeof(*vmw_bo
), GFP_KERNEL
);
407 ret
= vmw_bo_init(vmw_priv
, vmw_bo
, size
,
411 if (unlikely(ret
!= 0))
412 goto err_unlock
; /* init frees the buffer on failure */
415 ttm_write_unlock(&vmw_priv
->reservation_sem
);
420 ttm_write_unlock(&vmw_priv
->reservation_sem
);
424 static int vmw_fb_compute_depth(struct fb_var_screeninfo
*var
,
427 switch (var
->bits_per_pixel
) {
429 *depth
= (var
->transp
.length
> 0) ? 32 : 24;
432 DRM_ERROR("Bad bpp %u.\n", var
->bits_per_pixel
);
439 static int vmwgfx_set_config_internal(struct drm_mode_set
*set
)
441 struct drm_crtc
*crtc
= set
->crtc
;
442 struct drm_modeset_acquire_ctx ctx
;
445 drm_modeset_acquire_init(&ctx
, 0);
448 ret
= crtc
->funcs
->set_config(set
, &ctx
);
450 if (ret
== -EDEADLK
) {
451 drm_modeset_backoff(&ctx
);
455 drm_modeset_drop_locks(&ctx
);
456 drm_modeset_acquire_fini(&ctx
);
461 static int vmw_fb_kms_detach(struct vmw_fb_par
*par
,
465 struct drm_framebuffer
*cur_fb
= par
->set_fb
;
468 /* Detach the KMS framebuffer from crtcs */
470 struct drm_mode_set set
;
472 set
.crtc
= par
->crtc
;
477 set
.num_connectors
= 0;
478 set
.connectors
= &par
->con
;
479 ret
= vmwgfx_set_config_internal(&set
);
481 DRM_ERROR("Could not unset a mode.\n");
484 drm_mode_destroy(par
->vmw_priv
->dev
, par
->set_mode
);
485 par
->set_mode
= NULL
;
489 drm_framebuffer_put(cur_fb
);
493 if (par
->vmw_bo
&& detach_bo
&& unref_bo
)
494 vmw_bo_unreference(&par
->vmw_bo
);
499 static int vmw_fb_kms_framebuffer(struct fb_info
*info
)
501 struct drm_mode_fb_cmd2 mode_cmd
;
502 struct vmw_fb_par
*par
= info
->par
;
503 struct fb_var_screeninfo
*var
= &info
->var
;
504 struct drm_framebuffer
*cur_fb
;
505 struct vmw_framebuffer
*vfb
;
509 ret
= vmw_fb_compute_depth(var
, &depth
);
513 mode_cmd
.width
= var
->xres
;
514 mode_cmd
.height
= var
->yres
;
515 mode_cmd
.pitches
[0] = ((var
->bits_per_pixel
+ 7) / 8) * mode_cmd
.width
;
516 mode_cmd
.pixel_format
=
517 drm_mode_legacy_fb_format(var
->bits_per_pixel
, depth
);
519 cur_fb
= par
->set_fb
;
520 if (cur_fb
&& cur_fb
->width
== mode_cmd
.width
&&
521 cur_fb
->height
== mode_cmd
.height
&&
522 cur_fb
->format
->format
== mode_cmd
.pixel_format
&&
523 cur_fb
->pitches
[0] == mode_cmd
.pitches
[0])
526 /* Need new buffer object ? */
527 new_bo_size
= (size_t) mode_cmd
.pitches
[0] * (size_t) mode_cmd
.height
;
528 ret
= vmw_fb_kms_detach(par
,
529 par
->bo_size
< new_bo_size
||
530 par
->bo_size
> 2*new_bo_size
,
536 ret
= vmw_fb_create_bo(par
->vmw_priv
, new_bo_size
,
539 DRM_ERROR("Failed creating a buffer object for "
543 par
->bo_size
= new_bo_size
;
546 vfb
= vmw_kms_new_framebuffer(par
->vmw_priv
, par
->vmw_bo
, NULL
,
551 par
->set_fb
= &vfb
->base
;
556 static int vmw_fb_set_par(struct fb_info
*info
)
558 struct vmw_fb_par
*par
= info
->par
;
559 struct vmw_private
*vmw_priv
= par
->vmw_priv
;
560 struct drm_mode_set set
;
561 struct fb_var_screeninfo
*var
= &info
->var
;
562 struct drm_display_mode new_mode
= { DRM_MODE("fb_mode",
563 DRM_MODE_TYPE_DRIVER
,
564 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
565 DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_PVSYNC
)
567 struct drm_display_mode
*mode
;
570 mode
= drm_mode_duplicate(vmw_priv
->dev
, &new_mode
);
572 DRM_ERROR("Could not create new fb mode.\n");
576 mode
->hdisplay
= var
->xres
;
577 mode
->vdisplay
= var
->yres
;
578 vmw_guess_mode_timing(mode
);
580 if (!vmw_kms_validate_mode_vram(vmw_priv
,
582 DIV_ROUND_UP(var
->bits_per_pixel
, 8),
584 drm_mode_destroy(vmw_priv
->dev
, mode
);
588 mutex_lock(&par
->bo_mutex
);
589 ret
= vmw_fb_kms_framebuffer(info
);
593 par
->fb_x
= var
->xoffset
;
594 par
->fb_y
= var
->yoffset
;
596 set
.crtc
= par
->crtc
;
600 set
.fb
= par
->set_fb
;
601 set
.num_connectors
= 1;
602 set
.connectors
= &par
->con
;
604 ret
= vmwgfx_set_config_internal(&set
);
608 vmw_fb_dirty_mark(par
, par
->fb_x
, par
->fb_y
,
609 par
->set_fb
->width
, par
->set_fb
->height
);
611 /* If there already was stuff dirty we wont
612 * schedule a new work, so lets do it now */
614 schedule_delayed_work(&par
->local_work
, 0);
618 drm_mode_destroy(vmw_priv
->dev
, par
->set_mode
);
619 par
->set_mode
= mode
;
621 mutex_unlock(&par
->bo_mutex
);
627 static const struct fb_ops vmw_fb_ops
= {
628 .owner
= THIS_MODULE
,
629 .fb_check_var
= vmw_fb_check_var
,
630 .fb_set_par
= vmw_fb_set_par
,
631 .fb_setcolreg
= vmw_fb_setcolreg
,
632 .fb_fillrect
= vmw_fb_fillrect
,
633 .fb_copyarea
= vmw_fb_copyarea
,
634 .fb_imageblit
= vmw_fb_imageblit
,
635 .fb_pan_display
= vmw_fb_pan_display
,
636 .fb_blank
= vmw_fb_blank
,
639 int vmw_fb_init(struct vmw_private
*vmw_priv
)
641 struct device
*device
= &vmw_priv
->dev
->pdev
->dev
;
642 struct vmw_fb_par
*par
;
643 struct fb_info
*info
;
644 unsigned fb_width
, fb_height
;
645 unsigned int fb_bpp
, fb_pitch
, fb_size
;
646 struct drm_display_mode
*init_mode
;
651 /* XXX As shouldn't these be as well. */
652 fb_width
= min(vmw_priv
->fb_max_width
, (unsigned)2048);
653 fb_height
= min(vmw_priv
->fb_max_height
, (unsigned)2048);
655 fb_pitch
= fb_width
* fb_bpp
/ 8;
656 fb_size
= fb_pitch
* fb_height
;
658 info
= framebuffer_alloc(sizeof(*par
), device
);
665 vmw_priv
->fb_info
= info
;
667 memset(par
, 0, sizeof(*par
));
668 INIT_DELAYED_WORK(&par
->local_work
, &vmw_fb_dirty_flush
);
669 par
->vmw_priv
= vmw_priv
;
671 par
->max_width
= fb_width
;
672 par
->max_height
= fb_height
;
674 ret
= vmw_kms_fbdev_init_data(vmw_priv
, 0, par
->max_width
,
675 par
->max_height
, &par
->con
,
676 &par
->crtc
, &init_mode
);
680 info
->var
.xres
= init_mode
->hdisplay
;
681 info
->var
.yres
= init_mode
->vdisplay
;
684 * Create buffers and alloc memory
686 par
->vmalloc
= vzalloc(fb_size
);
687 if (unlikely(par
->vmalloc
== NULL
)) {
695 strcpy(info
->fix
.id
, "svgadrmfb");
696 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
697 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
698 info
->fix
.type_aux
= 0;
699 info
->fix
.xpanstep
= 1; /* doing it in hw */
700 info
->fix
.ypanstep
= 1; /* doing it in hw */
701 info
->fix
.ywrapstep
= 0;
702 info
->fix
.accel
= FB_ACCEL_NONE
;
703 info
->fix
.line_length
= fb_pitch
;
705 info
->fix
.smem_start
= 0;
706 info
->fix
.smem_len
= fb_size
;
708 info
->pseudo_palette
= par
->pseudo_palette
;
709 info
->screen_base
= (char __iomem
*)par
->vmalloc
;
710 info
->screen_size
= fb_size
;
712 info
->fbops
= &vmw_fb_ops
;
714 /* 24 depth per default */
715 info
->var
.red
.offset
= 16;
716 info
->var
.green
.offset
= 8;
717 info
->var
.blue
.offset
= 0;
718 info
->var
.red
.length
= 8;
719 info
->var
.green
.length
= 8;
720 info
->var
.blue
.length
= 8;
721 info
->var
.transp
.offset
= 0;
722 info
->var
.transp
.length
= 0;
724 info
->var
.xres_virtual
= fb_width
;
725 info
->var
.yres_virtual
= fb_height
;
726 info
->var
.bits_per_pixel
= fb_bpp
;
727 info
->var
.xoffset
= 0;
728 info
->var
.yoffset
= 0;
729 info
->var
.activate
= FB_ACTIVATE_NOW
;
730 info
->var
.height
= -1;
731 info
->var
.width
= -1;
733 /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
734 info
->apertures
= alloc_apertures(1);
735 if (!info
->apertures
) {
739 info
->apertures
->ranges
[0].base
= vmw_priv
->vram_start
;
740 info
->apertures
->ranges
[0].size
= vmw_priv
->vram_size
;
743 * Dirty & Deferred IO
745 par
->dirty
.x1
= par
->dirty
.x2
= 0;
746 par
->dirty
.y1
= par
->dirty
.y2
= 0;
747 par
->dirty
.active
= true;
748 spin_lock_init(&par
->dirty
.lock
);
749 mutex_init(&par
->bo_mutex
);
750 info
->fbdefio
= &vmw_defio
;
751 fb_deferred_io_init(info
);
753 ret
= register_framebuffer(info
);
754 if (unlikely(ret
!= 0))
757 vmw_fb_set_par(info
);
762 fb_deferred_io_cleanup(info
);
767 framebuffer_release(info
);
768 vmw_priv
->fb_info
= NULL
;
773 int vmw_fb_close(struct vmw_private
*vmw_priv
)
775 struct fb_info
*info
;
776 struct vmw_fb_par
*par
;
778 if (!vmw_priv
->fb_info
)
781 info
= vmw_priv
->fb_info
;
785 fb_deferred_io_cleanup(info
);
786 cancel_delayed_work_sync(&par
->local_work
);
787 unregister_framebuffer(info
);
789 mutex_lock(&par
->bo_mutex
);
790 (void) vmw_fb_kms_detach(par
, true, true);
791 mutex_unlock(&par
->bo_mutex
);
794 framebuffer_release(info
);
799 int vmw_fb_off(struct vmw_private
*vmw_priv
)
801 struct fb_info
*info
;
802 struct vmw_fb_par
*par
;
805 if (!vmw_priv
->fb_info
)
808 info
= vmw_priv
->fb_info
;
811 spin_lock_irqsave(&par
->dirty
.lock
, flags
);
812 par
->dirty
.active
= false;
813 spin_unlock_irqrestore(&par
->dirty
.lock
, flags
);
815 flush_delayed_work(&info
->deferred_work
);
816 flush_delayed_work(&par
->local_work
);
821 int vmw_fb_on(struct vmw_private
*vmw_priv
)
823 struct fb_info
*info
;
824 struct vmw_fb_par
*par
;
827 if (!vmw_priv
->fb_info
)
830 info
= vmw_priv
->fb_info
;
833 spin_lock_irqsave(&par
->dirty
.lock
, flags
);
834 par
->dirty
.active
= true;
835 spin_unlock_irqrestore(&par
->dirty
.lock
, flags
);
838 * Need to reschedule a dirty update, because otherwise that's
839 * only done in dirty_mark() if the previous coalesced
840 * dirty region was empty.
842 schedule_delayed_work(&par
->local_work
, 0);