Skip to content

Commit

Permalink
virtio: call all virtqueue procedures via pointers
Browse files Browse the repository at this point in the history
Refactored virtio header to call all the virtqueue procedures
by pointers. Renamed all the actual procedures, added suffix
'_split', upon queue creation the function table in the
virtqueue structure filled with pointers of split ring procedures.
This is preparation patch for implementation of packed ring.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
  • Loading branch information
ybendito authored and YanVugenfirer committed Dec 31, 2019
1 parent 0a1f50c commit 986b0b7
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 39 deletions.
129 changes: 101 additions & 28 deletions VirtIO/VirtIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,119 @@ struct VirtIOBufferDescriptor {
ULONG length;
};

/* Represents one virtqueue; only data pointed to by the vring structure is exposed to the host */
struct virtqueue {
VirtIODevice *vdev;
unsigned int index;
void (*notification_cb)(struct virtqueue *vq);
void *notification_addr;
void *avail_va;
void *used_va;
};
typedef int (*proc_virtqueue_add_buf)(
struct virtqueue *vq,
struct scatterlist sg[],
unsigned int out_num,
unsigned int in_num,
void *opaque,
void *va_indirect,
ULONGLONG phys_indirect);

int virtqueue_add_buf(struct virtqueue *vq,
struct scatterlist sg[],
unsigned int out_num,
unsigned int in_num,
void *opaque,
void *va_indirect,
ULONGLONG phys_indirect);
typedef bool(*proc_virtqueue_kick_prepare)(struct virtqueue *vq);

void virtqueue_kick(struct virtqueue *vq);
typedef void(*proc_virtqueue_kick_always)(struct virtqueue *vq);

bool virtqueue_kick_prepare(struct virtqueue *vq);
typedef void * (*proc_virtqueue_get_buf)(struct virtqueue *vq, unsigned int *len);

void virtqueue_kick_always(struct virtqueue *vq);
typedef void(*proc_virtqueue_disable_cb)(struct virtqueue *vq);

void virtqueue_notify(struct virtqueue *vq);
typedef bool(*proc_virtqueue_enable_cb)(struct virtqueue *vq);

void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
typedef bool(*proc_virtqueue_enable_cb_delayed)(struct virtqueue *vq);

void virtqueue_disable_cb(struct virtqueue *vq);
typedef void * (*proc_virtqueue_detach_unused_buf)(struct virtqueue *vq);

bool virtqueue_enable_cb(struct virtqueue *vq);
typedef BOOLEAN(*proc_virtqueue_is_interrupt_enabled)(struct virtqueue *vq);

bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
typedef BOOLEAN(*proc_virtqueue_has_buf)(struct virtqueue *vq);

void *virtqueue_detach_unused_buf(struct virtqueue *vq);
typedef void(*proc_virtqueue_shutdown)(struct virtqueue *vq);

BOOLEAN virtqueue_is_interrupt_enabled(struct virtqueue *_vq);
/* Represents one virtqueue; only data pointed to by the vring structure is exposed to the host */
struct virtqueue {
VirtIODevice *vdev;
unsigned int index;
void (*notification_cb)(struct virtqueue *vq);
void *notification_addr;
void *avail_va;
void *used_va;
proc_virtqueue_add_buf add_buf;
proc_virtqueue_kick_prepare kick_prepare;
proc_virtqueue_kick_always kick_always;
proc_virtqueue_get_buf get_buf;
proc_virtqueue_disable_cb disable_cb;
proc_virtqueue_enable_cb enable_cb;
proc_virtqueue_enable_cb_delayed enable_cb_delayed;
proc_virtqueue_detach_unused_buf detach_unused_buf;
proc_virtqueue_is_interrupt_enabled is_interrupt_enabled;
proc_virtqueue_has_buf has_buf;
proc_virtqueue_shutdown shutdown;
};

BOOLEAN virtqueue_has_buf(struct virtqueue *_vq);
static inline int virtqueue_add_buf(
struct virtqueue *vq,
struct scatterlist sg[],
unsigned int out_num,
unsigned int in_num,
void *opaque,
void *va_indirect,
ULONGLONG phys_indirect)
{
return vq->add_buf(vq, sg, out_num, in_num, opaque, va_indirect, phys_indirect);
}

static inline bool virtqueue_kick_prepare(struct virtqueue *vq)
{
return vq->kick_prepare(vq);
}

static inline void virtqueue_kick_always(struct virtqueue *vq)
{
vq->kick_always(vq);
}

static inline void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
{
return vq->get_buf(vq, len);
}

static inline void virtqueue_disable_cb(struct virtqueue *vq)
{
vq->disable_cb(vq);
}

static inline bool virtqueue_enable_cb(struct virtqueue *vq)
{
return vq->enable_cb(vq);
}

static inline bool virtqueue_enable_cb_delayed(struct virtqueue *vq)
{
return vq->enable_cb_delayed(vq);
}

static inline void *virtqueue_detach_unused_buf(struct virtqueue *vq)
{
return vq->detach_unused_buf(vq);
}

static inline BOOLEAN virtqueue_is_interrupt_enabled(struct virtqueue *vq)
{
return vq->is_interrupt_enabled(vq);
}

