summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/block/virtio-blk.c8
-rw-r--r--hw/sd/sd.c4
-rw-r--r--hw/sd/sdhci.c42
-rw-r--r--hw/sd/sdhci.h2
-rw-r--r--hw/virtio/dataplane/vring.c69
5 files changed, 95 insertions, 30 deletions
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index f9301ae541..8beb26b4db 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -30,7 +30,7 @@
 
 VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
 {
-    VirtIOBlockReq *req = g_slice_new(VirtIOBlockReq);
+    VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1);
     req->dev = s;
     req->qiov.size = 0;
     req->in_len = 0;
@@ -42,7 +42,7 @@ VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
 void virtio_blk_free_request(VirtIOBlockReq *req)
 {
     if (req) {
-        g_slice_free(VirtIOBlockReq, req);
+        g_free(req);
     }
 }
 
@@ -600,6 +600,8 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
         return;
     }
 
+    blk_io_plug(s->blk);
+
     while ((req = virtio_blk_get_request(s))) {
         virtio_blk_handle_request(req, &mrb);
     }
@@ -607,6 +609,8 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
     if (mrb.num_reqs) {
         virtio_blk_submit_multireq(s->blk, &mrb);
     }
+
+    blk_io_unplug(s->blk);
 }
 
 static void virtio_blk_dma_restart_bh(void *opaque)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 3e2a451154..393a75c0bc 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -492,7 +492,9 @@ SDState *sd_init(BlockBackend *blk, bool is_spi)
     sd->blk = blk;
     sd_reset(sd);
     if (sd->blk) {
-        blk_attach_dev_nofail(sd->blk, sd);
+        /* Attach dev if not already attached.  (This call ignores an
+         * error return code if sd->blk is already attached.) */
+        blk_attach_dev(sd->blk, sd);
         blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
     }
     vmstate_register(NULL, -1, &sd_vmstate, sd);
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 8b0f9f0df5..7f73527d44 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1009,6 +1009,16 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
             MASKED_WRITE(s->blksize, mask, value);
             MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16);
         }
+
+        /* Limit block size to the maximum buffer size */
+        if (extract32(s->blksize, 0, 12) > s->buf_maxsz) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \
+                          "the maximum buffer 0x%x", __func__, s->blksize,
+                          s->buf_maxsz);
+
+            s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz);
+        }
+
         break;
     case SDHC_ARGUMENT:
         MASKED_WRITE(s->argument, mask, value);
@@ -1145,13 +1155,9 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
     }
 }
 
