[PATCH v4] video: hyperv: hyperv_fb: Use physical memory for fb on HyperV Gen 1 VMs.

2019-12-09 Thread Wei Hu
On Hyper-V, Generation 1 VMs can directly use VM's physical memory for
their framebuffers. This can improve the efficiency of framebuffer and
overall performence for VM. The physical memory assigned to framebuffer
must be contiguous. We use CMA allocator to get contiguouse physicial
memory when the framebuffer size is greater than 4MB. For size under
4MB, we use alloc_pages to achieve this.

To enable framebuffer memory allocation from CMA, supply a kernel
parameter to give enough space to CMA allocator at boot time. For
example:
cma=130m
This gives 130MB memory to CAM allocator that can be allocated to
framebuffer. If this fails, we fall back to the old way of using
mmio for framebuffer.

Reported-by: kbuild test robot 
Signed-off-by: Wei Hu 
---
v2: Incorporated review comments form h...@lst.de, Michael Kelley and
Dexuan Cui
- Use dma_alloc_coherent to allocate large contiguous memory
- Use phys_addr_t for physical addresses
- Corrected a few spelling errors and minor cleanups
- Also tested on 32 bit Ubuntu guest
v3: Fixed a build issue reported by kbuild test robot and incorported
some review comments from Michael Kelley
- Add CMA check to avoid link failure
- Fixed small memory leak introduced by alloc_apertures
- Cleaned up so code
v4: Removed request_pages variable as it is no longer needed

 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 182 +---
 2 files changed, 144 insertions(+), 39 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index aa9541bf964b..f65991a67af2 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2215,6 +2215,7 @@ config FB_HYPERV
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_DEFERRED_IO
+   select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 3f60b7bc8589..c15ce2a00886 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -31,6 +31,16 @@
  * "set-vmvideo" command. For example
  * set-vmvideo -vmname name -horizontalresolution:1920 \
  * -verticalresolution:1200 -resolutiontype single
+ *
+ * Gen 1 VMs also support direct using VM's physical memory for framebuffer.
+ * It could improve the efficiency and performance for framebuffer and VM.
+ * This requires to allocate contiguous physical memory from Linux kernel's
+ * CMA memory allocator. To enable this, supply a kernel parameter to give
+ * enough memory space to CMA allocator for framebuffer. For example:
+ *cma=130m
+ * This gives 130MB memory to CMA allocator that can be allocated to
+ * framebuffer. For reference, 8K resolution (7680x4320) takes about
+ * 127MB memory.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -227,7 +237,6 @@ struct synthvid_msg {
 } __packed;
 
 
-
 /* FB driver definitions and structures */
 #define HVFB_WIDTH 1152 /* default screen width */
 #define HVFB_HEIGHT 864 /* default screen height */