static inline BOOLEAN virtqueue_has_buf(struct virtqueue *vq)
{
return vq->has_buf(vq);
}

static inline void virtqueue_shutdown(struct virtqueue *vq)
{
vq->shutdown(vq);
}

void virtqueue_shutdown(struct virtqueue *_vq);
void virtqueue_notify(struct virtqueue *vq);
void virtqueue_kick(struct virtqueue *vq);

#endif /* _LINUX_VIRTIO_H */
33 changes: 22 additions & 11 deletions VirtIO/VirtIORing.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ static inline void put_unused_desc_chain(struct virtqueue_split *vq, u16 idx)
}

/* Adds a buffer to a virtqueue, returns 0 on success, negative number on error */
int virtqueue_add_buf(
static int virtqueue_add_buf_split(
struct virtqueue *_vq, /* the queue */
struct scatterlist sg[], /* sg array of length out + in */
unsigned int out, /* number of driver->device buffer descriptors in sg */
Expand Down Expand Up @@ -300,7 +300,7 @@ int virtqueue_add_buf(
}

/* Gets the opaque pointer associated with a returned buffer, or NULL if no buffer is available */
void *virtqueue_get_buf(
static void *virtqueue_get_buf_split(
struct virtqueue *_vq, /* the queue */
unsigned int *len) /* number of bytes returned by the device */
{
Expand Down Expand Up @@ -335,14 +335,14 @@ void *virtqueue_get_buf(
}

/* Returns true if at least one returned buffer is available, false otherwise */
BOOLEAN virtqueue_has_buf(struct virtqueue *_vq)
static BOOLEAN virtqueue_has_buf_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
return (vq->last_used != vq->vring.used->idx);
}

/* Returns true if the device should be notified, false otherwise */
bool virtqueue_kick_prepare(struct virtqueue *_vq)
static bool virtqueue_kick_prepare_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
bool wrap_around;
Expand All @@ -363,7 +363,7 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq)
}

/* Notifies the device even if it's not necessary according to the event suppression logic */
void virtqueue_kick_always(struct virtqueue *_vq)
static void virtqueue_kick_always_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
KeMemoryBarrier();
Expand All @@ -373,7 +373,7 @@ void virtqueue_kick_always(struct virtqueue *_vq)

/* Enables interrupts on a virtqueue and returns false if the queue has at least one returned
* buffer available to be fetched by virtqueue_get_buf, true otherwise */
bool virtqueue_enable_cb(struct virtqueue *_vq)
static bool virtqueue_enable_cb_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
if (!virtqueue_is_interrupt_enabled(_vq)) {
Expand All @@ -391,7 +391,7 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)

/* Enables interrupts on a virtqueue after ~3/4 of the currently pushed buffers have been
* returned, returns false if this condition currently holds, false otherwise */
bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
static bool virtqueue_enable_cb_delayed_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
u16 bufs;
Expand All @@ -412,7 +412,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
}

/* Disables interrupts on a virtqueue */
void virtqueue_disable_cb(struct virtqueue *_vq)
static void virtqueue_disable_cb_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
if (virtqueue_is_interrupt_enabled(_vq)) {
Expand All @@ -425,14 +425,14 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
}

/* Returns true if interrupts are enabled on a virtqueue, false otherwise */
BOOLEAN virtqueue_is_interrupt_enabled(struct virtqueue *_vq)
static BOOLEAN virtqueue_is_interrupt_enabled_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
return !(vq->master_vring_avail.flags & VIRTQ_AVAIL_F_NO_INTERRUPT);
}

/* Re-initializes an already initialized virtqueue */
void virtqueue_shutdown(struct virtqueue *_vq)
static void virtqueue_shutdown_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
unsigned int num = vq->vring.num;
Expand All @@ -452,7 +452,7 @@ void virtqueue_shutdown(struct virtqueue *_vq)

/* Gets the opaque pointer associated with a not-yet-returned buffer, or NULL if no buffer is available
* to aid drivers with cleaning up all data on virtqueue shutdown */
void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
static void *virtqueue_detach_unused_buf_split(struct virtqueue *_vq)
{
struct virtqueue_split *vq = splitvq(_vq);
u16 idx;
Expand Down Expand Up @@ -512,6 +512,17 @@ struct virtqueue *vring_new_virtqueue(
}
vq->vq.avail_va = vq->vring.avail;
vq->vq.used_va = vq->vring.used;
vq->vq.add_buf = virtqueue_add_buf_split;
vq->vq.detach_unused_buf = virtqueue_detach_unused_buf_split;
vq->vq.disable_cb = virtqueue_disable_cb_split;
vq->vq.enable_cb = virtqueue_enable_cb_split;
vq->vq.enable_cb_delayed = virtqueue_enable_cb_delayed_split;
vq->vq.get_buf = virtqueue_get_buf_split;
vq->vq.has_buf = virtqueue_has_buf_split;
vq->vq.is_interrupt_enabled = virtqueue_is_interrupt_enabled_split;
vq->vq.kick_always = virtqueue_kick_always_split;
vq->vq.kick_prepare = virtqueue_kick_prepare_split;
vq->vq.shutdown = virtqueue_shutdown_split;
return &vq->vq;
}

Expand Down

0 comments on commit 986b0b7

Please sign in to comment.