Skip to contentSkip to conversation

virtio implementation (draft VI)

PATCH In review Rusty Russell 10 participants 39 messages Sep 24, 2007 – Sep 26, 2007 15 messages not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover virtio implementation (draft VI)

I'm not reposting the drivers this time since they haven't changed significantly. See http://lguest.ozlabs.org/patches for the whole thing, from new-io.patch onwards).

Changes since last version:
- Switch to our own bus implementation, rather than relying on an implementation-specific bus to back this up.

- Make virtio_config_ops much higher-level, don't assume layout of config space.

- Expose "struct virtqueue" again and move ops inside that.

- virtio_ring uses 64 bit address, 32 bit length, not addr64 + offset16 + len16.

- flags in virtio_ring to allow suppression of interrupts (by guest) or notifications (by host).

I'm not too unhappy with this as it stands. Feedback welcome!

Cheers,
Rusty.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190625194.27805.199.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#2 lore raw

PATCH 1/3 virtio interface

This attempts to implement a "virtual I/O" layer which should allow common drivers to be efficiently used across most virtual I/O mechanisms. It will no-doubt need further enhancement.

The virtio drivers add buffers to virtio queues; as the buffers are consumed the driver "interrupt" callbacks are invoked.

There is also a generic implementation of config space which drivers can query to get setup information from the host.

---
 drivers/Kconfig                 |    2 
 drivers/Makefile                |    1 
 drivers/virtio/Kconfig          |    3 
 drivers/virtio/Makefile         |    1 
 drivers/virtio/config.c         |   13 ++
 drivers/virtio/virtio.c         |  187 +++++++++++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h |    6 +
 include/linux/virtio.h          |  110 ++++++++++++++++++++++
 include/linux/virtio_config.h   |  111 +++++++++++++++++++++++
 9 files changed, 434 insertions(+)

===================================================================

drivers/Kconfig +2 -0
@@ -87,4 +87,6 @@ source "drivers/kvm/Kconfig"
 source "drivers/kvm/Kconfig"
 
 source "drivers/uio/Kconfig"
+
+source "drivers/virtio/Kconfig"
 endmenu

===================================================================

drivers/Makefile +1 -0
@@ -88,3 +88,4 @@ obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
 obj-$(CONFIG_OF)		+= of/
+obj-$(CONFIG_VIRTIO)		+= virtio/

===================================================================

drivers/virtio/Kconfig new file +3 -0
@@ -0,0 +1,3 @@
+# Virtio always gets selected by whoever wants it.
+config VIRTIO
+	bool

===================================================================

drivers/virtio/Makefile new file +1 -0
@@ -0,0 +1,1 @@
+obj-$(CONFIG_VIRTIO) += virtio.o

===================================================================

drivers/virtio/config.c new file +13 -0
@@ -0,0 +1,13 @@
+/* Configuration space parsing helpers for virtio.
+ *
+ * The configuration is [type][len][... len bytes ...] fields.
+ *
+ * Copyright 2007 Rusty Russell, IBM Corporation.
+ * GPL v2 or later.
+ */
+#include <linux/err.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/bug.h>
+#include <asm/system.h>
+

===================================================================

drivers/virtio/virtio.c new file +187 -0

187 lines not on this page · raw message

===================================================================

include/linux/mod_devicetable.h +6 -0
@@ -340,4 +340,10 @@ struct parisc_device_id {
 #define PA_HVERSION_ANY_ID	0xffff
 #define PA_SVERSION_ANY_ID	0xffffffff
 
+struct virtio_device_id {
+	__u32 device;
+	__u32 vendor;
+};
+#define VIRTIO_DEV_ANY_ID	0xffffffff
+
 #endif /* LINUX_MOD_DEVICETABLE_H */

===================================================================

include/linux/virtio.h new file +110 -0

110 lines not on this page · raw message

===================================================================

include/linux/virtio_config.h new file +111 -0

111 lines not on this page · raw message

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190625256.27805.201.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#4 lore raw

PATCH 2/3 virtio ring implementation

These helper routines supply most of the virtqueue_ops for hypervisors which want to use a ring for virtio. Unlike the previous lguest implementation:

1) The rings are variable sized (2^n-1 elements).
2) They have an unfortunate limit of 65535 bytes per sg element.
3) The page numbers are always 64 bit (PAE anyone?)
4) They no longer place used[] on a separate page, just a separate cacheline.
5) We do a modulo on a variable. We could be tricky if we cared.
6) Interrupts and notifies are suppressed using flags within the rings.

Users need only implement the new_vq and free_vq hooks (KVM wants the guest to allocate the rings, lguest does it sanely).

---
 arch/i386/lguest/Kconfig     |    1 
 drivers/virtio/Kconfig       |    5 
 drivers/virtio/Makefile      |    1 
 drivers/virtio/virtio_ring.c |  316 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/virtio_ring.h  |  119 +++++++++++++++
 5 files changed, 442 insertions(+)

===================================================================

arch/i386/lguest/Kconfig +1 -0
@@ -2,6 +2,7 @@ config LGUEST_GUEST
 	bool "Lguest guest support"
 	select PARAVIRT
 	depends on !X86_PAE
+	select VIRTIO_RING
 	help
 	  Lguest is a tiny in-kernel hypervisor.  Selecting this will
 	  allow your kernel to boot under lguest.  This option will increase

===================================================================

drivers/virtio/Kconfig +5 -0
@@ -1,3 +1,8 @@
 # Virtio always gets selected by whoever wants it.
 config VIRTIO
 	bool
+
+# Similarly the virtio ring implementation.
+config VIRTIO_RING
+	bool
+	depends on VIRTIO

===================================================================

drivers/virtio/Makefile +1 -0
@@ -1,1 +1,2 @@ obj-$(CONFIG_VIRTIO) += virtio.o
 obj-$(CONFIG_VIRTIO) += virtio.o
+obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o

===================================================================

drivers/virtio/virtio_ring.c new file +316 -0

316 lines not on this page · raw message

===================================================================

include/linux/virtio_ring.h new file +119 -0

119 lines not on this page · raw message

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190625307.27805.203.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#6 lore raw

PATCH 3/3 virtio module alias support

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

---
 drivers/virtio/virtio.c  |    9 +++++++++
 scripts/mod/file2alias.c |   18 ++++++++++++++++++
 2 files changed, 27 insertions(+)

===================================================================

drivers/virtio/virtio.c +9 -0
@@ -20,10 +20,19 @@ static ssize_t status_show(struct device
 	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
 	return sprintf(buf, "0x%08x", dev->config->get_status(dev));
 }
+static ssize_t modalias_show(struct device *_d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+
+	return sprintf(buf, "virtio:d%08Xv%08X\n",
+		       dev->id.device, dev->id.vendor);
+}
 static struct device_attribute virtio_dev_attrs[] = {
 	__ATTR_RO(device),
 	__ATTR_RO(vendor),
 	__ATTR_RO(status),
+	__ATTR_RO(modalias),
 	__ATTR_NULL
 };
 

===================================================================

scripts/mod/file2alias.c +18 -0
@@ -484,6 +484,20 @@ static int do_parisc_entry(const char *f
 	return 1;
 }
 
