Hi,
This patch series adds virtio 1.0 support to the virtio blk and scsi drivers in seabios. With this series applied seabios happily boots in virtio 1.0 mode from both transitional and modern devices. This series also moves all virtio code to 32bit.
Tested with Fedora 22 guest, booting from virtio-scsi cdrom (live iso), virtio-scsi disk and virtio-blk disk.
The patches are also available in the git repository at: git://git.kraxel.org/seabios virtio
v3 changes: * change vp_device allocation. * fix capability detection. * add some cleanup patches (drop MAKESEGMENT and GET_* macros). * allocate virt queues in high memory.
v2 changes: * rename vp_modern_{read_write} to vp_{read,write} * switch legacy virtio code to vp_{read,write} too. * make vp_read return the values.
Gerd Hoffmann (25): pci: allow to loop over capabilities virtio: run drivers in 32bit mode virtio: add struct vp_device virtio: pass struct pci_device to vp_init_simple virtio: add version 1.0 structs and #defines virtio: add version 0.9.5 struct virtio: find version 1.0 virtio capabilities virtio: create vp_cap struct for legacy bar virtio: add read/write functions and macros virtio: make features 64bit, support version 1.0 features virtio: add version 1.0 support to vp_{get,set}_status virtio: add version 1.0 support to vp_get_isr virtio: add version 1.0 support to vp_reset virtio: add version 1.0 support to vp_notify virtio: remove unused vp_del_vq virtio: add version 1.0 support to vp_find_vq virtio-scsi: fix initialization for version 1.0 virtio-blk: fix initialization for version 1.0 virtio: use version 1.0 if available (flip the big switch) virtio: also probe version 1.0 pci ids virtio: legacy cleanup virtio-blk: 32bit cleanup virtio-scsi: 32bit cleanup virtio-ring: 32bit cleanup virtio-pci: use high memory for rings
Makefile | 2 +- src/block.c | 8 +- src/fw/pciinit.c | 4 +- src/hw/blockcmd.c | 5 +- src/hw/pci.c | 11 ++- src/hw/pci.h | 2 +- src/hw/pci_ids.h | 8 +- src/hw/virtio-blk.c | 112 ++++++++++++++++------- src/hw/virtio-pci.c | 228 +++++++++++++++++++++++++++++++++++++++++----- src/hw/virtio-pci.h | 252 ++++++++++++++++++++++++++++++++++++--------------- src/hw/virtio-ring.c | 65 +++++++------ src/hw/virtio-ring.h | 9 +- src/hw/virtio-scsi.c | 75 ++++++++++----- 13 files changed, 582 insertions(+), 199 deletions(-)
Add a parameter to pci_find_capability, to specify the start point. This allows to find multiple capabilities of the same type, by calling pci_find_capability again with the offset of the last capability found.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/fw/pciinit.c | 4 ++-- src/hw/pci.c | 11 ++++++++--- src/hw/pci.h | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index ac39d23..45870f2 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -642,7 +642,7 @@ pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
static int pci_bus_hotplug_support(struct pci_bus *bus) { - u8 pcie_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_EXP); + u8 pcie_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_EXP, 0); u8 shpc_cap;
if (pcie_cap) { @@ -666,7 +666,7 @@ static int pci_bus_hotplug_support(struct pci_bus *bus) return downstream_port && slot_implemented; }
- shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC); + shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC, 0); return !!shpc_cap; }
diff --git a/src/hw/pci.c b/src/hw/pci.c index 0379b55..a241d06 100644 --- a/src/hw/pci.c +++ b/src/hw/pci.c @@ -221,16 +221,21 @@ pci_find_init_device(const struct pci_device_id *ids, void *arg) return NULL; }
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id) +u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap) { int i; - u8 cap; u16 status = pci_config_readw(pci->bdf, PCI_STATUS);
if (!(status & PCI_STATUS_CAP_LIST)) return 0;
- cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST); + if (cap == 0) { + /* find first */ + cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST); + } else { + /* find next */ + cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT); + } for (i = 0; cap && i <= 0xff; i++) { if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id) return cap; diff --git a/src/hw/pci.h b/src/hw/pci.h index 0aaa84c..fc5e7b9 100644 --- a/src/hw/pci.h +++ b/src/hw/pci.h @@ -123,7 +123,7 @@ int pci_init_device(const struct pci_device_id *ids , struct pci_device *pci, void *arg); struct pci_device *pci_find_init_device(const struct pci_device_id *ids , void *arg); -u8 pci_find_capability(struct pci_device *pci, u8 cap_id); +u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap); int pci_bridge_has_region(struct pci_device *pci, enum pci_region_type region_type); void pci_reboot(void);
virtio version 1.0 registers can (and actually do in the qemu implementation) live in mmio space. So we must run the blk and scsi virtio drivers in 32bit mode, otherwise we can't access them.
This also allows to drop a bunch of GET_LOWFLAT calls from the virtio code in the following patches.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- Makefile | 2 +- src/block.c | 8 +++++--- src/hw/blockcmd.c | 5 +++-- src/hw/virtio-blk.c | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile index f97b1bd..e287530 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,6 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \ hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \ hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \ - hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c SRC16=$(SRCBOTH) SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \ @@ -43,6 +42,7 @@ SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \ fw/coreboot.c fw/lzmadecode.c fw/multiboot.c fw/csm.c fw/biostables.c \ fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \ fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \ + hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \ hw/tpm_drivers.c SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c DIRS=src src/hw src/fw vgasrc diff --git a/src/block.c b/src/block.c index 3f7ecb1..a9b9851 100644 --- a/src/block.c +++ b/src/block.c @@ -503,8 +503,10 @@ process_op(struct disk_op_s *op) case DTYPE_CDEMU: ret = process_cdemu_op(op); break; - case DTYPE_VIRTIO_BLK: - ret = process_virtio_blk_op(op); + case DTYPE_VIRTIO_BLK: ; + extern void _cfunc32flat_process_virtio_blk_op(void); + ret = call32(_cfunc32flat_process_virtio_blk_op + , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); break; case DTYPE_AHCI: ; extern void _cfunc32flat_process_ahci_op(void); @@ -526,7 +528,6 @@ process_op(struct disk_op_s *op) break; case DTYPE_USB: case DTYPE_UAS: - case DTYPE_VIRTIO_SCSI: case DTYPE_LSI_SCSI: case DTYPE_ESP_SCSI: case DTYPE_MEGASAS: @@ -534,6 +535,7 @@ process_op(struct disk_op_s *op) break; case DTYPE_USB_32: case DTYPE_UAS_32: + case DTYPE_VIRTIO_SCSI: case DTYPE_PVSCSI: ; extern void _cfunc32flat_scsi_process_op(void); ret = call32(_cfunc32flat_scsi_process_op diff --git a/src/hw/blockcmd.c b/src/hw/blockcmd.c index 78c0e65..4440201 100644 --- a/src/hw/blockcmd.c +++ b/src/hw/blockcmd.c @@ -35,14 +35,15 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) return usb_cmd_data(op, cdbcmd, blocksize); case DTYPE_UAS: return uas_cmd_data(op, cdbcmd, blocksize); - case DTYPE_VIRTIO_SCSI: - return virtio_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_LSI_SCSI: return lsi_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_ESP_SCSI: return esp_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_MEGASAS: return megasas_cmd_data(op, cdbcmd, blocksize); + case DTYPE_VIRTIO_SCSI: + if (!MODESEGMENT) + return virtio_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_USB_32: if (!MODESEGMENT) return usb_cmd_data(op, cdbcmd, blocksize); diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index e2dbd3c..15ac171 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -77,7 +77,7 @@ virtio_blk_op(struct disk_op_s *op, int write) return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; }
-int +int VISIBLE32FLAT process_virtio_blk_op(struct disk_op_s *op) { if (! CONFIG_VIRTIO_BLK)
For virtio 1.0 support we will need more state than just the (legacy mode) ioaddr for each virtio-pci device. Prepare for that by adding a new struct for it. For now it carries the ioaddr only.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-blk.c | 19 +++++++++---------- src/hw/virtio-pci.c | 12 ++++++------ src/hw/virtio-pci.h | 46 +++++++++++++++++++++++++++------------------- src/hw/virtio-ring.c | 4 ++-- src/hw/virtio-ring.h | 3 ++- src/hw/virtio-scsi.c | 37 ++++++++++++++++++++++--------------- 6 files changed, 68 insertions(+), 53 deletions(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 15ac171..3a71510 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -25,7 +25,7 @@ struct virtiodrive_s { struct drive_s drive; struct vring_virtqueue *vq; - u16 ioaddr; + struct vp_device vp; };
static int @@ -60,7 +60,7 @@ virtio_blk_op(struct disk_op_s *op, int write) vring_add_buf(vq, sg, 2, 1, 0, 0); else vring_add_buf(vq, sg, 1, 2, 0, 0); - vring_kick(GET_GLOBALFLAT(vdrive_gf->ioaddr), vq, 1); + vring_kick(&vdrive_gf->vp, vq, 1);
/* Wait for reply */ while (!vring_more_used(vq)) @@ -72,7 +72,7 @@ virtio_blk_op(struct disk_op_s *op, int write) /* Clear interrupt status register. Avoid leaving interrupts stuck if * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. */ - vp_get_isr(GET_GLOBALFLAT(vdrive_gf->ioaddr)); + vp_get_isr(&vdrive_gf->vp);
return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; } @@ -113,18 +113,17 @@ init_virtio_blk(struct pci_device *pci) vdrive->drive.type = DTYPE_VIRTIO_BLK; vdrive->drive.cntl_id = bdf;
- u16 ioaddr = vp_init_simple(bdf); - vdrive->ioaddr = ioaddr; - if (vp_find_vq(ioaddr, 0, &vdrive->vq) < 0 ) { + vp_init_simple(&vdrive->vp, bdf); + if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) { dprintf(1, "fail to find vq for virtio-blk %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); goto fail; }
struct virtio_blk_config cfg; - vp_get(ioaddr, 0, &cfg, sizeof(cfg)); + vp_get(&vdrive->vp, 0, &cfg, sizeof(cfg));
- u32 f = vp_get_features(ioaddr); + u32 f = vp_get_features(&vdrive->vp); vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? cfg.blk_size : DISK_SECTOR_SIZE;
@@ -148,12 +147,12 @@ init_virtio_blk(struct pci_device *pci)
boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci));
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + vp_set_status(&vdrive->vp, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); return;
fail: - vp_reset(ioaddr); + vp_reset(&vdrive->vp); free(vdrive->vq); free(vdrive); } diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index b9b3ab1..f648328 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -24,9 +24,10 @@ #include "virtio-pci.h" #include "virtio-ring.h"
-int vp_find_vq(unsigned int ioaddr, int queue_index, +int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { + int ioaddr = GET_LOWFLAT(vp->ioaddr); u16 num;
ASSERT32FLAT(); @@ -84,14 +85,13 @@ fail: return -1; }
-u16 vp_init_simple(u16 bdf) +void vp_init_simple(struct vp_device *vp, u16 bdf) { - u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & + vp->ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & PCI_BASE_ADDRESS_IO_MASK;
- vp_reset(ioaddr); + vp_reset(vp); pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); - vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER ); - return ioaddr; } diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index bc04b03..c1caf67 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -2,6 +2,7 @@ #define _VIRTIO_PCI_H
#include "x86.h" // inl +#include "biosvar.h" // GET_LOWFLAT
/* A 32-bit r/o bitmask of the features supported by the host */ #define VIRTIO_PCI_HOST_FEATURES 0 @@ -39,19 +40,24 @@ /* Virtio ABI version, this must match exactly */ #define VIRTIO_PCI_ABI_VERSION 0
-static inline u32 vp_get_features(unsigned int ioaddr) +struct vp_device { + unsigned int ioaddr; +}; + +static inline u32 vp_get_features(struct vp_device *vp) { - return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES); + return inl(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_HOST_FEATURES); }
-static inline void vp_set_features(unsigned int ioaddr, u32 features) +static inline void vp_set_features(struct vp_device *vp, u32 features) { - outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES); + outl(features, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_GUEST_FEATURES); }
-static inline void vp_get(unsigned int ioaddr, unsigned offset, +static inline void vp_get(struct vp_device *vp, unsigned offset, void *buf, unsigned len) { + int ioaddr = GET_LOWFLAT(vp->ioaddr); u8 *ptr = buf; unsigned i;
@@ -59,47 +65,49 @@ static inline void vp_get(unsigned int ioaddr, unsigned offset, ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i); }
-static inline u8 vp_get_status(unsigned int ioaddr) +static inline u8 vp_get_status(struct vp_device *vp) { - return inb(ioaddr + VIRTIO_PCI_STATUS); + return inb(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_STATUS); }
-static inline void vp_set_status(unsigned int ioaddr, u8 status) +static inline void vp_set_status(struct vp_device *vp, u8 status) { if (status == 0) /* reset */ return; - outb(status, ioaddr + VIRTIO_PCI_STATUS); + outb(status, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_STATUS); }
-static inline u8 vp_get_isr(unsigned int ioaddr) +static inline u8 vp_get_isr(struct vp_device *vp) { - return inb(ioaddr + VIRTIO_PCI_ISR); + return inb(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_ISR); }
-static inline void vp_reset(unsigned int ioaddr) +static inline void vp_reset(struct vp_device *vp) { + int ioaddr = GET_LOWFLAT(vp->ioaddr); + outb(0, ioaddr + VIRTIO_PCI_STATUS); (void)inb(ioaddr + VIRTIO_PCI_ISR); }
-static inline void vp_notify(unsigned int ioaddr, int queue_index) +static inline void vp_notify(struct vp_device *vp, int queue_index) { - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); + outw(queue_index, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_QUEUE_NOTIFY); }
-static inline void vp_del_vq(unsigned int ioaddr, int queue_index) +static inline void vp_del_vq(struct vp_device *vp, int queue_index) { + int ioaddr = GET_LOWFLAT(vp->ioaddr); + /* select the queue */ - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
/* deactivate the queue */ - outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN); }
struct vring_virtqueue; -u16 vp_init_simple(u16 bdf); -int vp_find_vq(unsigned int ioaddr, int queue_index, +void vp_init_simple(struct vp_device *vp, u16 bdf); +int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq); #endif /* _VIRTIO_PCI_H_ */ diff --git a/src/hw/virtio-ring.c b/src/hw/virtio-ring.c index 97e0b34..5c6a32e 100644 --- a/src/hw/virtio-ring.c +++ b/src/hw/virtio-ring.c @@ -136,7 +136,7 @@ void vring_add_buf(struct vring_virtqueue *vq, SET_LOWFLAT(avail->ring[av], head); }
-void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) +void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added) { struct vring *vr = &vq->vring; struct vring_avail *avail = GET_LOWFLAT(vr->avail); @@ -145,5 +145,5 @@ void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) smp_wmb(); SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added);
- vp_notify(ioaddr, GET_LOWFLAT(vq->queue_index)); + vp_notify(vp, GET_LOWFLAT(vq->queue_index)); } diff --git a/src/hw/virtio-ring.h b/src/hw/virtio-ring.h index b7a7aaf..fe5133b 100644 --- a/src/hw/virtio-ring.h +++ b/src/hw/virtio-ring.h @@ -120,12 +120,13 @@ static inline void vring_init(struct vring *vr, vr->desc[i].next = 0; }
+struct vp_device; 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); +void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added);
#endif /* _VIRTIO_RING_H_ */ diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c index 8f96687..eb7eb81 100644 --- a/src/hw/virtio-scsi.c +++ b/src/hw/virtio-scsi.c @@ -27,14 +27,15 @@ struct virtio_lun_s { struct drive_s drive; struct pci_device *pci; struct vring_virtqueue *vq; - u16 ioaddr; + struct vp_device *vp; u16 target; u16 lun; };
static int -virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, - void *cdbcmd, u16 target, u16 lun, u16 blocksize) +virtio_scsi_cmd(struct vp_device *vp, struct vring_virtqueue *vq, + struct disk_op_s *op, void *cdbcmd, u16 target, u16 lun, + u16 blocksize) { struct virtio_scsi_req_cmd req; struct virtio_scsi_resp_cmd resp; @@ -66,7 +67,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
/* Add to virtqueue and kick host */ vring_add_buf(vq, sg, out_num, in_num, 0, 0); - vring_kick(ioaddr, vq, 1); + vring_kick(vp, vq, 1);
/* Wait for reply */ while (!vring_more_used(vq)) @@ -78,7 +79,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, /* Clear interrupt status register. Avoid leaving interrupts stuck if * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. */ - vp_get_isr(ioaddr); + vp_get_isr(vp);
if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) { return DISK_RET_SUCCESS; @@ -92,7 +93,7 @@ virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) struct virtio_lun_s *vlun_gf = container_of(op->drive_gf, struct virtio_lun_s, drive);
- return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->ioaddr), + return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->vp), GET_GLOBALFLAT(vlun_gf->vq), op, cdbcmd, GET_GLOBALFLAT(vlun_gf->target), GET_GLOBALFLAT(vlun_gf->lun), @@ -100,7 +101,7 @@ virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) }
static int -virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr, +virtio_scsi_add_lun(struct pci_device *pci, struct vp_device *vp, struct vring_virtqueue *vq, u16 target, u16 lun) { struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun)); @@ -112,7 +113,7 @@ virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr, vlun->drive.type = DTYPE_VIRTIO_SCSI; vlun->drive.cntl_id = pci->bdf; vlun->pci = pci; - vlun->ioaddr = ioaddr; + vlun->vp = vp; vlun->vq = vq; vlun->target = target; vlun->lun = lun; @@ -129,11 +130,11 @@ fail: }
static int -virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr, +virtio_scsi_scan_target(struct pci_device *pci, struct vp_device *vp, struct vring_virtqueue *vq, u16 target) { /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */ - int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0); + int ret = virtio_scsi_add_lun(pci, vp, vq, target, 0); return ret < 0 ? 0 : 1; }
@@ -144,19 +145,24 @@ init_virtio_scsi(struct pci_device *pci) dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); struct vring_virtqueue *vq = NULL; - u16 ioaddr = vp_init_simple(bdf); - if (vp_find_vq(ioaddr, 2, &vq) < 0 ) { + struct vp_device *vp = malloc_high(sizeof(*vp)); + if (!vp) { + warn_noalloc(); + return; + } + vp_init_simple(vp, bdf); + if (vp_find_vq(vp, 2, &vq) < 0 ) { dprintf(1, "fail to find vq for virtio-scsi %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); goto fail; }
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
int i, tot; for (tot = 0, i = 0; i < 256; i++) - tot += virtio_scsi_scan_target(pci, ioaddr, vq, i); + tot += virtio_scsi_scan_target(pci, vp, vq, i);
if (!tot) goto fail; @@ -164,7 +170,8 @@ init_virtio_scsi(struct pci_device *pci) return;
fail: - vp_reset(ioaddr); + vp_reset(vp); + free(vp); free(vq); }
... instead of the bdf only.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-blk.c | 2 +- src/hw/virtio-pci.c | 6 +++--- src/hw/virtio-pci.h | 3 ++- src/hw/virtio-scsi.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 3a71510..1a13129 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -113,7 +113,7 @@ init_virtio_blk(struct pci_device *pci) vdrive->drive.type = DTYPE_VIRTIO_BLK; vdrive->drive.cntl_id = bdf;
- vp_init_simple(&vdrive->vp, bdf); + vp_init_simple(&vdrive->vp, pci); if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) { dprintf(1, "fail to find vq for virtio-blk %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index f648328..9428d04 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -85,13 +85,13 @@ fail: return -1; }
-void vp_init_simple(struct vp_device *vp, u16 bdf) +void vp_init_simple(struct vp_device *vp, struct pci_device *pci) { - vp->ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & + vp->ioaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & PCI_BASE_ADDRESS_IO_MASK;
vp_reset(vp); - pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER ); } diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index c1caf67..85e623f 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -106,8 +106,9 @@ static inline void vp_del_vq(struct vp_device *vp, int queue_index) outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN); }
+struct pci_device; struct vring_virtqueue; -void vp_init_simple(struct vp_device *vp, u16 bdf); +void vp_init_simple(struct vp_device *vp, struct pci_device *pci); int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq); #endif /* _VIRTIO_PCI_H_ */ diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c index eb7eb81..8073c77 100644 --- a/src/hw/virtio-scsi.c +++ b/src/hw/virtio-scsi.c @@ -150,7 +150,7 @@ init_virtio_scsi(struct pci_device *pci) warn_noalloc(); return; } - vp_init_simple(vp, bdf); + vp_init_simple(vp, pci); if (vp_find_vq(vp, 2, &vq) < 0 ) { dprintf(1, "fail to find vq for virtio-scsi %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hw/virtio-ring.h | 5 +++++ 2 files changed, 66 insertions(+)
diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 85e623f..83ebcda 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -40,6 +40,67 @@ /* Virtio ABI version, this must match exactly */ #define VIRTIO_PCI_ABI_VERSION 0
+/* --- virtio 1.0 (modern) structs ---------------------------------- */ + +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR access */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + u8 cap_next; /* Generic PCI field: next ptr. */ + u8 cap_len; /* Generic PCI field: capability length */ + u8 cfg_type; /* Identifies the structure. */ + u8 bar; /* Where to find it. */ + u8 padding[3]; /* Pad to full dword. */ + u32 offset; /* Offset within bar. */ + u32 length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + u32 notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +typedef struct virtio_pci_common_cfg { + /* About the whole device. */ + u32 device_feature_select; /* read-write */ + u32 device_feature; /* read-only */ + u32 guest_feature_select; /* read-write */ + u32 guest_feature; /* read-write */ + u16 msix_config; /* read-write */ + u16 num_queues; /* read-only */ + u8 device_status; /* read-write */ + u8 config_generation; /* read-only */ + + /* About a specific virtqueue. */ + u16 queue_select; /* read-write */ + u16 queue_size; /* read-write, power of 2. */ + u16 queue_msix_vector; /* read-write */ + u16 queue_enable; /* read-write */ + u16 queue_notify_off; /* read-only */ + u32 queue_desc_lo; /* read-write */ + u32 queue_desc_hi; /* read-write */ + u32 queue_avail_lo; /* read-write */ + u32 queue_avail_hi; /* read-write */ + u32 queue_used_lo; /* read-write */ + u32 queue_used_hi; /* read-write */ +} virtio_pci_common_cfg; + +typedef struct virtio_pci_isr { + u8 isr; +} virtio_pci_isr; + +/* --- driver structs ----------------------------------------------- */ + struct vp_device { unsigned int ioaddr; }; diff --git a/src/hw/virtio-ring.h b/src/hw/virtio-ring.h index fe5133b..553a508 100644 --- a/src/hw/virtio-ring.h +++ b/src/hw/virtio-ring.h @@ -20,9 +20,14 @@ #define VIRTIO_CONFIG_S_DRIVER 2 /* Driver has used its parts of the config, and is happy */ #define VIRTIO_CONFIG_S_DRIVER_OK 4 +/* Driver has finished configuring features */ +#define VIRTIO_CONFIG_S_FEATURES_OK 8 /* We've given up on this device. */ #define VIRTIO_CONFIG_S_FAILED 0x80
+/* v1.0 compliant. */ +#define VIRTIO_F_VERSION_1 32 + #define MAX_QUEUE_NUM (128)
#define VRING_DESC_F_NEXT 1
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 83ebcda..42e2b7f 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -40,6 +40,20 @@ /* Virtio ABI version, this must match exactly */ #define VIRTIO_PCI_ABI_VERSION 0
+/* --- virtio 0.9.5 (legacy) struct --------------------------------- */ + +typedef struct virtio_pci_legacy { + u32 host_features; + u32 guest_features; + u32 queue_pfn; + u16 queue_num; + u16 queue_sel; + u16 queue_notify; + u8 status; + u8 isr; + u8 device[]; +} virtio_pci_legacy; + /* --- virtio 1.0 (modern) structs ---------------------------------- */
/* Common configuration */
virtio 1.0 specifies the location of the various virtio regions using pci capabilities. Look them up and store the results.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hw/virtio-pci.h | 8 ++++++++ 2 files changed, 64 insertions(+)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 9428d04..58f3d39 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -87,6 +87,62 @@ fail:
void vp_init_simple(struct vp_device *vp, struct pci_device *pci) { + u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0); + struct vp_cap *vp_cap; + u32 addr, offset; + u8 type; + + memset(vp, 0, sizeof(*vp)); + while (cap != 0) { + type = pci_config_readb(pci->bdf, cap + + offsetof(struct virtio_pci_cap, cfg_type)); + switch (type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + vp_cap = &vp->common; + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + vp_cap = &vp->notify; + break; + case VIRTIO_PCI_CAP_ISR_CFG: + vp_cap = &vp->isr; + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + vp_cap = &vp->device; + break; + default: + vp_cap = NULL; + break; + } + if (vp_cap && !vp_cap->cap) { + vp_cap->cap = cap; + vp_cap->bar = pci_config_readb(pci->bdf, cap + + offsetof(struct virtio_pci_cap, bar)); + offset = pci_config_readl(pci->bdf, cap + + offsetof(struct virtio_pci_cap, offset)); + addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar); + if (addr & PCI_BASE_ADDRESS_SPACE_IO) { + vp_cap->is_io = 1; + addr &= PCI_BASE_ADDRESS_IO_MASK; + } else { + vp_cap->is_io = 0; + addr &= PCI_BASE_ADDRESS_MEM_MASK; + } + vp_cap->addr = addr + offset; + dprintf(3, "pci dev %x:%x virtio cap at 0x%x type %d " + "bar %d at 0x%08x off +0x%04x [%s]\n", + pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf), + vp_cap->cap, type, vp_cap->bar, addr, offset, + vp_cap->is_io ? "io" : "mmio"); + } + + cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, cap); + } + + if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) { + dprintf(1, "pci dev %x:%x supports virtio 1.0\n", + pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)); + } + vp->ioaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & PCI_BASE_ADDRESS_IO_MASK;
diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 42e2b7f..467c02f 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -115,8 +115,16 @@ typedef struct virtio_pci_isr {
/* --- driver structs ----------------------------------------------- */
+struct vp_cap { + u32 addr; + u8 cap; + u8 bar; + u8 is_io; +}; + struct vp_device { unsigned int ioaddr; + struct vp_cap common, notify, isr, device; };
static inline u32 vp_get_features(struct vp_device *vp)
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 5 ++++- src/hw/virtio-pci.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 58f3d39..3c8fb7b 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -143,8 +143,11 @@ void vp_init_simple(struct vp_device *vp, struct pci_device *pci) pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)); }
- vp->ioaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & + vp->legacy.bar = 0; + vp->legacy.addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & PCI_BASE_ADDRESS_IO_MASK; + vp->legacy.is_io = 1; + vp->ioaddr = vp->legacy.addr; /* temporary */
vp_reset(vp); pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 467c02f..147e529 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -124,7 +124,7 @@ struct vp_cap {
struct vp_device { unsigned int ioaddr; - struct vp_cap common, notify, isr, device; + struct vp_cap common, notify, isr, device, legacy; };
static inline u32 vp_get_features(struct vp_device *vp)
Add macros to read/write virtio registers.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.h | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+)
diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 147e529..f7510f2 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -127,6 +127,92 @@ struct vp_device { struct vp_cap common, notify, isr, device, legacy; };
+static inline u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size) +{ + u32 addr = cap->addr + offset; + u64 var; + + if (cap->is_io) { + switch (size) { + case 8: + var = inl(addr); + var |= (u64)inl(addr+4) << 32; + break; + case 4: + var = inl(addr); + break; + case 2: + var = inw(addr); + break; + case 1: + var = inb(addr); + break; + default: + var = 0; + } + } else { + switch (size) { + case 8: + var = readl((void*)addr); + var |= (u64)readl((void*)(addr+4)) << 32; + break; + case 4: + var = readl((void*)addr); + break; + case 2: + var = readw((void*)addr); + break; + case 1: + var = readb((void*)addr); + break; + default: + var = 0; + } + } + dprintf(9, "vp read %x (%d) -> 0x%llx\n", addr, size, var); + return var; +} + +static inline void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var) +{ + u32 addr = cap->addr + offset; + + dprintf(9, "vp write %x (%d) <- 0x%llx\n", addr, size, var); + if (cap->is_io) { + switch (size) { + case 4: + outl(var, addr); + break; + case 2: + outw(var, addr); + break; + case 1: + outb(var, addr); + break; + } + } else { + switch (size) { + case 4: + writel((void*)addr, var); + break; + case 2: + writew((void*)addr, var); + break; + case 1: + writeb((void*)addr, var); + break; + } + } +} + +#define vp_read(_cap, _struct, _field) \ + _vp_read(_cap, offsetof(_struct, _field), \ + sizeof(((_struct *)0)->_field)) + +#define vp_write(_cap, _struct, _field, _var) \ + _vp_write(_cap, offsetof(_struct, _field), \ + sizeof(((_struct *)0)->_field), _var) + static inline u32 vp_get_features(struct vp_device *vp) { return inl(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_HOST_FEATURES);
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-blk.c | 2 +- src/hw/virtio-pci.c | 33 +++++++++++++++++++++++++++++++++ src/hw/virtio-pci.h | 12 +++--------- 3 files changed, 37 insertions(+), 10 deletions(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 1a13129..8378a34 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -123,7 +123,7 @@ init_virtio_blk(struct pci_device *pci) struct virtio_blk_config cfg; vp_get(&vdrive->vp, 0, &cfg, sizeof(cfg));
- u32 f = vp_get_features(&vdrive->vp); + u64 f = vp_get_features(&vdrive->vp); vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? cfg.blk_size : DISK_SECTOR_SIZE;
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 3c8fb7b..5ae6a76 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -24,6 +24,39 @@ #include "virtio-pci.h" #include "virtio-ring.h"
+u64 vp_get_features(struct vp_device *vp) +{ + u32 f0, f1; + + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 0); + f0 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature); + vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 1); + f1 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature); + } else { + f0 = vp_read(&vp->legacy, virtio_pci_legacy, host_features); + f1 = 0; + } + return ((u64)f1 << 32) | f0; +} + +void vp_set_features(struct vp_device *vp, u64 features) +{ + u32 f0, f1; + + f0 = features; + f1 = features >> 32; + + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 0); + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f0); + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 1); + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f1); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, guest_features, f0); + } +} + int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index f7510f2..962d6c0 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -125,6 +125,7 @@ struct vp_cap { struct vp_device { unsigned int ioaddr; struct vp_cap common, notify, isr, device, legacy; + u8 use_modern; };
static inline u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size) @@ -213,15 +214,8 @@ static inline void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var) _vp_write(_cap, offsetof(_struct, _field), \ sizeof(((_struct *)0)->_field), _var)
-static inline u32 vp_get_features(struct vp_device *vp) -{ - return inl(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_HOST_FEATURES); -} - -static inline void vp_set_features(struct vp_device *vp, u32 features) -{ - outl(features, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_GUEST_FEATURES); -} +u64 vp_get_features(struct vp_device *vp); +void vp_set_features(struct vp_device *vp, u64 features);
static inline void vp_get(struct vp_device *vp, unsigned offset, void *buf, unsigned len)
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 20 ++++++++++++++++++++ src/hw/virtio-pci.h | 13 ++----------- 2 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 5ae6a76..c9c79b3 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -57,6 +57,26 @@ void vp_set_features(struct vp_device *vp, u64 features) } }
+u8 vp_get_status(struct vp_device *vp) +{ + if (vp->use_modern) { + return vp_read(&vp->common, virtio_pci_common_cfg, device_status); + } else { + return vp_read(&vp->legacy, virtio_pci_legacy, status); + } +} + +void vp_set_status(struct vp_device *vp, u8 status) +{ + if (status == 0) /* reset */ + return; + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, device_status, status); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, status, status); + } +} + int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 962d6c0..e3f6f99 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -228,17 +228,8 @@ static inline void vp_get(struct vp_device *vp, unsigned offset, ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i); }
-static inline u8 vp_get_status(struct vp_device *vp) -{ - return inb(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_STATUS); -} - -static inline void vp_set_status(struct vp_device *vp, u8 status) -{ - if (status == 0) /* reset */ - return; - outb(status, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_STATUS); -} +u8 vp_get_status(struct vp_device *vp); +void vp_set_status(struct vp_device *vp, u8 status);
static inline u8 vp_get_isr(struct vp_device *vp) {
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 9 +++++++++ src/hw/virtio-pci.h | 6 +----- 2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index c9c79b3..2f0bb40 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -77,6 +77,15 @@ void vp_set_status(struct vp_device *vp, u8 status) } }
+u8 vp_get_isr(struct vp_device *vp) +{ + if (vp->use_modern) { + return vp_read(&vp->isr, virtio_pci_isr, isr); + } else { + return vp_read(&vp->legacy, virtio_pci_legacy, isr); + } +} + int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index e3f6f99..c891b7c 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -230,11 +230,7 @@ static inline void vp_get(struct vp_device *vp, unsigned offset,
u8 vp_get_status(struct vp_device *vp); void vp_set_status(struct vp_device *vp, u8 status); - -static inline u8 vp_get_isr(struct vp_device *vp) -{ - return inb(GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_ISR); -} +u8 vp_get_isr(struct vp_device *vp);
static inline void vp_reset(struct vp_device *vp) {
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 11 +++++++++++ src/hw/virtio-pci.h | 9 +-------- 2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 2f0bb40..bd51d8a 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -86,6 +86,17 @@ u8 vp_get_isr(struct vp_device *vp) } }
+void vp_reset(struct vp_device *vp) +{ + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, device_status, 0); + vp_read(&vp->isr, virtio_pci_isr, isr); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, status, 0); + vp_read(&vp->legacy, virtio_pci_legacy, isr); + } +} + int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index c891b7c..f2ae5b9 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -231,14 +231,7 @@ static inline void vp_get(struct vp_device *vp, unsigned offset, u8 vp_get_status(struct vp_device *vp); void vp_set_status(struct vp_device *vp, u8 status); u8 vp_get_isr(struct vp_device *vp); - -static inline void vp_reset(struct vp_device *vp) -{ - int ioaddr = GET_LOWFLAT(vp->ioaddr); - - outb(0, ioaddr + VIRTIO_PCI_STATUS); - (void)inb(ioaddr + VIRTIO_PCI_ISR); -} +void vp_reset(struct vp_device *vp);
static inline void vp_notify(struct vp_device *vp, int queue_index) {
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 22 +++++++++++++++++++++- src/hw/virtio-pci.h | 7 ++----- src/hw/virtio-ring.c | 2 +- src/hw/virtio-ring.h | 1 + 4 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index bd51d8a..240cd2f 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -97,6 +97,24 @@ void vp_reset(struct vp_device *vp) } }
+void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq) +{ + if (vp->use_modern) { + u32 addr = vp->notify.addr + + vq->queue_notify_off * + vp->notify_off_multiplier; + if (vp->notify.is_io) { + outw(vq->queue_index, addr); + } else { + writew((void*)addr, vq->queue_index); + } + dprintf(9, "vp notify %x (%d) -- 0x%x\n", + addr, 2, vq->queue_index); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, queue_notify, vq->queue_index); + } +} + int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { @@ -162,7 +180,7 @@ void vp_init_simple(struct vp_device *vp, struct pci_device *pci) { u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0); struct vp_cap *vp_cap; - u32 addr, offset; + u32 addr, offset, mul; u8 type;
memset(vp, 0, sizeof(*vp)); @@ -175,6 +193,8 @@ void vp_init_simple(struct vp_device *vp, struct pci_device *pci) break; case VIRTIO_PCI_CAP_NOTIFY_CFG: vp_cap = &vp->notify; + mul = offsetof(struct virtio_pci_notify_cap, notify_off_multiplier); + vp->notify_off_multiplier = pci_config_readl(pci->bdf, cap + mul); break; case VIRTIO_PCI_CAP_ISR_CFG: vp_cap = &vp->isr; diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index f2ae5b9..3054a13 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -125,6 +125,7 @@ struct vp_cap { struct vp_device { unsigned int ioaddr; struct vp_cap common, notify, isr, device, legacy; + u32 notify_off_multiplier; u8 use_modern; };
@@ -233,11 +234,6 @@ void vp_set_status(struct vp_device *vp, u8 status); u8 vp_get_isr(struct vp_device *vp); void vp_reset(struct vp_device *vp);
-static inline void vp_notify(struct vp_device *vp, int queue_index) -{ - outw(queue_index, GET_LOWFLAT(vp->ioaddr) + VIRTIO_PCI_QUEUE_NOTIFY); -} - static inline void vp_del_vq(struct vp_device *vp, int queue_index) { int ioaddr = GET_LOWFLAT(vp->ioaddr); @@ -252,6 +248,7 @@ static inline void vp_del_vq(struct vp_device *vp, int queue_index) struct pci_device; struct vring_virtqueue; void vp_init_simple(struct vp_device *vp, struct pci_device *pci); +void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq); int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq); #endif /* _VIRTIO_PCI_H_ */ diff --git a/src/hw/virtio-ring.c b/src/hw/virtio-ring.c index 5c6a32e..6c86c38 100644 --- a/src/hw/virtio-ring.c +++ b/src/hw/virtio-ring.c @@ -145,5 +145,5 @@ void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added) smp_wmb(); SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added);
- vp_notify(vp, GET_LOWFLAT(vq->queue_index)); + vp_notify(vp, vq); } diff --git a/src/hw/virtio-ring.h b/src/hw/virtio-ring.h index 553a508..7df9004 100644 --- a/src/hw/virtio-ring.h +++ b/src/hw/virtio-ring.h @@ -88,6 +88,7 @@ struct vring_virtqueue { u16 vdata[MAX_QUEUE_NUM]; /* PCI */ int queue_index; + int queue_notify_off; };
struct vring_list {
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.h | 11 ----------- 1 file changed, 11 deletions(-)
diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 3054a13..1b5c61d 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -234,17 +234,6 @@ void vp_set_status(struct vp_device *vp, u8 status); u8 vp_get_isr(struct vp_device *vp); void vp_reset(struct vp_device *vp);
-static inline void vp_del_vq(struct vp_device *vp, int queue_index) -{ - int ioaddr = GET_LOWFLAT(vp->ioaddr); - - /* select the queue */ - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); - - /* deactivate the queue */ - outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN); -} - struct pci_device; struct vring_virtqueue; void vp_init_simple(struct vp_device *vp, struct pci_device *pci);
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 58 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 15 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 240cd2f..dcbf6d7 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -118,7 +118,6 @@ void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq) int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { - int ioaddr = GET_LOWFLAT(vp->ioaddr); u16 num;
ASSERT32FLAT(); @@ -129,34 +128,49 @@ int vp_find_vq(struct vp_device *vp, int queue_index, } memset(vq, 0, sizeof(*vq));
+ /* select the queue */ - - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, queue_select, queue_index); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, queue_sel, queue_index); + }
/* check if the queue is available */ - - num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM); + if (vp->use_modern) { + num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size); + if (num > MAX_QUEUE_NUM) { + vp_write(&vp->common, virtio_pci_common_cfg, queue_size, + MAX_QUEUE_NUM); + num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size); + } + } else { + num = vp_read(&vp->legacy, virtio_pci_legacy, queue_num); + } if (!num) { dprintf(1, "ERROR: queue size is 0\n"); goto fail; } - if (num > MAX_QUEUE_NUM) { dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); goto fail; }
/* check if the queue is already active */ - - if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) { - dprintf(1, "ERROR: queue already active\n"); - goto fail; + if (vp->use_modern) { + if (vp_read(&vp->common, virtio_pci_common_cfg, queue_enable)) { + dprintf(1, "ERROR: queue already active\n"); + goto fail; + } + } else { + if (vp_read(&vp->legacy, virtio_pci_legacy, queue_pfn)) { + dprintf(1, "ERROR: queue already active\n"); + goto fail; + } } - vq->queue_index = queue_index;
/* initialize the queue */ - struct vring * vr = &vq->vring; vring_init(vr, num, (unsigned char*)&vq->queue);
@@ -165,9 +179,23 @@ int vp_find_vq(struct vp_device *vp, int queue_index, * NOTE: vr->desc is initialized by vring_init() */
- outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, - ioaddr + VIRTIO_PCI_QUEUE_PFN); - + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_lo, + (unsigned long)virt_to_phys(vr->desc)); + vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_hi, 0); + vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_lo, + (unsigned long)virt_to_phys(vr->avail)); + vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_hi, 0); + vp_write(&vp->common, virtio_pci_common_cfg, queue_used_lo, + (unsigned long)virt_to_phys(vr->used)); + vp_write(&vp->common, virtio_pci_common_cfg, queue_used_hi, 0); + vp_write(&vp->common, virtio_pci_common_cfg, queue_enable, 1); + vq->queue_notify_off = vp_read(&vp->common, virtio_pci_common_cfg, + queue_notify_off); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, queue_pfn, + (unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT); + } return num;
fail:
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-scsi.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c index 8073c77..89dcb8d 100644 --- a/src/hw/virtio-scsi.c +++ b/src/hw/virtio-scsi.c @@ -151,14 +151,35 @@ init_virtio_scsi(struct pci_device *pci) return; } vp_init_simple(vp, pci); + u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER; + + if (vp->use_modern) { + u64 features = vp_get_features(vp); + u64 version1 = 1ull << VIRTIO_F_VERSION_1; + if (!(features & version1)) { + dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + + vp_set_features(vp, version1); + status |= VIRTIO_CONFIG_S_FEATURES_OK; + vp_set_status(vp, status); + if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) { + dprintf(1, "device didn't accept features: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + } + if (vp_find_vq(vp, 2, &vq) < 0 ) { dprintf(1, "fail to find vq for virtio-scsi %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); goto fail; }
- vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); + status |= VIRTIO_CONFIG_S_DRIVER_OK; + vp_set_status(vp, status);
int i, tot; for (tot = 0, i = 0; i < 256; i++)
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-blk.c | 84 +++++++++++++++++++++++++++++++++++++++++------------ src/hw/virtio-pci.h | 13 ++++----- 2 files changed, 72 insertions(+), 25 deletions(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 8378a34..703b147 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -102,6 +102,7 @@ static void init_virtio_blk(struct pci_device *pci) { u16 bdf = pci->bdf; + u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER; dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); struct virtiodrive_s *vdrive = malloc_fseg(sizeof(*vdrive)); @@ -120,35 +121,82 @@ init_virtio_blk(struct pci_device *pci) goto fail; }
- struct virtio_blk_config cfg; - vp_get(&vdrive->vp, 0, &cfg, sizeof(cfg)); + if (vdrive->vp.use_modern) { + struct vp_device *vp = &vdrive->vp; + u64 features = vp_get_features(vp); + u64 version1 = 1ull << VIRTIO_F_VERSION_1; + u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE; + if (!(features & version1)) { + dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + }
- u64 f = vp_get_features(&vdrive->vp); - vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? - cfg.blk_size : DISK_SECTOR_SIZE; + features = features & (version1 | blk_size); + vp_set_features(vp, features); + status |= VIRTIO_CONFIG_S_FEATURES_OK; + vp_set_status(vp, status); + if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) { + dprintf(1, "device didn't accept features: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + }
- vdrive->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->drive.blksize, (u32)vdrive->drive.sectors); + vdrive->drive.sectors = + vp_read(&vp->device, struct virtio_blk_config, capacity); + if (features & blk_size) { + vdrive->drive.blksize = + vp_read(&vp->device, struct virtio_blk_config, blk_size); + } else { + vdrive->drive.blksize = DISK_SECTOR_SIZE; + } + if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { + dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize); + goto fail; + } + dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize, (u32)vdrive->drive.sectors); + + vdrive->drive.pchs.cylinder = + vp_read(&vp->device, struct virtio_blk_config, cylinders); + vdrive->drive.pchs.head = + vp_read(&vp->device, struct virtio_blk_config, heads); + vdrive->drive.pchs.sector = + vp_read(&vp->device, struct virtio_blk_config, sectors); + } else { + struct virtio_blk_config cfg; + vp_get_legacy(&vdrive->vp, 0, &cfg, sizeof(cfg));
- if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { - dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + u64 f = vp_get_features(&vdrive->vp); + vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? + cfg.blk_size : DISK_SECTOR_SIZE; + + vdrive->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->drive.blksize); - goto fail; + vdrive->drive.blksize, (u32)vdrive->drive.sectors); + + if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { + dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize); + goto fail; + } + vdrive->drive.pchs.cylinder = cfg.cylinders; + vdrive->drive.pchs.head = cfg.heads; + vdrive->drive.pchs.sector = cfg.sectors; }
- vdrive->drive.pchs.cylinder = cfg.cylinders; - vdrive->drive.pchs.head = cfg.heads; - vdrive->drive.pchs.sector = cfg.sectors; char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci));
- vp_set_status(&vdrive->vp, VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); + status |= VIRTIO_CONFIG_S_DRIVER_OK; + vp_set_status(&vdrive->vp, status); return;
fail: diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 1b5c61d..08267ad 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -218,15 +218,14 @@ static inline void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var) u64 vp_get_features(struct vp_device *vp); void vp_set_features(struct vp_device *vp, u64 features);
-static inline void vp_get(struct vp_device *vp, unsigned offset, - void *buf, unsigned len) +static inline void vp_get_legacy(struct vp_device *vp, unsigned offset, + void *buf, unsigned len) { - int ioaddr = GET_LOWFLAT(vp->ioaddr); - u8 *ptr = buf; - unsigned i; + u8 *ptr = buf; + unsigned i;
- for (i = 0; i < len; i++) - ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i); + for (i = 0; i < len; i++) + ptr[i] = inb(vp->ioaddr + VIRTIO_PCI_CONFIG + offset + i); }
u8 vp_get_status(struct vp_device *vp);
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index dcbf6d7..5cb0e73 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -260,16 +260,19 @@ void vp_init_simple(struct vp_device *vp, struct pci_device *pci) }
if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) { - dprintf(1, "pci dev %x:%x supports virtio 1.0\n", + dprintf(1, "pci dev %x:%x using modern (1.0) virtio mode\n", pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)); + vp->use_modern = 1; + } else { + dprintf(1, "pci dev %x:%x using legacy (0.9.5) virtio mode\n", + pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)); + vp->legacy.bar = 0; + vp->legacy.addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & + PCI_BASE_ADDRESS_IO_MASK; + vp->legacy.is_io = 1; + vp->ioaddr = vp->legacy.addr; /* temporary */ }
- vp->legacy.bar = 0; - vp->legacy.addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & - PCI_BASE_ADDRESS_IO_MASK; - vp->legacy.is_io = 1; - vp->ioaddr = vp->legacy.addr; /* temporary */ - vp_reset(vp); pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/pci_ids.h | 8 ++++++-- src/hw/virtio-blk.c | 5 +++-- src/hw/virtio-scsi.c | 5 +++-- 3 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/src/hw/pci_ids.h b/src/hw/pci_ids.h index 1cd4f72..cdf9b3c 100644 --- a/src/hw/pci_ids.h +++ b/src/hw/pci_ids.h @@ -2616,8 +2616,12 @@ #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 -#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 -#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 +/* virtio 0.9.5 ids (legacy/transitional devices) */ +#define PCI_DEVICE_ID_VIRTIO_BLK_09 0x1001 +#define PCI_DEVICE_ID_VIRTIO_SCSI_09 0x1004 +/* virtio 1.0 ids (modern devices) */ +#define PCI_DEVICE_ID_VIRTIO_BLK_10 0x1042 +#define PCI_DEVICE_ID_VIRTIO_SCSI_10 0x1048
#define PCI_VENDOR_ID_VMWARE 0x15ad #define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index 703b147..c3052bb 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -216,8 +216,9 @@ virtio_blk_setup(void)
struct pci_device *pci; foreachpci(pci) { - if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET - || pci->device != PCI_DEVICE_ID_VIRTIO_BLK) + if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET || + (pci->device != PCI_DEVICE_ID_VIRTIO_BLK_09 && + pci->device != PCI_DEVICE_ID_VIRTIO_BLK_10)) continue; init_virtio_blk(pci); } diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c index 89dcb8d..6b4ed1a 100644 --- a/src/hw/virtio-scsi.c +++ b/src/hw/virtio-scsi.c @@ -207,8 +207,9 @@ virtio_scsi_setup(void)
struct pci_device *pci; foreachpci(pci) { - if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET - || pci->device != PCI_DEVICE_ID_VIRTIO_SCSI) + if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET || + (pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_09 && + pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_10)) continue; init_virtio_scsi(pci); }
Now that all code is switched over to use vp_read/write we can drop the ioaddr field from vp_device and the offset #defines.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 1 - src/hw/virtio-pci.h | 33 +-------------------------------- 2 files changed, 1 insertion(+), 33 deletions(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 5cb0e73..8e7ea46 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -270,7 +270,6 @@ void vp_init_simple(struct vp_device *vp, struct pci_device *pci) vp->legacy.addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & PCI_BASE_ADDRESS_IO_MASK; vp->legacy.is_io = 1; - vp->ioaddr = vp->legacy.addr; /* temporary */ }
vp_reset(vp); diff --git a/src/hw/virtio-pci.h b/src/hw/virtio-pci.h index 08267ad..b11c355 100644 --- a/src/hw/virtio-pci.h +++ b/src/hw/virtio-pci.h @@ -4,39 +4,9 @@ #include "x86.h" // inl #include "biosvar.h" // GET_LOWFLAT
-/* 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
@@ -123,7 +93,6 @@ struct vp_cap { };
struct vp_device { - unsigned int ioaddr; struct vp_cap common, notify, isr, device, legacy; u32 notify_off_multiplier; u8 use_modern; @@ -225,7 +194,7 @@ static inline void vp_get_legacy(struct vp_device *vp, unsigned offset, unsigned i;
for (i = 0; i < len; i++) - ptr[i] = inb(vp->ioaddr + VIRTIO_PCI_CONFIG + offset + i); + ptr[i] = vp_read(&vp->legacy, virtio_pci_legacy, device[i]); }
u8 vp_get_status(struct vp_device *vp);
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-blk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index c3052bb..29bc4a5 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -33,7 +33,7 @@ virtio_blk_op(struct disk_op_s *op, int write) { struct virtiodrive_s *vdrive_gf = container_of(op->drive_gf, struct virtiodrive_s, drive); - struct vring_virtqueue *vq = GET_GLOBALFLAT(vdrive_gf->vq); + struct vring_virtqueue *vq = vdrive_gf->vq; struct virtio_blk_outhdr hdr = { .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN, .ioprio = 0, @@ -42,15 +42,15 @@ virtio_blk_op(struct disk_op_s *op, int write) u8 status = VIRTIO_BLK_S_UNSUPP; struct vring_list sg[] = { { - .addr = MAKE_FLATPTR(GET_SEG(SS), &hdr), + .addr = (void*)(&hdr), .length = sizeof(hdr), }, { .addr = op->buf_fl, - .length = GET_GLOBALFLAT(vdrive_gf->drive.blksize) * op->count, + .length = vdrive_gf->drive.blksize * op->count, }, { - .addr = MAKE_FLATPTR(GET_SEG(SS), &status), + .addr = (void*)(&status), .length = sizeof(status), }, };
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-scsi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c index 6b4ed1a..cb825d4 100644 --- a/src/hw/virtio-scsi.c +++ b/src/hw/virtio-scsi.c @@ -53,10 +53,10 @@ virtio_scsi_cmd(struct vp_device *vp, struct vring_virtqueue *vq, int in_num = (datain ? 2 : 1); int out_num = (len ? 3 : 2) - in_num;
- sg[0].addr = MAKE_FLATPTR(GET_SEG(SS), &req); + sg[0].addr = (void*)(&req); sg[0].length = sizeof(req);
- sg[out_num].addr = MAKE_FLATPTR(GET_SEG(SS), &resp); + sg[out_num].addr = (void*)(&resp); sg[out_num].length = sizeof(resp);
if (len) { @@ -93,10 +93,10 @@ virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) struct virtio_lun_s *vlun_gf = container_of(op->drive_gf, struct virtio_lun_s, drive);
- return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->vp), - GET_GLOBALFLAT(vlun_gf->vq), op, cdbcmd, - GET_GLOBALFLAT(vlun_gf->target), - GET_GLOBALFLAT(vlun_gf->lun), + return virtio_scsi_cmd(vlun_gf->vp, + vlun_gf->vq, op, cdbcmd, + vlun_gf->target, + vlun_gf->lun, blocksize); }
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-ring.c | 61 ++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 31 deletions(-)
diff --git a/src/hw/virtio-ring.c b/src/hw/virtio-ring.c index 6c86c38..7205a0a 100644 --- a/src/hw/virtio-ring.c +++ b/src/hw/virtio-ring.c @@ -35,8 +35,8 @@
int vring_more_used(struct vring_virtqueue *vq) { - struct vring_used *used = GET_LOWFLAT(vq->vring.used); - int more = GET_LOWFLAT(vq->last_used_idx) != GET_LOWFLAT(used->idx); + struct vring_used *used = vq->vring.used; + int more = vq->last_used_idx != used->idx; /* Make sure ring reads are done after idx read above. */ smp_rmb(); return more; @@ -57,13 +57,13 @@ void vring_detach(struct vring_virtqueue *vq, unsigned int head) /* find end of given descriptor */
i = head; - while (GET_LOWFLAT(desc[i].flags) & VRING_DESC_F_NEXT) - i = GET_LOWFLAT(desc[i].next); + while (desc[i].flags & VRING_DESC_F_NEXT) + i = desc[i].next;
/* link it with free list and point to it */
- SET_LOWFLAT(desc[i].next, GET_LOWFLAT(vq->free_head)); - SET_LOWFLAT(vq->free_head, head); + desc[i].next = vq->free_head; + vq->free_head = head; }
/* @@ -77,22 +77,22 @@ 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_LOWFLAT(vq->vring.used); + struct vring_used *used = vq->vring.used; u32 id; int ret;
// BUG_ON(!vring_more_used(vq));
- elem = &used->ring[GET_LOWFLAT(vq->last_used_idx) % GET_LOWFLAT(vr->num)]; - id = GET_LOWFLAT(elem->id); + elem = &used->ring[vq->last_used_idx % vr->num]; + id = elem->id; if (len != NULL) - *len = GET_LOWFLAT(elem->len); + *len = elem->len;
- ret = GET_LOWFLAT(vq->vdata[id]); + ret = vq->vdata[id];
vring_detach(vq, id);
- SET_LOWFLAT(vq->last_used_idx, GET_LOWFLAT(vq->last_used_idx) + 1); + vq->last_used_idx = vq->last_used_idx + 1;
return ret; } @@ -104,46 +104,45 @@ void vring_add_buf(struct vring_virtqueue *vq, { struct vring *vr = &vq->vring; int i, av, head, prev; - struct vring_desc *desc = GET_LOWFLAT(vr->desc); - struct vring_avail *avail = GET_LOWFLAT(vr->avail); + struct vring_desc *desc = vr->desc; + struct vring_avail *avail = vr->avail;
BUG_ON(out + in == 0);
prev = 0; - head = GET_LOWFLAT(vq->free_head); - for (i = head; out; i = GET_LOWFLAT(desc[i].next), out--) { - SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT); - SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr)); - SET_LOWFLAT(desc[i].len, list->length); + head = vq->free_head; + for (i = head; out; i = desc[i].next, out--) { + desc[i].flags = VRING_DESC_F_NEXT; + desc[i].addr = (u64)virt_to_phys(list->addr); + desc[i].len = list->length; prev = i; list++; } - for ( ; in; i = GET_LOWFLAT(desc[i].next), in--) { - SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE); - SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr)); - SET_LOWFLAT(desc[i].len, list->length); + for ( ; in; i = desc[i].next, in--) { + desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; + desc[i].addr = (u64)virt_to_phys(list->addr); + desc[i].len = list->length; prev = i; list++; } - SET_LOWFLAT(desc[prev].flags, - GET_LOWFLAT(desc[prev].flags) & ~VRING_DESC_F_NEXT); + desc[prev].flags = desc[prev].flags & ~VRING_DESC_F_NEXT;
- SET_LOWFLAT(vq->free_head, i); + vq->free_head = i;
- SET_LOWFLAT(vq->vdata[head], index); + vq->vdata[head] = index;
- av = (GET_LOWFLAT(avail->idx) + num_added) % GET_LOWFLAT(vr->num); - SET_LOWFLAT(avail->ring[av], head); + av = (avail->idx + num_added) % vr->num; + avail->ring[av] = head; }
void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added) { struct vring *vr = &vq->vring; - struct vring_avail *avail = GET_LOWFLAT(vr->avail); + struct vring_avail *avail = vr->avail;
/* Make sure idx update is done after ring write. */ smp_wmb(); - SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added); + avail->idx = avail->idx + num_added;
vp_notify(vp, vq); }
That way we should be able to manage *alot* more devices.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/hw/virtio-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 8e7ea46..6df5194 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -121,7 +121,7 @@ int vp_find_vq(struct vp_device *vp, int queue_index, u16 num;
ASSERT32FLAT(); - struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq)); + struct vring_virtqueue *vq = *p_vq = memalign_high(PAGE_SIZE, sizeof(*vq)); if (!vq) { warn_noalloc(); goto fail;
On Wed, Jul 01, 2015 at 04:40:45PM +0200, Gerd Hoffmann wrote:
Hi,
This patch series adds virtio 1.0 support to the virtio blk and scsi drivers in seabios. With this series applied seabios happily boots in virtio 1.0 mode from both transitional and modern devices. This series also moves all virtio code to 32bit.
Tested with Fedora 22 guest, booting from virtio-scsi cdrom (live iso), virtio-scsi disk and virtio-blk disk.
Thanks - the series looks good to me.
-Kevin
On Mi, 2015-07-01 at 11:21 -0400, Kevin O'Connor wrote:
On Wed, Jul 01, 2015 at 04:40:45PM +0200, Gerd Hoffmann wrote:
Hi,
This patch series adds virtio 1.0 support to the virtio blk and scsi drivers in seabios. With this series applied seabios happily boots in virtio 1.0 mode from both transitional and modern devices. This series also moves all virtio code to 32bit.
Tested with Fedora 22 guest, booting from virtio-scsi cdrom (live iso), virtio-scsi disk and virtio-blk disk.
Thanks - the series looks good to me.
Pushed now.
cheers, Gerd