video: hyperv_fb: Add the support of hibernation
authorDexuan Cui <decui@microsoft.com>
Wed, 11 Sep 2019 23:34:10 +0000 (23:34 +0000)
committerSasha Levin <sashal@kernel.org>
Fri, 22 Nov 2019 01:10:44 +0000 (20:10 -0500)
This patch depends on the vmbus side change of the definition of
struct hv_driver.

Signed-off-by: Dexuan Cui <decui@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/video/fbdev/hyperv_fb.c

index 2dcb7c5..fe4731f 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/fb.h>
 #include <linux/pci.h>
 #include <linux/efi.h>
+#include <linux/console.h>
 
 #include <linux/hyperv.h>
 
@@ -211,6 +212,7 @@ struct hvfb_par {
 
        struct delayed_work dwork;
        bool update;
+       bool update_saved; /* The value of 'update' before hibernation */
 
        u32 pseudo_palette[16];
        u8 init_buf[MAX_VMBUS_PKT_SIZE];
@@ -878,6 +880,61 @@ static int hvfb_remove(struct hv_device *hdev)
        return 0;
 }
 
+static int hvfb_suspend(struct hv_device *hdev)
+{
+       struct fb_info *info = hv_get_drvdata(hdev);
+       struct hvfb_par *par = info->par;
+
+       console_lock();
+
+       /* 1 means do suspend */
+       fb_set_suspend(info, 1);
+
+       cancel_delayed_work_sync(&par->dwork);
+
+       par->update_saved = par->update;
+       par->update = false;
+       par->fb_ready = false;
+
+       vmbus_close(hdev->channel);
+
+       console_unlock();
+
+       return 0;
+}
+
+static int hvfb_resume(struct hv_device *hdev)
+{
+       struct fb_info *info = hv_get_drvdata(hdev);
+       struct hvfb_par *par = info->par;
+       int ret;
+
+       console_lock();
+
+       ret = synthvid_connect_vsp(hdev);
+       if (ret != 0)
+               goto out;
+
+       ret = synthvid_send_config(hdev);
+       if (ret != 0) {
+               vmbus_close(hdev->channel);
+               goto out;
+       }
+
+       par->fb_ready = true;
+       par->update = par->update_saved;
+
+       schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
+
+       /* 0 means do resume */
+       fb_set_suspend(info, 0);
+
+out:
+       console_unlock();
+
+       return ret;
+}
+
 
 static const struct pci_device_id pci_stub_id_table[] = {
        {
@@ -901,6 +958,8 @@ static struct hv_driver hvfb_drv = {
        .id_table = id_table,
        .probe = hvfb_probe,
        .remove = hvfb_remove,
+       .suspend = hvfb_suspend,
+       .resume = hvfb_resume,
        .driver = {
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },