Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F171348802
D55012.id178333.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D55012.id178333.diff
View Options
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,14 @@
/* 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;
+static int vtgpu_flush_enabled = 0;
+
+TUNABLE_INT("hw.virtio_gpu.width", &vtgpu_width_override);
+TUNABLE_INT("hw.virtio_gpu.height", &vtgpu_height_override);
+TUNABLE_INT("hw.virtio_gpu.flush_enabled", &vtgpu_flush_enabled);
+
struct vtgpu_softc {
/* Must be first so we can cast from info -> softc */
struct fb_info vtgpu_fb_info;
@@ -70,9 +82,18 @@
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;
+ bool vtgpu_flush_enabled; /* periodic flush on/off */
+ int vtgpu_refresh_rate; /* FPS for periodic flush */
+ struct sysctl_ctx_list vtgpu_sysctl_ctx;
+
bool vtgpu_have_fb_info;
};
@@ -81,6 +102,7 @@
static int vtgpu_probe(device_t);
static int vtgpu_attach(device_t);
static int vtgpu_detach(device_t);
+static int vtgpu_shutdown(device_t);
static int vtgpu_negotiate_features(struct vtgpu_softc *);
static int vtgpu_setup_features(struct vtgpu_softc *);
@@ -96,6 +118,13 @@
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);
+static int vtgpu_sysctl_refresh_rate(SYSCTL_HANDLER_ARGS);
+
+#define VTGPU_DEFAULT_REFRESH_RATE 30
+#define VTGPU_FLUSH_INTERVAL(sc) \
+ (hz / ((sc)->vtgpu_refresh_rate > 0 ? (sc)->vtgpu_refresh_rate : 1))
static vd_blank_t vtgpu_fb_blank;
static vd_bitblt_text_t vtgpu_fb_bitblt_text;
@@ -103,6 +132,7 @@
static vd_drawrect_t vtgpu_fb_drawrect;
static vd_setpixel_t vtgpu_fb_setpixel;
static vd_bitblt_argb_t vtgpu_fb_bitblt_argb;
+static vd_fb_mmap_t vtgpu_fb_mmap;
static struct vt_driver vtgpu_fb_driver = {
.vd_name = "virtio_gpu",
@@ -118,7 +148,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 = vtgpu_fb_mmap,
.vd_suspend = vt_fb_suspend,
.vd_resume = vt_fb_resume,
};
@@ -226,6 +256,23 @@
vtgpu_resource_flush(sc, x, y, 1, 1);
}
+static int
+vtgpu_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
+ int prot, vm_memattr_t *memattr)
+{
+ struct vtgpu_softc *sc;
+ struct fb_info *info;
+
+ info = vd->vd_softc;
+ sc = (struct vtgpu_softc *)info;
+
+ /* Deny mmap when periodic flush is not active */
+ if (!sc->vtgpu_flush_enabled)
+ return (ENODEV);
+
+ return (vt_fb_mmap(vd, offset, paddr, prot, memattr));
+}
+
static struct virtio_feature_desc vtgpu_feature_desc[] = {
{ VIRTIO_GPU_F_VIRGL, "VirGL" },
{ VIRTIO_GPU_F_EDID, "EDID" },
@@ -240,6 +287,7 @@
DEVMETHOD(device_probe, vtgpu_probe),
DEVMETHOD(device_attach, vtgpu_attach),
DEVMETHOD(device_detach, vtgpu_detach),
+ DEVMETHOD(device_shutdown, vtgpu_shutdown),
DEVMETHOD_END
};
@@ -293,6 +341,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 +372,21 @@
goto fail;
}
+ sc->vtgpu_refresh_rate = VTGPU_DEFAULT_REFRESH_RATE;
+ sc->vtgpu_flush_enabled = vtgpu_flush_enabled ? true : false;
+ sysctl_ctx_init(&sc->vtgpu_sysctl_ctx);
+ SYSCTL_ADD_INT(&sc->vtgpu_sysctl_ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "flush_enabled", CTLFLAG_RD, &vtgpu_flush_enabled, 0,
+ "Periodic framebuffer flush");
+ if (sc->vtgpu_flush_enabled) {
+ SYSCTL_ADD_PROC(&sc->vtgpu_sysctl_ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "refresh_rate", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, vtgpu_sysctl_refresh_rate, "I",
+ "Framebuffer flush rate in FPS");
+ }
+
/*
* TODO: This doesn't need to be contigmalloc as we
* can use scatter-gather lists.
@@ -325,6 +395,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 +424,29 @@
vt_allocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info);
sc->vtgpu_have_fb_info = true;
+ 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);
+ } 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)
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 enabled */
+ if (sc->vtgpu_fb_registered && sc->vtgpu_flush_enabled) {
+ callout_reset(&sc->vtgpu_flush_callout, VTGPU_FLUSH_INTERVAL(sc),
+ vtgpu_flush_callout_cb, sc);
+ }
fail:
if (error != 0)
@@ -367,19 +461,101 @@
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 int
+vtgpu_shutdown(device_t dev)
+{
+ struct vtgpu_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ sc->vtgpu_detaching = true;
+ callout_drain(&sc->vtgpu_flush_callout);
+ taskqueue_drain(taskqueue_thread, &sc->vtgpu_flush_task);
+
+ return (0);
+}
+
+static int
+vtgpu_sysctl_refresh_rate(SYSCTL_HANDLER_ARGS)
+{
+ struct vtgpu_softc *sc = arg1;
+ int rate = sc->vtgpu_refresh_rate;
+ int error;
+
+ error = sysctl_handle_int(oidp, &rate, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ if (!sc->vtgpu_flush_enabled)
+ return (EPERM);
+
+ if (rate < 1 || rate > 120)
+ return (EINVAL);
+
+ sc->vtgpu_refresh_rate = rate;
+ return (0);
+}
+
+static void
+vtgpu_flush_callout_cb(void *arg)
+{
+ struct vtgpu_softc *sc = arg;
+
+ if (!sc->vtgpu_detaching && sc->vtgpu_flush_enabled)
+ 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 && sc->vtgpu_flush_enabled)
+ 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,6 +628,8 @@
struct sglist_seg segs[3];
int error, rcount;
+ mtx_lock(&sc->vtgpu_mtx);
+
sglist_init(&sg, 3, segs);
rcount = 1;
@@ -460,6 +638,7 @@
device_printf(sc->vtgpu_dev,
"Unable to append the request to the sglist: %d\n",
error);
+ mtx_unlock(&sc->vtgpu_mtx);
return (error);
}
if (req2 != NULL) {
@@ -468,6 +647,7 @@
device_printf(sc->vtgpu_dev,
"Unable to append the request to the sglist: %d\n",
error);
+ mtx_unlock(&sc->vtgpu_mtx);
return (error);
}
rcount++;
@@ -477,17 +657,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, rcount, 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);
}
@@ -527,6 +711,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
@@ -3408,7 +3408,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
Details
Attached
Mime Type
text/plain
Expires
Fri, Sep 11, 2:42 PM (4 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38711555
Default Alt Text
D55012.id178333.diff (10 KB)
Attached To
Mode
D55012: virtio_gpu: add support for xf86-video-scfb
Attached
Detach File
Event Timeline
Log In to Comment