On Mon, May 10, 2010 at 10:48:42AM -0500, Anthony Liguori wrote:
On 05/10/2010 03:11 AM, Gleb Natapov wrote:
This patch adds native support for booting from virtio disks to Seabios.
Signed-off-by: Gleb Natapovgleb@redhat.com
A related problem that I think we need to think about how we solve is indicating to Seabios which device we want to boot from
With your patch, a user can select a virtio device explicitly or if they use only one virtio device, it will Just Work.
However, if a user uses IDE and virtio, or a user has multiple disks, they cannot select a device via -boot.
Isn't this problem unrelated to this patch? I mean if I start qemu with two ide devices can I specify from qemu command line which one I want to boot from?
Is this something we need to address? I don't think we'd break libvirt if we didn't.
Regards,
Anthony Liguori
Changelog: v1->v2:
- free memory in case of vq initialization error.
- change license of virtio ring/pci to LGPLv3 with permission of Laurent Vivier (aka the author).
diff --git a/Makefile b/Makefile index 327a1bf..d0b8881 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,8 @@ OUT=out/ SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \ kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \
usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c
usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \
virtio-ring.c virtio-pci.c virtio-blk.c
SRC16=$(SRCBOTH) system.c disk.c apm.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ diff --git a/src/block.c b/src/block.c index ddf441f..b6b1902 100644 --- a/src/block.c +++ b/src/block.c @@ -11,6 +11,7 @@ #include "util.h" // dprintf #include "ata.h" // process_ata_op #include "usb-msc.h" // process_usb_op +#include "virtio-blk.h" // process_virtio_op
struct drives_s Drives VAR16VISIBLE;
@@ -289,6 +290,8 @@ process_op(struct disk_op_s *op) return process_cdemu_op(op); case DTYPE_USB: return process_usb_op(op);
- case DTYPE_VIRTIO:
- return process_virtio_op(op); default: op->count = 0; return DISK_RET_EPARAM;
diff --git a/src/config.h b/src/config.h index b101174..ad569c6 100644 --- a/src/config.h +++ b/src/config.h @@ -136,6 +136,9 @@ #define CONFIG_SUBMODEL_ID 0x00 #define CONFIG_BIOS_REVISION 0x01
+// Support boot from virtio storage +#define CONFIG_VIRTIO_BLK 1
// Various memory addresses used by the code. #define BUILD_STACK_ADDR 0x7000 #define BUILD_S3RESUME_STACK_ADDR 0x1000 diff --git a/src/disk.h b/src/disk.h index 0cd1b74..9e5b083 100644 --- a/src/disk.h +++ b/src/disk.h @@ -197,6 +197,7 @@ struct drive_s { #define DTYPE_RAMDISK 0x04 #define DTYPE_CDEMU 0x05 #define DTYPE_USB 0x06 +#define DTYPE_VIRTIO 0x07
#define MAXDESCSIZE 80
diff --git a/src/pci_ids.h b/src/pci_ids.h index 1800f1d..e1cded2 100644 --- a/src/pci_ids.h +++ b/src/pci_ids.h @@ -2605,3 +2605,6 @@ #define PCI_DEVICE_ID_RME_DIGI32 0x9896 #define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 diff --git a/src/post.c b/src/post.c index 638b0f7..25535e2 100644 --- a/src/post.c +++ b/src/post.c @@ -23,6 +23,7 @@ #include "smbios.h" // smbios_init #include "paravirt.h" // qemu_cfg_port_probe #include "ps2port.h" // ps2port_setup +#include "virtio-blk.h" // virtio_blk_setup
void __set_irq(int vector, void *loc) @@ -184,6 +185,7 @@ init_hw(void) floppy_setup(); ata_setup(); ramdisk_setup();
- virtio_blk_setup();
}
// Main setup code. diff --git a/src/virtio-blk.c b/src/virtio-blk.c new file mode 100644 index 0000000..a41c336 --- /dev/null +++ b/src/virtio-blk.c @@ -0,0 +1,155 @@ +// Virtio blovl boot support. +// +// Copyright (C) 2010 Red Hat Inc. +// +// Authors: +// Gleb Natapovgnatapov@redhat.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license.
+#include "util.h" // dprintf +#include "pci.h" // foreachpci +#include "config.h" // CONFIG_* +#include "virtio-pci.h" +#include "virtio-blk.h" +#include "disk.h"
+struct virtiodrive_s {
- struct drive_s drive;
- struct vring_virtqueue *vq;
- u16 ioaddr;
+};
+static int +virtio_blk_read(struct disk_op_s *op) +{
- struct virtiodrive_s *vdrive_g =
container_of(op->drive_g, struct virtiodrive_s, drive);
- struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g->vq);
- struct virtio_blk_outhdr hdr = {
.type = VIRTIO_BLK_T_IN,
.ioprio = 0,
.sector = op->lba,
- };
- u8 status = VIRTIO_BLK_S_UNSUPP;
- struct vring_list sg[] = {
{
.addr = MAKE_FLATPTR(GET_SEG(SS),&hdr),
.length = sizeof(hdr),
},
{
.addr = op->buf_fl,
.length = GET_GLOBAL(vdrive_g->drive.blksize) * op->count,
},
{
.addr = MAKE_FLATPTR(GET_SEG(SS),&status),
.length = sizeof(status),
},
- };
- /* Add to virtqueue and kick host */
- vring_add_buf(vq, sg, 1, 2, 0, 0);
- vring_kick(GET_GLOBAL(vdrive_g->ioaddr), vq, 1);
- /* Wait for reply */
- while (!vring_more_used(vq))
udelay(5);
- /* Reclaim virtqueue element */
- vring_get_buf(vq, NULL);
- return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+int +process_virtio_op(struct disk_op_s *op) +{
- switch (op->command) {
- case CMD_READ:
return virtio_blk_read(op);
- case CMD_FORMAT:
- case CMD_WRITE:
return DISK_RET_EWRITEPROTECT;
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
return DISK_RET_SUCCESS;
- default:
op->count = 0;
return DISK_RET_EPARAM;
- }
+}
+void +virtio_blk_setup(void) +{
- ASSERT32FLAT();
- if (! CONFIG_VIRTIO_BLK)
return;
- dprintf(3, "init virtio-blk\n");
- int bdf, max;
- u32 id = PCI_VENDOR_ID_REDHAT_QUMRANET | (PCI_DEVICE_ID_VIRTIO_BLK<< 16);
- foreachpci(bdf, max) {
u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
if (v != id)
continue;
dprintf(3, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
pci_bdf_to_dev(bdf));
char *desc = malloc_tmphigh(MAXDESCSIZE);
struct virtiodrive_s *vdrive_g = malloc_fseg(sizeof(*vdrive_g));
struct vring_virtqueue *vq = malloc_low(sizeof(*vq));
if (!vdrive_g || !desc || !vq) {
warn_noalloc();
return;
}
memset(vdrive_g, 0, sizeof(*vdrive_g));
vdrive_g->drive.type = DTYPE_VIRTIO;
vdrive_g->drive.cntl_id = bdf;
vdrive_g->vq = vq;
u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0)&
PCI_BASE_ADDRESS_IO_MASK;
vdrive_g->ioaddr = ioaddr;
vp_reset(ioaddr);
vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER );
if (vp_find_vq(ioaddr, 0, vdrive_g->vq)< 0 ) {
free(vdrive_g);
free(desc);
free(vq);
dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
pci_bdf_to_bus (bdf), pci_bdf_to_dev(bdf));
continue;
}
struct virtio_blk_config cfg;
vp_get(ioaddr, 0,&cfg, sizeof(cfg));
vdrive_g->drive.blksize = cfg.blk_size;
vdrive_g->drive.sectors = cfg.capacity;
dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
pci_bdf_to_bus (bdf), pci_bdf_to_dev(bdf),
vdrive_g->drive.blksize, (u32)vdrive_g->drive.sectors);
vdrive_g->drive.pchs.cylinders = cfg.cylinders;
vdrive_g->drive.pchs.heads = cfg.heads;
vdrive_g->drive.pchs.spt = cfg.sectors;
setup_translation(&vdrive_g->drive);
add_bcv_internal(&vdrive_g->drive);
snprintf(desc, MAXDESCSIZE, "Virtio disk PCI:%x:%x",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
vdrive_g->drive.desc = desc;
vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
- }
+}
diff --git a/src/virtio-blk.h b/src/virtio-blk.h new file mode 100644 index 0000000..3369ea4 --- /dev/null +++ b/src/virtio-blk.h @@ -0,0 +1,40 @@ +#ifndef _VIRTIO_BLK_H +#define _VIRTIO_BLK_H
+struct virtio_blk_config +{
- u64 capacity;
- u32 size_max;
- u32 seg_max;
- u16 cylinders;
- u8 heads;
- u8 sectors;
- u32 blk_size;
- u8 physical_block_exp;
- u8 alignment_offset;
- u16 min_io_size;
- u32 opt_io_size;
+} __attribute__((packed));
+/* These two define direction. */ +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1
+/* This is the first element of the read scatter-gather list. */ +struct virtio_blk_outhdr {
- /* VIRTIO_BLK_T* */
- u32 type;
- /* io priority. */
- u32 ioprio;
- /* Sector (ie. 512 byte offset) */
- u64 sector;
+};
+#define VIRTIO_BLK_S_OK 0 +#define VIRTIO_BLK_S_IOERR 1 +#define VIRTIO_BLK_S_UNSUPP 2
+int process_virtio_op(struct disk_op_s *op); +void virtio_blk_setup(void);
+#endif /* _VIRTIO_BLK_H */ diff --git a/src/virtio-pci.c b/src/virtio-pci.c new file mode 100644 index 0000000..e171ea3 --- /dev/null +++ b/src/virtio-pci.c @@ -0,0 +1,67 @@ +/* virtio-pci.c - pci interface for virtio interface
- (c) Copyright 2008 Bull S.A.S.
- Author: Laurent VivierLaurent.Vivier@bull.net
- some parts from Linux Virtio PCI driver
- Copyright IBM Corp. 2007
- Authors: Anthony Liguorialiguori@us.ibm.com
- Adopted for Seabios: Gleb Natapovgleb@redhat.com
- This work is licensed under the terms of the GNU LGPLv3
- See the COPYING file in the top-level directory.
- */
+#include "virtio-ring.h" +#include "virtio-pci.h"
+int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq)
+{
- struct vring * vr =&vq->vring;
- u16 num;
- ASSERT32FLAT();
- /* select the queue */
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
- /* check if the queue is available */
- num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
- if (!num) {
dprintf(1, "ERROR: queue size is 0\n");
return -1;
- }
- if (num> MAX_QUEUE_NUM) {
dprintf(1, "ERROR: queue size %d> %d\n", num, MAX_QUEUE_NUM);
return -1;
- }
- /* check if the queue is already active */
- if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
dprintf(1, "ERROR: queue already active\n");
return -1;
- }
- vq->queue_index = queue_index;
- /* initialize the queue */
- vring_init(vr, num, (unsigned char*)&vq->queue);
- /* activate the queue
- NOTE: vr->desc is initialized by vring_init()
- */
- outl((unsigned long)virt_to_phys(vr->desc)>> PAGE_SHIFT,
ioaddr + VIRTIO_PCI_QUEUE_PFN);
- return num;
+} diff --git a/src/virtio-pci.h b/src/virtio-pci.h new file mode 100644 index 0000000..6932036 --- /dev/null +++ b/src/virtio-pci.h @@ -0,0 +1,97 @@ +#ifndef _VIRTIO_PCI_H +#define _VIRTIO_PCI_H
+/* A 32-bit r/o bitmask of the features supported by the host */ +#define VIRTIO_PCI_HOST_FEATURES 0
+/* A 32-bit r/w bitmask of features activated by the guest */ +#define VIRTIO_PCI_GUEST_FEATURES 4
+/* A 32-bit r/w PFN for the currently selected queue */ +#define VIRTIO_PCI_QUEUE_PFN 8
+/* A 16-bit r/o queue size for the currently selected queue */ +#define VIRTIO_PCI_QUEUE_NUM 12
+/* A 16-bit r/w queue selector */ +#define VIRTIO_PCI_QUEUE_SEL 14
+/* A 16-bit r/w queue notifier */ +#define VIRTIO_PCI_QUEUE_NOTIFY 16
+/* An 8-bit device status register. */ +#define VIRTIO_PCI_STATUS 18
+/* An 8-bit r/o interrupt status register. Reading the value will return the
- current contents of the ISR and will also clear it. This is effectively
- a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR 19
+/* The bit of the ISR which indicates a device configuration change. */ +#define VIRTIO_PCI_ISR_CONFIG 0x2
+/* The remaining space is defined by each driver as the per-driver
- configuration space */
+#define VIRTIO_PCI_CONFIG 20
+/* Virtio ABI version, this must match exactly */ +#define VIRTIO_PCI_ABI_VERSION 0
+static inline u32 vp_get_features(unsigned int ioaddr) +{
- return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+static inline void vp_set_features(unsigned int ioaddr, u32 features) +{
outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+}
+static inline void vp_get(unsigned int ioaddr, unsigned offset,
void *buf, unsigned len)
+{
- u8 *ptr = buf;
- unsigned i;
- for (i = 0; i< len; i++)
ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+}
+static inline u8 vp_get_status(unsigned int ioaddr) +{
- return inb(ioaddr + VIRTIO_PCI_STATUS);
+}
+static inline void vp_set_status(unsigned int ioaddr, u8 status) +{
- if (status == 0) /* reset */
return;
- outb(status, ioaddr + VIRTIO_PCI_STATUS);
+}
+static inline void vp_reset(unsigned int ioaddr) +{
- outb(0, ioaddr + VIRTIO_PCI_STATUS);
- (void)inb(ioaddr + VIRTIO_PCI_ISR);
+}
+static inline void vp_notify(unsigned int ioaddr, int queue_index) +{
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+}
+static inline void vp_del_vq(unsigned int ioaddr, int queue_index) +{
- /* select the queue */
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
- /* deactivate the queue */
- outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
+}
+int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq);
+#endif /* _VIRTIO_PCI_H_ */ diff --git a/src/virtio-ring.c b/src/virtio-ring.c new file mode 100644 index 0000000..f4a2efe --- /dev/null +++ b/src/virtio-ring.c @@ -0,0 +1,152 @@ +/* virtio-pci.c - virtio ring management
- (c) Copyright 2008 Bull S.A.S.
- Author: Laurent VivierLaurent.Vivier@bull.net
- some parts from Linux Virtio Ring
- Copyright Rusty Russell IBM Corporation 2007
- Adopted for Seabios: Gleb Natapovgleb@redhat.com
- This work is licensed under the terms of the GNU LGPLv3
- See the COPYING file in the top-level directory.
- */
+#include "virtio-ring.h" +#include "virtio-pci.h"
+#define BUG() do { \
dprintf(1, "BUG: failure at %s:%d/%s()!\n", \
__FILE__, __LINE__, __FUNCTION__); \
while(1); \
} while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
+/*
- vring_more_used
- is there some used buffers ?
- */
+int vring_more_used(struct vring_virtqueue *vq) +{
- struct vring_used *used = GET_FLATPTR(vq->vring.used);
- wmb();
- return GET_FLATPTR(vq->last_used_idx) != GET_FLATPTR(used->idx);
+}
+/*
- vring_free
- put at the begin of the free list the current desc[head]
- */
+void vring_detach(struct vring_virtqueue *vq, unsigned int head) +{
- struct vring *vr =&vq->vring;
- struct vring_desc *desc = GET_FLATPTR(vr->desc);
- unsigned int i;
- /* find end of given descriptor */
- i = head;
- while (GET_FLATPTR(desc[i].flags)& VRING_DESC_F_NEXT)
i = GET_FLATPTR(desc[i].next);
- /* link it with free list and point to it */
- SET_FLATPTR(desc[i].next, GET_FLATPTR(vq->free_head));
- wmb();
- SET_FLATPTR(vq->free_head, head);
+}
+/*
- vring_get_buf
- get a buffer from the used list
- */
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len) +{
- struct vring *vr =&vq->vring;
- struct vring_used_elem *elem;
- struct vring_used *used = GET_FLATPTR(vq->vring.used);
- u32 id;
- int ret;
+// BUG_ON(!vring_more_used(vq));
- elem =&used->ring[GET_FLATPTR(vq->last_used_idx) % GET_FLATPTR(vr->num)];
- wmb();
- id = GET_FLATPTR(elem->id);
- if (len != NULL)
*len = GET_FLATPTR(elem->len);
- ret = GET_FLATPTR(vq->vdata[id]);
- vring_detach(vq, id);
- SET_FLATPTR(vq->last_used_idx, GET_FLATPTR(vq->last_used_idx) + 1);
- return ret;
+}
+void vring_add_buf(struct vring_virtqueue *vq,
struct vring_list list[],
unsigned int out, unsigned int in,
int index, int num_added)
+{
- struct vring *vr =&vq->vring;
- int i, av, head, prev;
- struct vring_desc *desc = GET_FLATPTR(vr->desc);
- struct vring_avail *avail = GET_FLATPTR(vr->avail);
- BUG_ON(out + in == 0);
- prev = 0;
- head = GET_FLATPTR(vq->free_head);
- for (i = head; out; i = GET_FLATPTR(desc[i].next), out--) {
SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT);
SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
SET_FLATPTR(desc[i].len, list->length);
prev = i;
list++;
- }
- for ( ; in; i = GET_FLATPTR(desc[i].next), in--) {
SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
SET_FLATPTR(desc[i].len, list->length);
prev = i;
list++;
- }
- SET_FLATPTR(desc[prev].flags,
GET_FLATPTR(desc[prev].flags)& ~VRING_DESC_F_NEXT);
- SET_FLATPTR(vq->free_head, i);
- SET_FLATPTR(vq->vdata[head], index);
- av = (GET_FLATPTR(avail->idx) + num_added) % GET_FLATPTR(vr->num);
- SET_FLATPTR(avail->ring[av], head);
- wmb();
+}
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) +{
- struct vring *vr =&vq->vring;
- struct vring_avail *avail = GET_FLATPTR(vr->avail);
- struct vring_used *used = GET_FLATPTR(vq->vring.used);
- wmb();
- SET_FLATPTR(avail->idx, GET_FLATPTR(avail->idx) + num_added);
- mb();
- if (!(GET_FLATPTR(used->flags)& VRING_USED_F_NO_NOTIFY))
vp_notify(ioaddr, GET_FLATPTR(vq->queue_index));
+} diff --git a/src/virtio-ring.h b/src/virtio-ring.h new file mode 100644 index 0000000..b97d572 --- /dev/null +++ b/src/virtio-ring.h @@ -0,0 +1,125 @@ +#ifndef _VIRTIO_RING_H +#define _VIRTIO_RING_H
+#define PAGE_SHIFT 12 +#define PAGE_MASK (PAGE_SIZE-1)
+#define virt_to_phys(v) (unsigned long)(v) +#define phys_to_virt(p) (void*)(p) +#define wmb() barrier() +#define mb() barrier()
+/* Status byte for guest to report progress, and synchronize features. */ +/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ +#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 +/* We have found a driver for the device. */ +#define VIRTIO_CONFIG_S_DRIVER 2 +/* Driver has used its parts of the config, and is happy */ +#define VIRTIO_CONFIG_S_DRIVER_OK 4 +/* We've given up on this device. */ +#define VIRTIO_CONFIG_S_FAILED 0x80
+#define MAX_QUEUE_NUM (128)
+#define VRING_DESC_F_NEXT 1 +#define VRING_DESC_F_WRITE 2
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+#define VRING_USED_F_NO_NOTIFY 1
+struct vring_desc +{
- u64 addr;
- u32 len;
- u16 flags;
- u16 next;
+};
+struct vring_avail +{
- u16 flags;
- u16 idx;
- u16 ring[0];
+};
+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;
+};
+#define vring_size(num) \
- (((((sizeof(struct vring_desc) * num) + \
(sizeof(struct vring_avail) + sizeof(u16) * num)) \
+ PAGE_MASK)& ~PAGE_MASK) + \
(sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
+struct vring_virtqueue {
- virtio_queue_t queue;
- struct vring vring;
- u16 free_head;
- u16 last_used_idx;
- u16 vdata[MAX_QUEUE_NUM];
- /* PCI */
- int queue_index;
+};
+struct vring_list {
- char *addr;
- unsigned int length;
+};
+static inline void vring_init(struct vring *vr,
unsigned int num, unsigned char *queue)
+{
- unsigned int i;
- unsigned long pa;
- ASSERT32FLAT();
- vr->num = num;
- /* physical address of desc must be page aligned */
- pa = virt_to_phys(queue);
- pa = (pa + PAGE_MASK)& ~PAGE_MASK;
- vr->desc = phys_to_virt(pa);
- vr->avail = (struct vring_avail *)&vr->desc[num];
- /* physical address of used must be page aligned */
- pa = virt_to_phys(&vr->avail->ring[num]);
- pa = (pa + PAGE_MASK)& ~PAGE_MASK;
- vr->used = phys_to_virt(pa);
- for (i = 0; i< num - 1; i++)
vr->desc[i].next = i + 1;
- vr->desc[i].next = 0;
+}
+int vring_more_used(struct vring_virtqueue *vq); +void vring_detach(struct vring_virtqueue *vq, unsigned int head); +int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len); +void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
unsigned int out, unsigned int in,
int index, int num_added);
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+#endif /* _VIRTIO_RING_H_ */
-- Gleb. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- Gleb.