+/* Looks like: virtio:dNvN */
+static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
+			   char *alias)
+{
+	id->device = TO_NATIVE(id->device);
+	id->vendor = TO_NATIVE(id->vendor);
+
+	strcpy(alias, "virtio:");
+	ADD(alias, "d", 1, id->device);
+	ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor);
+
+	return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -599,6 +613,10 @@ void handle_moddevtable(struct module *m
 		do_table(symval, sym->st_size,
 			 sizeof(struct parisc_device_id), "parisc",
 			 do_parisc_entry, mod);
+	else if (sym_is(symname, "__mod_virtio_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct virtio_device_id), "virtio",
+			 do_virtio_entry, mod);
 }
 
 /* Now add out buffered information to the generated C source */

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190625394.27805.206.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#8 lore raw

Re: [PATCH 3/3] virtio module alias support

Quoted 6 lines · Rusty Russell

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

You also need to pass the MODINFO environment variable to the hotplug call so that udev can pick it up.

hope this helps,

greg k-h

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw

Re: [PATCH 3/3] virtio module alias support

Quoted 4 lines · Greg KH
Quoted 3 lines · Rusty Russell

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Quoted 8 lines
Quoted 3 lines

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

You also need to pass the MODINFO environment variable to the hotplug call so that udev can pick it up.

hope this helps,

Well, I finally decoded this as follows:

You need to implement the bus_type.uevent hook, and use add_uevent_var() to add a "MODALIAS=virtio:..." var. See drivers/pci/hotplug.c.

Not sure why I need the modalias here when it's in sysfs. But, it works.

Thanks!
Rusty.

---
Module autoprobing support for virtio drivers.

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs and the env var to make probing work.

---
 drivers/virtio/virtio.c  |    9 +++++++++
 scripts/mod/file2alias.c |   18 ++++++++++++++++++
 2 files changed, 27 insertions(+)
drivers/virtio/virtio.c +26 -0
diff -r 4b377c58d110 drivers/virtio/virtio.c
@@ -19,11 +19,20 @@ static ssize_t status_show(struct device
 {
 	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
 	return sprintf(buf, "0x%08x", dev->config->get_status(dev));
+}
+static ssize_t modalias_show(struct device *_d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+
+	return sprintf(buf, "virtio:d%08Xv%08X\n",
+		       dev->id.device, dev->id.vendor);
 }
 static struct device_attribute virtio_dev_attrs[] = {
 	__ATTR_RO(device),
 	__ATTR_RO(vendor),
 	__ATTR_RO(status),
+	__ATTR_RO(modalias),
 	__ATTR_NULL
 };
 
@@ -48,6 +57,22 @@ static int virtio_dev_match(struct devic
 	for (i = 0; ids[i].device; i++)
 		if (virtio_id_match(dev, &ids[i]))
 			return 1;
+	return 0;
+}
+
+static int virtio_uevent(struct device *_dv, char **envp,
+			 int num_envp, char *buffer, int buffer_size)
+{
+	struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+	int i = 0, err;
+	int length = 0;
+
+	err = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+			     "MODALIAS=virtio:d%08Xv%08X",
+			     dev->id.device, dev->id.vendor);
+	if (err)
+		return err;
+	envp[i] = NULL;
 	return 0;
 }
 
@@ -61,6 +86,7 @@ static struct virtio_bus virtio_bus = {
 		.name  = "virtio",
 		.match = virtio_dev_match,
 		.dev_attrs = virtio_dev_attrs,
+		.uevent = virtio_uevent,
 	},
 	.dev = {
 		/* Can override this if you have a real bus behind it. */
scripts/mod/file2alias.c +18 -0
diff -r 4b377c58d110 scripts/mod/file2alias.c
@@ -484,6 +484,20 @@ static int do_parisc_entry(const char *f
 	return 1;
 }
 
+/* Looks like: virtio:dNvN */
+static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
+			   char *alias)
+{
+	id->device = TO_NATIVE(id->device);
+	id->vendor = TO_NATIVE(id->vendor);
+
+	strcpy(alias, "virtio:");
+	ADD(alias, "d", 1, id->device);
+	ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor);
+
+	return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -599,6 +613,10 @@ void handle_moddevtable(struct module *m
 		do_table(symval, sym->st_size,
 			 sizeof(struct parisc_device_id), "parisc",
 			 do_parisc_entry, mod);
+	else if (sym_is(symname, "__mod_virtio_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct virtio_device_id), "virtio",
+			 do_virtio_entry, mod);
 }
 
 /* Now add out buffered information to the generated C source */

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190681405.27805.243.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#12 lore raw

Re: [PATCH 3/3] virtio module alias support

Quoted 12 lines · Rusty Russell
Quoted 11 lines · Greg KH
Quoted 6 lines · Rusty Russell

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

You also need to pass the MODINFO environment variable to the hotplug call so that udev can pick it up.

Quoted 7 lines
Quoted 1 line

hope this helps,

Well, I finally decoded this as follows:

You need to implement the bus_type.uevent hook, and use add_uevent_var() to add a "MODALIAS=virtio:..." var. See drivers/pci/hotplug.c.

Ah, sorry, thanks for intrepreting it properly :)

Quoted 2 lines

Not sure why I need the modalias here when it's in sysfs. But, it works.

udev does not read from sysfs anymore, it just uses the environment variables. It's faster and race-free that way.

thanks,

greg k-h

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#14 lore raw

Re: [PATCH 3/3] virtio module alias support

Quoted 6 lines · Greg KH
Quoted 2 lines · Rusty Russell

Not sure why I need the modalias here when it's in sysfs. But, it works.

udev does not read from sysfs anymore, it just uses the environment variables. It's faster and race-free that way.

Should I leave the modalias entry in sysfs for back compat, or not? This will be for >= 2.6.24 only...

Thanks,
Rusty.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190686275.27805.255.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#16 lore raw

Re: [PATCH 3/3] virtio module alias support

Quoted 10 lines · Rusty Russell
Quoted 6 lines · Greg KH
Quoted 2 lines · Rusty Russell

Not sure why I need the modalias here when it's in sysfs. But, it works.

udev does not read from sysfs anymore, it just uses the environment variables. It's faster and race-free that way.

Should I leave the modalias entry in sysfs for back compat, or not? This will be for >= 2.6.24 only...

No, leave it in sysfs, other tools use it (like older versions of udev).

thanks,

greg k-h

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#17 lore raw

Re: [PATCH 3/3] virtio module alias support

In reply to Rusty Russell
Quoted 10 lines · Rusty Russell
Quoted 6 lines · Greg KH
Quoted 2 lines · Rusty Russell

Not sure why I need the modalias here when it's in sysfs. But, it works.

udev does not read from sysfs anymore, it just uses the environment variables. It's faster and race-free that way.

Should I leave the modalias entry in sysfs for back compat, or not? This will be for >= 2.6.24 only...

No, leave it in sysfs, other tools use it (like older versions of udev).

thanks,

greg k-h

#18 lore raw

Re: [PATCH 3/3] virtio module alias support

In reply to Greg KH
Quoted 6 lines · Greg KH
Quoted 2 lines · Rusty Russell

Not sure why I need the modalias here when it's in sysfs. But, it works.

udev does not read from sysfs anymore, it just uses the environment variables. It's faster and race-free that way.

Should I leave the modalias entry in sysfs for back compat, or not? This will be for >= 2.6.24 only...

Thanks,
Rusty.

#19 lore raw

Re: [PATCH 3/3] virtio module alias support

In reply to Rusty Russell
Quoted 12 lines · Rusty Russell
Quoted 11 lines · Greg KH
Quoted 6 lines · Rusty Russell

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

You also need to pass the MODINFO environment variable to the hotplug call so that udev can pick it up.

Quoted 7 lines
Quoted 1 line

hope this helps,

Well, I finally decoded this as follows:

You need to implement the bus_type.uevent hook, and use add_uevent_var() to add a "MODALIAS=virtio:..." var. See drivers/pci/hotplug.c.

Ah, sorry, thanks for intrepreting it properly :)

Quoted 2 lines

Not sure why I need the modalias here when it's in sysfs. But, it works.

udev does not read from sysfs anymore, it just uses the environment variables. It's faster and race-free that way.

thanks,

greg k-h

#20 lore raw

Re: [PATCH 3/3] virtio module alias support

In reply to Greg KH
Quoted 4 lines · Greg KH
Quoted 3 lines · Rusty Russell

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Quoted 8 lines
Quoted 3 lines

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

You also need to pass the MODINFO environment variable to the hotplug call so that udev can pick it up.

hope this helps,

Well, I finally decoded this as follows:

You need to implement the bus_type.uevent hook, and use add_uevent_var() to add a "MODALIAS=virtio:..." var. See drivers/pci/hotplug.c.

Not sure why I need the modalias here when it's in sysfs. But, it works.

Thanks!
Rusty.

---
Module autoprobing support for virtio drivers.

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs and the env var to make probing work.

---
 drivers/virtio/virtio.c  |    9 +++++++++
 scripts/mod/file2alias.c |   18 ++++++++++++++++++
 2 files changed, 27 insertions(+)
drivers/virtio/virtio.c +26 -0
diff -r 4b377c58d110 drivers/virtio/virtio.c
@@ -19,11 +19,20 @@ static ssize_t status_show(struct device
 {
 	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
 	return sprintf(buf, "0x%08x", dev->config->get_status(dev));
+}
+static ssize_t modalias_show(struct device *_d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+
+	return sprintf(buf, "virtio:d%08Xv%08X\n",
+		       dev->id.device, dev->id.vendor);
 }
 static struct device_attribute virtio_dev_attrs[] = {
 	__ATTR_RO(device),
 	__ATTR_RO(vendor),
 	__ATTR_RO(status),
+	__ATTR_RO(modalias),
 	__ATTR_NULL
 };
 
@@ -48,6 +57,22 @@ static int virtio_dev_match(struct devic
 	for (i = 0; ids[i].device; i++)
 		if (virtio_id_match(dev, &ids[i]))
 			return 1;
+	return 0;
+}
+
+static int virtio_uevent(struct device *_dv, char **envp,
+			 int num_envp, char *buffer, int buffer_size)
+{
+	struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+	int i = 0, err;
+	int length = 0;
+
+	err = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+			     "MODALIAS=virtio:d%08Xv%08X",
+			     dev->id.device, dev->id.vendor);
+	if (err)
+		return err;
+	envp[i] = NULL;
 	return 0;
 }
 
