#include <linux/virtio_ring.h>
#include <linux/virtio_blk.h>
+#include <linux/list.h>
#include <linux/types.h>
#include <pthread.h>
struct blk_dev {
pthread_mutex_t mutex;
+ struct list_head list;
struct virtio_blk_config blk_config;
struct disk_image *disk;
+ u64 base_addr;
u32 host_features;
u32 guest_features;
u16 config_vector;
u8 status;
u8 isr;
- u8 idx;
/* virtio queue */
u16 queue_selector;
struct pci_device_header pci_hdr;
};
-static struct blk_dev *bdevs[VIRTIO_BLK_MAX_DEV];
+static LIST_HEAD(bdevs);
static bool virtio_blk_dev_in(struct blk_dev *bdev, void *data, unsigned long offset, int size, u32 count)
{
return true;
}
-/* Translate port into device id + offset in that device addr space */
-static void virtio_blk_port2dev(u16 port, u16 base, u16 size, u16 *dev_idx, u16 *offset)
-{
- *dev_idx = (port - base) / size;
- *offset = port - (base + *dev_idx * size);
-}
-
static bool virtio_blk_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
struct blk_dev *bdev;
- u16 offset, dev_idx;
+ u16 offset;
bool ret = true;
- virtio_blk_port2dev(port, IOPORT_VIRTIO_BLK, IOPORT_VIRTIO_BLK_SIZE, &dev_idx, &offset);
-
- bdev = bdevs[dev_idx];
+ bdev = ioport->priv;
+ offset = port - bdev->base_addr;
mutex_lock(&bdev->mutex);
static bool virtio_blk_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count)
{
struct blk_dev *bdev;
- u16 offset, dev_idx;
+ u16 offset;
bool ret = true;
- virtio_blk_port2dev(port, IOPORT_VIRTIO_BLK, IOPORT_VIRTIO_BLK_SIZE, &dev_idx, &offset);
-
- bdev = bdevs[dev_idx];
+ bdev = ioport->priv;
+ offset = port - bdev->base_addr;
mutex_lock(&bdev->mutex);
}
static struct ioport_operations virtio_blk_io_ops = {
- .io_in = virtio_blk_pci_io_in,
- .io_out = virtio_blk_pci_io_out,
+ .io_in = virtio_blk_pci_io_in,
+ .io_out = virtio_blk_pci_io_out,
};
-static int virtio_blk_find_empty_dev(void)
-{
- int i;
-
- for (i = 0; i < VIRTIO_BLK_MAX_DEV; i++) {
- if (bdevs[i] == NULL)
- return i;
- }
-
- return -1;
-}
-
void virtio_blk__init(struct kvm *kvm, struct disk_image *disk)
{
u16 blk_dev_base_addr;
u8 dev, pin, line;
struct blk_dev *bdev;
- int new_dev_idx;
if (!disk)
return;
- new_dev_idx = virtio_blk_find_empty_dev();
- if (new_dev_idx < 0)
- die("Could not find an empty block device slot");
-
- bdevs[new_dev_idx] = calloc(1, sizeof(struct blk_dev));
- if (bdevs[new_dev_idx] == NULL)
+ bdev = calloc(1, sizeof(struct blk_dev));
+ if (bdev == NULL)
die("Failed allocating bdev");
- bdev = bdevs[new_dev_idx];
-
- blk_dev_base_addr = IOPORT_VIRTIO_BLK + new_dev_idx * IOPORT_VIRTIO_BLK_SIZE;
+ blk_dev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_blk_io_ops, IOPORT_SIZE, bdev);
*bdev = (struct blk_dev) {
.mutex = PTHREAD_MUTEX_INITIALIZER,
.disk = disk,
- .idx = new_dev_idx,
+ .base_addr = blk_dev_base_addr,
.blk_config = (struct virtio_blk_config) {
.capacity = disk->size / SECTOR_SIZE,
.seg_max = DISK_SEG_MAX,
.host_features = (1UL << VIRTIO_BLK_F_SEG_MAX | 1UL << VIRTIO_BLK_F_FLUSH),
};
+ list_add_tail(&bdev->list, &bdevs);
+
if (irq__register_device(VIRTIO_ID_BLOCK, &dev, &pin, &line) < 0)
return;
bdev->pci_hdr.irq_line = line;
pci__register(&bdev->pci_hdr, dev);
-
- ioport__register(blk_dev_base_addr, &virtio_blk_io_ops, IOPORT_VIRTIO_BLK_SIZE, NULL);
}
void virtio_blk__init_all(struct kvm *kvm)
void virtio_blk__delete_all(struct kvm *kvm)
{
- int i;
+ while (!list_empty(&bdevs)) {
+ struct blk_dev *bdev;
- for (i = 0; i < kvm->nr_disks; i++)
- free(bdevs[i]);
+ bdev = list_first_entry(&bdevs, struct blk_dev, list);
+ list_del(&bdev->list);
+ free(bdev);
+ }
}