public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Val Packett <val@invisiblethingslab.com>
To: "Michael S. Tsirkin" <mst@redhat.com>,
	"Jason Wang" <jasowang@redhat.com>,
	"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
	"Eugenio Pérez" <eperezma@redhat.com>
Cc: "Val Packett" <val@invisiblethingslab.com>,
	"Marek Marczykowski-Górecki" <marmarek@invisiblethingslab.com>,
	"Viresh Kumar" <viresh.kumar@linaro.org>,
	xen-devel@lists.xenproject.org, linux-kernel@vger.kernel.org,
	virtualization@lists.linux.dev
Subject: [RFC PATCH] virtio-mmio: add xenbus probing
Date: Wed, 29 Apr 2026 10:52:17 -0300	[thread overview]
Message-ID: <20260429141339.74472-1-val@invisiblethingslab.com> (raw)

The experimental virtio-mmio support for Xen was initially developed
on aarch64, so device trees were used to configure the mmio devices,
with arbitrary vGIC interrupts used by the hypervisor. On x86_64
however, the only reasonable way to interrupt the guest is over Xen
event channels, which can only be acquired by children of xenbus,
the virtual bus driven by Xen's configuration database, XenStore.
It is also a more convenient and "Xen-ish" way to provision devices.

Implement a xenbus client for virtio-mmio which negotiates an
event channel and provides it as a platform IRQ to the
virtio-mmio driver.


Signed-off-by: Val Packett <val@invisiblethingslab.com>
---

Hi,

I've been working on porting virtio-mmio support from Arm to x86_64,
with the goal of running vhost-user-gpu to power Wayland/GPU integration
for Qubes OS. (I'm aware of various proposals for alternative virtio
transports but virtio-mmio seems to be the only one that *is* upstream
already and just Works..) Setting up virtio-mmio through xenbus, initially
motivated just by event channels being the only real way to get interrupts
working on HVM, turned out to generally be quite pleasant and nice :)

I'd like to get some early feedback for this patch, particularly
the general stuff:

* is this whole thing acceptable in general?
* should it be extracted into a different file?
* (from the Xen side) any input on the xenstore keys, what goes where?
* anything else to keep in mind?

It does seem simple enough, so hopefully this can be done?

The corresponding userspace-side WIP is available at:
https://github.com/QubesOS/xen-vhost-frontend

And the required DMOP for firing the evtchn events will be sent
to xen-devel shortly as well.

Thanks,
~val

---
 drivers/virtio/Kconfig       |   7 ++
 drivers/virtio/virtio_mmio.c | 177 ++++++++++++++++++++++++++++++++++-
 2 files changed, 183 insertions(+), 1 deletion(-)

diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index ce5bc0d9ea28..56bc2b10526b 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -171,6 +171,13 @@ config VIRTIO_MMIO_CMDLINE_DEVICES
 
 	 If unsure, say 'N'.
 
+config VIRTIO_MMIO_XENBUS
+	bool "Memory mapped virtio devices parameter parsing"
+	depends on VIRTIO_MMIO && XEN
+	select XEN_XENBUS_FRONTEND
+	help
+	 Allow virtio-mmio devices instantiation for Xen guests via xenbus.
+
 config VIRTIO_DMA_SHARED_BUFFER
 	tristate
 	depends on DMA_SHARED_BUFFER
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 595c2274fbb5..32295284bdbf 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -70,6 +70,11 @@
 #include <uapi/linux/virtio_mmio.h>
 #include <linux/virtio_ring.h>
 