@@ -61,6 +86,7 @@ static struct virtio_bus virtio_bus = {
 		.name  = "virtio",
 		.match = virtio_dev_match,
 		.dev_attrs = virtio_dev_attrs,
+		.uevent = virtio_uevent,
 	},
 	.dev = {
 		/* Can override this if you have a real bus behind it. */
scripts/mod/file2alias.c +18 -0
diff -r 4b377c58d110 scripts/mod/file2alias.c
@@ -484,6 +484,20 @@ static int do_parisc_entry(const char *f
 	return 1;
 }
 
+/* Looks like: virtio:dNvN */
+static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
+			   char *alias)
+{
+	id->device = TO_NATIVE(id->device);
+	id->vendor = TO_NATIVE(id->vendor);
+
+	strcpy(alias, "virtio:");
+	ADD(alias, "d", 1, id->device);
+	ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor);
+
+	return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -599,6 +613,10 @@ void handle_moddevtable(struct module *m
 		do_table(symval, sym->st_size,
 			 sizeof(struct parisc_device_id), "parisc",
 			 do_parisc_entry, mod);
+	else if (sym_is(symname, "__mod_virtio_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct virtio_device_id), "virtio",
+			 do_virtio_entry, mod);
 }
 
 /* Now add out buffered information to the generated C source */
#21 lore raw

Re: [PATCH 3/3] virtio module alias support

In reply to Rusty Russell
Quoted 6 lines · Rusty Russell

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

You also need to pass the MODINFO environment variable to the hotplug call so that udev can pick it up.

hope this helps,

greg k-h

#22 lore raw

Re: [PATCH 2/3] virtio ring implementation

In reply to a message not in the archive
Quoted 18 lines · Rusty Russell

These helper routines supply most of the virtqueue_ops for hypervisors which want to use a ring for virtio. Unlike the previous lguest implementation:

1) The rings are variable sized (2^n-1 elements).
2) They have an unfortunate limit of 65535 bytes per sg element.
3) The page numbers are always 64 bit (PAE anyone?)
4) They no longer place used[] on a separate page, just a separate cacheline.
5) We do a modulo on a variable. We could be tricky if we cared.
6) Interrupts and notifies are suppressed using flags within the rings.

Users need only implement the new_vq and free_vq hooks (KVM wants the guest to allocate the rings, lguest does it sanely).

[snip]

Quoted 19 lines
drivers/virtio/virtio_ring.c new file +16 -0
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       pr_debug("virtqueue interrupt for %p\n", vq);
+
+       if (unlikely(vq->broken))
+               return IRQ_HANDLED;
+
+       if (more_used(vq)) {
+               pr_debug("virtqueue callback for %p (%p)\n",
+                        vq, vq->vq.callback);
+               if (!vq->vq.callback)
+                       return IRQ_NONE;
+               if (!vq->vq.callback(&vq->vq))
+                       vq->vring.avail->flags |= 

VRING_AVAIL_F_NO_INTERRUPT;

drivers/virtio/virtio_ring.c line 265

Quoted 6 lines
drivers/virtio/virtio_ring.c new file +6 -0
+       } else
+               pr_debug("virtqueue %p no more used\n", vq);
+
+       return IRQ_HANDLED;
+}
+

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

It can be solved by having a host irq counter (in the shared ring) and a guest irq counter and return mb(); return (host_counter!=guest_counter)? IRQ_HANDLED:IRQ_NONE;

Dor.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): 46F7BF41.9060705-atKUWr5tajBWk0Htik3J/[email protected]

#24 lore raw

Re: [PATCH 2/3] virtio ring implementation

Quoted 7 lines · Dor Laor

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

It can be solved by having a host irq counter (in the shared ring) and a guest irq counter and return
mb(); return (host_counter!=guest_counter)? IRQ_HANDLED:IRQ_NONE;

Or we could make the callback return irqreturn_t and have an explicit "disable" hook to disable interrupts.

Using the return value of the callback to disable the queue has always made be a little uncomfortable, but it's slightly more efficient than a separate hook.

Thanks,
Rusty.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#25 lore raw

Re: [PATCH 2/3] virtio ring implementation

In reply to a message not in the archive
Quoted 20 lines · Dor Laor
Quoted 19 lines · Rusty Russell
drivers/virtio/virtio_ring.c new file +16 -0
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       pr_debug("virtqueue interrupt for %p\n", vq);
+
+       if (unlikely(vq->broken))
+               return IRQ_HANDLED;
+
+       if (more_used(vq)) {
+               pr_debug("virtqueue callback for %p (%p)\n",
+                        vq, vq->vq.callback);
+               if (!vq->vq.callback)
+                       return IRQ_NONE;
+               if (!vq->vq.callback(&vq->vq))
+                       vq->vring.avail->flags |=

VRING_AVAIL_F_NO_INTERRUPT;

drivers/virtio/virtio_ring.c new file +2 -0
+       } else
+               pr_debug("virtqueue %p no more used\n", vq);
Quoted 8 lines

drivers/virtio/virtio_ring.c line 265

Quoted 5 lines
drivers/virtio/virtio_ring.c new file +4 -0
+
+       return IRQ_HANDLED;
+}
+

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

To reply for a second time, this time with thought. Sorry.

Yes, this code is wrong. It should be:

irqreturn_t vring_interrupt(int irq, void *_vq)

{
	struct vring_virtqueue *vq = to_vvq(_vq);

	if (!more_used(vq)) {
		pr_debug("virtqueue interrupt with no work for %p\n", vq);
		return IRQ_NONE;
	}

	if (unlikely(vq->broken))
		return IRQ_HANDLED;

	pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
	if (vq->vq.callback && !vq->vq.callback(&vq->vq))
		vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;

	return IRQ_HANDLED;
}

Cheers,
Rusty.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190727156.27805.332.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#27 lore raw

Re: [PATCH 2/3] virtio ring implementation

Quoted 54 lines · Rusty Russell
Quoted 20 lines · Dor Laor
Quoted 19 lines · Rusty Russell
drivers/virtio/virtio_ring.c new file +16 -0
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       pr_debug("virtqueue interrupt for %p\n", vq);
+
+       if (unlikely(vq->broken))
+               return IRQ_HANDLED;
+
+       if (more_used(vq)) {
+               pr_debug("virtqueue callback for %p (%p)\n",
+                        vq, vq->vq.callback);
+               if (!vq->vq.callback)
+                       return IRQ_NONE;
+               if (!vq->vq.callback(&vq->vq))
+                       vq->vring.avail->flags |=

VRING_AVAIL_F_NO_INTERRUPT;

drivers/virtio/virtio_ring.c new file +2 -0
+       } else
+               pr_debug("virtqueue %p no more used\n", vq);
Quoted 8 lines

drivers/virtio/virtio_ring.c line 265

Quoted 5 lines
drivers/virtio/virtio_ring.c new file +4 -0
+
+       return IRQ_HANDLED;
+}
+

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

To reply for a second time, this time with thought. Sorry.

Yes, this code is wrong. It should be:

irqreturn_t vring_interrupt(int irq, void *_vq)

{
        struct vring_virtqueue *vq = to_vvq(_vq);

        if (!more_used(vq)) {
                pr_debug("virtqueue interrupt with no work for %p\n", vq);
                return IRQ_NONE;
        }

        if (unlikely(vq->broken))
                return IRQ_HANDLED;

        pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
        if (vq->vq.callback && !vq->vq.callback(&vq->vq))
                vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;

        return IRQ_HANDLED;
}
Quoted 3 lines

Cheers,
Rusty.

At the moment it's not good enough, there is a potential race were the guest optimistically turn off the VRING_AVAIL_F_NO_INTERRUPT in the vring_restart and afterwards finds there are more_used so it consume them in the poll function.
If in the middle, packets arrive the host will see the flag is off and send irq.
In that case the above irq handler will report IRQ_NONE.

It's also not trivial to cancel the optimistic approach in the restart function since then there might be another race that will result in missing irq reaching the guest.
I'll try to think of something better than a hypercall for switching irq on/off.
Cheers mate,
Dor.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): 46F94243.2000602-atKUWr5tajBWk0Htik3J/[email protected]

#29 lore raw

Re: [PATCH 2/3] virtio ring implementation

Quoted 8 lines · Dor Laor

