aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorDexuan Cui <decui@microsoft.com>2014-08-01 07:27:54 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-08-04 02:35:27 -0400
commit3686fe964285a9a0c25265f37ada117d47614f1e (patch)
treed1ac734487e1257c68959963b8c14915e53fa41e /drivers/video
parent1d5167b72ca05b2096760e1200fcd53b5f9a7562 (diff)
video: hyperv: hyperv_fb: refresh the VM screen by force on VM panic
Currently the VSC has no chance to notify the VSP of the dirty rectangle on VM panic because the notification work is done in a workqueue, and in panic() the kernel typically ends up in an infinite loop, and a typical kernel config has CONFIG_PREEMPT_VOLUNTARY=y and CONFIG_PREEMPT is not set, so a context switch can't happen in panic() and the workqueue won't have a chance to run. As a result, the VM Connection window can't refresh until it's closed and we re-connect to the VM. We can register a handler on panic_notifier_list: the handler can notify the VSC and switch the framebuffer driver to a "synchronous mode", meaning the VSC flushes any future framebuffer change to the VSP immediately. v2: removed the MS-TFS line in the commit message v3: remove some 'unlikely' markings v4: avoid global variables as Tomi Valkeinen suggested Cc: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: Dexuan Cui <decui@microsoft.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/hyperv_fb.c62
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index e23392ec5af3..569e7562fa3d 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -224,6 +224,11 @@ struct hvfb_par {
224 u32 pseudo_palette[16]; 224 u32 pseudo_palette[16];
225 u8 init_buf[MAX_VMBUS_PKT_SIZE]; 225 u8 init_buf[MAX_VMBUS_PKT_SIZE];
226 u8 recv_buf[MAX_VMBUS_PKT_SIZE]; 226 u8 recv_buf[MAX_VMBUS_PKT_SIZE];
227
228 /* If true, the VSC notifies the VSP on every framebuffer change */
229 bool synchronous_fb;
230
231 struct notifier_block hvfb_panic_nb;
227}; 232};
228 233
229static uint screen_width = HVFB_WIDTH; 234static uint screen_width = HVFB_WIDTH;
@@ -532,6 +537,19 @@ static void hvfb_update_work(struct work_struct *w)
532 schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY); 537 schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
533} 538}
534 539
540static int hvfb_on_panic(struct notifier_block *nb,
541 unsigned long e, void *p)
542{
543 struct hvfb_par *par;
544 struct fb_info *info;
545
546 par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
547 par->synchronous_fb = true;
548 info = par->info;
549 synthvid_update(info);
550
551 return NOTIFY_DONE;
552}
535 553
536/* Framebuffer operation handlers */ 554/* Framebuffer operation handlers */
537 555
@@ -582,14 +600,44 @@ static int hvfb_blank(int blank, struct fb_info *info)
582 return 1; /* get fb_blank to set the colormap to all black */ 600 return 1; /* get fb_blank to set the colormap to all black */
583} 601}
584 602
603static void hvfb_cfb_fillrect(struct fb_info *p,
604 const struct fb_fillrect *rect)
605{
606 struct hvfb_par *par = p->par;
607
608 cfb_fillrect(p, rect);
609 if (par->synchronous_fb)
610 synthvid_update(p);
611}
612
613static void hvfb_cfb_copyarea(struct fb_info *p,
614 const struct fb_copyarea *area)
615{
616 struct hvfb_par *par = p->par;
617
618 cfb_copyarea(p, area);
619 if (par->synchronous_fb)
620 synthvid_update(p);
621}
622
623static void hvfb_cfb_imageblit(struct fb_info *p,
624 const struct fb_image *image)
625{
626 struct hvfb_par *par = p->par;
627
628 cfb_imageblit(p, image);
629 if (par->synchronous_fb)
630 synthvid_update(p);
631}
632
585static struct fb_ops hvfb_ops = { 633static struct fb_ops hvfb_ops = {
586 .owner = THIS_MODULE, 634 .owner = THIS_MODULE,
587 .fb_check_var = hvfb_check_var, 635 .fb_check_var = hvfb_check_var,
588 .fb_set_par = hvfb_set_par, 636 .fb_set_par = hvfb_set_par,
589 .fb_setcolreg = hvfb_setcolreg, 637 .fb_setcolreg = hvfb_setcolreg,
590 .fb_fillrect = cfb_fillrect, 638 .fb_fillrect = hvfb_cfb_fillrect,
591 .fb_copyarea = cfb_copyarea, 639 .fb_copyarea = hvfb_cfb_copyarea,
592 .fb_imageblit = cfb_imageblit, 640 .fb_imageblit = hvfb_cfb_imageblit,
593 .fb_blank = hvfb_blank, 641 .fb_blank = hvfb_blank,
594}; 642};
595 643
@@ -801,6 +849,11 @@ static int hvfb_probe(struct hv_device *hdev,
801 849
802 par->fb_ready = true; 850 par->fb_ready = true;
803 851
852 par->synchronous_fb = false;
853 par->hvfb_panic_nb.notifier_call = hvfb_on_panic;
854 atomic_notifier_chain_register(&panic_notifier_list,
855 &par->hvfb_panic_nb);
856
804 return 0; 857 return 0;
805 858
806error: 859error:
@@ -820,6 +873,9 @@ static int hvfb_remove(struct hv_device *hdev)
820 struct fb_info *info = hv_get_drvdata(hdev); 873 struct fb_info *info = hv_get_drvdata(hdev);
821 struct hvfb_par *par = info->par; 874 struct hvfb_par *par = info->par;
822 875
876 atomic_notifier_chain_unregister(&panic_notifier_list,
877 &par->hvfb_panic_nb);
878
823 par->update = false; 879 par->update = false;
824 par->fb_ready = false; 880 par->fb_ready = false;
825 881