|
Olaf Hering |
cc714a |
From: Wei Hu <weh@microsoft.com>
|
|
Olaf Hering |
cc714a |
Date: Wed, 18 Sep 2019 06:03:20 +0000
|
|
Olaf Hering |
cc714a |
Patch-mainline: v5.5-rc1
|
|
Olaf Hering |
cc714a |
References: bsc#1175306
|
|
Olaf Hering |
cc714a |
Subject: video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver
|
|
Olaf Hering |
cc714a |
Git-commit: d21987d709e807ba7bbf47044deb56a3c02e8be4
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
Without deferred IO support, hyperv_fb driver informs the host to refresh
|
|
Olaf Hering |
cc714a |
the entire guest frame buffer at fixed rate, e.g. at 20Hz, no matter there
|
|
Olaf Hering |
cc714a |
is screen update or not. This patch supports deferred IO for screens in
|
|
Olaf Hering |
cc714a |
graphics mode and also enables the frame buffer on-demand refresh. The
|
|
Olaf Hering |
cc714a |
highest refresh rate is still set at 20Hz.
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
Currently Hyper-V only takes a physical address from guest as the starting
|
|
Olaf Hering |
cc714a |
address of frame buffer. This implies the guest must allocate contiguous
|
|
Olaf Hering |
cc714a |
physical memory for frame buffer. In addition, Hyper-V Gen 2 VMs only
|
|
Olaf Hering |
cc714a |
accept address from MMIO region as frame buffer address. Due to these
|
|
Olaf Hering |
cc714a |
limitations on Hyper-V host, we keep a shadow copy of frame buffer
|
|
Olaf Hering |
cc714a |
in the guest. This means one more copy of the dirty rectangle inside
|
|
Olaf Hering |
cc714a |
guest when doing the on-demand refresh. This can be optimized in the
|
|
Olaf Hering |
cc714a |
future with help from host. For now the host performance gain from deferred
|
|
Olaf Hering |
cc714a |
IO outweighs the shadow copy impact in the guest.
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
Signed-off-by: Wei Hu <weh@microsoft.com>
|
|
Olaf Hering |
cc714a |
Reviewed-by: Dexuan Cui <decui@microsoft.com>
|
|
Olaf Hering |
cc714a |
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
|
|
Olaf Hering |
cc714a |
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
|
Olaf Hering |
cc714a |
Acked-by: Olaf Hering <ohering@suse.de>
|
|
Olaf Hering |
cc714a |
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
|
|
Olaf Hering |
cc714a |
---
|
|
Olaf Hering |
cc714a |
drivers/video/fbdev/Kconfig | 1 +
|
|
Olaf Hering |
cc714a |
drivers/video/fbdev/hyperv_fb.c | 210 ++++++++++++++++++++++++++++++++++++----
|
|
Olaf Hering |
cc714a |
2 files changed, 190 insertions(+), 21 deletions(-)
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
|
|
Olaf Hering |
cc714a |
--- a/drivers/video/fbdev/Kconfig
|
|
Olaf Hering |
cc714a |
+++ b/drivers/video/fbdev/Kconfig
|
|
Olaf Hering |
cc714a |
@@ -2214,6 +2214,7 @@ config FB_HYPERV
|
|
Olaf Hering |
cc714a |
select FB_CFB_FILLRECT
|
|
Olaf Hering |
cc714a |
select FB_CFB_COPYAREA
|
|
Olaf Hering |
cc714a |
select FB_CFB_IMAGEBLIT
|
|
Olaf Hering |
cc714a |
+ select FB_DEFERRED_IO
|
|
Olaf Hering |
cc714a |
help
|
|
Olaf Hering |
cc714a |
This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
|
|
Olaf Hering |
cc714a |
--- a/drivers/video/fbdev/hyperv_fb.c
|
|
Olaf Hering |
cc714a |
+++ b/drivers/video/fbdev/hyperv_fb.c
|
|
Olaf Hering |
cc714a |
@@ -238,6 +238,7 @@ struct synthvid_msg {
|
|
Olaf Hering |
cc714a |
#define RING_BUFSIZE (256 * 1024)
|
|
Olaf Hering |
cc714a |
#define VSP_TIMEOUT (10 * HZ)
|
|
Olaf Hering |
cc714a |
#define HVFB_UPDATE_DELAY (HZ / 20)
|
|
Olaf Hering |
cc714a |
+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
struct hvfb_par {
|
|
Olaf Hering |
cc714a |
struct fb_info *info;
|
|
Olaf Hering |
cc714a |
@@ -258,6 +259,16 @@ struct hvfb_par {
|
|
Olaf Hering |
cc714a |
bool synchronous_fb;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
struct notifier_block hvfb_panic_nb;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Memory for deferred IO and frame buffer itself */
|
|
Olaf Hering |
cc714a |
+ unsigned char *dio_vp;
|
|
Olaf Hering |
cc714a |
+ unsigned char *mmio_vp;
|
|
Olaf Hering |
cc714a |
+ unsigned long mmio_pp;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Dirty rectangle, protected by delayed_refresh_lock */
|
|
Olaf Hering |
cc714a |
+ int x1, y1, x2, y2;
|
|
Olaf Hering |
cc714a |
+ bool delayed_refresh;
|
|
Olaf Hering |
cc714a |
+ spinlock_t delayed_refresh_lock;
|
|
Olaf Hering |
cc714a |
};
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
static uint screen_width = HVFB_WIDTH;
|
|
Olaf Hering |
cc714a |
@@ -266,6 +277,7 @@ static uint screen_width_max = HVFB_WIDTH;
|
|
Olaf Hering |
cc714a |
static uint screen_height_max = HVFB_HEIGHT;
|
|
Olaf Hering |
cc714a |
static uint screen_depth;
|
|
Olaf Hering |
cc714a |
static uint screen_fb_size;
|
|
Olaf Hering |
cc714a |
+static uint dio_fb_size; /* FB size for deferred IO */
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
/* Send message to Hyper-V host */
|
|
Olaf Hering |
cc714a |
static inline int synthvid_send(struct hv_device *hdev,
|
|
Olaf Hering |
cc714a |
@@ -352,28 +364,88 @@ static int synthvid_send_ptr(struct hv_device *hdev)
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
/* Send updated screen area (dirty rectangle) location to host */
|
|
Olaf Hering |
cc714a |
-static int synthvid_update(struct fb_info *info)
|
|
Olaf Hering |
cc714a |
+static int
|
|
Olaf Hering |
cc714a |
+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
|
|
Olaf Hering |
cc714a |
{
|
|
Olaf Hering |
cc714a |
struct hv_device *hdev = device_to_hv_device(info->device);
|
|
Olaf Hering |
cc714a |
struct synthvid_msg msg;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
memset(&msg, 0, sizeof(struct synthvid_msg));
|
|
Olaf Hering |
cc714a |
+ if (x2 == INT_MAX)
|
|
Olaf Hering |
cc714a |
+ x2 = info->var.xres;
|
|
Olaf Hering |
cc714a |
+ if (y2 == INT_MAX)
|
|
Olaf Hering |
cc714a |
+ y2 = info->var.yres;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
msg.vid_hdr.type = SYNTHVID_DIRT;
|
|
Olaf Hering |
cc714a |
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
|
|
Olaf Hering |
cc714a |
sizeof(struct synthvid_dirt);
|
|
Olaf Hering |
cc714a |
msg.dirt.video_output = 0;
|
|
Olaf Hering |
cc714a |
msg.dirt.dirt_count = 1;
|
|
Olaf Hering |
cc714a |
- msg.dirt.rect[0].x1 = 0;
|
|
Olaf Hering |
cc714a |
- msg.dirt.rect[0].y1 = 0;
|
|
Olaf Hering |
cc714a |
- msg.dirt.rect[0].x2 = info->var.xres;
|
|
Olaf Hering |
cc714a |
- msg.dirt.rect[0].y2 = info->var.yres;
|
|
Olaf Hering |
cc714a |
+ msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
|
|
Olaf Hering |
cc714a |
+ msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
|
|
Olaf Hering |
cc714a |
+ msg.dirt.rect[0].x2 =
|
|
Olaf Hering |
cc714a |
+ (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
|
|
Olaf Hering |
cc714a |
+ msg.dirt.rect[0].y2 =
|
|
Olaf Hering |
cc714a |
+ (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
synthvid_send(hdev, &msg;;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
return 0;
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+static void hvfb_docopy(struct hvfb_par *par,
|
|
Olaf Hering |
cc714a |
+ unsigned long offset,
|
|
Olaf Hering |
cc714a |
+ unsigned long size)
|
|
Olaf Hering |
cc714a |
+{
|
|
Olaf Hering |
cc714a |
+ if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
|
|
Olaf Hering |
cc714a |
+ size == 0 || offset >= dio_fb_size)
|
|
Olaf Hering |
cc714a |
+ return;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ if (offset + size > dio_fb_size)
|
|
Olaf Hering |
cc714a |
+ size = dio_fb_size - offset;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ memcpy(par->mmio_vp + offset, par->dio_vp + offset, size);
|
|
Olaf Hering |
cc714a |
+}
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+/* Deferred IO callback */
|
|
Olaf Hering |
cc714a |
+static void synthvid_deferred_io(struct fb_info *p,
|
|
Olaf Hering |
cc714a |
+ struct list_head *pagelist)
|
|
Olaf Hering |
cc714a |
+{
|
|
Olaf Hering |
cc714a |
+ struct hvfb_par *par = p->par;
|
|
Olaf Hering |
cc714a |
+ struct page *page;
|
|
Olaf Hering |
cc714a |
+ unsigned long start, end;
|
|
Olaf Hering |
cc714a |
+ int y1, y2, miny, maxy;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ miny = INT_MAX;
|
|
Olaf Hering |
cc714a |
+ maxy = 0;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /*
|
|
Olaf Hering |
cc714a |
+ * Merge dirty pages. It is possible that last page cross
|
|
Olaf Hering |
cc714a |
+ * over the end of frame buffer row yres. This is taken care of
|
|
Olaf Hering |
cc714a |
+ * in synthvid_update function by clamping the y2
|
|
Olaf Hering |
cc714a |
+ * value to yres.
|
|
Olaf Hering |
cc714a |
+ */
|
|
Olaf Hering |
cc714a |
+ list_for_each_entry(page, pagelist, lru) {
|
|
Olaf Hering |
cc714a |
+ start = page->index << PAGE_SHIFT;
|
|
Olaf Hering |
cc714a |
+ end = start + PAGE_SIZE - 1;
|
|
Olaf Hering |
cc714a |
+ y1 = start / p->fix.line_length;
|
|
Olaf Hering |
cc714a |
+ y2 = end / p->fix.line_length;
|
|
Olaf Hering |
cc714a |
+ miny = min_t(int, miny, y1);
|
|
Olaf Hering |
cc714a |
+ maxy = max_t(int, maxy, y2);
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Copy from dio space to mmio address */
|
|
Olaf Hering |
cc714a |
+ if (par->fb_ready)
|
|
Olaf Hering |
cc714a |
+ hvfb_docopy(par, start, PAGE_SIZE);
|
|
Olaf Hering |
cc714a |
+ }
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ if (par->fb_ready && par->update)
|
|
Olaf Hering |
cc714a |
+ synthvid_update(p, 0, miny, p->var.xres, maxy + 1);
|
|
Olaf Hering |
cc714a |
+}
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+static struct fb_deferred_io synthvid_defio = {
|
|
Olaf Hering |
cc714a |
+ .delay = HZ / 20,
|
|
Olaf Hering |
cc714a |
+ .deferred_io = synthvid_deferred_io,
|
|
Olaf Hering |
cc714a |
+};
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
/*
|
|
Olaf Hering |
cc714a |
* Actions on received messages from host:
|
|
Olaf Hering |
cc714a |
@@ -620,7 +692,7 @@ static int synthvid_send_config(struct hv_device *hdev)
|
|
Olaf Hering |
cc714a |
msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
|
|
Olaf Hering |
cc714a |
msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
|
|
Olaf Hering |
cc714a |
sizeof(struct synthvid_vram_location);
|
|
Olaf Hering |
cc714a |
- msg->vram.user_ctx = msg->vram.vram_gpa = info->fix.smem_start;
|
|
Olaf Hering |
cc714a |
+ msg->vram.user_ctx = msg->vram.vram_gpa = par->mmio_pp;
|
|
Olaf Hering |
cc714a |
msg->vram.is_vram_gpa_specified = 1;
|
|
Olaf Hering |
cc714a |
synthvid_send(hdev, msg);
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
@@ -630,7 +702,7 @@ static int synthvid_send_config(struct hv_device *hdev)
|
|
Olaf Hering |
cc714a |
ret = -ETIMEDOUT;
|
|
Olaf Hering |
cc714a |
goto out;
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
- if (msg->vram_ack.user_ctx != info->fix.smem_start) {
|
|
Olaf Hering |
cc714a |
+ if (msg->vram_ack.user_ctx != par->mmio_pp) {
|
|
Olaf Hering |
cc714a |
pr_err("Unable to set VRAM location\n");
|
|
Olaf Hering |
cc714a |
ret = -ENODEV;
|
|
Olaf Hering |
cc714a |
goto out;
|
|
Olaf Hering |
cc714a |
@@ -647,19 +719,77 @@ out:
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
/*
|
|
Olaf Hering |
cc714a |
* Delayed work callback:
|
|
Olaf Hering |
cc714a |
- * It is called at HVFB_UPDATE_DELAY or longer time interval to process
|
|
Olaf Hering |
cc714a |
- * screen updates. It is re-scheduled if further update is necessary.
|
|
Olaf Hering |
cc714a |
+ * It is scheduled to call whenever update request is received and it has
|
|
Olaf Hering |
cc714a |
+ * not been called in last HVFB_ONDEMAND_THROTTLE time interval.
|
|
Olaf Hering |
cc714a |
*/
|
|
Olaf Hering |
cc714a |
static void hvfb_update_work(struct work_struct *w)
|
|
Olaf Hering |
cc714a |
{
|
|
Olaf Hering |
cc714a |
struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
|
|
Olaf Hering |
cc714a |
struct fb_info *info = par->info;
|
|
Olaf Hering |
cc714a |
+ unsigned long flags;
|
|
Olaf Hering |
cc714a |
+ int x1, x2, y1, y2;
|
|
Olaf Hering |
cc714a |
+ int j;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ spin_lock_irqsave(&par->delayed_refresh_lock, flags);
|
|
Olaf Hering |
cc714a |
+ /* Reset the request flag */
|
|
Olaf Hering |
cc714a |
+ par->delayed_refresh = false;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Store the dirty rectangle to local variables */
|
|
Olaf Hering |
cc714a |
+ x1 = par->x1;
|
|
Olaf Hering |
cc714a |
+ x2 = par->x2;
|
|
Olaf Hering |
cc714a |
+ y1 = par->y1;
|
|
Olaf Hering |
cc714a |
+ y2 = par->y2;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Clear dirty rectangle */
|
|
Olaf Hering |
cc714a |
+ par->x1 = par->y1 = INT_MAX;
|
|
Olaf Hering |
cc714a |
+ par->x2 = par->y2 = 0;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ if (x1 > info->var.xres || x2 > info->var.xres ||
|
|
Olaf Hering |
cc714a |
+ y1 > info->var.yres || y2 > info->var.yres || x2 <= x1)
|
|
Olaf Hering |
cc714a |
+ return;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Copy the dirty rectangle to frame buffer memory */
|
|
Olaf Hering |
cc714a |
+ for (j = y1; j < y2; j++) {
|
|
Olaf Hering |
cc714a |
+ hvfb_docopy(par,
|
|
Olaf Hering |
cc714a |
+ j * info->fix.line_length +
|
|
Olaf Hering |
cc714a |
+ (x1 * screen_depth / 8),
|
|
Olaf Hering |
cc714a |
+ (x2 - x1) * screen_depth / 8);
|
|
Olaf Hering |
cc714a |
+ }
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Refresh */
|
|
Olaf Hering |
cc714a |
+ if (par->fb_ready && par->update)
|
|
Olaf Hering |
cc714a |
+ synthvid_update(info, x1, y1, x2, y2);
|
|
Olaf Hering |
cc714a |
+}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
- if (par->fb_ready)
|
|
Olaf Hering |
cc714a |
- synthvid_update(info);
|
|
Olaf Hering |
cc714a |
+/*
|
|
Olaf Hering |
cc714a |
+ * Control the on-demand refresh frequency. It schedules a delayed
|
|
Olaf Hering |
cc714a |
+ * screen update if it has not yet.
|
|
Olaf Hering |
cc714a |
+ */
|
|
Olaf Hering |
cc714a |
+static void hvfb_ondemand_refresh_throttle(struct hvfb_par *par,
|
|
Olaf Hering |
cc714a |
+ int x1, int y1, int w, int h)
|
|
Olaf Hering |
cc714a |
+{
|
|
Olaf Hering |
cc714a |
+ unsigned long flags;
|
|
Olaf Hering |
cc714a |
+ int x2 = x1 + w;
|
|
Olaf Hering |
cc714a |
+ int y2 = y1 + h;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ spin_lock_irqsave(&par->delayed_refresh_lock, flags);
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Merge dirty rectangle */
|
|
Olaf Hering |
cc714a |
+ par->x1 = min_t(int, par->x1, x1);
|
|
Olaf Hering |
cc714a |
+ par->y1 = min_t(int, par->y1, y1);
|
|
Olaf Hering |
cc714a |
+ par->x2 = max_t(int, par->x2, x2);
|
|
Olaf Hering |
cc714a |
+ par->y2 = max_t(int, par->y2, y2);
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
+ /* Schedule a delayed screen update if not yet */
|
|
Olaf Hering |
cc714a |
+ if (par->delayed_refresh == false) {
|
|
Olaf Hering |
cc714a |
+ schedule_delayed_work(&par->dwork,
|
|
Olaf Hering |
cc714a |
+ HVFB_ONDEMAND_THROTTLE);
|
|
Olaf Hering |
cc714a |
+ par->delayed_refresh = true;
|
|
Olaf Hering |
cc714a |
+ }
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
- if (par->update)
|
|
Olaf Hering |
cc714a |
- schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
|
|
Olaf Hering |
cc714a |
+ spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
static int hvfb_on_panic(struct notifier_block *nb,
|
|
Olaf Hering |
cc714a |
@@ -671,7 +801,8 @@ static int hvfb_on_panic(struct notifier_block *nb,
|
|
Olaf Hering |
cc714a |
par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
|
|
Olaf Hering |
cc714a |
par->synchronous_fb = true;
|
|
Olaf Hering |
cc714a |
info = par->info;
|
|
Olaf Hering |
cc714a |
- synthvid_update(info);
|
|
Olaf Hering |
cc714a |
+ hvfb_docopy(par, 0, dio_fb_size);
|
|
Olaf Hering |
cc714a |
+ synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
return NOTIFY_DONE;
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
@@ -732,7 +863,10 @@ static void hvfb_cfb_fillrect(struct fb_info *p,
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
cfb_fillrect(p, rect);
|
|
Olaf Hering |
cc714a |
if (par->synchronous_fb)
|
|
Olaf Hering |
cc714a |
- synthvid_update(p);
|
|
Olaf Hering |
cc714a |
+ synthvid_update(p, 0, 0, INT_MAX, INT_MAX);
|
|
Olaf Hering |
cc714a |
+ else
|
|
Olaf Hering |
cc714a |
+ hvfb_ondemand_refresh_throttle(par, rect->dx, rect->dy,
|
|
Olaf Hering |
cc714a |
+ rect->width, rect->height);
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
static void hvfb_cfb_copyarea(struct fb_info *p,
|
|
Olaf Hering |
cc714a |
@@ -742,7 +876,10 @@ static void hvfb_cfb_copyarea(struct fb_info *p,
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
cfb_copyarea(p, area);
|
|
Olaf Hering |
cc714a |
if (par->synchronous_fb)
|
|
Olaf Hering |
cc714a |
- synthvid_update(p);
|
|
Olaf Hering |
cc714a |
+ synthvid_update(p, 0, 0, INT_MAX, INT_MAX);
|
|
Olaf Hering |
cc714a |
+ else
|
|
Olaf Hering |
cc714a |
+ hvfb_ondemand_refresh_throttle(par, area->dx, area->dy,
|
|
Olaf Hering |
cc714a |
+ area->width, area->height);
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
static void hvfb_cfb_imageblit(struct fb_info *p,
|
|
Olaf Hering |
cc714a |
@@ -752,7 +889,10 @@ static void hvfb_cfb_imageblit(struct fb_info *p,
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
cfb_imageblit(p, image);
|
|
Olaf Hering |
cc714a |
if (par->synchronous_fb)
|
|
Olaf Hering |
cc714a |
- synthvid_update(p);
|
|
Olaf Hering |
cc714a |
+ synthvid_update(p, 0, 0, INT_MAX, INT_MAX);
|
|
Olaf Hering |
cc714a |
+ else
|
|
Olaf Hering |
cc714a |
+ hvfb_ondemand_refresh_throttle(par, image->dx, image->dy,
|
|
Olaf Hering |
cc714a |
+ image->width, image->height);
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
static struct fb_ops hvfb_ops = {
|
|
Olaf Hering |
cc714a |
@@ -811,6 +951,9 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
|
|
Olaf Hering |
cc714a |
resource_size_t pot_start, pot_end;
|
|
Olaf Hering |
cc714a |
int ret;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+ dio_fb_size =
|
|
Olaf Hering |
cc714a |
+ screen_width * screen_height * screen_depth / 8;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
if (gen2vm) {
|
|
Olaf Hering |
cc714a |
pot_start = 0;
|
|
Olaf Hering |
cc714a |
pot_end = -1;
|
|
Olaf Hering |
cc714a |
@@ -845,9 +988,14 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
|
|
Olaf Hering |
cc714a |
if (!fb_virt)
|
|
Olaf Hering |
cc714a |
goto err2;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+ /* Allocate memory for deferred IO */
|
|
Olaf Hering |
cc714a |
+ par->dio_vp = vzalloc(round_up(dio_fb_size, PAGE_SIZE));
|
|
Olaf Hering |
cc714a |
+ if (par->dio_vp == NULL)
|
|
Olaf Hering |
cc714a |
+ goto err3;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
info->apertures = alloc_apertures(1);
|
|
Olaf Hering |
cc714a |
if (!info->apertures)
|
|
Olaf Hering |
cc714a |
- goto err3;
|
|
Olaf Hering |
cc714a |
+ goto err4;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
if (gen2vm) {
|
|
Olaf Hering |
cc714a |
info->apertures->ranges[0].base = screen_info.lfb_base;
|
|
Olaf Hering |
cc714a |
@@ -859,16 +1007,23 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
|
|
Olaf Hering |
cc714a |
info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
|
|
Olaf Hering |
cc714a |
}
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+ /* Physical address of FB device */
|
|
Olaf Hering |
cc714a |
+ par->mmio_pp = par->mem->start;
|
|
Olaf Hering |
cc714a |
+ /* Virtual address of FB device */
|
|
Olaf Hering |
cc714a |
+ par->mmio_vp = (unsigned char *) fb_virt;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
info->fix.smem_start = par->mem->start;
|
|
Olaf Hering |
cc714a |
- info->fix.smem_len = screen_fb_size;
|
|
Olaf Hering |
cc714a |
- info->screen_base = fb_virt;
|
|
Olaf Hering |
cc714a |
- info->screen_size = screen_fb_size;
|
|
Olaf Hering |
cc714a |
+ info->fix.smem_len = dio_fb_size;
|
|
Olaf Hering |
cc714a |
+ info->screen_base = par->dio_vp;
|
|
Olaf Hering |
cc714a |
+ info->screen_size = dio_fb_size;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
if (!gen2vm)
|
|
Olaf Hering |
cc714a |
pci_dev_put(pdev);
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
return 0;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+err4:
|
|
Olaf Hering |
cc714a |
+ vfree(par->dio_vp);
|
|
Olaf Hering |
cc714a |
err3:
|
|
Olaf Hering |
cc714a |
iounmap(fb_virt);
|
|
Olaf Hering |
cc714a |
err2:
|
|
Olaf Hering |
cc714a |
@@ -886,6 +1041,7 @@ static void hvfb_putmem(struct fb_info *info)
|
|
Olaf Hering |
cc714a |
{
|
|
Olaf Hering |
cc714a |
struct hvfb_par *par = info->par;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+ vfree(par->dio_vp);
|
|
Olaf Hering |
cc714a |
iounmap(info->screen_base);
|
|
Olaf Hering |
cc714a |
vmbus_free_mmio(par->mem->start, screen_fb_size);
|
|
Olaf Hering |
cc714a |
par->mem = NULL;
|
|
Olaf Hering |
cc714a |
@@ -909,6 +1065,11 @@ static int hvfb_probe(struct hv_device *hdev,
|
|
Olaf Hering |
cc714a |
init_completion(&par->wait);
|
|
Olaf Hering |
cc714a |
INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+ par->delayed_refresh = false;
|
|
Olaf Hering |
cc714a |
+ spin_lock_init(&par->delayed_refresh_lock);
|
|
Olaf Hering |
cc714a |
+ par->x1 = par->y1 = INT_MAX;
|
|
Olaf Hering |
cc714a |
+ par->x2 = par->y2 = 0;
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
/* Connect to VSP */
|
|
Olaf Hering |
cc714a |
hv_set_drvdata(hdev, info);
|
|
Olaf Hering |
cc714a |
ret = synthvid_connect_vsp(hdev);
|
|
Olaf Hering |
cc714a |
@@ -960,6 +1121,10 @@ static int hvfb_probe(struct hv_device *hdev,
|
|
Olaf Hering |
cc714a |
info->fbops = &hvfb_ops;
|
|
Olaf Hering |
cc714a |
info->pseudo_palette = par->pseudo_palette;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+ /* Initialize deferred IO */
|
|
Olaf Hering |
cc714a |
+ info->fbdefio = &synthvid_defio;
|
|
Olaf Hering |
cc714a |
+ fb_deferred_io_init(info);
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
/* Send config to host */
|
|
Olaf Hering |
cc714a |
ret = synthvid_send_config(hdev);
|
|
Olaf Hering |
cc714a |
if (ret)
|
|
Olaf Hering |
cc714a |
@@ -981,6 +1146,7 @@ static int hvfb_probe(struct hv_device *hdev,
|
|
Olaf Hering |
cc714a |
return 0;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
error:
|
|
Olaf Hering |
cc714a |
+ fb_deferred_io_cleanup(info);
|
|
Olaf Hering |
cc714a |
hvfb_putmem(info);
|
|
Olaf Hering |
cc714a |
error2:
|
|
Olaf Hering |
cc714a |
vmbus_close(hdev->channel);
|
|
Olaf Hering |
cc714a |
@@ -1003,6 +1169,8 @@ static int hvfb_remove(struct hv_device *hdev)
|
|
Olaf Hering |
cc714a |
par->update = false;
|
|
Olaf Hering |
cc714a |
par->fb_ready = false;
|
|
Olaf Hering |
cc714a |
|
|
Olaf Hering |
cc714a |
+ fb_deferred_io_cleanup(info);
|
|
Olaf Hering |
cc714a |
+
|
|
Olaf Hering |
cc714a |
unregister_framebuffer(info);
|
|
Olaf Hering |
cc714a |
cancel_delayed_work_sync(&par->dwork);
|
|
Olaf Hering |
cc714a |
|