Patchwork [PATCHv5,04/11] virtio: notifier support + APIs for queue fields

login
register
mail settings
Submitter Michael S. Tsirkin
Date March 16, 2010, 5:10 p.m.
Message ID <8cc7396586d6e6caf90611dbddd8eb901b3ecaf4.1268758544.git.mst@redhat.com>
Download mbox | patch
Permalink /patch/47874/
State New
Headers show

Comments

Michael S. Tsirkin - March 16, 2010, 5:10 p.m.
vhost needs physical addresses for ring and other queue fields,
so add APIs for these. In particular, add binding API to set
host/guest notifiers.  Will be used by vhost.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/virtio.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/virtio.h |   18 ++++++++++++-
 2 files changed, 96 insertions(+), 2 deletions(-)
Amit Shah - March 17, 2010, 4:14 a.m.
On (Tue) Mar 16 2010 [19:10:58], Michael S. Tsirkin wrote:
> 
> diff --git a/hw/virtio.c b/hw/virtio.c
> index 7c020a3..f54129f 100644
> --- a/hw/virtio.c
> +++ b/hw/virtio.c
> @@ -73,6 +73,9 @@ struct VirtQueue
>      int inuse;
>      uint16_t vector;
>      void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
> +    VirtIODevice *vdev;
> +    EventNotifier guest_notifier;
> +    EventNotifier host_notifier;

Another thing that terribly confused me was this: in the vq struct you
have guest_notifier and host_notifier of type EventNotifier and in the
virtio binding structs you have guest_notifier and host_notifier which
are function callbacks.

Also, these vq->{guest_|host_}notifier assignments weren't easily found
using grep because they're assigned by assigning a pointer value and
initialising that pointer. Thanks to Juan for finding that for me :-)

		Amit
Michael S. Tsirkin - March 17, 2010, 10:48 a.m.
On Wed, Mar 17, 2010 at 09:44:05AM +0530, Amit Shah wrote:
> On (Tue) Mar 16 2010 [19:10:58], Michael S. Tsirkin wrote:
> > 
> > diff --git a/hw/virtio.c b/hw/virtio.c
> > index 7c020a3..f54129f 100644
> > --- a/hw/virtio.c
> > +++ b/hw/virtio.c
> > @@ -73,6 +73,9 @@ struct VirtQueue
> >      int inuse;
> >      uint16_t vector;
> >      void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
> > +    VirtIODevice *vdev;
> > +    EventNotifier guest_notifier;
> > +    EventNotifier host_notifier;
> 
> Another thing that terribly confused me was this: in the vq struct you
> have guest_notifier and host_notifier of type EventNotifier and in the
> virtio binding structs you have guest_notifier and host_notifier which
> are function callbacks.
> Also, these vq->{guest_|host_}notifier assignments weren't easily found
> using grep because they're assigned by assigning a pointer value and
> initialising that pointer. Thanks to Juan for finding that for me :-)
> 
> 		Amit

I've renamed them to set_xxx_notifier to avoid confusion.

> -- 
> http://log.amitshah.net/

Patch

diff --git a/hw/virtio.c b/hw/virtio.c
index 7c020a3..f54129f 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -73,6 +73,9 @@  struct VirtQueue
     int inuse;
     uint16_t vector;
     void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
+    VirtIODevice *vdev;
+    EventNotifier guest_notifier;
+    EventNotifier host_notifier;
 };
 
 /* virt queue functions */
@@ -592,6 +595,12 @@  VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
     return &vdev->vq[i];
 }
 
+void virtio_irq(VirtQueue *vq)
+{
+    vq->vdev->isr |= 0x01;
+    virtio_notify_vector(vq->vdev, vq->vector);
+}
+
 void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
 {
     /* Always notify when queue is empty (when feature acknowledge) */
@@ -714,8 +723,10 @@  VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
     vdev->queue_sel = 0;
     vdev->config_vector = VIRTIO_NO_VECTOR;
     vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
-    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++)
+    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+        vdev->vq[i].vdev = vdev;
+    }
 
     vdev->name = name;
     vdev->config_len = config_size;
@@ -733,3 +744,70 @@  void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
     vdev->binding = binding;
     vdev->binding_opaque = opaque;
 }
+
+target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.desc;
+}
+
+target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.avail;
+}
+
+target_phys_addr_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.used;
+}
+
+target_phys_addr_t virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.desc;
+}
+
+target_phys_addr_t virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
+{
+    return sizeof(VRingDesc) * vdev->vq[n].vring.num;
+}
+
+target_phys_addr_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
+{
+    return offsetof(VRingAvail, ring) +
+        sizeof(u_int64_t) * vdev->vq[n].vring.num;
+}
+
+target_phys_addr_t virtio_queue_get_used_size(VirtIODevice *vdev, int n)
+{
+    return offsetof(VRingUsed, ring) +
+        sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
+}
+
+target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.used - vdev->vq[n].vring.desc +
+	    virtio_queue_get_used_size(vdev, n);
+}
+
+uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].last_avail_idx;
+}
+
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
+{
+    vdev->vq[n].last_avail_idx = idx;
+}
+
+VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
+{
+    return vdev->vq + n;
+}
+
+EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
+{
+    return &vq->guest_notifier;
+}
+EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
+{
+    return &vq->host_notifier;
+}
diff --git a/hw/virtio.h b/hw/virtio.h
index 3baa2a3..a074a65 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -19,6 +19,7 @@ 
 #include "qdev.h"
 #include "sysemu.h"
 #include "block_int.h"
+#include "event_notifier.h"
 
 /* from Linux's linux/virtio_config.h */
 
@@ -89,6 +90,8 @@  typedef struct {
     int (*load_config)(void * opaque, QEMUFile *f);
     int (*load_queue)(void * opaque, int n, QEMUFile *f);
     unsigned (*get_features)(void * opaque);
+    int (*guest_notifier)(void * opaque, int n, bool assigned);
+    int (*host_notifier)(void * opaque, int n, bool assigned);
 } VirtIOBindings;
 
 #define VIRTIO_PCI_QUEUE_MAX 64
@@ -181,5 +184,18 @@  void virtio_net_exit(VirtIODevice *vdev);
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
 			VIRTIO_RING_F_INDIRECT_DESC, true)
 
-
+target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_ring_addr(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_desc_size(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_used_size(VirtIODevice *vdev, int n);
+target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
+uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
+VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
+EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
+EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
+void virtio_irq(VirtQueue *vq);
 #endif