At the moment it's not good enough, there is a potential race were the guest optimistically turn off
the VRING_AVAIL_F_NO_INTERRUPT in the vring_restart and afterwards finds there are more_used so
it consume them in the poll function.
If in the middle, packets arrive the host will see the flag is off and send irq.
In that case the above irq handler will report IRQ_NONE.

Good point. On the one hand, reporting IRQ_NONE occasionally is not fatal. On the other, it'd be nice to get this right.

Quoted 3 lines

It's also not trivial to cancel the optimistic approach in the restart function since then there might be another race
that will result in missing irq reaching the guest.

I did it optimistically because otherwise we need two barriers (and still have a window).

Quoted 2 lines

I'll try to think of something better than a hypercall for switching irq on/off.

Erk. That would be v. bad...

Thanks,
Rusty.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190763475.2227.20.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#31 lore raw

Re: [PATCH 2/3] virtio ring implementation

Quoted 25 lines · Rusty Russell
Quoted 9 lines · Dor Laor

At the moment it's not good enough, there is a potential race were the guest optimistically turn off
the VRING_AVAIL_F_NO_INTERRUPT in the vring_restart and afterwards finds there are more_used so
it consume them in the poll function.
If in the middle, packets arrive the host will see the flag is off and send irq.
In that case the above irq handler will report IRQ_NONE.

Good point. On the one hand, reporting IRQ_NONE occasionally is not fatal. On the other, it'd be nice to get this right.

Quoted 4 lines

It's also not trivial to cancel the optimistic approach in the restart function since then there might be another race
that will result in missing irq reaching the guest.

I did it optimistically because otherwise we need two barriers (and still have a window).

Quoted 6 lines
Quoted 3 lines

I'll try to think of something better than a hypercall for switching irq on/off.

Erk. That would be v. bad...

Actually double barrier will satisfy non-shared irq lines and will report irq handling right.
The more complex scenario is shared irqs (pci...), since several devices are raising the irq line (level triggered)
in the same time, while the tap add receive packets it always leaves a potential race for irq handled return
value. So seems like we better not have shared irq and if only if shared irq is a must we should do the
naughty naughty things.

If returning IRQ_NONE once in a while is not too bad (including the matching windows implementation)
then there is no issue.
Dor.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#32 lore raw

Re: [kvm-devel] [PATCH 2/3] virtio ring implementation

In reply to Rusty Russell
Quoted 24 lines · Rusty Russell
Quoted 8 lines · Dor Laor

At the moment it's not good enough, there is a potential race were the
guest optimistically turn off
the VRING_AVAIL_F_NO_INTERRUPT in the vring_restart and afterwards
finds there are more_used so
it consume them in the poll function. If in the middle, packets arrive the host will see the flag is off and send irq.
In that case the above irq handler will report IRQ_NONE.

Good point. On the one hand, reporting IRQ_NONE occasionally is not fatal. On the other, it'd be nice to get this right.

Quoted 4 lines

It's also not trivial to cancel the optimistic approach in the restart function since then there might be another race
that will result in missing irq reaching the guest.

I did it optimistically because otherwise we need two barriers (and still have a window).

Quoted 6 lines
Quoted 3 lines

I'll try to think of something better than a hypercall for switching irq on/off.

Erk. That would be v. bad...

Actually double barrier will satisfy non-shared irq lines and will report irq handling right. The more complex scenario is shared irqs (pci...), since several devices are raising the irq line (level triggered) in the same time, while the tap add receive packets it always leaves a potential race for irq handled return value. So seems like we better not have shared irq and if only if shared irq is a must we should do the naughty naughty things.

If returning IRQ_NONE once in a while is not too bad (including the matching windows implementation) then there is no issue.
Dor.

#33 lore raw

Re: [kvm-devel] [PATCH 2/3] virtio ring implementation

In reply to Dor Laor
Quoted 8 lines · Dor Laor

At the moment it's not good enough, there is a potential race were the guest optimistically turn off
the VRING_AVAIL_F_NO_INTERRUPT in the vring_restart and afterwards finds there are more_used so
it consume them in the poll function.
If in the middle, packets arrive the host will see the flag is off and send irq.
In that case the above irq handler will report IRQ_NONE.

Good point. On the one hand, reporting IRQ_NONE occasionally is not fatal. On the other, it'd be nice to get this right.

Quoted 3 lines

It's also not trivial to cancel the optimistic approach in the restart function since then there might be another race
that will result in missing irq reaching the guest.

I did it optimistically because otherwise we need two barriers (and still have a window).

Quoted 2 lines

I'll try to think of something better than a hypercall for switching irq on/off.

Erk. That would be v. bad...

Thanks,
Rusty.

#34 lore raw

Re: [kvm-devel] [PATCH 2/3] virtio ring implementation

In reply to Rusty Russell
Quoted 54 lines · Rusty Russell
Quoted 20 lines · Dor Laor
Quoted 19 lines · Rusty Russell
drivers/virtio/virtio_ring.c new file +16 -0
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       pr_debug("virtqueue interrupt for %p\n", vq);
+
+       if (unlikely(vq->broken))
+               return IRQ_HANDLED;
+
+       if (more_used(vq)) {
+               pr_debug("virtqueue callback for %p (%p)\n",
+                        vq, vq->vq.callback);
+               if (!vq->vq.callback)
+                       return IRQ_NONE;
+               if (!vq->vq.callback(&vq->vq))
+                       vq->vring.avail->flags |=

VRING_AVAIL_F_NO_INTERRUPT;

drivers/virtio/virtio_ring.c new file +2 -0
+       } else
+               pr_debug("virtqueue %p no more used\n", vq);
Quoted 8 lines

drivers/virtio/virtio_ring.c line 265

Quoted 5 lines
drivers/virtio/virtio_ring.c new file +4 -0
+
+       return IRQ_HANDLED;
+}
+

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

To reply for a second time, this time with thought. Sorry.

Yes, this code is wrong. It should be:

irqreturn_t vring_interrupt(int irq, void *_vq)

{
        struct vring_virtqueue *vq = to_vvq(_vq);

        if (!more_used(vq)) {
                pr_debug("virtqueue interrupt with no work for %p\n", vq);
                return IRQ_NONE;
        }

        if (unlikely(vq->broken))
                return IRQ_HANDLED;

        pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
        if (vq->vq.callback && !vq->vq.callback(&vq->vq))
                vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;

        return IRQ_HANDLED;
}
Quoted 3 lines

Cheers,
Rusty.

At the moment it's not good enough, there is a potential race were the guest optimistically turn off the VRING_AVAIL_F_NO_INTERRUPT in the vring_restart and afterwards finds there are more_used so it consume them in the poll function.
If in the middle, packets arrive the host will see the flag is off and send irq.
In that case the above irq handler will report IRQ_NONE.

It's also not trivial to cancel the optimistic approach in the restart function since then there might be another race that will result in missing irq reaching the guest.
I'll try to think of something better than a hypercall for switching irq on/off.
Cheers mate,
Dor.

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

#35 lore raw

Re: [kvm-devel] [PATCH 2/3] virtio ring implementation

In reply to Dor Laor
Quoted 7 lines · Dor Laor

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

It can be solved by having a host irq counter (in the shared ring) and a guest irq counter and return
mb(); return (host_counter!=guest_counter)? IRQ_HANDLED:IRQ_NONE;

Or we could make the callback return irqreturn_t and have an explicit "disable" hook to disable interrupts.

Using the return value of the callback to disable the queue has always made be a little uncomfortable, but it's slightly more efficient than a separate hook.

Thanks,
Rusty.

#36 lore raw

Re: [kvm-devel] [PATCH 2/3] virtio ring implementation

In reply to Dor Laor
Quoted 20 lines · Dor Laor
Quoted 19 lines · Rusty Russell
drivers/virtio/virtio_ring.c new file +16 -0
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       pr_debug("virtqueue interrupt for %p\n", vq);
+
+       if (unlikely(vq->broken))
+               return IRQ_HANDLED;
+
+       if (more_used(vq)) {
+               pr_debug("virtqueue callback for %p (%p)\n",
+                        vq, vq->vq.callback);
+               if (!vq->vq.callback)
+                       return IRQ_NONE;
+               if (!vq->vq.callback(&vq->vq))
+                       vq->vring.avail->flags |=

VRING_AVAIL_F_NO_INTERRUPT;

drivers/virtio/virtio_ring.c new file +2 -0
+       } else
+               pr_debug("virtqueue %p no more used\n", vq);
Quoted 8 lines

drivers/virtio/virtio_ring.c line 265

Quoted 5 lines
drivers/virtio/virtio_ring.c new file +4 -0
+
+       return IRQ_HANDLED;
+}
+

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