+#ifdef CONFIG_VIRTIO_MMIO_XENBUS
+#include <xen/xen.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#endif
 
 
 /* The alignment to use between consumer and producer parts of vring.
@@ -810,13 +815,183 @@ static struct platform_driver virtio_mmio_driver = {
 	},
 };
 
+#ifdef CONFIG_VIRTIO_MMIO_XENBUS
+struct virtio_mmio_xen_info {
+	struct resource resources[2];
+	unsigned int evtchn;
+	struct platform_device *pdev;
+};
+
+static int virtio_mmio_xen_probe(struct xenbus_device *dev,
+			const struct xenbus_device_id *id)
+{
+	int err;
+	long long base, size;
+	char *mem;
+	struct virtio_mmio_xen_info *info;
+	struct xenbus_transaction xbt;
+
+	/* TODO: allocate an unused address here and pass it to the host instead */
+	err = xenbus_scanf(XBT_NIL, dev->otherend, "base", "0x%llx",
+			   &base);
+	if (err < 0) {
+		xenbus_dev_fatal(dev, err, "reading base");
+		return -EINVAL;
+	}
+
+	mem = xenbus_read(XBT_NIL, dev->otherend, "size", NULL);
+	if (XENBUS_IS_ERR_READ(mem))
+		return PTR_ERR(mem);
+	size = memparse(mem, NULL);
+	kfree(mem);
+
+	info = kzalloc_obj(*info);
+	if (!info) {
+		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+		return -ENOMEM;
+	}
+
+	info->resources[0].flags = IORESOURCE_MEM;
+	info->resources[0].start = base;
+	info->resources[0].end = base + size - 1;
+
+	err = xenbus_alloc_evtchn(dev, &info->evtchn);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "xenbus_alloc_evtchn");
+		goto error_info;
+	}
+
+	err = bind_evtchn_to_irq(info->evtchn);
+	if (err <= 0) {
+		xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq");
+		goto error_evtchan;
+	}
+
+	info->resources[1].flags = IORESOURCE_IRQ;
+	info->resources[1].start = info->resources[1].end = err;
+
+again:
+	err = xenbus_transaction_start(&xbt);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "starting transaction");
+		goto error_irq;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+			    info->evtchn);
+	if (err) {
+		xenbus_transaction_end(xbt, 1);
+		xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+		goto error_irq;
+	}
+
+	err = xenbus_transaction_end(xbt, 0);
+	if (err) {
+		if (err == -EAGAIN)
+			goto again;
+		xenbus_dev_fatal(dev, err, "completing transaction");
+		goto error_irq;
+	}
+
+	dev_set_drvdata(&dev->dev, info);
+	xenbus_switch_state(dev, XenbusStateInitialised);
+	return 0;
+
+error_irq:
+	unbind_from_irqhandler(info->resources[1].start, info);
+error_evtchan:
+	xenbus_free_evtchn(dev, info->evtchn);
+error_info:
+	kfree(info);
+
+	return err;
+}
+
+static void virtio_mmio_xen_backend_changed(struct xenbus_device *dev,
+				   enum xenbus_state backend_state)
+{
+	struct virtio_mmio_xen_info *info = dev_get_drvdata(&dev->dev);
+
+	switch (backend_state) {
+	case XenbusStateInitialising:
+	case XenbusStateInitWait:
+	case XenbusStateInitialised:
+	case XenbusStateReconfiguring:
+	case XenbusStateReconfigured:
+	case XenbusStateUnknown:
+		break;
+
+	case XenbusStateConnected:
+		if (dev->state != XenbusStateInitialised) {
+			dev_warn(&dev->dev, "state %d on connect", dev->state);
+			break;
+		}
+		info->pdev = platform_device_register_resndata(&dev->dev,
+				"virtio-mmio", PLATFORM_DEVID_AUTO,
+				info->resources, ARRAY_SIZE(info->resources), NULL, 0);
+		xenbus_switch_state(dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosed:
+		if (dev->state == XenbusStateClosed)
+			break;
+		fallthrough;	/* Missed the backend's Closing state. */
+	case XenbusStateClosing:
+		platform_device_unregister(info->pdev);
+		xenbus_switch_state(dev, XenbusStateClosed);
+		break;
+
+	default:
+		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+				 backend_state);
+		break;
+	}
+}
+
+static void virtio_mmio_xen_remove(struct xenbus_device *dev)
+{
+	struct virtio_mmio_xen_info *info = dev_get_drvdata(&dev->dev);
+
+	kfree(info);
+	dev_set_drvdata(&dev->dev, NULL);
+}
+
+static const struct xenbus_device_id virtio_mmio_xen_ids[] = {
+	{ "virtio" },
+	{ "" },
+};
+
+static struct xenbus_driver virtio_mmio_xen_driver = {
+	.ids			= virtio_mmio_xen_ids,
+	.probe			= virtio_mmio_xen_probe,
+	.otherend_changed	= virtio_mmio_xen_backend_changed,
+	.remove			= virtio_mmio_xen_remove,
+};
+#endif
+
 static int __init virtio_mmio_init(void)
 {
-	return platform_driver_register(&virtio_mmio_driver);
+	int ret;
+
+	ret = platform_driver_register(&virtio_mmio_driver);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_VIRTIO_MMIO_XENBUS
+	if (xen_domain())
+		ret = xenbus_register_frontend(&virtio_mmio_xen_driver);
+#endif
+
+	return ret;
 }
 
 static void __exit virtio_mmio_exit(void)
 {
+#ifdef CONFIG_VIRTIO_MMIO_XENBUS
+	if (xen_domain())
+		xenbus_unregister_driver(&virtio_mmio_xen_driver);
+#endif
+
 	platform_driver_unregister(&virtio_mmio_driver);
 	vm_unregister_cmdline_devices();
 }
-- 
2.53.0


             reply	other threads:[~2026-04-29 14:14 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-29 13:52 Val Packett [this message]
2026-04-29 15:35 ` [RFC PATCH] virtio-mmio: add xenbus probing Jürgen Groß
2026-04-30  4:04   ` Val Packett
     [not found] ` <1777473712.8631fc262581453bbf619ec5b2062170.19dd9b07146000f373@vates.tech>
2026-04-30  4:01   ` Val Packett
     [not found]     ` <1777536698.8631fc262581453bbf619ec5b2062170.19ddd7187da000f373@vates.tech>
2026-04-30  8:48       ` Val Packett
     [not found]         ` <1777556830.8631fc262581453bbf619ec5b2062170.19ddea4b728000f373@vates.tech>
2026-04-30 18:50           ` Val Packett

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260429141339.74472-1-val@invisiblethingslab.com \
    --to=val@invisiblethingslab.com \
    --cc=eperezma@redhat.com \
    --cc=jasowang@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marmarek@invisiblethingslab.com \
    --cc=mst@redhat.com \
    --cc=viresh.kumar@linaro.org \
    --cc=virtualization@lists.linux.dev \
    --cc=xen-devel@lists.xenproject.org \
    --cc=xuanzhuo@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox