Page MenuHomeFreeBSD

D55012.diff
No OneTemporary

D55012.diff

diff --git a/sys/dev/virtio/gpu/virtio_gpu.c b/sys/dev/virtio/gpu/virtio_gpu.c
--- a/sys/dev/virtio/gpu/virtio_gpu.c
+++ b/sys/dev/virtio/gpu/virtio_gpu.c
@@ -35,9 +35,13 @@
#include <sys/callout.h>
#include <sys/fbio.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/sglist.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
#include <machine/atomic.h>
#include <machine/bus.h>
@@ -61,6 +65,12 @@
/* The guest can allocate resource IDs, we only need one */
#define VTGPU_RESOURCE_ID 1
+static int vtgpu_width_override = 0;
+static int vtgpu_height_override = 0;
+
+TUNABLE_INT("hw.virtio_gpu.width", &vtgpu_width_override);
+TUNABLE_INT("hw.virtio_gpu.height", &vtgpu_height_override);
+
struct vtgpu_softc {
/* Must be first so we can cast from info -> softc */
struct fb_info vtgpu_fb_info;
@@ -70,9 +80,17 @@
uint64_t vtgpu_features;
struct virtqueue *vtgpu_ctrl_vq;
+ struct mtx vtgpu_mtx;
uint64_t vtgpu_next_fence;
+ struct callout vtgpu_flush_callout;
+ struct task vtgpu_flush_task;
+ bool vtgpu_fb_registered;
+ bool vtgpu_detaching;
+ int vtgpu_refresh_rate; /* FPS for periodic flush */
+ struct sysctl_ctx_list vtgpu_sysctl_ctx;
+
bool vtgpu_have_fb_info;
};
@@ -96,6 +114,11 @@
uint32_t, uint32_t, uint32_t);
static int vtgpu_resource_flush(struct vtgpu_softc *, uint32_t, uint32_t,
uint32_t, uint32_t);
+static void vtgpu_flush_callout_cb(void *);
+static void vtgpu_flush_task_cb(void *, int);
+
+#define VTGPU_DEFAULT_REFRESH_RATE 30
+#define VTGPU_FLUSH_INTERVAL(sc) (hz / (sc)->vtgpu_refresh_rate)
static vd_blank_t vtgpu_fb_blank;
static vd_bitblt_text_t vtgpu_fb_bitblt_text;
@@ -118,7 +141,7 @@
.vd_postswitch = vt_fb_postswitch,
.vd_priority = VD_PRIORITY_GENERIC+10,
.vd_fb_ioctl = vt_fb_ioctl,
- .vd_fb_mmap = NULL, /* No mmap as we need to signal the host */
+ .vd_fb_mmap = vt_fb_mmap, /* mmap with periodic flushes to host */
.vd_suspend = vt_fb_suspend,
.vd_resume = vt_fb_resume,
};
@@ -293,6 +316,13 @@
sc->vtgpu_have_fb_info = false;
sc->vtgpu_dev = dev;
sc->vtgpu_next_fence = 1;
+ sc->vtgpu_detaching = false;
+ sc->vtgpu_fb_registered = false;
+
+ TASK_INIT(&sc->vtgpu_flush_task, 0, vtgpu_flush_task_cb, sc);
+ callout_init(&sc->vtgpu_flush_callout, 1);
+ mtx_init(&sc->vtgpu_mtx, "vtgpu", NULL, MTX_DEF);
+
virtio_set_feature_desc(dev, vtgpu_feature_desc);
error = vtgpu_setup_features(sc);
@@ -317,6 +347,14 @@
goto fail;
}
+ /* Setup sysctl for refresh rate control */
+ sc->vtgpu_refresh_rate = VTGPU_DEFAULT_REFRESH_RATE;
+ sysctl_ctx_init(&sc->vtgpu_sysctl_ctx);
+ SYSCTL_ADD_INT(&sc->vtgpu_sysctl_ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "refresh_rate", CTLFLAG_RW, &sc->vtgpu_refresh_rate, 0,
+ "Framebuffer flush rate in FPS (1-120)");
+
/*
* TODO: This doesn't need to be contigmalloc as we
* can use scatter-gather lists.
@@ -325,6 +363,13 @@
sc->vtgpu_fb_info.fb_size, M_DEVBUF, M_WAITOK|M_ZERO, 0, ~0, 4, 0);
sc->vtgpu_fb_info.fb_pbase = pmap_kextract(sc->vtgpu_fb_info.fb_vbase);
+ /*
+ * Since this is a shadow buffer in regular RAM (not actual GPU VRAM),
+ * use VM_MEMATTR_DEFAULT
+ */
+ sc->vtgpu_fb_info.fb_flags |= FB_FLAG_MEMATTR;
+ sc->vtgpu_fb_info.fb_memattr = VM_MEMATTR_DEFAULT;
+
/* Create the 2d resource */
error = vtgpu_create_2d(sc);
if (error != 0) {
@@ -347,12 +392,34 @@
vt_allocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info);
sc->vtgpu_have_fb_info = true;
+ /* Register framebuffer device so userland can access it via /dev/fb0 */
+ error = fbd_register(&sc->vtgpu_fb_info);
+ if (error != 0 && error != EEXIST) {
+ device_printf(dev, "warning: cannot register /dev/fb device"
+ " (error %d)\n", error);
+ /* Non-fatal - continue without /dev/fbN, console still works */
+ } else {
+ device_printf(dev, "/dev/fb0 created\n");
+ sc->vtgpu_fb_registered = true;
+ }
+
error = vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
sc->vtgpu_fb_info.fb_height);
- if (error != 0)
+ if (error != 0) {
goto fail;
+ }
+
error = vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
sc->vtgpu_fb_info.fb_height);
+ if (error != 0) {
+ goto fail;
+ }
+
+ /* Start the periodic flush mechanism */
+ if (sc->vtgpu_fb_registered== true) {
+ callout_reset(&sc->vtgpu_flush_callout, VTGPU_FLUSH_INTERVAL(sc),
+ vtgpu_flush_callout_cb, sc);
+ }
fail:
if (error != 0)
@@ -367,19 +434,66 @@
struct vtgpu_softc *sc;
sc = device_get_softc(dev);
- if (sc->vtgpu_have_fb_info)
+
+ /* Stop the periodic flush callout and task */
+ sc->vtgpu_detaching = true;
+ callout_drain(&sc->vtgpu_flush_callout);
+ taskqueue_drain(taskqueue_thread, &sc->vtgpu_flush_task);
+
+ /* Unregister the framebuffer device */
+ if (sc->vtgpu_fb_registered) {
+ fbd_unregister(&sc->vtgpu_fb_info);
+ sc->vtgpu_fb_registered = false;
+ }
+
+ if (sc->vtgpu_have_fb_info) {
vt_deallocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info);
+ }
if (sc->vtgpu_fb_info.fb_vbase != 0) {
MPASS(sc->vtgpu_fb_info.fb_size != 0);
free((void *)sc->vtgpu_fb_info.fb_vbase,
M_DEVBUF);
}
+ mtx_destroy(&sc->vtgpu_mtx);
+
+ sysctl_ctx_free(&sc->vtgpu_sysctl_ctx);
+
/* TODO: Tell the host we are detaching */
return (0);
}
+static void
+vtgpu_flush_callout_cb(void *arg)
+{
+ struct vtgpu_softc *sc = arg;
+
+ if (!sc->vtgpu_detaching)
+ taskqueue_enqueue(taskqueue_thread, &sc->vtgpu_flush_task);
+}
+
+static void
+vtgpu_flush_task_cb(void *arg, int pending __unused)
+{
+ struct vtgpu_softc *sc = arg;
+
+ if (sc->vtgpu_detaching)
+ return;
+
+ /* Transfer the entire framebuffer to the host and flush */
+ vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
+ sc->vtgpu_fb_info.fb_height);
+ vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width,
+ sc->vtgpu_fb_info.fb_height);
+
+ /* Reschedule the callout for the next flush */
+ if (!sc->vtgpu_detaching)
+ callout_reset(&sc->vtgpu_flush_callout,
+ VTGPU_FLUSH_INTERVAL(sc),
+ vtgpu_flush_callout_cb, sc);
+}
+
static int
vtgpu_negotiate_features(struct vtgpu_softc *sc)
{
@@ -452,12 +566,15 @@
struct sglist_seg segs[2];
int error;
+ mtx_lock(&sc->vtgpu_mtx);
+
sglist_init(&sg, 2, segs);
error = sglist_append(&sg, req, reqlen);
if (error != 0) {
device_printf(sc->vtgpu_dev,
"Unable to append the request to the sglist: %d\n", error);
+ mtx_unlock(&sc->vtgpu_mtx);
return (error);
}
error = sglist_append(&sg, resp, resplen);
@@ -465,17 +582,21 @@
device_printf(sc->vtgpu_dev,
"Unable to append the response buffer to the sglist: %d\n",
error);
+ mtx_unlock(&sc->vtgpu_mtx);
return (error);
}
error = virtqueue_enqueue(sc->vtgpu_ctrl_vq, resp, &sg, 1, 1);
if (error != 0) {
device_printf(sc->vtgpu_dev, "Enqueue failed: %d\n", error);
+ mtx_unlock(&sc->vtgpu_mtx);
return (error);
}
virtqueue_notify(sc->vtgpu_ctrl_vq);
virtqueue_poll(sc->vtgpu_ctrl_vq, NULL);
+ mtx_unlock(&sc->vtgpu_mtx);
+
return (0);
}
@@ -508,6 +629,18 @@
le32toh(s.resp.pmodes[i].r.width);
sc->vtgpu_fb_info.fb_height =
le32toh(s.resp.pmodes[i].r.height);
+
+ if (vtgpu_width_override > 0 && vtgpu_height_override > 0) {
+ device_printf(sc->vtgpu_dev,
+ "overriding resolution %dx%d -> %dx%d\n",
+ sc->vtgpu_fb_info.fb_width,
+ sc->vtgpu_fb_info.fb_height,
+ vtgpu_width_override,
+ vtgpu_height_override);
+ sc->vtgpu_fb_info.fb_width = vtgpu_width_override;
+ sc->vtgpu_fb_info.fb_height = vtgpu_height_override;
+ }
+
/* 32 bits per pixel */
sc->vtgpu_fb_info.fb_bpp = 32;
sc->vtgpu_fb_info.fb_depth = 32;
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -3370,7 +3370,7 @@
* it is bad idea to replace KMS driver with generic VGA one.
*/
if (drv->vd_priority <= main_vd->vd_driver->vd_priority) {
- printf("VT: Driver priority %d too low. Current %d\n ",
+ printf("VT: Driver priority %d too low. Current %d\n",
drv->vd_priority, main_vd->vd_driver->vd_priority);
return (EEXIST);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Feb 25, 9:27 PM (8 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28995698
Default Alt Text
D55012.diff (8 KB)

Event Timeline