To reply for a second time, this time with thought. Sorry.

Yes, this code is wrong. It should be:

irqreturn_t vring_interrupt(int irq, void *_vq)

{
	struct vring_virtqueue *vq = to_vvq(_vq);

	if (!more_used(vq)) {
		pr_debug("virtqueue interrupt with no work for %p\n", vq);
		return IRQ_NONE;
	}

	if (unlikely(vq->broken))
		return IRQ_HANDLED;

	pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
	if (vq->vq.callback && !vq->vq.callback(&vq->vq))
		vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;

	return IRQ_HANDLED;
}

Cheers,
Rusty.

#37 lore raw

PATCH 3/3 virtio module alias support

In reply to Rusty Russell

This adds the logic to convert the virtio ids into module aliases, and includes a modalias entry in sysfs.

Unfortunately this does not seem sufficient to have the module autoprobed at startup on my Ubuntu system. Greg? Am I missing some udev magic?

---
 drivers/virtio/virtio.c  |    9 +++++++++
 scripts/mod/file2alias.c |   18 ++++++++++++++++++
 2 files changed, 27 insertions(+)

===================================================================

drivers/virtio/virtio.c +9 -0
@@ -20,10 +20,19 @@ static ssize_t status_show(struct device
 	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
 	return sprintf(buf, "0x%08x", dev->config->get_status(dev));
 }
+static ssize_t modalias_show(struct device *_d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+
+	return sprintf(buf, "virtio:d%08Xv%08X\n",
+		       dev->id.device, dev->id.vendor);
+}
 static struct device_attribute virtio_dev_attrs[] = {
 	__ATTR_RO(device),
 	__ATTR_RO(vendor),
 	__ATTR_RO(status),
+	__ATTR_RO(modalias),
 	__ATTR_NULL
 };
 

===================================================================

scripts/mod/file2alias.c +18 -0
@@ -484,6 +484,20 @@ static int do_parisc_entry(const char *f
 	return 1;
 }
 
+/* Looks like: virtio:dNvN */
+static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
+			   char *alias)
+{
+	id->device = TO_NATIVE(id->device);
+	id->vendor = TO_NATIVE(id->vendor);
+
+	strcpy(alias, "virtio:");
+	ADD(alias, "d", 1, id->device);
+	ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor);
+
+	return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -599,6 +613,10 @@ void handle_moddevtable(struct module *m
 		do_table(symval, sym->st_size,
 			 sizeof(struct parisc_device_id), "parisc",
 			 do_parisc_entry, mod);
+	else if (sym_is(symname, "__mod_virtio_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct virtio_device_id), "virtio",
+			 do_virtio_entry, mod);
 }
 
 /* Now add out buffered information to the generated C source */
#38 lore raw

Re: [kvm-devel] [PATCH 2/3] virtio ring implementation

In reply to Rusty Russell
Quoted 18 lines · Rusty Russell

These helper routines supply most of the virtqueue_ops for hypervisors which want to use a ring for virtio. Unlike the previous lguest implementation:

1) The rings are variable sized (2^n-1 elements).
2) They have an unfortunate limit of 65535 bytes per sg element.
3) The page numbers are always 64 bit (PAE anyone?)
4) They no longer place used[] on a separate page, just a separate cacheline.
5) We do a modulo on a variable. We could be tricky if we cared.
6) Interrupts and notifies are suppressed using flags within the rings.

Users need only implement the new_vq and free_vq hooks (KVM wants the guest to allocate the rings, lguest does it sanely).

[snip]

Quoted 19 lines
drivers/virtio/virtio_ring.c new file +16 -0
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       pr_debug("virtqueue interrupt for %p\n", vq);
+
+       if (unlikely(vq->broken))
+               return IRQ_HANDLED;
+
+       if (more_used(vq)) {
+               pr_debug("virtqueue callback for %p (%p)\n",
+                        vq, vq->vq.callback);
+               if (!vq->vq.callback)
+                       return IRQ_NONE;
+               if (!vq->vq.callback(&vq->vq))
+                       vq->vring.avail->flags |= 

VRING_AVAIL_F_NO_INTERRUPT;

drivers/virtio/virtio_ring.c line 265

Quoted 6 lines
drivers/virtio/virtio_ring.c new file +6 -0
+       } else
+               pr_debug("virtqueue %p no more used\n", vq);
+
+       return IRQ_HANDLED;
+}
+

Seems like there is a problem with shared irq line, the interrupt handler always returns IRQ_HANDLED (except for the trivial case were the callback is null).

It can be solved by having a host irq counter (in the shared ring) and a guest irq counter and return mb(); return (host_counter!=guest_counter)? IRQ_HANDLED:IRQ_NONE;

Dor.

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

#39 lore raw

Re: [PATCH 1/3] virtio interface

In reply to a message not in the archive
Quoted 3 lines · Rusty Russell

This attempts to implement a "virtual I/O" layer which should allow common drivers to be efficiently used across most virtual I/O mechanisms. It will no-doubt need further enhancement.

Hi Rusty,

Thanks for your update, as you can imagine, I'm much happier with this version ;-)

Quoted 8 lines
drivers/virtio/virtio.c new file +8 -0
+
+struct virtio_bus {
+	struct bus_type bus;
+	struct device dev;
+};
+
+static struct virtio_bus virtio_bus = {
+	.bus = {

drivers/virtio/virtio.c line 70

Quoted 10 lines
drivers/virtio/virtio.c new file +10 -0
+		.name  = "virtio",
+		.match = virtio_dev_match,
+		.dev_attrs = virtio_dev_attrs,
+	},
+	.dev = {
+		/* Can override this if you have a real bus behind it. */
+		.parent = NULL,
+		.bus_id = "virtio",
+	}
+};

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

Also, I would not mix the two in a single source file. Instead, I think every driver that can provide virtio devices (pci, lguest, ...) should be responsible for setting the parent appropriately.

Quoted 61 lines
include/linux/virtio_config.h new file +61 -0
+#ifndef _LINUX_VIRTIO_CONFIG_H
+#define _LINUX_VIRTIO_CONFIG_H
+/* Virtio devices use a standardized configuration space to define their
+ * features and pass configuration information, but each implementation can
+ * store and access that space differently. */
+#include <linux/types.h>
+
+/* Status byte for guest to report progress, and synchronize config. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE	1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER		2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK	4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED		0x80
+
+/* Feature byte (actually 7 bits availabe): */
+/* Requirements/features of the virtio implementation. */
+#define VIRTIO_CONFIG_F_VIRTIO 1
+/* Requirements/features of the virtqueue (may have more than one). */
+#define VIRTIO_CONFIG_F_VIRTQUEUE 2
+
+#ifdef __KERNEL__
+struct virtio_device;
+
+/**
+ * virtio_config_ops - operations for configuring a virtio device
+ * @find: search for the next configuration field of the given type.
+ *	vdev: the virtio_device
+ *	type: the feature type
+ *	len: the (returned) length of the field if found.
+ *	Returns a token if found, or NULL.  Never returnes the same field twice
+ *	(ie. it's used up).
+ * @get: read the value of a configuration field after find().
+ *	vdev: the virtio_device
+ *	token: the token returned from find().
+ *	buf: the buffer to write the field value into.
+ *	len: the length of the buffer (given by find()).
+ *	Note that contents are conventionally little-endian.
+ * @set: write the value of a configuration field after find().
+ *	vdev: the virtio_device
+ *	token: the token returned from find().
+ *	buf: the buffer to read the field value from.
+ *	len: the length of the buffer (given by find()).
+ *	Note that contents are conventionally little-endian.
+ * @get_status: read the status byte
+ *	vdev: the virtio_device
+ *	Returns the status byte
+ * @set_status: write the status byte
+ *	vdev: the virtio_device
+ *	status: the new status byte
+ * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue.
+ *	vdev: the virtio_device
+ *	callback: the virqtueue callback
+ *	Returns the new virtqueue or ERR_PTR().
+ * @del_vq: free a virtqueue found by find_vq().
+ */
+struct virtio_config_ops
+{
+	void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len);

include/linux/virtio_config.h line 71

Quoted 10 lines
include/linux/virtio_config.h new file +10 -0
+	void (*get)(struct virtio_device *vdev, void *token,
+		    void *buf, unsigned len);
+	void (*set)(struct virtio_device *vdev, void *token,
+		    const void *buf, unsigned len);
+	u8 (*get_status)(struct virtio_device *vdev);
+	void (*set_status)(struct virtio_device *vdev, u8 status);
+	struct virtqueue *(*find_vq)(struct virtio_device *vdev,
+				     bool (*callback)(struct virtqueue *));
+	void (*del_vq)(struct virtqueue *vq);
+};

