blob: 2c31fdc7f7f311dda45de0a088ba6d4901c02c2b [file] [log] [blame]
#ifndef _VIRTIO_H_
#define _VIRTIO_H_
/*
* A minimal implementation of virtio.
* Structures adapted from the Linux Kernel.
*
* Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2.
*/
#include "libcflat.h"
#define VIRTIO_ID_CONSOLE 3
struct virtio_device_id {
u32 device;
u32 vendor;
};
struct virtio_device {
struct virtio_device_id id;
const struct virtio_config_ops *config;
};
struct virtqueue {
void (*callback)(struct virtqueue *vq);
const char *name;
struct virtio_device *vdev;
unsigned int index;
unsigned int num_free;
void *priv;
};
typedef void vq_callback_t(struct virtqueue *);
struct virtio_config_ops {
void (*get)(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len);
void (*set)(struct virtio_device *vdev, unsigned offset,
const void *buf, unsigned len);
int (*find_vqs)(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
const char *names[]);
};
static inline u8
virtio_config_readb(struct virtio_device *vdev, unsigned offset)
{
u8 val;
vdev->config->get(vdev, offset, &val, 1);
return val;
}
static inline u16
virtio_config_readw(struct virtio_device *vdev, unsigned offset)
{
u16 val;
vdev->config->get(vdev, offset, &val, 2);
return val;
}
static inline u32
virtio_config_readl(struct virtio_device *vdev, unsigned offset)
{
u32 val;
vdev->config->get(vdev, offset, &val, 4);
return val;
}
static inline void
virtio_config_writeb(struct virtio_device *vdev, unsigned offset, u8 val)
{
vdev->config->set(vdev, offset, &val, 1);
}
static inline void
virtio_config_writew(struct virtio_device *vdev, unsigned offset, u16 val)
{
vdev->config->set(vdev, offset, &val, 2);
}
static inline void
virtio_config_writel(struct virtio_device *vdev, unsigned offset, u32 val)
{
vdev->config->set(vdev, offset, &val, 4);
}
#define VRING_DESC_F_NEXT 1
#define VRING_DESC_F_WRITE 2
struct vring_desc {
u64 addr;
u32 len;
u16 flags;
u16 next;
};
struct vring_avail {
u16 flags;
u16 idx;
u16 ring[];
};
struct vring_used_elem {
u32 id;
u32 len;
};
struct vring_used {
u16 flags;
u16 idx;
struct vring_used_elem ring[];
};
struct vring {
unsigned int num;
struct vring_desc *desc;
struct vring_avail *avail;
struct vring_used *used;
};
struct vring_virtqueue {
struct virtqueue vq;
struct vring vring;
unsigned int free_head;
unsigned int num_added;
u16 last_used_idx;
bool (*notify)(struct virtqueue *vq);
void *data[];
};
#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
extern void vring_init(struct vring *vr, unsigned int num, void *p,
unsigned long align);
extern void vring_init_virtqueue(struct vring_virtqueue *vq, unsigned index,
unsigned num, unsigned vring_align,
struct virtio_device *vdev, void *pages,
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
const char *name);
extern int virtqueue_add_outbuf(struct virtqueue *vq, char *buf,
unsigned int len);
extern bool virtqueue_kick(struct virtqueue *vq);
extern void detach_buf(struct vring_virtqueue *vq, unsigned head);
extern void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len);
extern struct virtio_device *virtio_bind(u32 devid);
#endif /* _VIRTIO_H_ */