| #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_ */ |