The configuration logic looks more complicated than it should be. Maybe more of this can be done using data structure definitions instead of dynamic callback. E.g. the virtqueues of a given device can be listed as members of the struct virtio_device.

Quoted 12 lines
include/linux/virtio_config.h new file +12 -0
+/**
+ * virtio_config_val - get a single virtio config and mark it used.
+ * @config: the virtio config space
+ * @type: the type to search for.
+ * @val: a pointer to the value to fill in.
+ *
+ * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't
+ * be found again.  This version does endian conversion. */
+#define virtio_config_val(vdev, type, v) ({				\
+	int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \
+									\
+	BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2		\

include/linux/virtio_config.h line 94

Quoted 10 lines
include/linux/virtio_config.h new file +10 -0
+		     && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);	\
+	if (!_err) {							\
+		switch (sizeof(*(v))) {					\
+		case 2: le16_to_cpus(v); break;				\
+		case 4: le32_to_cpus(v); break;				\
+		case 8: le64_to_cpus(v); break;				\
+		}							\
+	}								\
+	_err;								\
+})

Especially the macro looks like something better avoided...

	Arnd <><

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#41 lore raw

Re: [PATCH 1/3] virtio interface

Quoted 9 lines · Arnd Bergmann
Quoted 3 lines · Rusty Russell

This attempts to implement a "virtual I/O" layer which should allow common drivers to be efficiently used across most virtual I/O mechanisms. It will no-doubt need further enhancement.

Hi Rusty,

Thanks for your update, as you can imagine, I'm much happier with this version ;-)

Hi Arnd,

Yes, I thought you might be...

Quoted 23 lines
Quoted 8 lines
drivers/virtio/virtio.c new file +8 -0
+
+struct virtio_bus {
+	struct bus_type bus;
+	struct device dev;
+};
+
+static struct virtio_bus virtio_bus = {
+	.bus = {

drivers/virtio/virtio.c line 70

Quoted 10 lines
drivers/virtio/virtio.c new file +10 -0
+		.name  = "virtio",
+		.match = virtio_dev_match,
+		.dev_attrs = virtio_dev_attrs,
+	},
+	.dev = {
+		/* Can override this if you have a real bus behind it. */
+		.parent = NULL,
+		.bus_id = "virtio",
+	}
+};

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

Quoted 2 lines

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

It's copied from the lguest bus which was copied from somewhere else. Creating a struct like this is a quiet complaint about the requirements to do so: it's not clear to me why I need to create a fake device, rather than making the bus the parent of the device if it needs one.

Quoted 3 lines

Also, I would not mix the two in a single source file. Instead, I think every driver that can provide virtio devices (pci, lguest, ...) should be responsible for setting the parent appropriately.

I don't mind: we could expose it.

Quoted 10 lines
Quoted 10 lines
include/linux/virtio_config.h new file +10 -0
+struct virtio_config_ops
+{
+	void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len);
+	void (*get)(struct virtio_device *vdev, void *token,
+		    void *buf, unsigned len);
+	void (*set)(struct virtio_device *vdev, void *token,
+		    const void *buf, unsigned len);
+	u8 (*get_status)(struct virtio_device *vdev);
+	void (*set_status)(struct virtio_device *vdev, u8 status);
+	struct virtqueue *(*find_vq)(struct virtio_device *vdev,
Quoted 8 lines

include/linux/virtio_config.h line 71

Quoted 3 lines
include/linux/virtio_config.h new file +3 -0
+				     bool (*callback)(struct virtqueue *));
+	void (*del_vq)(struct virtqueue *vq);
+};

The configuration logic looks more complicated than it should be. Maybe more of this can be done using data structure definitions instead of dynamic callback. E.g. the virtqueues of a given device can be listed as members of the struct virtio_device.

I agree about the complexity, but the reason I didn't do that is the way the config system works. Drivers look for fields they want, and those fields are marked so the host can see what was used. This makes it fairly easy to add new fields and then tell if the guest understood them or not.

This includes new virtqueues, so the core must not simply grab them all. My previous solution was to put a "new_vq" and "del_vq" inside
virtqueue_ops: the driver found the config field and handed it through. That was a little messier for the driver.

Quoted 16 lines
Quoted 16 lines
include/linux/virtio_config.h new file +16 -0
+/**
+ * virtio_config_val - get a single virtio config and mark it used.
+ * @config: the virtio config space
+ * @type: the type to search for.
+ * @val: a pointer to the value to fill in.
+ *
+ * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't
+ * be found again.  This version does endian conversion. */
+#define virtio_config_val(vdev, type, v) ({				\
+	int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \
+									\
+	BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2		\
+		     && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);	\
+	if (!_err) {							\
+		switch (sizeof(*(v))) {					\
+		case 2: le16_to_cpus(v); break;				\
Quoted 8 lines

include/linux/virtio_config.h line 94

Quoted 6 lines
include/linux/virtio_config.h new file +6 -0
+		case 4: le32_to_cpus(v); break;				\
+		case 8: le64_to_cpus(v); break;				\
+		}							\
+	}								\
+	_err;								\
+})

Especially the macro looks like something better avoided...

C'mon, everyone loves optimization!

(Which reminds me, I said little endian here but didn't actually do that in the lguest launcher, bad Rusty).

Thanks,
Rusty.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): 1190677058.27805.225.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#43 lore raw

Re: [PATCH 1/3] virtio interface

Quoted 13 lines · Rusty Russell
Quoted 6 lines · Arnd Bergmann

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

It's copied from the lguest bus which was copied from somewhere else. Creating a struct like this is a quiet complaint about the requirements to do so: it's not clear to me why I need to create a fake device, rather than making the bus the parent of the device if it needs one.

Quoted 5 lines
Quoted 3 lines

Also, I would not mix the two in a single source file. Instead, I think every driver that can provide virtio devices (pci, lguest, ...) should be responsible for setting the parent appropriately.

I don't mind: we could expose it.

What I mean with setting the parent appropriately is not to have a global device that is used by the hv-specific probing code, but to make sure that each of them provides their own one. The bus_type should either be global or provide the wrappers for device_register and driver_register that you have, but the host bridge device belongs with the code that probes it. E.g. when all virtio devices are behind PCI bridges, there does not need to be an empty /virtio or /lguest device node at all.

	Arnd <><

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#45 lore raw

Re: [PATCH 1/3] virtio interface

Quoted 10 lines · Arnd Bergmann
Quoted 1 line · Rusty Russell

I don't mind: we could expose it.

What I mean with setting the parent appropriately is not to have a global device that is used by the hv-specific probing code, but to make sure that each of them provides their own one. The bus_type should either be global or provide the wrappers for device_register and driver_register that you have, but the host bridge device belongs with the code that probes it. E.g. when all virtio devices are behind PCI bridges, there does not need to be an empty /virtio or /lguest device node at all.

Right, that makes sense. I'll shift this "virtio" device node out to the lguest code.

Thanks!
Rusty.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#46 lore raw

Re: [kvm-devel] [PATCH 1/3] virtio interface

In reply to Arnd Bergmann
Quoted 10 lines · Arnd Bergmann
Quoted 1 line · Rusty Russell

I don't mind: we could expose it.

What I mean with setting the parent appropriately is not to have a global device that is used by the hv-specific probing code, but to make sure that each of them provides their own one. The bus_type should either be global or provide the wrappers for device_register and driver_register that you have, but the host bridge device belongs with the code that probes it. E.g. when all virtio devices are behind PCI bridges, there does not need to be an empty /virtio or /lguest device node at all.

Right, that makes sense. I'll shift this "virtio" device node out to the lguest code.

Thanks!
Rusty.

#47 lore raw

Re: [PATCH 1/3] virtio interface

In reply to a message not in the archive
Quoted 25 lines · Rusty Russell
Quoted 24 lines · Arnd Bergmann
Quoted 8 lines · Rusty Russell
drivers/virtio/virtio.c new file +8 -0
+
+struct virtio_bus {
+	struct bus_type bus;
+	struct device dev;
+};
+
+static struct virtio_bus virtio_bus = {
+	.bus = {

drivers/virtio/virtio.c line 70

Quoted 10 lines
drivers/virtio/virtio.c new file +10 -0
+		.name  = "virtio",
+		.match = virtio_dev_match,
+		.dev_attrs = virtio_dev_attrs,
+	},
+	.dev = {
+		/* Can override this if you have a real bus behind it. */
+		.parent = NULL,
+		.bus_id = "virtio",
+	}
+};

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

Quoted 7 lines
Quoted 2 lines

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