@@ -256,12 +265,15 @@ struct hvfb_par {
/* If true, the VSC notifies the VSP on every framebuffer change */
bool synchronous_fb;
 
+   /* If true, need to copy from deferred IO mem to framebuffer mem */
+   bool need_docopy;
+
struct notifier_block hvfb_panic_nb;
 
/* Memory for deferred IO and frame buffer itself */
unsigned char *dio_vp;
unsigned char *mmio_vp;
-   unsigned long mmio_pp;
+   phys_addr_t mmio_pp;
 
/* Dirty rectangle, protected by delayed_refresh_lock */
int x1, y1, x2, y2;
@@ -432,7 +444,7 @@ static void synthvid_deferred_io(struct fb_info *p,
maxy = max_t(int, maxy, y2);
 
/* Copy from dio space to mmio address */
-   if (par->fb_ready)
+   if (par->fb_ready && par->need_docopy)
hvfb_docopy(par, start, PAGE_SIZE);
}
 
@@ -749,12 +761,12 @@ static void hvfb_update_work(struct work_struct *w)
return;
 
/* Copy the dirty rectangle to frame buffer memory */
-   for (j = y1; j < y2; j++) {
-   hvfb_docopy(par,
-   j * info->fix.line_length +
-   (x1 * screen_depth / 8),
-   (x2 - x1) * screen_depth / 8);
-   }
+   if (par->need_docopy)
+   for (j = y1; j < y2; j++)
+   hvfb_docopy(par,
+   j * info->fix.line_length +
+   (x1 * screen_depth / 8),
+   (x2 - x1) * screen_depth / 8);
 
/* Refresh */
if (par->fb_ready && par->update)
@@ -799,7 +811,8 @@ static in

[PATCH v3] video: hyperv: hyperv_fb: Use physical memory for fb on HyperV Gen 1 VMs.

2019-12-06 Thread Wei Hu
On Hyper-V, Generation 1 VMs can directly use VM's physical memory for
their framebuffers. This can improve the efficiency of framebuffer and
overall performence for VM. The physical memory assigned to framebuffer
must be contiguous. We use CMA allocator to get contiguouse physicial
memory when the framebuffer size is greater than 4MB. For size under
4MB, we use alloc_pages to achieve this.

To enable framebuffer memory allocation from CMA, supply a kernel
parameter to give enough space to CMA allocator at boot time. For
example:
cma=130m
This gives 130MB memory to CAM allocator that can be allocated to
framebuffer. If this fails, we fall back to the old way of using
mmio for framebuffer.

Reported-by: kbuild test robot 
Signed-off-by: Wei Hu 
---
v2: Incorporated review comments form h...@lst.de, Michael Kelley and
Dexuan Cui
- Use dma_alloc_coherent to allocate large contiguous memory
- Use phys_addr_t for physical addresses
- Corrected a few spelling errors and minor cleanups
- Also tested on 32 bit Ubuntu guest
v3: Fixed a build issue reported by kbuild test robot and incorported
some review comments from Michael Kelley
- Add CMA check to avoid link failure
- Fixed small memory leak introduced by alloc_apertures
- Cleaned up so code

 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 187 +---
 2 files changed, 149 insertions(+), 39 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index aa9541bf964b..f65991a67af2 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2215,6 +2215,7 @@ config FB_HYPERV
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_DEFERRED_IO
+   select DMA_CMA if HAVE_DMA_CONTIGUOUS && CMA
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 3f60b7bc8589..7dff82c77551 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -31,6 +31,16 @@
  * "set-vmvideo" command. For example
  * set-vmvideo -vmname name -horizontalresolution:1920 \
  * -verticalresolution:1200 -resolutiontype single
+ *
+ * Gen 1 VMs also support direct using VM's physical memory for framebuffer.
+ * It could improve the efficiency and performance for framebuffer and VM.
+ * This requires to allocate contiguous physical memory from Linux kernel's
+ * CMA memory allocator. To enable this, supply a kernel parameter to give
+ * enough memory space to CMA allocator for framebuffer. For example:
+ *cma=130m
+ * This gives 130MB memory to CMA allocator that can be allocated to
+ * framebuffer. For reference, 8K resolution (7680x4320) takes about
+ * 127MB memory.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -227,7 +237,6 @@ struct synthvid_msg {
 } __packed;
 
 
-
 /* FB driver definitions and structures */
 #define HVFB_WIDTH 1152 /* default screen width */
 #define HVFB_HEIGHT 864 /* default screen height */
@@ -256,12 +265,15 @@ struct hvfb_par {
/* If true, the VSC notifies the VSP on every framebuffer change */
bool synchronous_fb;
 
+   /* If true, need to copy from deferred IO mem to framebuffer mem */
+   bool need_docopy;
+
struct notifier_block hvfb_panic_nb;
 
/* Memory for deferred IO and frame buffer itself */
unsigned char *dio_vp;
unsigned char *mmio_vp;
-   unsigned long mmio_pp;
+   phys_addr_t mmio_pp;
 
/* Dirty rectangle, protected by delayed_refresh_lock */
int x1, y1, x2, y2;
@@ -432,7 +444,7 @@ static void synthvid_deferred_io(struct fb_info *p,
maxy = max_t(int, maxy, y2);
 
/* Copy from dio space to mmio address */
-   if (par->fb_ready)
+   if (par->fb_ready && par->need_docopy)
hvfb_docopy(par, start, PAGE_SIZE);
}
 
@@ -749,12 +761,12 @@ static void hvfb_update_work(struct work_struct *w)
return;
 
/* Copy the dirty rectangle to frame buffer memory */
-   for (j = y1; j < y2; j++) {
-   hvfb_docopy(par,
-   j * info->fix.line_length +
-   (x1 * screen_depth / 8),
-   (x2 - x1) * screen_depth / 8);
-   }
+   if (par->need_docopy)
+   for (j = y1; j < y2; j++)
+   hvfb_docopy(par,
+   j * info->fix.line_length +
+   (x1 * screen_depth / 8),
+   (x2 - x1) * screen_depth / 8);
 
/* Refresh */
if (par->fb_ready && par->update)
@@ -799,7 +811,8 @@ static int hvfb_on_panic(struct notifier_block *nb,
par = container

[PATCH v2] video: hyperv: hyperv_fb: Use physical memory for fb on HyperV Gen 1 VMs.

2019-11-22 Thread Wei Hu
On Hyper-V, Generation 1 VMs can directly use VM's physical memory for
their framebuffers. This can improve the efficiency of framebuffer and
overall performence for VM. The physical memory assigned to framebuffer
must be contiguous. We use CMA allocator to get contiguouse physicial
memory when the framebuffer size is greater than 4MB. For size under
4MB, we use alloc_pages to achieve this.

To enable framebuffer memory allocation from CMA, supply a kernel
parameter to give enough space to CMA allocator at boot time. For
example:
cma=130m
This gives 130MB memory to CAM allocator that can be allocated to
framebuffer. If this fails, we fall back to the old way of using
mmio for framebuffer.

Signed-off-by: Wei Hu 
---
v2: Incorporated review comments form h...@lst.de, Michael Kelley and
Dexuan Cui
- Use dma_alloc_coherent to allocate large contiguous memory
- Use phys_addr_t for physical addresses
- Corrected a few spelling errors and minor cleanups
- Also tested on 32 bit Ubuntu guest 

 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 196 +---
 2 files changed, 158 insertions(+), 39 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index aa9541bf964b..87b82de4598d 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2215,6 +2215,7 @@ config FB_HYPERV
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_DEFERRED_IO
+   select DMA_CMA if HAVE_DMA_CONTIGUOUS
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 3f60b7bc8589..8ba96764c749 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -31,6 +31,16 @@
  * "set-vmvideo" command. For example
  * set-vmvideo -vmname name -horizontalresolution:1920 \
  * -verticalresolution:1200 -resolutiontype single
+ *
+ * Gen 1 VMs also support direct using VM's physical memory for framebuffer.
+ * It could improve the efficiency and performance for framebuffer and VM.
+ * This requires to allocate contiguous physical memory from Linux kernel's
+ * CMA memory allocator. To enable this, supply a kernel parameter to give
+ * enough memory space to CMA allocator for framebuffer. For example:
+ *cma=130m
+ * This gives 130MB memory to CMA allocator that can be allocated to
+ * framebuffer. For reference, 8K resolution (7680x4320) takes about
+ * 127MB memory.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -227,7 +237,6 @@ struct synthvid_msg {
 } __packed;
 
 
-
 /* FB driver definitions and structures */
 #define HVFB_WIDTH 1152 /* default screen width */
 #define HVFB_HEIGHT 864 /* default screen height */
@@ -256,12 +265,15 @@ struct hvfb_par {
/* If true, the VSC notifies the VSP on every framebuffer change */
bool synchronous_fb;
 
+   /* If true, need to copy from deferred IO mem to framebuffer mem */
+   bool need_docopy;
+
struct notifier_block hvfb_panic_nb;
 
/* Memory for deferred IO and frame buffer itself */
unsigned char *dio_vp;
unsigned char *mmio_vp;
-   unsigned long mmio_pp;
+   phys_addr_t mmio_pp;
 
/* Dirty rectangle, protected by delayed_refresh_lock */
int x1, y1, x2, y2;
@@ -432,7 +444,7 @@ static void synthvid_deferred_io(struct fb_info *p,
maxy = max_t(int, maxy, y2);
 
/* Copy from dio space to mmio address */
-   if (par->fb_ready)
+   if (par->fb_ready && par->need_docopy)
hvfb_docopy(par, start, PAGE_SIZE);
}
 
@@ -749,12 +761,12 @@ static void hvfb_update_work(struct work_struct *w)
return;
 
/* Copy the dirty rectangle to frame buffer memory */
-   for (j = y1; j < y2; j++) {
-   hvfb_docopy(par,
-   j * info->fix.line_length +
-   (x1 * screen_depth / 8),
-   (x2 - x1) * screen_depth / 8);
-   }
+   if (par->need_docopy)
+   for (j = y1; j < y2; j++)
+   hvfb_docopy(par,
+   j * info->fix.line_length +
+   (x1 * screen_depth / 8),
+   (x2 - x1) * screen_depth / 8);
 
/* Refresh */
if (par->fb_ready && par->update)
@@ -799,7 +811,8 @@ static int hvfb_on_panic(struct notifier_block *nb,
par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
par->synchronous_fb = true;
info = par->info;
-   hvfb_docopy(par, 0, dio_fb_size);
+   if (par->need_docopy)
+   hvfb_docopy(par, 0, dio_fb_size);
synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
 
 

RE: [PATCH] video: hyperv_fb: Fix hibernation for the deferred IO feature

2019-11-21 Thread Wei Hu
> -Original Message-
> From: Dexuan Cui 
> Sent: Wednesday, November 20, 2019 3:14 PM
> To: KY Srinivasan ; Haiyang Zhang
> ; Stephen Hemminger ;
> sas...@kernel.org; b.zolnier...@samsung.com; linux-hyp...@vger.kernel.org;
> dri-devel@lists.freedesktop.org; linux-fb...@vger.kernel.org; linux-
> ker...@vger.kernel.org; Michael Kelley ; Sasha Levin
> 
> Cc: Wei Hu ; Dexuan Cui 
> Subject: [PATCH] video: hyperv_fb: Fix hibernation for the deferred IO feature
> 
> fb_deferred_io_work() can access the vmbus ringbuffer by calling
> fbdefio->deferred_io() -> synthvid_deferred_io() -> synthvid_update().
> 
> Because the vmbus ringbuffer is inaccessible between hvfb_suspend() and
> hvfb_resume(), we must cancel info->deferred_work before calling
> vmbus_close() and then reschedule it after we reopen the channel in
> hvfb_resume().
> 
> Fixes: a4ddb11d297e ("video: hyperv: hyperv_fb: Support deferred IO for
> Hyper-V frame buffer driver")
> Fixes: 824946a8b6fb ("video: hyperv_fb: Add the support of hibernation")
> Signed-off-by: Dexuan Cui 
> ---
> 
> This patch fixes the 2 aforementioned patches on Sasha Levin's Hyper-V tree's
> hyperv-next branch:
> https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Fhyperv%2Flinux.git%2Flog
> %2F%3Fh%3Dhyperv-
> next&data=02%7C01%7Cweh%40microsoft.com%7C451143ff78f04401d9
> 6f08d76d893a84%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637
> 098308493217121&sdata=P2fo%2F1TJUMIj5FtJCOp2QwDrghhVfPSCEJ4f1
> vkOXvI%3D&reserved=0
> 
> The 2 aforementioned patches have not appeared in the mainline yet, so please
> pick up this patch onto he same hyperv-next branch.
> 
>  drivers/video/fbdev/hyperv_fb.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
> index 4cd27e5172a1..08bc0dfb5ce7 100644
> --- a/drivers/video/fbdev/hyperv_fb.c
> +++ b/drivers/video/fbdev/hyperv_fb.c
> @@ -1194,6 +1194,7 @@ static int hvfb_suspend(struct hv_device *hdev)
>   fb_set_suspend(info, 1);
> 
>   cancel_delayed_work_sync(&par->dwork);
> + cancel_delayed_work_sync(&info->deferred_work);
> 
>   par->update_saved = par->update;
>   par->update = false;
> @@ -1227,6 +1228,7 @@ static int hvfb_resume(struct hv_device *hdev)
>   par->fb_ready = true;
>   par->update = par->update_saved;
> 
> + schedule_delayed_work(&info->deferred_work, info->fbdefio->delay);
>   schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
> 
>   /* 0 means do resume */
> --
> 2.19.1

Signed-off-by: Wei Hu 
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

RE: [PATCH] video: hyperv_fb: Fix hibernation for the deferred IO feature

2019-11-21 Thread Wei Hu

> -Original Message-
> From: Wei Hu
> Sent: 2019年11月21日 10:47
> To: Dexuan Cui ; KY Srinivasan ;
> Haiyang Zhang ; Stephen Hemminger
> ; sas...@kernel.org; b.zolnier...@samsung.com;
> linux-hyp...@vger.kernel.org; dri-devel@lists.freedesktop.org; linux-
> fb...@vger.kernel.org; linux-ker...@vger.kernel.org; Michael Kelley
> ; Sasha Levin 
> Subject: RE: [PATCH] video: hyperv_fb: Fix hibernation for the deferred IO
> feature
> 
> > -Original Message-
> > From: Dexuan Cui 
> > Sent: Wednesday, November 20, 2019 3:14 PM
> > To: KY Srinivasan ; Haiyang Zhang
> > ; Stephen Hemminger
> ;
> > sas...@kernel.org; b.zolnier...@samsung.com; linux-hyp...@vger.kernel.org;
> > dri-devel@lists.freedesktop.org; linux-fb...@vger.kernel.org; linux-
> > ker...@vger.kernel.org; Michael Kelley ; Sasha
> Levin
> > 
> > Cc: Wei Hu ; Dexuan Cui 
> > Subject: [PATCH] video: hyperv_fb: Fix hibernation for the deferred IO 
> > feature
> >
> > fb_deferred_io_work() can access the vmbus ringbuffer by calling
> > fbdefio->deferred_io() -> synthvid_deferred_io() -> synthvid_update().
> >
> > Because the vmbus ringbuffer is inaccessible between hvfb_suspend() and
> > hvfb_resume(), we must cancel info->deferred_work before calling
> > vmbus_close() and then reschedule it after we reopen the channel in
> > hvfb_resume().
> >
> > Fixes: a4ddb11d297e ("video: hyperv: hyperv_fb: Support deferred IO for
> > Hyper-V frame buffer driver")
> > Fixes: 824946a8b6fb ("video: hyperv_fb: Add the support of hibernation")
> > Signed-off-by: Dexuan Cui 
> > ---
> >
> > This patch fixes the 2 aforementioned patches on Sasha Levin's Hyper-V 
> > tree's
> > hyperv-next branch:
> >
> https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> > el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Fhyperv%2Flinux.git%2Flog
> > %2F%3Fh%3Dhyperv-
> >
> next&data=02%7C01%7Cweh%40microsoft.com%7C451143ff78f04401d9
> > 6f08d76d893a84%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637
> >
> 098308493217121&sdata=P2fo%2F1TJUMIj5FtJCOp2QwDrghhVfPSCEJ4f1
> > vkOXvI%3D&reserved=0
> >
> > The 2 aforementioned patches have not appeared in the mainline yet, so
> please
> > pick up this patch onto he same hyperv-next branch.
> >
> >  drivers/video/fbdev/hyperv_fb.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/drivers/video/fbdev/hyperv_fb.c 
> > b/drivers/video/fbdev/hyperv_fb.c
> > index 4cd27e5172a1..08bc0dfb5ce7 100644
> > --- a/drivers/video/fbdev/hyperv_fb.c
> > +++ b/drivers/video/fbdev/hyperv_fb.c
> > @@ -1194,6 +1194,7 @@ static int hvfb_suspend(struct hv_device *hdev)
> > fb_set_suspend(info, 1);
> >
> > cancel_delayed_work_sync(&par->dwork);
> > +   cancel_delayed_work_sync(&info->deferred_work);
> >
> > par->update_saved = par->update;
> > par->update = false;
> > @@ -1227,6 +1228,7 @@ static int hvfb_resume(struct hv_device *hdev)
> > par->fb_ready = true;
> > par->update = par->update_saved;
> >
> > +   schedule_delayed_work(&info->deferred_work, info->fbdefio->delay);
> > schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
> >
> > /* 0 means do resume */
> > --
> > 2.19.1
> 
> Signed-off-by: Wei Hu 

Sorry, please disregard the Signed-off-by line I added above. It was my mistake.
should be:

Reviewed-by: Wei Hu 


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

RE: [PATCH] video: hyperv: hyperv_fb: Use physical memory for fb on HyperV Gen 1 VMs.

2019-10-28 Thread Wei Hu
Thanks for the review. Please see my response inline.

> > +   select DMA_CMA
> 
> Thіs needs to be
> 
>   select DMA_CMA if HAVE_DMA_CONTIGUOUS
> 
> > +#include 
> 
> > +   /* Allocate from CMA */
> > +   // request_pages = (request_size >> PAGE_SHIFT) + 1;
> > +   request_pages = (round_up(request_size, PAGE_SIZE) >> PAGE_SHIFT);
> > +   page = dma_alloc_from_contiguous(NULL, request_pages, 0, false);
> 
> dma_alloc_from_contiguous is an internal helper, you must use it
> through dma_alloc_coherent and pass a struct device to that function.
> 

Can I directly use cma_alloc() and cma_release() in this case? The contiguous
memory allocated is just for virtual framebuffer device, not for any DMA
operation. I think using dma_alloc_coherent() might be a bit of overkill.

> > +   if (!gen2vm) {
> > +   pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
> > +   PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
> > +   if (!pdev) {
> > +   pr_err("Unable to find PCI Hyper-V video\n");
> > +   return -ENODEV;
> > +   }
> > +   }
> 
> Please actually implement a pci_driver instead of hacks like this.
> 

I don't quite follow this. What do you mean implementing a pci_driver
in this case?

> > +   par->need_docopy = false;
> > +   goto getmem1;
> > +   } else {
> 
> No need for an else after a goto.
Thanks. Will do.

Wei
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH] video: hyperv: hyperv_fb: Use physical memory for fb on HyperV Gen 1 VMs.

2019-10-22 Thread Wei Hu
On Hyper-V, Generation 1 VMs can directly use VM's physical memory for
their framebuffers. This can improve the efficiency of framebuffer and
overall performence for VM. The physical memory assigned to framebuffer
must be contiguous. We use CMA allocator to get contiguouse physicial
memory when the framebuffer size is greater than 4MB. For size under
4MB, we use alloc_pages to achieve this.

To enable framebuffer memory allocation from CMA, supply a kernel
parameter to give enough space to CMA allocator at boot time. For
example:
cma=130m
This gives 130MB memory to CAM allocator that can be allocated to
framebuffer. If this fails, we fall back to the old way of using
mmio for framebuffer.

Signed-off-by: Wei Hu 
---
 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 179 +---
 kernel/dma/contiguous.c |   2 +
 3 files changed, 147 insertions(+), 35 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index aa9541bf964b..f534059461ee 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2215,6 +2215,7 @@ config FB_HYPERV
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_DEFERRED_IO
+   select DMA_CMA
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 3f60b7bc8589..ea2fd3481225 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -31,6 +31,16 @@
  * "set-vmvideo" command. For example
  * set-vmvideo -vmname name -horizontalresolution:1920 \
  * -verticalresolution:1200 -resolutiontype single
+ *
+ * Gen 1 VMs also support directly using VM's phyiscal memory for framebuffer.
+ * It could improve the efficiency and performance for framebuffer and VM.
+ * This requires to allocate contiguous physical memory from Linux kernel's
+ * CMA memory allocator. To enable this, supply a kernel parameter to give
+ * enough memory space to CMA allocator for framebuffer. For example:
+ *cma=130m
+ * This gives 130MB memory to CMA allocator that can be allocated to
+ * framebuffer. For reference, 8K resolution (7680x4320) takes about
+ * 127MB memory.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -42,6 +52,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -227,7 +238,6 @@ struct synthvid_msg {
 } __packed;
 
 
-
 /* FB driver definitions and structures */
 #define HVFB_WIDTH 1152 /* default screen width */
 #define HVFB_HEIGHT 864 /* default screen height */
@@ -256,6 +266,9 @@ struct hvfb_par {
/* If true, the VSC notifies the VSP on every framebuffer change */
bool synchronous_fb;
 
+   /* If true, need to copy from deferred IO mem to framebuffer mem */
+   bool need_docopy;
+
struct notifier_block hvfb_panic_nb;
 
/* Memory for deferred IO and frame buffer itself */
@@ -432,7 +445,7 @@ static void synthvid_deferred_io(struct fb_info *p,
maxy = max_t(int, maxy, y2);
 
/* Copy from dio space to mmio address */
-   if (par->fb_ready)
+   if (par->fb_ready && par->need_docopy)
hvfb_docopy(par, start, PAGE_SIZE);
}
 
@@ -749,12 +762,12 @@ static void hvfb_update_work(struct work_struct *w)
return;
 
/* Copy the dirty rectangle to frame buffer memory */
-   for (j = y1; j < y2; j++) {
-   hvfb_docopy(par,
-   j * info->fix.line_length +
-   (x1 * screen_depth / 8),
-   (x2 - x1) * screen_depth / 8);
-   }
+   if (par->need_docopy)
+   for (j = y1; j < y2; j++)
+   hvfb_docopy(par,
+   j * info->fix.line_length +
+   (x1 * screen_depth / 8),
+   (x2 - x1) * screen_depth / 8);
 
/* Refresh */
if (par->fb_ready && par->update)
@@ -799,7 +812,8 @@ static int hvfb_on_panic(struct notifier_block *nb,
par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
par->synchronous_fb = true;
info = par->info;
-   hvfb_docopy(par, 0, dio_fb_size);
+   if (par->need_docopy)
+   hvfb_docopy(par, 0, dio_fb_size);
synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
 
return NOTIFY_DONE;
@@ -938,6 +952,62 @@ static void hvfb_get_option(struct fb_info *info)
return;
 }
 
+/*
+ * Allocate enough contiguous physical memory.
+ * Return physical address if succeeded or -1 if failed.
+ */
+static unsigned long hvfb_get_phymem(unsigned int request_size)
+{
+   struct page *page = NULL;
+   unsigned int request_pages;
+   unsigned long paddr = 0;
+   unsigned in

[PATHC v6] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-09-17 Thread Wei Hu
Without deferred IO support, hyperv_fb driver informs the host to refresh
the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
is screen update or not. This patch supports deferred IO for screens in
graphics mode and also enables the frame buffer on-demand refresh. The
highest refresh rate is still set at 20Hz.

Currently Hyper-V only takes a physical address from guest as the starting
address of frame buffer. This implies the guest must allocate contiguous
physical memory for frame buffer. In addition, Hyper-V Gen 2 VMs only
accept address from MMIO region as frame buffer address. Due to these
limitations on Hyper-V host, we keep a shadow copy of frame buffer
in the guest. This means one more copy of the dirty rectangle inside
guest when doing the on-demand refresh. This can be optimized in the
future with help from host. For now the host performance gain from deferred
IO outweighs the shadow copy impact in the guest.

Signed-off-by: Wei Hu 
---
v2: Incorporated review comments from Michael Kelley
- Increased dirty rectangle by one row in deferred IO case when sending
to Hyper-V.
- Corrected the dirty rectangle size in the text mode.
- Added more comments.
- Other minor code cleanups.

v3: Incorporated more review comments
- Removed a few unnecessary variable tests

v4: Incorporated test and review feedback from Dexuan Cui
- Not disable interrupt while acquiring docopy_lock in
  hvfb_update_work(). This avoids significant bootup delay in
  large vCPU count VMs.

v5: Completely remove the unnecessary docopy_lock after discussing
with Dexuan Cui.

v6: Do not request host refresh when the VM guest screen is
closed or minimized.

 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 210 
 2 files changed, 190 insertions(+), 21 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 1b2f5f31fb6f..e781f89a1824 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2241,6 +2241,7 @@ config FB_HYPERV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+   select FB_DEFERRED_IO
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index fe319fc39bec..0c57445f8357 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -237,6 +237,7 @@ struct synthvid_msg {
 #define RING_BUFSIZE (256 * 1024)
 #define VSP_TIMEOUT (10 * HZ)
 #define HVFB_UPDATE_DELAY (HZ / 20)
+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
 
 struct hvfb_par {
struct fb_info *info;
@@ -256,6 +257,16 @@ struct hvfb_par {
bool synchronous_fb;
 
struct notifier_block hvfb_panic_nb;
+
+   /* Memory for deferred IO and frame buffer itself */
+   unsigned char *dio_vp;
+   unsigned char *mmio_vp;
+   unsigned long mmio_pp;
+
+   /* Dirty rectangle, protected by delayed_refresh_lock */
+   int x1, y1, x2, y2;
+   bool delayed_refresh;
+   spinlock_t delayed_refresh_lock;
 };
 
 static uint screen_width = HVFB_WIDTH;
@@ -264,6 +275,7 @@ static uint screen_width_max = HVFB_WIDTH;
 static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
+static uint dio_fb_size; /* FB size for deferred IO */
 
 /* Send message to Hyper-V host */
 static inline int synthvid_send(struct hv_device *hdev,
@@ -350,28 +362,88 @@ static int synthvid_send_ptr(struct hv_device *hdev)
 }
 
 /* Send updated screen area (dirty rectangle) location to host */
-static int synthvid_update(struct fb_info *info)
+static int
+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
 {
struct hv_device *hdev = device_to_hv_device(info->device);
struct synthvid_msg msg;
 
memset(&msg, 0, sizeof(struct synthvid_msg));
+   if (x2 == INT_MAX)
+   x2 = info->var.xres;
+   if (y2 == INT_MAX)
+   y2 = info->var.yres;
 
msg.vid_hdr.type = SYNTHVID_DIRT;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_dirt);
msg.dirt.video_output = 0;
msg.dirt.dirt_count = 1;
-   msg.dirt.rect[0].x1 = 0;
-   msg.dirt.rect[0].y1 = 0;
-   msg.dirt.rect[0].x2 = info->var.xres;
-   msg.dirt.rect[0].y2 = info->var.yres;
+   msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
+   msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
+   msg.dirt.rect[0].x2 =
+   (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
+   msg.dirt.rect[0].y2 =
+   (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
 
synthvid_send(hdev, &msg);
 
return 0;
 }
 
+static void hvfb_docopy(struct hvfb_p

[PATCH v5] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-09-12 Thread Wei Hu
Without deferred IO support, hyperv_fb driver informs the host to refresh
the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
is screen update or not. This patch supports deferred IO for screens in
graphics mode and also enables the frame buffer on-demand refresh. The
highest refresh rate is still set at 20Hz.

Currently Hyper-V only takes a physical address from guest as the starting
address of frame buffer. This implies the guest must allocate contiguous
physical memory for frame buffer. In addition, Hyper-V Gen 2 VMs only
accept address from MMIO region as frame buffer address. Due to these
limitations on Hyper-V host, we keep a shadow copy of frame buffer
in the guest. This means one more copy of the dirty rectangle inside
guest when doing the on-demand refresh. This can be optimized in the
future with help from host. For now the host performance gain from deferred
IO outweighs the shadow copy impact in the guest.

Signed-off-by: Wei Hu 
---
v2: Incorporated review comments from Michael Kelley
- Increased dirty rectangle by one row in deferred IO case when sending
to Hyper-V.
- Corrected the dirty rectangle size in the text mode.
- Added more comments.
- Other minor code cleanups.

v3: Incorporated more review comments
- Removed a few unnecessary variable tests

v4: Incorporated test and review feedback from Dexuan Cui
- Not disable interrupt while acquiring docopy_lock in
  hvfb_update_work(). This avoids significant bootup delay in
  large vCPU count VMs.

v5: Completely remove the unnecessary docopy_lock after discussing
with Dexuan Cui.

 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 208 +---
 2 files changed, 189 insertions(+), 20 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 1b2f5f31fb6f..e781f89a1824 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2241,6 +2241,7 @@ config FB_HYPERV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+   select FB_DEFERRED_IO
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index fe319fc39bec..89a5ec3741b9 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -237,6 +237,7 @@ struct synthvid_msg {
 #define RING_BUFSIZE (256 * 1024)
 #define VSP_TIMEOUT (10 * HZ)
 #define HVFB_UPDATE_DELAY (HZ / 20)
+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
 
 struct hvfb_par {
struct fb_info *info;
@@ -256,6 +257,16 @@ struct hvfb_par {
bool synchronous_fb;
 
struct notifier_block hvfb_panic_nb;
+
+   /* Memory for deferred IO and frame buffer itself */
+   unsigned char *dio_vp;
+   unsigned char *mmio_vp;
+   unsigned long mmio_pp;
+
+   /* Dirty rectangle, protected by delayed_refresh_lock */
+   int x1, y1, x2, y2;
+   bool delayed_refresh;
+   spinlock_t delayed_refresh_lock;
 };
 
 static uint screen_width = HVFB_WIDTH;
@@ -264,6 +275,7 @@ static uint screen_width_max = HVFB_WIDTH;
 static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
+static uint dio_fb_size; /* FB size for deferred IO */
 
 /* Send message to Hyper-V host */
 static inline int synthvid_send(struct hv_device *hdev,
@@ -350,28 +362,88 @@ static int synthvid_send_ptr(struct hv_device *hdev)
 }
 
 /* Send updated screen area (dirty rectangle) location to host */
-static int synthvid_update(struct fb_info *info)
+static int
+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
 {
struct hv_device *hdev = device_to_hv_device(info->device);
struct synthvid_msg msg;
 
memset(&msg, 0, sizeof(struct synthvid_msg));
+   if (x2 == INT_MAX)
+   x2 = info->var.xres;
+   if (y2 == INT_MAX)
+   y2 = info->var.yres;
 
msg.vid_hdr.type = SYNTHVID_DIRT;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_dirt);
msg.dirt.video_output = 0;
msg.dirt.dirt_count = 1;
-   msg.dirt.rect[0].x1 = 0;
-   msg.dirt.rect[0].y1 = 0;
-   msg.dirt.rect[0].x2 = info->var.xres;
-   msg.dirt.rect[0].y2 = info->var.yres;
+   msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
+   msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
+   msg.dirt.rect[0].x2 =
+   (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
+   msg.dirt.rect[0].y2 =
+   (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
 
synthvid_send(hdev, &msg);
 
return 0;
 }
 
+static void hvfb_docopy(struct hvfb_par *par,
+   unsigned long offset,
+   unsigned long size)
+{
+   

[PATCH v4] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-09-12 Thread Wei Hu
Without deferred IO support, hyperv_fb driver informs the host to refresh
the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
is screen update or not. This patch supports deferred IO for screens in
graphics mode and also enables the frame buffer on-demand refresh. The
highest refresh rate is still set at 20Hz.

Currently Hyper-V only takes a physical address from guest as the starting
address of frame buffer. This implies the guest must allocate contiguous
physical memory for frame buffer. In addition, Hyper-V Gen 2 VMs only
accept address from MMIO region as frame buffer address. Due to these
limitations on Hyper-V host, we keep a shadow copy of frame buffer
in the guest. This means one more copy of the dirty rectangle inside
guest when doing the on-demand refresh. This can be optimized in the
future with help from host. For now the host performance gain from deferred
IO outweighs the shadow copy impact in the guest.

Signed-off-by: Wei Hu 
---
v2: Incorporated review comments from Michael Kelley
- Increased dirty rectangle by one row in deferred IO case when sending
to Hyper-V.
- Corrected the dirty rectangle size in the text mode.
- Added more comments.
- Other minor code cleanups.

v3: Incorporated more review comments
- Removed a few unnecessary variable tests

v4: Incorporated test and review feedback from Dexuan Cui
- Not disable interrupt while acquiring docopy_lock in
  hvfb_update_work(). This avoids significant bootup delay in
  large vCPU count VMs.

 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 216 +---
 2 files changed, 197 insertions(+), 20 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 1b2f5f31fb6f..e781f89a1824 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2241,6 +2241,7 @@ config FB_HYPERV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+   select FB_DEFERRED_IO
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index fe319fc39bec..711c46a5d5d2 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -237,6 +237,7 @@ struct synthvid_msg {
 #define RING_BUFSIZE (256 * 1024)
 #define VSP_TIMEOUT (10 * HZ)
 #define HVFB_UPDATE_DELAY (HZ / 20)
+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
 
 struct hvfb_par {
struct fb_info *info;
@@ -256,6 +257,17 @@ struct hvfb_par {
bool synchronous_fb;
 
struct notifier_block hvfb_panic_nb;
+
+   /* Memory for deferred IO and frame buffer itself */
+   unsigned char *dio_vp;
+   unsigned char *mmio_vp;
+   unsigned long mmio_pp;
+   spinlock_t docopy_lock; /* Lock to protect memory copy */
+
+   /* Dirty rectangle, protected by delayed_refresh_lock */
+   int x1, y1, x2, y2;
+   bool delayed_refresh;
+   spinlock_t delayed_refresh_lock;
 };
 
 static uint screen_width = HVFB_WIDTH;
@@ -264,6 +276,7 @@ static uint screen_width_max = HVFB_WIDTH;
 static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
+static uint dio_fb_size; /* FB size for deferred IO */
 
 /* Send message to Hyper-V host */
 static inline int synthvid_send(struct hv_device *hdev,
@@ -350,28 +363,92 @@ static int synthvid_send_ptr(struct hv_device *hdev)
 }
 
 /* Send updated screen area (dirty rectangle) location to host */
-static int synthvid_update(struct fb_info *info)
+static int
+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
 {
struct hv_device *hdev = device_to_hv_device(info->device);
struct synthvid_msg msg;
 
memset(&msg, 0, sizeof(struct synthvid_msg));
+   if (x2 == INT_MAX)
+   x2 = info->var.xres;
+   if (y2 == INT_MAX)
+   y2 = info->var.yres;
 
msg.vid_hdr.type = SYNTHVID_DIRT;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_dirt);
msg.dirt.video_output = 0;
msg.dirt.dirt_count = 1;
-   msg.dirt.rect[0].x1 = 0;
-   msg.dirt.rect[0].y1 = 0;
-   msg.dirt.rect[0].x2 = info->var.xres;
-   msg.dirt.rect[0].y2 = info->var.yres;
+   msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
+   msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
+   msg.dirt.rect[0].x2 =
+   (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
+   msg.dirt.rect[0].y2 =
+   (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
 
synthvid_send(hdev, &msg);
 
return 0;
 }
 
+static void hvfb_docopy(struct hvfb_par *par,
+   unsigned long offset,
+   unsigned long size)
+{
+   if (!par || !par->mmio_

[PATCH v4] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host

2019-09-05 Thread Wei Hu
Beginning from Windows 10 RS5+, VM screen resolution is obtained from host.
The "video=hyperv_fb" boot time option is not needed, but still can be
used to overwrite what the host specifies. The VM resolution on the host
could be set by executing the powershell "set-vmvideo" command.

Signed-off-by: Iouri Tarassov 
Signed-off-by: Wei Hu 
---
v2:
- Implemented fallback when version negotiation failed.
- Defined full size for supported_resolution array.

v3:
- Corrected the synthvid major and minor version comparison problem.

v4:
- Changed function name to synthvid_ver_ge().

 drivers/video/fbdev/hyperv_fb.c | 159 +---
 1 file changed, 147 insertions(+), 12 deletions(-)

diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 00f5bdcc6c6f..fe319fc39bec 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -23,6 +23,14 @@
  *
  * Portrait orientation is also supported:
  * For example: video=hyperv_fb:864x1152
+ *
+ * When a Windows 10 RS5+ host is used, the virtual machine screen
+ * resolution is obtained from the host. The "video=hyperv_fb" option is
+ * not needed, but still can be used to overwrite what the host specifies.
+ * The VM resolution on the host could be set by executing the powershell
+ * "set-vmvideo" command. For example
+ * set-vmvideo -vmname name -horizontalresolution:1920 \
+ * -verticalresolution:1200 -resolutiontype single
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -44,6 +52,10 @@
 #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
 #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
 #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
+
+#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x)
+#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0x) >> 16)
 
 #define SYNTHVID_DEPTH_WIN7 16
 #define SYNTHVID_DEPTH_WIN8 32
@@ -82,16 +94,25 @@ enum synthvid_msg_type {
SYNTHVID_POINTER_SHAPE  = 8,
SYNTHVID_FEATURE_CHANGE = 9,
SYNTHVID_DIRT   = 10,
+   SYNTHVID_RESOLUTION_REQUEST = 13,
+   SYNTHVID_RESOLUTION_RESPONSE= 14,
 
-   SYNTHVID_MAX= 11
+   SYNTHVID_MAX= 15
 };
 
+#defineSYNTHVID_EDID_BLOCK_SIZE128
+#defineSYNTHVID_MAX_RESOLUTION_COUNT   64
+
+struct hvd_screen_info {
+   u16 width;
+   u16 height;
+} __packed;
+
 struct synthvid_msg_hdr {
u32 type;
u32 size;  /* size of this header + payload after this field*/
 } __packed;
 
-
 struct synthvid_version_req {
u32 version;
 } __packed;
@@ -102,6 +123,19 @@ struct synthvid_version_resp {
u8 max_video_outputs;
 } __packed;
 
+struct synthvid_supported_resolution_req {
+   u8 maximum_resolution_count;
+} __packed;
+
+struct synthvid_supported_resolution_resp {
+   u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
+   u8 resolution_count;
+   u8 default_resolution_index;
+   u8 is_standard;
+   struct hvd_screen_info
+   supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
+} __packed;
+
 struct synthvid_vram_location {
u64 user_ctx;
u8 is_vram_gpa_specified;
@@ -187,6 +221,8 @@ struct synthvid_msg {
struct synthvid_pointer_shape ptr_shape;
struct synthvid_feature_change feature_chg;
struct synthvid_dirt dirt;
+   struct synthvid_supported_resolution_req resolution_req;
+   struct synthvid_supported_resolution_resp resolution_resp;
};
 } __packed;
 
@@ -224,6 +260,8 @@ struct hvfb_par {
 
 static uint screen_width = HVFB_WIDTH;
 static uint screen_height = HVFB_HEIGHT;
+static uint screen_width_max = HVFB_WIDTH;
+static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
 
@@ -354,6 +392,7 @@ static void synthvid_recv_sub(struct hv_device *hdev)
 
/* Complete the wait event */
if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
+   msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
complete(&par->wait);
@@ -400,6 +439,17 @@ static void synthvid_receive(void *ctx)
} while (bytes_recvd > 0 && ret == 0);
 }
 
+/* Check if the ver1 version is equal or greater than ver2 */
+static inline bool synthvid_ver_ge(u32 ver1, u32 ver2)
+{
+   if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
+   (SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
+SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
+   return true;
+
+  

[PATCH v3] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-09-05 Thread Wei Hu
Without deferred IO support, hyperv_fb driver informs the host to refresh
the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
is screen update or not. This patch supports deferred IO for screens in
graphics mode and also enables the frame buffer on-demand refresh. The
highest refresh rate is still set at 20Hz.

Currently Hyper-V only takes a physical address from guest as the starting
address of frame buffer. This implies the guest must allocate contiguous
physical memory for frame buffer. In addition, Hyper-V Gen 2 VMs only
accept address from MMIO region as frame buffer address. Due to these
limitations on Hyper-V host, we keep a shadow copy of frame buffer
in the guest. This means one more copy of the dirty rectangle inside
guest when doing the on-demand refresh. This can be optimized in the
future with help from host. For now the host performance gain from deferred
IO outweighs the shadow copy impact in the guest.

Signed-off-by: Wei Hu 
---
v2: Incorporated review comments from Michael Kelley
- Increased dirty rectangle by one row in deferred IO case when sending
to Hyper-V.
- Corrected the dirty rectangle size in the text mode.
- Added more comments.
- Other minor code cleanups.

v3: Incorporated more review comments
- Removed a few unnecessary variable tests

 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 216 +---
 2 files changed, 197 insertions(+), 20 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 1b2f5f31fb6f..e781f89a1824 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2241,6 +2241,7 @@ config FB_HYPERV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+   select FB_DEFERRED_IO
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 1464c6f14687..63bfd35e392c 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -237,6 +237,7 @@ struct synthvid_msg {
 #define RING_BUFSIZE (256 * 1024)
 #define VSP_TIMEOUT (10 * HZ)
 #define HVFB_UPDATE_DELAY (HZ / 20)
+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
 
 struct hvfb_par {
struct fb_info *info;
@@ -256,6 +257,17 @@ struct hvfb_par {
bool synchronous_fb;
 
struct notifier_block hvfb_panic_nb;
+
+   /* Memory for deferred IO and frame buffer itself */
+   unsigned char *dio_vp;
+   unsigned char *mmio_vp;
+   unsigned long mmio_pp;
+   spinlock_t docopy_lock; /* Lock to protect memory copy */
+
+   /* Dirty rectangle, protected by delayed_refresh_lock */
+   int x1, y1, x2, y2;
+   bool delayed_refresh;
+   spinlock_t delayed_refresh_lock;
 };
 
 static uint screen_width = HVFB_WIDTH;
@@ -264,6 +276,7 @@ static uint screen_width_max = HVFB_WIDTH;
 static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
+static uint dio_fb_size; /* FB size for deferred IO */
 
 /* Send message to Hyper-V host */
 static inline int synthvid_send(struct hv_device *hdev,
@@ -350,28 +363,92 @@ static int synthvid_send_ptr(struct hv_device *hdev)
 }
 
 /* Send updated screen area (dirty rectangle) location to host */
-static int synthvid_update(struct fb_info *info)
+static int
+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
 {
struct hv_device *hdev = device_to_hv_device(info->device);
struct synthvid_msg msg;
 
memset(&msg, 0, sizeof(struct synthvid_msg));
+   if (x2 == INT_MAX)
+   x2 = info->var.xres;
+   if (y2 == INT_MAX)
+   y2 = info->var.yres;
 
msg.vid_hdr.type = SYNTHVID_DIRT;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_dirt);
msg.dirt.video_output = 0;
msg.dirt.dirt_count = 1;
-   msg.dirt.rect[0].x1 = 0;
-   msg.dirt.rect[0].y1 = 0;
-   msg.dirt.rect[0].x2 = info->var.xres;
-   msg.dirt.rect[0].y2 = info->var.yres;
+   msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
+   msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
+   msg.dirt.rect[0].x2 =
+   (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
+   msg.dirt.rect[0].y2 =
+   (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
 
synthvid_send(hdev, &msg);
 
return 0;
 }
 
+static void hvfb_docopy(struct hvfb_par *par,
+   unsigned long offset,
+   unsigned long size)
+{
+   if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
+   size == 0 || offset >= dio_fb_size)
+   return;
+
+   if (offset + size > dio_fb_size)
+   size = dio_fb_size - offset

RE: [PATHC v2] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-08-29 Thread Wei Hu


> -Original Message-
> From: Michael Kelley 
> 
> From: Wei Hu   Sent: Tuesday, August 27, 2019 4:25 AM
> >
> > Without deferred IO support, hyperv_fb driver informs the host to refresh
> > the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
> > is screen update or not. This patch supports deferred IO for screens in
> > graphics mode and also enables the frame buffer on-demand refresh. The
> > highest refresh rate is still set at 20Hz.
> >
> > Currently Hyper-V only takes a physical address from guest as the starting
> > address of frame buffer. This implies the guest must allocate contiguous
> > physical memory for frame buffer. In addition, Hyper-V Gen 2 VMs only
> > accept address from MMIO region as frame buffer address. Due to these
> > limitations on Hyper-V host, we keep a shadow copy of frame buffer
> > in the guest. This means one more copy of the dirty rectangle inside
> > guest when doing the on-demand refresh. This can be optimized in the
> > future with help from host. For now the host performance gain from deferred
> > IO outweighs the shadow copy impact in the guest.
> >
> > v2: Incorporated review comments from Michael Kelley
> > - Increased dirty rectangle by one row in deferred IO case when sending
> > to Hyper-V.
> > - Corrected the dirty rectangle size in the text mode.
> > - Added more comments.
> > - Other minor code cleanups.
> 
> Version history should go after the "---" below so it is not included in
> the commit message.
> 
[Wei Hu] 
I saw version history in the commit logs. 

> >
> > Signed-off-by: Wei Hu 
> > ---
> >  drivers/video/fbdev/Kconfig |   1 +
> >  drivers/video/fbdev/hyperv_fb.c | 221 +---
> >  2 files changed, 202 insertions(+), 20 deletions(-)
> >
> > +/* Deferred IO callback */
> > +static void synthvid_deferred_io(struct fb_info *p,
> > +struct list_head *pagelist)
> > +{
> > +   struct hvfb_par *par = p->par;
> > +   struct page *page;
> > +   unsigned long start, end;
> > +   int y1, y2, miny, maxy;
> > +   unsigned long flags;
> > +
> > +   miny = INT_MAX;
> > +   maxy = 0;
> > +
> > +   /*
> > +* Merge dirty pages. It is possible that last page cross
> > +* over the end of frame buffer row yres. This is taken care of
> > +* in synthvid_update function by clamping the y2
> > +* value to yres.
> > +*/
> > +   list_for_each_entry(page, pagelist, lru) {
> > +   start = page->index << PAGE_SHIFT;
> > +   end = start + PAGE_SIZE - 1;
> > +   y1 = start / p->fix.line_length;
> > +   y2 = end / p->fix.line_length;
> > +   if (y2 > p->var.yres)
> > +   y2 = p->var.yres;
> 
> The above test seems contradictory to the comment that
> says the clamping is done in synthvid_update().  Also, since
> the above calculation of y2 is "inclusive", the clamping should
> be done to yres - 1 in order to continue to be inclusive.  Then
> when maxy + 1 is passed to synthvid_update() everything works
> out correctly.
>
[Wei Hu] 
Actually the original code I sent out just works correctly.  It always get
the inclusive rectangle in the above loop, and only send one more extra
line (if y2 == yres) to sythvid_update() and it is clamped inside that 
function. Changing it to yres -1 and sending maxy + 1 to sytnvid_update()
makes it the same as the original code in this case, and would end up 
always copy and refresh one extra row when y2 < yres.

The comment I added was according to your last review comment asking
to add some comments explaining it. Maybe I mis-understood. I thought
since you wanted me to change to maxy + 1, the code could reach yres + 1
so it will be clamped in synthvid_update() to yres.

 Wei

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

RE: [PATCH v3] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host

2019-08-28 Thread Wei Hu



> -Original Message-
> From: Michael Kelley 
> >
> > Beginning from Windows 10 RS5+, VM screen resolution is obtained from host.
> > The "video=hyperv_fb" boot time option is not needed, but still can be
> > used to overwrite what the host specifies. The VM resolution on the host
> > could be set by executing the powershell "set-vmvideo" command.
> >
> > v2:
> > - Implemented fallback when version negotiation failed.
> > - Defined full size for supported_resolution array.
> >
> > v3:
> > - Corrected the synthvid major and minor version comparison problem.
> 
> The changelog for v2 and v3 should actually go after the "---" below so
> that the changelog does not end up as part of the commit message.  Take
> a look at other postings to LKML for an example.
> 
[Wei Hu] 
I saw people putting v2 and vN in commit message. The git log of this file also 
contains similar lines like v2. But if you prefer I can move it after ---. 


> >
> > Signed-off-by: Iouri Tarassov 
> > Signed-off-by: Wei Hu 
> > ---
> >  drivers/video/fbdev/hyperv_fb.c | 159 +---
> >  1 file changed, 147 insertions(+), 12 deletions(-)
> >
> >
> > +/* Check if the ver1 version is equal or greater than ver2 */
> > +static inline bool synthvid_ver_eg(u32 ver1, u32 ver2)
> 
> I'm being picky here, but I would call this synthvid_ver_ge().   In my
> experience "ge" is the shorthand for "greater than or equal", rather
> than the "eg" you have used.
> 
[Wei Hu] 
Okay.

Thanks,
Wei


> Michael
> 



[PATCH v3] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host

2019-08-28 Thread Wei Hu
Beginning from Windows 10 RS5+, VM screen resolution is obtained from host.
The "video=hyperv_fb" boot time option is not needed, but still can be
used to overwrite what the host specifies. The VM resolution on the host
could be set by executing the powershell "set-vmvideo" command.

v2:
- Implemented fallback when version negotiation failed.
- Defined full size for supported_resolution array.

v3:
- Corrected the synthvid major and minor version comparison problem.

Signed-off-by: Iouri Tarassov 
Signed-off-by: Wei Hu 
---
 drivers/video/fbdev/hyperv_fb.c | 159 +---
 1 file changed, 147 insertions(+), 12 deletions(-)

diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 00f5bdcc6c6f..1464c6f14687 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -23,6 +23,14 @@
  *
  * Portrait orientation is also supported:
  * For example: video=hyperv_fb:864x1152
+ *
+ * When a Windows 10 RS5+ host is used, the virtual machine screen
+ * resolution is obtained from the host. The "video=hyperv_fb" option is
+ * not needed, but still can be used to overwrite what the host specifies.
+ * The VM resolution on the host could be set by executing the powershell
+ * "set-vmvideo" command. For example
+ * set-vmvideo -vmname name -horizontalresolution:1920 \
+ * -verticalresolution:1200 -resolutiontype single
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -44,6 +52,10 @@
 #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
 #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
 #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
+
+#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x)
+#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0x) >> 16)
 
 #define SYNTHVID_DEPTH_WIN7 16
 #define SYNTHVID_DEPTH_WIN8 32
@@ -82,16 +94,25 @@ enum synthvid_msg_type {
SYNTHVID_POINTER_SHAPE  = 8,
SYNTHVID_FEATURE_CHANGE = 9,
SYNTHVID_DIRT   = 10,
+   SYNTHVID_RESOLUTION_REQUEST = 13,
+   SYNTHVID_RESOLUTION_RESPONSE= 14,
 
-   SYNTHVID_MAX= 11
+   SYNTHVID_MAX= 15
 };
 
+#defineSYNTHVID_EDID_BLOCK_SIZE128
+#defineSYNTHVID_MAX_RESOLUTION_COUNT   64
+
+struct hvd_screen_info {
+   u16 width;
+   u16 height;
+} __packed;
+
 struct synthvid_msg_hdr {
u32 type;
u32 size;  /* size of this header + payload after this field*/
 } __packed;
 
-
 struct synthvid_version_req {
u32 version;
 } __packed;
@@ -102,6 +123,19 @@ struct synthvid_version_resp {
u8 max_video_outputs;
 } __packed;
 
+struct synthvid_supported_resolution_req {
+   u8 maximum_resolution_count;
+} __packed;
+
+struct synthvid_supported_resolution_resp {
+   u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
+   u8 resolution_count;
+   u8 default_resolution_index;
+   u8 is_standard;
+   struct hvd_screen_info
+   supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
+} __packed;
+
 struct synthvid_vram_location {
u64 user_ctx;
u8 is_vram_gpa_specified;
@@ -187,6 +221,8 @@ struct synthvid_msg {
struct synthvid_pointer_shape ptr_shape;
struct synthvid_feature_change feature_chg;
struct synthvid_dirt dirt;
+   struct synthvid_supported_resolution_req resolution_req;
+   struct synthvid_supported_resolution_resp resolution_resp;
};
 } __packed;
 
@@ -224,6 +260,8 @@ struct hvfb_par {
 
 static uint screen_width = HVFB_WIDTH;
 static uint screen_height = HVFB_HEIGHT;
+static uint screen_width_max = HVFB_WIDTH;
+static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
 
@@ -354,6 +392,7 @@ static void synthvid_recv_sub(struct hv_device *hdev)
 
/* Complete the wait event */
if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
+   msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
complete(&par->wait);
@@ -400,6 +439,17 @@ static void synthvid_receive(void *ctx)
} while (bytes_recvd > 0 && ret == 0);
 }
 
+/* Check if the ver1 version is equal or greater than ver2 */
+static inline bool synthvid_ver_eg(u32 ver1, u32 ver2)
+{
+   if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
+   (SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
+SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
+   return true;
+
+   return false;
+}
+
 /* Check synthetic video protocol version with 

[PATHC v2] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-08-27 Thread Wei Hu
Without deferred IO support, hyperv_fb driver informs the host to refresh
the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
is screen update or not. This patch supports deferred IO for screens in
graphics mode and also enables the frame buffer on-demand refresh. The
highest refresh rate is still set at 20Hz.

Currently Hyper-V only takes a physical address from guest as the starting
address of frame buffer. This implies the guest must allocate contiguous
physical memory for frame buffer. In addition, Hyper-V Gen 2 VMs only
accept address from MMIO region as frame buffer address. Due to these
limitations on Hyper-V host, we keep a shadow copy of frame buffer
in the guest. This means one more copy of the dirty rectangle inside
guest when doing the on-demand refresh. This can be optimized in the
future with help from host. For now the host performance gain from deferred
IO outweighs the shadow copy impact in the guest.

v2: Incorporated review comments from Michael Kelley
- Increased dirty rectangle by one row in deferred IO case when sending
to Hyper-V.
- Corrected the dirty rectangle size in the text mode.
- Added more comments.
- Other minor code cleanups.

Signed-off-by: Wei Hu 
---
 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 221 +---
 2 files changed, 202 insertions(+), 20 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 1b2f5f31fb6f..e781f89a1824 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2241,6 +2241,7 @@ config FB_HYPERV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+   select FB_DEFERRED_IO
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 2ca400c0d621..279a2164a57c 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -234,6 +234,7 @@ struct synthvid_msg {
 #define RING_BUFSIZE (256 * 1024)
 #define VSP_TIMEOUT (10 * HZ)
 #define HVFB_UPDATE_DELAY (HZ / 20)
+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
 
 struct hvfb_par {
struct fb_info *info;
@@ -253,6 +254,17 @@ struct hvfb_par {
bool synchronous_fb;
 
struct notifier_block hvfb_panic_nb;
+
+   /* Memory for deferred IO and frame buffer itself */
+   unsigned char *dio_vp;
+   unsigned char *mmio_vp;
+   unsigned long mmio_pp;
+   spinlock_t docopy_lock; /* Lock to protect memory copy */
+
+   /* Dirty rectangle, protected by delayed_refresh_lock */
+   int x1, y1, x2, y2;
+   bool delayed_refresh;
+   spinlock_t delayed_refresh_lock;
 };
 
 static uint screen_width = HVFB_WIDTH;
@@ -261,6 +273,7 @@ static uint screen_width_max = HVFB_WIDTH;
 static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
+static uint dio_fb_size; /* FB size for deferred IO */
 
 /* Send message to Hyper-V host */
 static inline int synthvid_send(struct hv_device *hdev,
@@ -347,28 +360,94 @@ static int synthvid_send_ptr(struct hv_device *hdev)
 }
 
 /* Send updated screen area (dirty rectangle) location to host */
-static int synthvid_update(struct fb_info *info)
+static int
+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
 {
struct hv_device *hdev = device_to_hv_device(info->device);
struct synthvid_msg msg;
 
memset(&msg, 0, sizeof(struct synthvid_msg));
+   if (x2 == INT_MAX)
+   x2 = info->var.xres;
+   if (y2 == INT_MAX)
+   y2 = info->var.yres;
 
msg.vid_hdr.type = SYNTHVID_DIRT;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_dirt);
msg.dirt.video_output = 0;
msg.dirt.dirt_count = 1;
-   msg.dirt.rect[0].x1 = 0;
-   msg.dirt.rect[0].y1 = 0;
-   msg.dirt.rect[0].x2 = info->var.xres;
-   msg.dirt.rect[0].y2 = info->var.yres;
+   msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
+   msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
+   msg.dirt.rect[0].x2 =
+   (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
+   msg.dirt.rect[0].y2 =
+   (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
 
synthvid_send(hdev, &msg);
 
return 0;
 }
 
+static void hvfb_docopy(struct hvfb_par *par,
+   unsigned long offset,
+   unsigned long size)
+{
+   if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
+   size == 0 || offset >= dio_fb_size)
+   return;
+
+   if (offset + size > dio_fb_size)
+   size = dio_fb_size - offset;
+
+   memcpy(par->mmio_vp + offset, par->dio_vp + offset, size);
+}
+
+/* D

RE: [PATCH v2] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host

2019-08-27 Thread Wei Hu
> -Original Message-
> From: Michael Kelley 
> Sent: Thursday, August 22, 2019 7:49 AM
> To: Wei Hu ; b.zolnier...@samsung.com; linux-
> hyp...@vger.kernel.org; dri-devel@lists.freedesktop.org; linux-
> fb...@vger.kernel.org; linux-ker...@vger.kernel.org; sas...@kernel.org;
> Stephen Hemminger ; Haiyang Zhang
> ; KY Srinivasan ; Dexuan Cui
> 
> Cc: Iouri Tarassov 
> > +
> > +struct synthvid_supported_resolution_resp {
> > +   u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
> > +   u8 resolution_count;
> > +   u8 default_resolution_index;
> > +   u8 is_standard;
> > +   struct hvd_screen_info
> > +   supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
> 
> Is there extra whitespace on this line?  Just wondering why it doesn't
> line up.
> 
[Wei Hu] 
No extra whitespace. It would be over 80 characters if I had put them in one 
line.


RE: [PATCH] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-08-22 Thread Wei Hu
Thanks Michael. See my reply inline to some of your comments.

> -Original Message-
> From: Michael Kelley 
> Sent: Monday, August 19, 2019 6:41 AM
> To: Wei Hu ; rdun...@infradead.org; shc_w...@mail.ru;

> > -   msg.dirt.rect[0].x1 = 0;
> > -   msg.dirt.rect[0].y1 = 0;
> > -   msg.dirt.rect[0].x2 = info->var.xres;
> > -   msg.dirt.rect[0].y2 = info->var.yres;
> > +   msg.dirt.rect[0].x1 = (x1 < 0 || x1 > x2) ? 0 : x1;
> > +   msg.dirt.rect[0].y1 = (y2 < 0 || y1 > y2) ? 0 : y1;
> 
> This should be:
> 
>   msg.dirt.rect[0].y1 = (y1 < 0 || y1 > y2) ? 0 : y1;
> 
> Also, throughout the code, I don't think there are any places where
> x or y coordinate values are ever negative.  INT_MAX or 0 is used as the
> sentinel value indicating "not set".  So can all the tests for less than 0
> now be eliminated, both in this function and in other functions?
> 
> > +   msg.dirt.rect[0].x2 =
> > +   (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
> > +   msg.dirt.rect[0].y2 =
> > +   (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
> 
> How exactly is the dirty rectangle specified to Hyper-V?  Suppose the frame
> buffer resolution is 100x200.  If you want to specify the entire rectangle, 
> the
> first coordinate is (0, 0).  But what is the second coordinate?  Should it be
> (99, 199) or (100, 200)?  The above code (and original code) implies it
> should specified as (100, 200), which is actually a point outside the
> maximum resolution, which is counter-intuitive and makes me wonder
> if the code is correct.
> 
[Wei Hu] 
The current code treat the entire framebuffer rectangle as (0,0) -> (var.xres, 
var.yres).
Every time it sends refresh request, these are two points sent to host and host
seems accept it. See the above (x1, y1) and (x2, y2)  in the deleted lines.

So in your example the second coordinate is (100, 200). 


> > +/* Deferred IO callback */
> > +static void synthvid_deferred_io(struct fb_info *p,
> > +struct list_head *pagelist)
> > +{
> > +   struct hvfb_par *par = p->par;
> > +   struct page *page;
> > +   unsigned long start, end;
> > +   int y1, y2, miny, maxy;
> > +   unsigned long flags;
> > +
> > +   miny = INT_MAX;
> > +   maxy = 0;
> > +
> > +   list_for_each_entry(page, pagelist, lru) {
> > +   start = page->index << PAGE_SHIFT;
> > +   end = start + PAGE_SIZE - 1;
> > +   y1 = start / p->fix.line_length;
> > +   y2 = end / p->fix.line_length;
> 
> The above division rounds down because any remainder is discarded.  I
> wondered whether rounding down is correct, which got me to thinking
> about how the dirty rectangle is specified.  Is y2 the index of the last
> dirty row?  If so, that's not consistent with the code in synthvid_update(),
> which might choose var.yres as y2, and that's the index of a row outside
> of the frame buffer.
> 
[Wei Hu] 
In this place we try to figure out and merge all the faulted pages into one
big dirty rectangle. A page in memory represents one or multiple lines in
frame buffer. For example, one faulted page could represent all the linear 
pixels from (x, y) to (x-1, y+1). In this case we just form the dirty rectangle
as (0, y) -> (var.xres, y+1). Also keep in mind we need to merge multiple
pages. That's why in the end the dirty rectangle is (0, miny) -> (var.xres, 
maxy).


> > +   if (y2 > p->var.yres)
> > +   y2 = p->var.yres;
> > +   miny = min_t(int, miny, y1);
> > +   maxy = max_t(int, maxy, y2);
> > +
> > +   /* Copy from dio space to mmio address */
> > +   if (par->fb_ready) {
> > +   spin_lock_irqsave(&par->docopy_lock, flags);
> > +   hvfb_docopy(par, start, PAGE_SIZE);
> > +   spin_unlock_irqrestore(&par->docopy_lock, flags);
> > +   }
> > +   }
> > +
> > +   if (par->fb_ready)
> > +   synthvid_update(p, 0, miny, p->var.xres, maxy);
> > +}




> > +
> > +   if (j == info->var.yres)
> > +   break;
> > +   hvfb_docopy(par,
> > +   j * info->fix.line_length +
> > +   (x1 * screen_depth / 8),
> > +   (x2 - x1 + 1) * screen_depth / 8);
> 
> Whether the +1 is needed above gets back to the question I
> raised earlier about how to interpret the coordinates -- whether
> the (x2, y2) coordinate is just outside

[PATCH v2] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host

2019-08-21 Thread Wei Hu
Beginning from Windows 10 RS5+, VM screen resolution is obtained from host.
The "video=hyperv_fb" boot time option is not needed, but still can be
used to overwrite what the host specifies. The VM resolution on the host
could be set by executing the powershell "set-vmvideo" command.

v2:
- Implemented fallback when version negotiation failed.
- Defined full size for supported_resolution array.

Signed-off-by: Iouri Tarassov 
Signed-off-by: Wei Hu 
Reviewed-by: Michael Kelley 
---
 drivers/video/fbdev/hyperv_fb.c | 145 +---
 1 file changed, 133 insertions(+), 12 deletions(-)

diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 00f5bdcc6c6f..2ca400c0d621 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -23,6 +23,14 @@
  *
  * Portrait orientation is also supported:
  * For example: video=hyperv_fb:864x1152
+ *
+ * When a Windows 10 RS5+ host is used, the virtual machine screen
+ * resolution is obtained from the host. The "video=hyperv_fb" option is
+ * not needed, but still can be used to overwrite what the host specifies.
+ * The VM resolution on the host could be set by executing the powershell
+ * "set-vmvideo" command. For example
+ * set-vmvideo -vmname name -horizontalresolution:1920 \
+ * -verticalresolution:1200 -resolutiontype single
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -44,6 +52,7 @@
 #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
 #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
 #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
 
 #define SYNTHVID_DEPTH_WIN7 16
 #define SYNTHVID_DEPTH_WIN8 32
@@ -82,16 +91,25 @@ enum synthvid_msg_type {
SYNTHVID_POINTER_SHAPE  = 8,
SYNTHVID_FEATURE_CHANGE = 9,
SYNTHVID_DIRT   = 10,
+   SYNTHVID_RESOLUTION_REQUEST = 13,
+   SYNTHVID_RESOLUTION_RESPONSE= 14,
 
-   SYNTHVID_MAX= 11
+   SYNTHVID_MAX= 15
 };
 
+#defineSYNTHVID_EDID_BLOCK_SIZE128
+#defineSYNTHVID_MAX_RESOLUTION_COUNT   64
+
+struct hvd_screen_info {
+   u16 width;
+   u16 height;
+} __packed;
+
 struct synthvid_msg_hdr {
u32 type;
u32 size;  /* size of this header + payload after this field*/
 } __packed;
 
-
 struct synthvid_version_req {
u32 version;
 } __packed;
@@ -102,6 +120,19 @@ struct synthvid_version_resp {
u8 max_video_outputs;
 } __packed;
 
+struct synthvid_supported_resolution_req {
+   u8 maximum_resolution_count;
+} __packed;
+
+struct synthvid_supported_resolution_resp {
+   u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
+   u8 resolution_count;
+   u8 default_resolution_index;
+   u8 is_standard;
+   struct hvd_screen_info
+   supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
+} __packed;
+
 struct synthvid_vram_location {
u64 user_ctx;
u8 is_vram_gpa_specified;
@@ -187,6 +218,8 @@ struct synthvid_msg {
struct synthvid_pointer_shape ptr_shape;
struct synthvid_feature_change feature_chg;
struct synthvid_dirt dirt;
+   struct synthvid_supported_resolution_req resolution_req;
+   struct synthvid_supported_resolution_resp resolution_resp;
};
 } __packed;
 
@@ -224,6 +257,8 @@ struct hvfb_par {
 
 static uint screen_width = HVFB_WIDTH;
 static uint screen_height = HVFB_HEIGHT;
+static uint screen_width_max = HVFB_WIDTH;
+static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
 
@@ -354,6 +389,7 @@ static void synthvid_recv_sub(struct hv_device *hdev)
 
/* Complete the wait event */
if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
+   msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
complete(&par->wait);
@@ -428,6 +464,64 @@ static int synthvid_negotiate_ver(struct hv_device *hdev, 
u32 ver)
}
 
par->synthvid_version = ver;
+   pr_info("Synthvid Version major %d, minor %d\n",
+   ver & 0x, (ver & 0x) >> 16);
+
+out:
+   return ret;
+}
+
+/* Get current resolution from the host */
+static int synthvid_get_supported_resolution(struct hv_device *hdev)
+{
+   struct fb_info *info = hv_get_drvdata(hdev);
+   struct hvfb_par *par = info->par;
+   struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+   int ret = 0;
+   unsigned long t;
+   u8 index;
+   int i;
+
+   memset(msg, 0, sizeof(struct synthvid_msg));
+   msg->vid_hdr.type = SYNTHVID_

[PATCH] video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver

2019-08-13 Thread Wei Hu
Without deferred IO support, hyperv_fb driver informs the host to refresh
the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
is screen update or not. This patch supports defered IO for screens in
graphic mode and also enables the framme buffer on-demand refresh. The
highest refresh rate is still set at 20Hz.

Due to limitation on Hyper-V host, we keep a shadow copy of frame buffer
in the guest. This means one more copy of the dirty rectangle inside
guest when doing the on-demand refresh. This can be optimized in the
future with help from host. For now the host performance gain from deferred
IO outweighs the shadow copy impact in the guest.

Signed-off-by: Wei Hu 
---
 drivers/video/fbdev/Kconfig |   1 +
 drivers/video/fbdev/hyperv_fb.c | 217 +---
 2 files changed, 198 insertions(+), 20 deletions(-)

diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 1b2f5f31fb6f..e781f89a1824 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2241,6 +2241,7 @@ config FB_HYPERV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+   select FB_DEFERRED_IO
help
  This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
 
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 1042f3311fa2..85198a6ea8e7 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -233,6 +233,7 @@ struct synthvid_msg {
 #define RING_BUFSIZE (256 * 1024)
 #define VSP_TIMEOUT (10 * HZ)
 #define HVFB_UPDATE_DELAY (HZ / 20)
+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
 
 struct hvfb_par {
struct fb_info *info;
@@ -252,6 +253,17 @@ struct hvfb_par {
bool synchronous_fb;
 
struct notifier_block hvfb_panic_nb;
+
+   /* Memory for deferred IO and frame buffer itself */
+   unsigned char *dio_vp;
+   unsigned char *mmio_vp;
+   unsigned long mmio_pp;
+   spinlock_t docopy_lock; /* Lock to protect memory copy */
+
+   /* Dirty rectangle, protected by delayed_refresh_lock */
+   int x1, y1, x2, y2;
+   bool delayed_refresh;
+   spinlock_t delayed_refresh_lock;
 };
 
 static uint screen_width = HVFB_WIDTH;
@@ -260,6 +272,7 @@ static uint screen_width_max = HVFB_WIDTH;
 static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
+static uint dio_fb_size; /* FB size for deferred IO */
 
 /* Send message to Hyper-V host */
 static inline int synthvid_send(struct hv_device *hdev,
@@ -346,28 +359,88 @@ static int synthvid_send_ptr(struct hv_device *hdev)
 }
 
 /* Send updated screen area (dirty rectangle) location to host */
-static int synthvid_update(struct fb_info *info)
+static int
+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
 {
struct hv_device *hdev = device_to_hv_device(info->device);
struct synthvid_msg msg;
 
memset(&msg, 0, sizeof(struct synthvid_msg));
+   if (x2 == INT_MAX)
+   x2 = info->var.xres;
+   if (y2 == INT_MAX)
+   y2 = info->var.yres;
 
msg.vid_hdr.type = SYNTHVID_DIRT;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_dirt);
msg.dirt.video_output = 0;
msg.dirt.dirt_count = 1;
-   msg.dirt.rect[0].x1 = 0;
-   msg.dirt.rect[0].y1 = 0;
-   msg.dirt.rect[0].x2 = info->var.xres;
-   msg.dirt.rect[0].y2 = info->var.yres;
+   msg.dirt.rect[0].x1 = (x1 < 0 || x1 > x2) ? 0 : x1;
+   msg.dirt.rect[0].y1 = (y2 < 0 || y1 > y2) ? 0 : y1;
+   msg.dirt.rect[0].x2 =
+   (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
+   msg.dirt.rect[0].y2 =
+   (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
 
synthvid_send(hdev, &msg);
 
return 0;
 }
 
+static void hvfb_docopy(struct hvfb_par *par,
+   unsigned long offset,
+   unsigned long size)
+{
+   if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
+   size == 0 || offset >= dio_fb_size)
+   return;
+
+   if (offset + size > dio_fb_size)
+   size = dio_fb_size - offset;
+
+   memcpy(par->mmio_vp + offset, par->dio_vp + offset, size);
+}
+
+/* Deferred IO callback */
+static void synthvid_deferred_io(struct fb_info *p,
+struct list_head *pagelist)
+{
+   struct hvfb_par *par = p->par;
+   struct page *page;
+   unsigned long start, end;
+   int y1, y2, miny, maxy;
+   unsigned long flags;
+
+   miny = INT_MAX;
+   maxy = 0;
+
+   list_for_each_entry(page, pagelist, lru) {
+   start = page->index << PAGE_SHIFT;
+   end = start + PAGE_SIZE - 1;
+   y1 = start / p

[PATCH] video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host

2019-08-13 Thread Wei Hu
Beginning from Windows 10 RS5+, VM screen resolution is obtained from host.
The "video=hyperv_fb" boot time option is not needed, but still can be
used to overwrite the VM resolution. The VM resolution on the host could be
set by executing the powershell "set-vmvideo" command.

Signed-off-by: Iouri Tarassov 
Signed-off-by: Wei Hu 
---
 drivers/video/fbdev/hyperv_fb.c | 136 +---
 1 file changed, 125 insertions(+), 11 deletions(-)

diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 00f5bdcc6c6f..1042f3311fa2 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -23,6 +23,14 @@
  *
  * Portrait orientation is also supported:
  * For example: video=hyperv_fb:864x1152
+ *
+ * When a Windows 10 RS5+ host is used, the virtual machine screen
+ * resolution is obtained from the host. The "video=hyperv_fb" option is
+ * not needed, but still can be used to overwrite the VM resolution. The
+ * VM resolution on the host could be set by executing the powershell
+ * "set-vmvideo" command. For example
+ * set-vmvideo -vmname name -horizontalresolution:1920 \
+ * -verticalresolution:1200 -resolutiontype single
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -44,6 +52,7 @@
 #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
 #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
 #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
 
 #define SYNTHVID_DEPTH_WIN7 16
 #define SYNTHVID_DEPTH_WIN8 32
@@ -82,16 +91,25 @@ enum synthvid_msg_type {
SYNTHVID_POINTER_SHAPE  = 8,
SYNTHVID_FEATURE_CHANGE = 9,
SYNTHVID_DIRT   = 10,
+   SYNTHVID_RESOLUTION_REQUEST = 13,
+   SYNTHVID_RESOLUTION_RESPONSE= 14,
 
-   SYNTHVID_MAX= 11
+   SYNTHVID_MAX= 15
 };
 
+#defineSYNTHVID_EDID_BLOCK_SIZE128
+#defineSYNTHVID_MAX_RESOLUTION_COUNT   64
+
+struct hvd_screen_info {
+   u16 width;
+   u16 height;
+} __packed;
+
 struct synthvid_msg_hdr {
u32 type;
u32 size;  /* size of this header + payload after this field*/
 } __packed;
 
-
 struct synthvid_version_req {
u32 version;
 } __packed;
@@ -102,6 +120,18 @@ struct synthvid_version_resp {
u8 max_video_outputs;
 } __packed;
 
+struct synthvid_supported_resolution_req {
+   u8 maximum_resolution_count;
+} __packed;
+
+struct synthvid_supported_resolution_resp {
+   u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
+   u8 resolution_count;
+   u8 default_resolution_index;
+   u8 is_standard;
+   struct hvd_screen_info supported_resolution[1];
+} __packed;
+
 struct synthvid_vram_location {
u64 user_ctx;
u8 is_vram_gpa_specified;
@@ -187,6 +217,8 @@ struct synthvid_msg {
struct synthvid_pointer_shape ptr_shape;
struct synthvid_feature_change feature_chg;
struct synthvid_dirt dirt;
+   struct synthvid_supported_resolution_req resolution_req;
+   struct synthvid_supported_resolution_resp resolution_resp;
};
 } __packed;
 
@@ -224,6 +256,8 @@ struct hvfb_par {
 
 static uint screen_width = HVFB_WIDTH;
 static uint screen_height = HVFB_HEIGHT;
+static uint screen_width_max = HVFB_WIDTH;
+static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
 
@@ -354,6 +388,7 @@ static void synthvid_recv_sub(struct hv_device *hdev)
 
/* Complete the wait event */
if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
+   msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
complete(&par->wait);
@@ -428,6 +463,64 @@ static int synthvid_negotiate_ver(struct hv_device *hdev, 
u32 ver)
}
 
par->synthvid_version = ver;
+   pr_info("Synthvid Version major %d, minor %d\n",
+   ver & 0x, (ver & 0x) >> 16);
+
+out:
+   return ret;
+}
+
+/* Get current resolution from the host */
+static int synthvid_get_supported_resolution(struct hv_device *hdev)
+{
+   struct fb_info *info = hv_get_drvdata(hdev);
+   struct hvfb_par *par = info->par;
+   struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+   int ret = 0;
+   unsigned long t;
+   u8 index;
+   int i;
+
+   memset(msg, 0, sizeof(struct synthvid_msg));
+   msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
+   msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+   sizeof(struct synthvid_supported_resolution_req);
+
+   msg->resolution_req.ma