-static void sdhci_initfn(SDHCIState *s)
+static void sdhci_initfn(SDHCIState *s, BlockBackend *blk)
 {
-    DriveInfo *di;
-
-    /* FIXME use a qdev drive property instead of drive_get_next() */
-    di = drive_get_next(IF_SD);
-    s->card = sd_init(di ? blk_by_legacy_dinfo(di) : NULL, false);
+    s->card = sd_init(blk, false);
     if (s->card == NULL) {
         exit(1);
     }
@@ -1215,7 +1221,8 @@ const VMStateDescription sdhci_vmstate = {
 
 /* Capabilities registers provide information on supported features of this
  * specific host controller implementation */
-static Property sdhci_properties[] = {
+static Property sdhci_pci_properties[] = {
+    DEFINE_BLOCK_PROPERTIES(SDHCIState, conf),
     DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
             SDHC_CAPAB_REG_DEFAULT),
     DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
@@ -1227,7 +1234,7 @@ static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
     SDHCIState *s = PCI_SDHCI(dev);
     dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */
     dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
-    sdhci_initfn(s);
+    sdhci_initfn(s, s->conf.blk);
     s->buf_maxsz = sdhci_get_fifolen(s);
     s->fifo_buffer = g_malloc0(s->buf_maxsz);
     s->irq = pci_allocate_irq(dev);
@@ -1254,9 +1261,7 @@ static void sdhci_pci_class_init(ObjectClass *klass, void *data)
     k->class_id = PCI_CLASS_SYSTEM_SDHCI;
     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
     dc->vmsd = &sdhci_vmstate;
-    dc->props = sdhci_properties;
-    /* Reason: realize() method uses drive_get_next() */
-    dc->cannot_instantiate_with_device_add_yet = true;
+    dc->props = sdhci_pci_properties;
 }
 
 static const TypeInfo sdhci_pci_info = {
@@ -1266,10 +1271,21 @@ static const TypeInfo sdhci_pci_info = {
     .class_init = sdhci_pci_class_init,
 };
 
+static Property sdhci_sysbus_properties[] = {
+    DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
+            SDHC_CAPAB_REG_DEFAULT),
+    DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void sdhci_sysbus_init(Object *obj)
 {
     SDHCIState *s = SYSBUS_SDHCI(obj);
-    sdhci_initfn(s);
+    DriveInfo *di;
+
+    /* FIXME use a qdev drive property instead of drive_get_next() */
+    di = drive_get_next(IF_SD);
+    sdhci_initfn(s, di ? blk_by_legacy_dinfo(di) : NULL);
 }
 
 static void sdhci_sysbus_finalize(Object *obj)
@@ -1296,7 +1312,7 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->vmsd = &sdhci_vmstate;
-    dc->props = sdhci_properties;
+    dc->props = sdhci_sysbus_properties;
     dc->realize = sdhci_sysbus_realize;
     /* Reason: instance_init() method uses drive_get_next() */
     dc->cannot_instantiate_with_device_add_yet = true;
diff --git a/hw/sd/sdhci.h b/hw/sd/sdhci.h
index 3352d23d68..e2de92d553 100644
--- a/hw/sd/sdhci.h
+++ b/hw/sd/sdhci.h
@@ -26,6 +26,7 @@
 #define SDHCI_H
 
 #include "qemu-common.h"
+#include "hw/block/block.h"
 #include "hw/pci/pci.h"
 #include "hw/sysbus.h"
 #include "hw/sd.h"
@@ -239,6 +240,7 @@ typedef struct SDHCIState {
     };
     SDState *card;
     MemoryRegion iomem;
+    BlockConf conf;
 
     QEMUTimer *insert_timer;       /* timer for 'changing' sd card. */
     QEMUTimer *transfer_timer;
diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c
index fece83a829..68f1994434 100644
--- a/hw/virtio/dataplane/vring.c
+++ b/hw/virtio/dataplane/vring.c
@@ -67,22 +67,53 @@ static void vring_unmap(void *buffer, bool is_write)
 /* Map the guest's vring to host memory */
 bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
 {
-    hwaddr vring_addr = virtio_queue_get_ring_addr(vdev, n);
-    hwaddr vring_size = virtio_queue_get_ring_size(vdev, n);
-    void *vring_ptr;
+    struct vring *vr = &vring->vr;
+    hwaddr addr;
+    hwaddr size;
+    void *ptr;
 
     vring->broken = false;
-
-    vring_ptr = vring_map(&vring->mr, vring_addr, vring_size, true);
-    if (!vring_ptr) {
-        error_report("Failed to map vring "
-                     "addr %#" HWADDR_PRIx " size %" HWADDR_PRIu,
-                     vring_addr, vring_size);
-        vring->broken = true;
-        return false;
+    vr->num = virtio_queue_get_num(vdev, n);
+
+    addr = virtio_queue_get_desc_addr(vdev, n);
+    size = virtio_queue_get_desc_size(vdev, n);
+    /* Map the descriptor area as read only */
+    ptr = vring_map(&vring->mr_desc, addr, size, false);
+    if (!ptr) {
+        error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring desc "
+                     "at 0x%" HWADDR_PRIx,
+                      size, addr);
+        goto out_err_desc;
     }
-
-    vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096);
+    vr->desc = ptr;
+
+    addr = virtio_queue_get_avail_addr(vdev, n);
+    size = virtio_queue_get_avail_size(vdev, n);
+    /* Add the size of the used_event_idx */
+    size += sizeof(uint16_t);
+    /* Map the driver area as read only */
+    ptr = vring_map(&vring->mr_avail, addr, size, false);
+    if (!ptr) {
+        error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring avail "
+                     "at 0x%" HWADDR_PRIx,
+                      size, addr);
+        goto out_err_avail;
+    }
+    vr->avail = ptr;
+
+    addr = virtio_queue_get_used_addr(vdev, n);
+    size = virtio_queue_get_used_size(vdev, n);
+    /* Add the size of the avail_event_idx */
+    size += sizeof(uint16_t);
+    /* Map the device area as read-write */
+    ptr = vring_map(&vring->mr_used, addr, size, true);
+    if (!ptr) {
+        error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring used "
+                     "at 0x%" HWADDR_PRIx,
+                      size, addr);
+        goto out_err_used;
+    }
+    vr->used = ptr;
 
     vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n);
     vring->last_used_idx = vring_get_used_idx(vdev, vring);
@@ -92,6 +123,14 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
     trace_vring_setup(virtio_queue_get_ring_addr(vdev, n),
                       vring->vr.desc, vring->vr.avail, vring->vr.used);
     return true;
+
+out_err_used:
+    memory_region_unref(vring->mr_avail);
+out_err_avail:
+    memory_region_unref(vring->mr_desc);
+out_err_desc:
+    vring->broken = true;
+    return false;
 }
 
 void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
@@ -99,7 +138,9 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
     virtio_queue_set_last_avail_idx(vdev, n, vring->last_avail_idx);
     virtio_queue_invalidate_signalled_used(vdev, n);
 
-    memory_region_unref(vring->mr);
+    memory_region_unref(vring->mr_desc);
+    memory_region_unref(vring->mr_avail);
+    memory_region_unref(vring->mr_used);
 }
 
 /* Disable guest->host notifies */