It's copied from the lguest bus which was copied from somewhere else. Creating a struct like this is a quiet complaint about the requirements to do so: it's not clear to me why I need to create a fake device, rather than making the bus the parent of the device if it needs one.

You may want to have different busses, all having their own root device, which share the same bus type.

Or you may want to embed the root device into a more complex structure.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#48 lore raw

Re: [kvm-devel] [PATCH 1/3] virtio interface

In reply to Rusty Russell
Quoted 13 lines · Rusty Russell
Quoted 6 lines · Arnd Bergmann

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

It's copied from the lguest bus which was copied from somewhere else. Creating a struct like this is a quiet complaint about the requirements to do so: it's not clear to me why I need to create a fake device, rather than making the bus the parent of the device if it needs one.

Quoted 5 lines
Quoted 3 lines

Also, I would not mix the two in a single source file. Instead, I think every driver that can provide virtio devices (pci, lguest, ...) should be responsible for setting the parent appropriately.

I don't mind: we could expose it.

What I mean with setting the parent appropriately is not to have a global device that is used by the hv-specific probing code, but to make sure that each of them provides their own one. The bus_type should either be global or provide the wrappers for device_register and driver_register that you have, but the host bridge device belongs with the code that probes it. E.g. when all virtio devices are behind PCI bridges, there does not need to be an empty /virtio or /lguest device node at all.

	Arnd <><
#49 lore raw

Re: [kvm-devel] [PATCH 1/3] virtio interface

In reply to Rusty Russell
Quoted 25 lines · Rusty Russell
Quoted 24 lines · Arnd Bergmann
Quoted 8 lines · Rusty Russell
drivers/virtio/virtio.c new file +8 -0
+
+struct virtio_bus {
+	struct bus_type bus;
+	struct device dev;
+};
+
+static struct virtio_bus virtio_bus = {
+	.bus = {

drivers/virtio/virtio.c line 70

Quoted 10 lines
drivers/virtio/virtio.c new file +10 -0
+		.name  = "virtio",
+		.match = virtio_dev_match,
+		.dev_attrs = virtio_dev_attrs,
+	},
+	.dev = {
+		/* Can override this if you have a real bus behind it. */
+		.parent = NULL,
+		.bus_id = "virtio",
+	}
+};

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

Quoted 7 lines
Quoted 2 lines

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

It's copied from the lguest bus which was copied from somewhere else. Creating a struct like this is a quiet complaint about the requirements to do so: it's not clear to me why I need to create a fake device, rather than making the bus the parent of the device if it needs one.

You may want to have different busses, all having their own root device, which share the same bus type.

Or you may want to embed the root device into a more complex structure.

#50 lore raw

Re: [kvm-devel] [PATCH 1/3] virtio interface

In reply to Arnd Bergmann
Quoted 9 lines · Arnd Bergmann
Quoted 3 lines · Rusty Russell

This attempts to implement a "virtual I/O" layer which should allow common drivers to be efficiently used across most virtual I/O mechanisms. It will no-doubt need further enhancement.

Hi Rusty,

Thanks for your update, as you can imagine, I'm much happier with this version ;-)

Hi Arnd,

Yes, I thought you might be...

Quoted 23 lines
Quoted 8 lines
drivers/virtio/virtio.c new file +8 -0
+
+struct virtio_bus {
+	struct bus_type bus;
+	struct device dev;
+};
+
+static struct virtio_bus virtio_bus = {
+	.bus = {

drivers/virtio/virtio.c line 70

Quoted 10 lines
drivers/virtio/virtio.c new file +10 -0
+		.name  = "virtio",
+		.match = virtio_dev_match,
+		.dev_attrs = virtio_dev_attrs,
+	},
+	.dev = {
+		/* Can override this if you have a real bus behind it. */
+		.parent = NULL,
+		.bus_id = "virtio",
+	}
+};

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

Quoted 2 lines

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

It's copied from the lguest bus which was copied from somewhere else. Creating a struct like this is a quiet complaint about the requirements to do so: it's not clear to me why I need to create a fake device, rather than making the bus the parent of the device if it needs one.

Quoted 3 lines

Also, I would not mix the two in a single source file. Instead, I think every driver that can provide virtio devices (pci, lguest, ...) should be responsible for setting the parent appropriately.

I don't mind: we could expose it.

Quoted 10 lines
Quoted 10 lines
include/linux/virtio_config.h new file +10 -0
+struct virtio_config_ops
+{
+	void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len);
+	void (*get)(struct virtio_device *vdev, void *token,
+		    void *buf, unsigned len);
+	void (*set)(struct virtio_device *vdev, void *token,
+		    const void *buf, unsigned len);
+	u8 (*get_status)(struct virtio_device *vdev);
+	void (*set_status)(struct virtio_device *vdev, u8 status);
+	struct virtqueue *(*find_vq)(struct virtio_device *vdev,
Quoted 8 lines

include/linux/virtio_config.h line 71

Quoted 3 lines
include/linux/virtio_config.h new file +3 -0
+				     bool (*callback)(struct virtqueue *));
+	void (*del_vq)(struct virtqueue *vq);
+};

The configuration logic looks more complicated than it should be. Maybe more of this can be done using data structure definitions instead of dynamic callback. E.g. the virtqueues of a given device can be listed as members of the struct virtio_device.

I agree about the complexity, but the reason I didn't do that is the way the config system works. Drivers look for fields they want, and those fields are marked so the host can see what was used. This makes it fairly easy to add new fields and then tell if the guest understood them or not.

This includes new virtqueues, so the core must not simply grab them all. My previous solution was to put a "new_vq" and "del_vq" inside
virtqueue_ops: the driver found the config field and handed it through. That was a little messier for the driver.

Quoted 16 lines
Quoted 16 lines
include/linux/virtio_config.h new file +16 -0
+/**
+ * virtio_config_val - get a single virtio config and mark it used.
+ * @config: the virtio config space
+ * @type: the type to search for.
+ * @val: a pointer to the value to fill in.
+ *
+ * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't
+ * be found again.  This version does endian conversion. */
+#define virtio_config_val(vdev, type, v) ({				\
+	int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \
+									\
+	BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2		\
+		     && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);	\
+	if (!_err) {							\
+		switch (sizeof(*(v))) {					\
+		case 2: le16_to_cpus(v); break;				\
Quoted 8 lines

include/linux/virtio_config.h line 94

Quoted 6 lines
include/linux/virtio_config.h new file +6 -0
+		case 4: le32_to_cpus(v); break;				\
+		case 8: le64_to_cpus(v); break;				\
+		}							\
+	}								\
+	_err;								\
+})

Especially the macro looks like something better avoided...

C'mon, everyone loves optimization!

(Which reminds me, I said little endian here but didn't actually do that in the lguest launcher, bad Rusty).

Thanks,
Rusty.

#51 lore raw

PATCH 2/3 virtio ring implementation

In reply to Rusty Russell

These helper routines supply most of the virtqueue_ops for hypervisors which want to use a ring for virtio. Unlike the previous lguest implementation:

1) The rings are variable sized (2^n-1 elements).
2) They have an unfortunate limit of 65535 bytes per sg element.
3) The page numbers are always 64 bit (PAE anyone?)
4) They no longer place used[] on a separate page, just a separate cacheline.
5) We do a modulo on a variable. We could be tricky if we cared.
6) Interrupts and notifies are suppressed using flags within the rings.

Users need only implement the new_vq and free_vq hooks (KVM wants the guest to allocate the rings, lguest does it sanely).

---
 arch/i386/lguest/Kconfig     |    1 
 drivers/virtio/Kconfig       |    5 
 drivers/virtio/Makefile      |    1 
 drivers/virtio/virtio_ring.c |  316 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/virtio_ring.h  |  119 +++++++++++++++
 5 files changed, 442 insertions(+)

===================================================================

arch/i386/lguest/Kconfig +1 -0
@@ -2,6 +2,7 @@ config LGUEST_GUEST
 	bool "Lguest guest support"
 	select PARAVIRT
 	depends on !X86_PAE
+	select VIRTIO_RING
 	help
 	  Lguest is a tiny in-kernel hypervisor.  Selecting this will
 	  allow your kernel to boot under lguest.  This option will increase

===================================================================

drivers/virtio/Kconfig +5 -0
@@ -1,3 +1,8 @@
 # Virtio always gets selected by whoever wants it.
 config VIRTIO
 	bool
+
+# Similarly the virtio ring implementation.
+config VIRTIO_RING
+	bool
+	depends on VIRTIO

===================================================================

drivers/virtio/Makefile +1 -0
@@ -1,1 +1,2 @@ obj-$(CONFIG_VIRTIO) += virtio.o
 obj-$(CONFIG_VIRTIO) += virtio.o
+obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o

===================================================================

drivers/virtio/virtio_ring.c new file +316 -0

316 lines not on this page · raw message

===================================================================

include/linux/virtio_ring.h new file +119 -0

119 lines not on this page · raw message

#52 lore raw

Re: [kvm-devel] [PATCH 1/3] virtio interface

In reply to Rusty Russell
Quoted 3 lines · Rusty Russell

This attempts to implement a "virtual I/O" layer which should allow common drivers to be efficiently used across most virtual I/O mechanisms. It will no-doubt need further enhancement.

Hi Rusty,

Thanks for your update, as you can imagine, I'm much happier with this version ;-)

Quoted 8 lines
drivers/virtio/virtio.c new file +8 -0
+
+struct virtio_bus {
+	struct bus_type bus;
+	struct device dev;
+};
+
+static struct virtio_bus virtio_bus = {
+	.bus = {

drivers/virtio/virtio.c line 70

Quoted 10 lines
drivers/virtio/virtio.c new file +10 -0
+		.name  = "virtio",
+		.match = virtio_dev_match,
+		.dev_attrs = virtio_dev_attrs,
+	},
+	.dev = {
+		/* Can override this if you have a real bus behind it. */
+		.parent = NULL,
+		.bus_id = "virtio",
+	}
+};

This is a pattern I've seen a few times before, but could never understand what it's good for. What is your reason for defining a new data structure that is used only once, instead of just

static struct bus_type virtio_bus_type;
static struct device virtio_root_dev;

Also, I would not mix the two in a single source file. Instead, I think every driver that can provide virtio devices (pci, lguest, ...) should be responsible for setting the parent appropriately.

Quoted 61 lines
include/linux/virtio_config.h new file +61 -0
+#ifndef _LINUX_VIRTIO_CONFIG_H
+#define _LINUX_VIRTIO_CONFIG_H
+/* Virtio devices use a standardized configuration space to define their
+ * features and pass configuration information, but each implementation can
+ * store and access that space differently. */
+#include <linux/types.h>
+
+/* Status byte for guest to report progress, and synchronize config. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE	1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER		2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK	4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED		0x80
+
+/* Feature byte (actually 7 bits availabe): */
+/* Requirements/features of the virtio implementation. */
+#define VIRTIO_CONFIG_F_VIRTIO 1
+/* Requirements/features of the virtqueue (may have more than one). */
+#define VIRTIO_CONFIG_F_VIRTQUEUE 2
+
+#ifdef __KERNEL__
+struct virtio_device;
+
+/**
+ * virtio_config_ops - operations for configuring a virtio device
+ * @find: search for the next configuration field of the given type.
+ *	vdev: the virtio_device
+ *	type: the feature type
+ *	len: the (returned) length of the field if found.
+ *	Returns a token if found, or NULL.  Never returnes the same field twice
+ *	(ie. it's used up).
+ * @get: read the value of a configuration field after find().
+ *	vdev: the virtio_device
+ *	token: the token returned from find().
+ *	buf: the buffer to write the field value into.
+ *	len: the length of the buffer (given by find()).
+ *	Note that contents are conventionally little-endian.
+ * @set: write the value of a configuration field after find().
+ *	vdev: the virtio_device
+ *	token: the token returned from find().
+ *	buf: the buffer to read the field value from.
+ *	len: the length of the buffer (given by find()).
+ *	Note that contents are conventionally little-endian.
+ * @get_status: read the status byte
+ *	vdev: the virtio_device
+ *	Returns the status byte
+ * @set_status: write the status byte
+ *	vdev: the virtio_device
+ *	status: the new status byte
+ * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue.
+ *	vdev: the virtio_device
+ *	callback: the virqtueue callback
+ *	Returns the new virtqueue or ERR_PTR().
+ * @del_vq: free a virtqueue found by find_vq().
+ */
+struct virtio_config_ops
+{
+	void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len);

include/linux/virtio_config.h line 71

Quoted 10 lines
include/linux/virtio_config.h new file +10 -0
+	void (*get)(struct virtio_device *vdev, void *token,
+		    void *buf, unsigned len);
+	void (*set)(struct virtio_device *vdev, void *token,
+		    const void *buf, unsigned len);
+	u8 (*get_status)(struct virtio_device *vdev);
+	void (*set_status)(struct virtio_device *vdev, u8 status);
+	struct virtqueue *(*find_vq)(struct virtio_device *vdev,
+				     bool (*callback)(struct virtqueue *));
+	void (*del_vq)(struct virtqueue *vq);
+};

The configuration logic looks more complicated than it should be. Maybe more of this can be done using data structure definitions instead of dynamic callback. E.g. the virtqueues of a given device can be listed as members of the struct virtio_device.

Quoted 12 lines
include/linux/virtio_config.h new file +12 -0
+/**
+ * virtio_config_val - get a single virtio config and mark it used.
+ * @config: the virtio config space
+ * @type: the type to search for.
+ * @val: a pointer to the value to fill in.
+ *
+ * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't
+ * be found again.  This version does endian conversion. */
+#define virtio_config_val(vdev, type, v) ({				\
+	int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \
+									\
+	BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2		\

include/linux/virtio_config.h line 94

Quoted 10 lines
include/linux/virtio_config.h new file +10 -0
+		     && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);	\
+	if (!_err) {							\
+		switch (sizeof(*(v))) {					\
+		case 2: le16_to_cpus(v); break;				\
+		case 4: le32_to_cpus(v); break;				\
+		case 8: le64_to_cpus(v); break;				\
+		}							\
+	}								\
+	_err;								\
+})

Especially the macro looks like something better avoided...

	Arnd <><
#53 lore raw

PATCH 1/3 virtio interface

In reply to Rusty Russell

This attempts to implement a "virtual I/O" layer which should allow common drivers to be efficiently used across most virtual I/O mechanisms. It will no-doubt need further enhancement.

The virtio drivers add buffers to virtio queues; as the buffers are consumed the driver "interrupt" callbacks are invoked.

There is also a generic implementation of config space which drivers can query to get setup information from the host.

---
 drivers/Kconfig                 |    2 
 drivers/Makefile                |    1 
 drivers/virtio/Kconfig          |    3 
 drivers/virtio/Makefile         |    1 
 drivers/virtio/config.c         |   13 ++
 drivers/virtio/virtio.c         |  187 +++++++++++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h |    6 +
 include/linux/virtio.h          |  110 ++++++++++++++++++++++
 include/linux/virtio_config.h   |  111 +++++++++++++++++++++++
 9 files changed, 434 insertions(+)

===================================================================

drivers/Kconfig +2 -0
@@ -87,4 +87,6 @@ source "drivers/kvm/Kconfig"
 source "drivers/kvm/Kconfig"
 
 source "drivers/uio/Kconfig"
+
+source "drivers/virtio/Kconfig"
 endmenu

===================================================================

drivers/Makefile +1 -0
@@ -88,3 +88,4 @@ obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
 obj-$(CONFIG_OF)		+= of/
+obj-$(CONFIG_VIRTIO)		+= virtio/

===================================================================

drivers/virtio/Kconfig new file +3 -0
@@ -0,0 +1,3 @@
+# Virtio always gets selected by whoever wants it.
+config VIRTIO
+	bool

===================================================================

drivers/virtio/Makefile new file +1 -0
@@ -0,0 +1,1 @@
+obj-$(CONFIG_VIRTIO) += virtio.o

===================================================================

drivers/virtio/config.c new file +13 -0
@@ -0,0 +1,13 @@
+/* Configuration space parsing helpers for virtio.
+ *
+ * The configuration is [type][len][... len bytes ...] fields.
+ *
+ * Copyright 2007 Rusty Russell, IBM Corporation.
+ * GPL v2 or later.
+ */
+#include <linux/err.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/bug.h>
+#include <asm/system.h>
+

===================================================================

drivers/virtio/virtio.c new file +187 -0

187 lines not on this page · raw message

===================================================================

include/linux/mod_devicetable.h +6 -0
@@ -340,4 +340,10 @@ struct parisc_device_id {
 #define PA_HVERSION_ANY_ID	0xffff
 #define PA_SVERSION_ANY_ID	0xffffffff
 
+struct virtio_device_id {
+	__u32 device;
+	__u32 vendor;
+};
+#define VIRTIO_DEV_ANY_ID	0xffffffff
+
 #endif /* LINUX_MOD_DEVICETABLE_H */

===================================================================

include/linux/virtio.h new file +110 -0

110 lines not on this page · raw message

===================================================================

include/linux/virtio_config.h new file +111 -0

111 lines not on this page · raw message