All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <levinsasha928@gmail.com>
To: penberg@kernel.org
Cc: john@jfloren.net, kvm@vger.kernel.org, mingo@elte.hu,
	asias.hejun@gmail.com, gorcunov@gmail.com,
	prasadjoshi124@gmail.com, Sasha Levin <levinsasha928@gmail.com>
Subject: [PATCH v2 4/8] kvm tools: Add support for multiple virtio-rng devices
Date: Thu, 26 May 2011 09:42:11 +0300	[thread overview]
Message-ID: <1306392135-16993-4-git-send-email-levinsasha928@gmail.com> (raw)
In-Reply-To: <1306392135-16993-1-git-send-email-levinsasha928@gmail.com>

Since multiple hardware rng devices of the same type are currently
unsupported by the kernel, this serves more as an example of a basic
virtio driver under kvm tools and can be used to debug the PCI layer.

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
 tools/kvm/include/kvm/ioport.h        |    2 -
 tools/kvm/include/kvm/parse-options.h |    9 +++
 tools/kvm/include/kvm/virtio-rng.h    |    1 +
 tools/kvm/kvm-run.c                   |    8 ++-
 tools/kvm/virtio/rng.c                |  126 ++++++++++++++++++++++-----------
 5 files changed, 100 insertions(+), 46 deletions(-)

diff --git a/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h
index 47f9fb5..ffa6893 100644
--- a/tools/kvm/include/kvm/ioport.h
+++ b/tools/kvm/include/kvm/ioport.h
@@ -18,8 +18,6 @@
 #define IOPORT_VIRTIO_CONSOLE_SIZE	256
 #define IOPORT_VIRTIO_NET		0xe200	/* Virtio network device */
 #define IOPORT_VIRTIO_NET_SIZE		256
-#define IOPORT_VIRTIO_RNG		0xf200	/* Virtio network device */
-#define IOPORT_VIRTIO_RNG_SIZE		256
 
 #define IOPORT_EMPTY			USHRT_MAX
 
diff --git a/tools/kvm/include/kvm/parse-options.h b/tools/kvm/include/kvm/parse-options.h
index 2d5c99e..6bf9a1d 100644
--- a/tools/kvm/include/kvm/parse-options.h
+++ b/tools/kvm/include/kvm/parse-options.h
@@ -132,6 +132,15 @@ intptr_t defval;
 	.help = (h)                         \
 }
 
