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); }