+#define OPT_INCR(s, l, v, h)                \
+{                                           \
+	.type = OPTION_INCR,	            \
+	.short_name = (s),                  \
+	.long_name = (l),                   \
+	.value = check_vtype(v, int *),     \
+	.help = (h)                         \
+}
+
 #define OPT_GROUP(h)                        \
 {                                           \
 	.type = OPTION_GROUP,               \
diff --git a/tools/kvm/include/kvm/virtio-rng.h b/tools/kvm/include/kvm/virtio-rng.h
index 7015c1f..c0a413b 100644
--- a/tools/kvm/include/kvm/virtio-rng.h
+++ b/tools/kvm/include/kvm/virtio-rng.h
@@ -4,5 +4,6 @@
 struct kvm;
 
 void virtio_rng__init(struct kvm *kvm);
+void virtio_rng__delete_all(struct kvm *kvm);
 
 #endif /* KVM__RNG_VIRTIO_H */
diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c
index adbb25b..76b5782 100644
--- a/tools/kvm/kvm-run.c
+++ b/tools/kvm/kvm-run.c
@@ -52,6 +52,7 @@ static __thread struct kvm_cpu *current_kvm_cpu;
 
 static u64 ram_size;
 static u8  image_count;
+static int virtio_rng;
 static const char *kernel_cmdline;
 static const char *kernel_filename;
 static const char *vmlinux_filename;
@@ -66,7 +67,6 @@ static const char *script;
 static const char *virtio_9p_dir;
 static bool single_step;
 static bool readonly_image[MAX_DISK_IMAGES];
-static bool virtio_rng;
 static bool vnc;
 extern bool ioport_debug;
 extern int  active_console;
@@ -107,7 +107,7 @@ static const struct option options[] = {
 	OPT_CALLBACK('d', "disk", NULL, "image", "Disk image", img_name_parser),
 	OPT_STRING('\0', "console", &console, "serial or virtio",
 			"Console to use"),
-	OPT_BOOLEAN('\0', "rng", &virtio_rng,
+	OPT_INCR('\0', "rng", &virtio_rng,
 			"Enable virtio Random Number Generator"),
 	OPT_STRING('\0', "kvm-dev", &kvm_dev, "kvm-dev", "KVM device file"),
 	OPT_STRING('\0', "virtio-9p", &virtio_9p_dir, "root dir",
@@ -570,7 +570,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
 		virtio_console__init(kvm);
 
 	if (virtio_rng)
-		virtio_rng__init(kvm);
+		while (virtio_rng--)
+			virtio_rng__init(kvm);
 
 	if (!network)
 		network = DEFAULT_NETWORK;
@@ -631,6 +632,7 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
 	}
 
 	virtio_blk__delete_all(kvm);
+	virtio_rng__delete_all(kvm);
 
 	disk_image__close_all(kvm->disks, image_count);
 	kvm__delete(kvm);
diff --git a/tools/kvm/virtio/rng.c b/tools/kvm/virtio/rng.c
index 9bd0098..f71a59b 100644
--- a/tools/kvm/virtio/rng.c
+++ b/tools/kvm/virtio/rng.c
@@ -5,7 +5,6 @@
 #include "kvm/disk-image.h"
 #include "kvm/virtio.h"
 #include "kvm/ioport.h"
-#include "kvm/mutex.h"
 #include "kvm/util.h"
 #include "kvm/kvm.h"
 #include "kvm/pci.h"
@@ -15,6 +14,7 @@
 #include <linux/virtio_ring.h>
 #include <linux/virtio_rng.h>
 
+#include <linux/list.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -23,18 +23,17 @@
 #define NUM_VIRT_QUEUES				1
 #define VIRTIO_RNG_QUEUE_SIZE			128
 
-static struct pci_device_header virtio_rng_pci_device = {
-	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
-	.device_id		= PCI_DEVICE_ID_VIRTIO_RNG,
-	.header_type		= PCI_HEADER_TYPE_NORMAL,
-	.revision_id		= 0,
-	.class			= 0x010000,
-	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
-	.subsys_id		= VIRTIO_ID_RNG,
-	.bar[0]			= IOPORT_VIRTIO_RNG | PCI_BASE_ADDRESS_SPACE_IO,
+struct rng_dev_job {
+	struct virt_queue		*vq;
+	struct rng_dev			*rdev;
+	void				*job_id;
 };
 
 struct rng_dev {
+	struct pci_device_header pci_hdr;
+	struct list_head	list;
+
+	u16			base_addr;
 	u8			status;
 	u8			isr;
 	u16			config_vector;
@@ -43,17 +42,19 @@ struct rng_dev {
 	/* virtio queue */
 	u16			queue_selector;
 	struct virt_queue	vqs[NUM_VIRT_QUEUES];
-	void			*jobs[NUM_VIRT_QUEUES];
+	struct rng_dev_job	jobs[NUM_VIRT_QUEUES];
 };
 
-static struct rng_dev rdev;
+static LIST_HEAD(rdevs);
 
-static bool virtio_rng_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_rng_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count, void *param)
 {
 	unsigned long offset;
 	bool ret = true;
+	struct rng_dev *rdev;
 
-	offset = port - IOPORT_VIRTIO_RNG;
+	rdev = param;
+	offset = port - rdev->base_addr;
 
 	switch (offset) {
 	case VIRTIO_PCI_HOST_FEATURES:
@@ -63,21 +64,21 @@ static bool virtio_rng_pci_io_in(struct kvm *kvm, u16 port, void *data, int size
 		ret		= false;
 		break;
 	case VIRTIO_PCI_QUEUE_PFN:
-		ioport__write32(data, rdev.vqs[rdev.queue_selector].pfn);
+		ioport__write32(data, rdev->vqs[rdev->queue_selector].pfn);
 		break;
 	case VIRTIO_PCI_QUEUE_NUM:
 		ioport__write16(data, VIRTIO_RNG_QUEUE_SIZE);
 		break;
 	case VIRTIO_PCI_STATUS:
-		ioport__write8(data, rdev.status);
+		ioport__write8(data, rdev->status);
 		break;
 	case VIRTIO_PCI_ISR:
-		ioport__write8(data, rdev.isr);
-		kvm__irq_line(kvm, virtio_rng_pci_device.irq_line, VIRTIO_IRQ_LOW);
-		rdev.isr = VIRTIO_IRQ_LOW;
+		ioport__write8(data, rdev->isr);
+		kvm__irq_line(kvm, rdev->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
+		rdev->isr = VIRTIO_IRQ_LOW;
 		break;
 	case VIRTIO_MSI_CONFIG_VECTOR:
-		ioport__write16(data, rdev.config_vector);
+		ioport__write16(data, rdev->config_vector);
 		break;
 	default:
 		ret		= false;
@@ -87,14 +88,14 @@ static bool virtio_rng_pci_io_in(struct kvm *kvm, u16 port, void *data, int size
 	return ret;
 }
 
-static bool virtio_rng_do_io_request(struct kvm *kvm, struct virt_queue *queue)
+static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, struct virt_queue *queue)
 {
 	struct iovec iov[VIRTIO_RNG_QUEUE_SIZE];
 	unsigned int len = 0;
 	u16 out, in, head;
 
 	head		= virt_queue__get_iov(queue, iov, &out, &in, kvm);
-	len		= readv(rdev.fd, iov, in);
+	len		= readv(rdev->fd, iov, in);
 
 	virt_queue__set_used_elem(queue, head, len);
 
@@ -103,20 +104,24 @@ static bool virtio_rng_do_io_request(struct kvm *kvm, struct virt_queue *queue)
 
 static void virtio_rng_do_io(struct kvm *kvm, void *param)
 {
-	struct virt_queue *vq = param;
+	struct rng_dev_job *job = param;
+	struct virt_queue *vq = job->vq;
+	struct rng_dev *rdev = job->rdev;
 
 	while (virt_queue__available(vq)) {
-		virtio_rng_do_io_request(kvm, vq);
-		virt_queue__trigger_irq(vq, virtio_rng_pci_device.irq_line, &rdev.isr, kvm);
+		virtio_rng_do_io_request(kvm, rdev, vq);
+		virt_queue__trigger_irq(vq, rdev->pci_hdr.irq_line, &rdev->isr, kvm);
 	}
 }
 
-static bool virtio_rng_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count)
+static bool virtio_rng_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count, void *param)
 {
 	unsigned long offset;
 	bool ret = true;
+	struct rng_dev *rdev;
 
-	offset		= port - IOPORT_VIRTIO_RNG;
+	rdev = param;
+	offset = port - rdev->base_addr;
 
 	switch (offset) {
 	case VIRTIO_MSI_QUEUE_VECTOR:
@@ -124,32 +129,40 @@ static bool virtio_rng_pci_io_out(struct kvm *kvm, u16 port, void *data, int siz
 		break;
 	case VIRTIO_PCI_QUEUE_PFN: {
 		struct virt_queue *queue;
+		struct rng_dev_job *job;
 		void *p;
 
-		queue			= &rdev.vqs[rdev.queue_selector];
+		queue			= &rdev->vqs[rdev->queue_selector];
 		queue->pfn		= ioport__read32(data);
 		p			= guest_pfn_to_host(kvm, queue->pfn);
 
+		job = &rdev->jobs[rdev->queue_selector];
+
 		vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
 
-		rdev.jobs[rdev.queue_selector] = thread_pool__add_job(kvm, virtio_rng_do_io, queue);
+		*job			= (struct rng_dev_job) {
+			.vq			= queue,
+			.rdev			= rdev,
+		};
+
+		job->job_id = thread_pool__add_job(kvm, virtio_rng_do_io, job);
 
 		break;
 	}
 	case VIRTIO_PCI_QUEUE_SEL:
-		rdev.queue_selector	= ioport__read16(data);
+		rdev->queue_selector	= ioport__read16(data);
 		break;
 	case VIRTIO_PCI_QUEUE_NOTIFY: {
 		u16 queue_index;
 		queue_index		= ioport__read16(data);
-		thread_pool__do_job(rdev.jobs[queue_index]);
+		thread_pool__do_job(rdev->jobs[queue_index].job_id);
 		break;
 	}
 	case VIRTIO_PCI_STATUS:
-		rdev.status		= ioport__read8(data);
+		rdev->status		= ioport__read8(data);
 		break;
 	case VIRTIO_MSI_CONFIG_VECTOR:
-		rdev.config_vector	= VIRTIO_MSI_NO_VECTOR;
+		rdev->config_vector	= VIRTIO_MSI_NO_VECTOR;
 		break;
 	default:
 		ret			= false;
@@ -160,24 +173,55 @@ static bool virtio_rng_pci_io_out(struct kvm *kvm, u16 port, void *data, int siz
 }
 
 static struct ioport_operations virtio_rng_io_ops = {
-	.io_in				= virtio_rng_pci_io_in,
-	.io_out				= virtio_rng_pci_io_out,
+	.io_in_param			= virtio_rng_pci_io_in,
+	.io_out_param			= virtio_rng_pci_io_out,
 };
 
 void virtio_rng__init(struct kvm *kvm)
 {
 	u8 pin, line, dev;
+	u16 rdev_base_addr;
+	struct rng_dev *rdev;
+
+	rdev = malloc(sizeof(*rdev));
+	if (rdev == NULL)
+		return;
+
+	rdev_base_addr = ioport__register_param(IOPORT_EMPTY, &virtio_rng_io_ops, IOPORT_SIZE, rdev);
+
+	rdev->pci_hdr = (struct pci_device_header) {
+		.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
+		.device_id		= PCI_DEVICE_ID_VIRTIO_RNG,
+		.header_type		= PCI_HEADER_TYPE_NORMAL,
+		.revision_id		= 0,
+		.class			= 0x010000,
+		.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
+		.subsys_id		= VIRTIO_ID_RNG,
+		.bar[0]			= rdev_base_addr | PCI_BASE_ADDRESS_SPACE_IO,
+	};
 
-	rdev.fd = open("/dev/urandom", O_RDONLY);
-	if (rdev.fd < 0)
+	rdev->base_addr = rdev_base_addr;
+	rdev->fd = open("/dev/urandom", O_RDONLY);
+	if (rdev->fd < 0)
 		die("Failed initializing RNG");
 
 	if (irq__register_device(VIRTIO_ID_RNG, &dev, &pin, &line) < 0)
 		return;
 
-	virtio_rng_pci_device.irq_pin	= pin;
-	virtio_rng_pci_device.irq_line	= line;
-	pci__register(&virtio_rng_pci_device, dev);
+	rdev->pci_hdr.irq_pin	= pin;
+	rdev->pci_hdr.irq_line	= line;
+	pci__register(&rdev->pci_hdr, dev);
+
+	list_add_tail(&rdev->list, &rdevs);
+}
+
+void virtio_rng__delete_all(struct kvm *kvm)
+{
+	while (!list_empty(&rdevs)) {
+		struct rng_dev *rdev;
 
-	ioport__register(IOPORT_VIRTIO_RNG, &virtio_rng_io_ops, IOPORT_VIRTIO_RNG_SIZE);
+		rdev = list_first_entry(&rdevs, struct rng_dev, list);
+		list_del(&rdev->list);
+		free(rdev);
+	}
 }
-- 
1.7.5.rc3


  parent reply	other threads:[~2011-05-26  6:42 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-26  6:42 [PATCH v2 1/8] kvm tools: Add optional parameter used in ioport callbacks Sasha Levin
2011-05-26  6:42 ` [PATCH v2 2/8] kvm tools: Add basic ioport dynamic allocation Sasha Levin
2011-05-26  6:42 ` [PATCH v2 3/8] kvm tools: Use ioport context to control blk devices Sasha Levin
2011-05-26  6:42 ` Sasha Levin [this message]
2011-05-26  6:42 ` [PATCH v2 5/8] kvm tools: Use dynamic IO port allocation in vesa driver Sasha Levin
2011-05-26  6:42 ` [PATCH v2 6/8] kvm tools: Use dynamic IO port allocation in 9p driver Sasha Levin
2011-05-26  6:42 ` [PATCH v2 7/8] kvm tools: Use dynamic IO port allocation in virtio-console Sasha Levin
2011-05-26  6:42 ` [PATCH v2 8/8] kvm tools: Use dynamic IO port allocation in virtio-net Sasha Levin
2011-05-26  8:53 ` [PATCH v2 1/8] kvm tools: Add optional parameter used in ioport callbacks Pekka Enberg
2011-05-26  9:02   ` Sasha Levin
2011-05-26  9:04     ` Pekka Enberg
2011-05-26  9:14       ` Sasha Levin
2011-05-26  9:20         ` Pekka Enberg
2011-05-26  9:38           ` Sasha Levin
2011-05-26  9:43             ` Pekka Enberg
2011-05-26  9:49               ` Pekka Enberg

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=1306392135-16993-4-git-send-email-levinsasha928@gmail.com \
    --to=levinsasha928@gmail.com \
    --cc=asias.hejun@gmail.com \
    --cc=gorcunov@gmail.com \
    --cc=john@jfloren.net \
    --cc=kvm@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=penberg@kernel.org \
    --cc=prasadjoshi124@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.