From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34238) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YAi5S-0002Xn-MG for qemu-devel@nongnu.org; Mon, 12 Jan 2015 11:43:35 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YAi5M-0001sG-5J for qemu-devel@nongnu.org; Mon, 12 Jan 2015 11:43:30 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41577) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YAi5L-0001pG-LK for qemu-devel@nongnu.org; Mon, 12 Jan 2015 11:43:24 -0500 From: Stefan Hajnoczi Date: Mon, 12 Jan 2015 16:40:15 +0000 Message-Id: <1421080834-14724-26-git-send-email-stefanha@redhat.com> In-Reply-To: <1421080834-14724-1-git-send-email-stefanha@redhat.com> References: <1421080834-14724-1-git-send-email-stefanha@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PULL v2 25/44] libqos: Add virtio MMIO support List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc=20Mar=C3=AD?= , Peter Maydell , Stefan Hajnoczi From: Marc Mar=C3=AD Add virtio MMIO support. Add virtio-blk-test MMIO test case. Signed-off-by: Marc Mar=C3=AD Signed-off-by: Stefan Hajnoczi --- tests/Makefile | 4 +- tests/libqos/virtio-mmio.c | 190 +++++++++++++++++++++++++++++++++++++++= ++++++ tests/libqos/virtio-mmio.h | 46 +++++++++++ tests/virtio-blk-test.c | 81 +++++++++++++++++-- 4 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 tests/libqos/virtio-mmio.c create mode 100644 tests/libqos/virtio-mmio.h diff --git a/tests/Makefile b/tests/Makefile index c2e2e52..77f995d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -185,6 +185,8 @@ gcov-files-sparc-y +=3D hw/timer/m48t59.c gcov-files-sparc64-y +=3D hw/timer/m48t59.c check-qtest-arm-y =3D tests/tmp105-test$(EXESUF) gcov-files-arm-y +=3D hw/misc/tmp105.c +check-qtest-arm-y +=3D tests/virtio-blk-test$(EXESUF) +gcov-files-arm-y +=3D arm-softmmu/hw/block/virtio-blk.c check-qtest-ppc-y +=3D tests/boot-order-test$(EXESUF) check-qtest-ppc64-y +=3D tests/boot-order-test$(EXESUF) check-qtest-ppc64-y +=3D tests/spapr-phb-test$(EXESUF) @@ -303,8 +305,8 @@ libqos-obj-y +=3D tests/libqos/i2c.o libqos-pc-obj-y =3D $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y +=3D tests/libqos/malloc-pc.o libqos-omap-obj-y =3D $(libqos-obj-y) tests/libqos/i2c-omap.o -libqos-virtio-obj-y =3D $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/= virtio.o tests/libqos/virtio-pci.o libqos-usb-obj-y =3D $(libqos-pc-obj-y) tests/libqos/usb.o +libqos-virtio-obj-y =3D $(libqos-pc-obj-y) tests/libqos/virtio.o tests/l= ibqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic= .o =20 tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c new file mode 100644 index 0000000..f5ca6c4 --- /dev/null +++ b/tests/libqos/virtio-mmio.c @@ -0,0 +1,190 @@ +/* + * libqos virtio MMIO driver + * + * Copyright (c) 2014 Marc Mar=C3=AD + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include "libqtest.h" +#include "libqos/virtio.h" +#include "libqos/virtio-mmio.h" +#include "libqos/malloc.h" +#include "libqos/malloc-generic.h" + +static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t addr= ) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + return readb(dev->addr + addr); +} + +static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t add= r) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + return readw(dev->addr + addr); +} + +static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t add= r) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + return readl(dev->addr + addr); +} + +static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t add= r) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + return readq(dev->addr + addr); +} + +static uint32_t qvirtio_mmio_get_features(QVirtioDevice *d) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + writel(dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0); + return readl(dev->addr + QVIRTIO_MMIO_HOST_FEATURES); +} + +static void qvirtio_mmio_set_features(QVirtioDevice *d, uint32_t feature= s) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + dev->features =3D features; + writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 0); + writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, features); +} + +static uint32_t qvirtio_mmio_get_guest_features(QVirtioDevice *d) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + return dev->features; +} + +static uint8_t qvirtio_mmio_get_status(QVirtioDevice *d) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + return (uint8_t)readl(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS); +} + +static void qvirtio_mmio_set_status(QVirtioDevice *d, uint8_t status) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + writel(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status); +} + +static bool qvirtio_mmio_get_queue_isr_status(QVirtioDevice *d, QVirtQue= ue *vq) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + uint32_t isr; + + isr =3D readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 1; + writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 1); + return isr !=3D 0; +} + +static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + uint32_t isr; + + isr =3D readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 2; + writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 2); + return isr !=3D 0; +} + +static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + writel(dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index); + + g_assert_cmphex(readl(dev->addr + QVIRTIO_MMIO_QUEUE_PFN), =3D=3D, 0= ); +} + +static uint16_t qvirtio_mmio_get_queue_size(QVirtioDevice *d) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + return (uint16_t)readl(dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX); +} + +static void qvirtio_mmio_set_queue_address(QVirtioDevice *d, uint32_t pf= n) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + writel(dev->addr + QVIRTIO_MMIO_QUEUE_PFN, pfn); +} + +static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d, + QGuestAllocator *alloc, uint16_t= index) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + QVirtQueue *vq; + uint64_t addr; + + vq =3D g_malloc0(sizeof(*vq)); + qvirtio_mmio_queue_select(d, index); + writel(dev->addr + QVIRTIO_MMIO_QUEUE_ALIGN, dev->page_size); + + vq->index =3D index; + vq->size =3D qvirtio_mmio_get_queue_size(d); + vq->free_head =3D 0; + vq->num_free =3D vq->size; + vq->align =3D dev->page_size; + vq->indirect =3D (dev->features & QVIRTIO_F_RING_INDIRECT_DESC) !=3D= 0; + vq->event =3D (dev->features & QVIRTIO_F_RING_EVENT_IDX) !=3D 0; + + writel(dev->addr + QVIRTIO_MMIO_QUEUE_NUM, vq->size); + + /* Check different than 0 */ + g_assert_cmpint(vq->size, !=3D, 0); + + /* Check power of 2 */ + g_assert_cmpint(vq->size & (vq->size - 1), =3D=3D, 0); + + addr =3D guest_alloc(alloc, qvring_size(vq->size, dev->page_size)); + qvring_init(alloc, vq, addr); + qvirtio_mmio_set_queue_address(d, vq->desc / dev->page_size); + + return vq; +} + +static void qvirtio_mmio_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq= ) +{ + QVirtioMMIODevice *dev =3D (QVirtioMMIODevice *)d; + writel(dev->addr + QVIRTIO_MMIO_QUEUE_NOTIFY, vq->index); +} + +const QVirtioBus qvirtio_mmio =3D { + .config_readb =3D qvirtio_mmio_config_readb, + .config_readw =3D qvirtio_mmio_config_readw, + .config_readl =3D qvirtio_mmio_config_readl, + .config_readq =3D qvirtio_mmio_config_readq, + .get_features =3D qvirtio_mmio_get_features, + .set_features =3D qvirtio_mmio_set_features, + .get_guest_features =3D qvirtio_mmio_get_guest_features, + .get_status =3D qvirtio_mmio_get_status, + .set_status =3D qvirtio_mmio_set_status, + .get_queue_isr_status =3D qvirtio_mmio_get_queue_isr_status, + .get_config_isr_status =3D qvirtio_mmio_get_config_isr_status, + .queue_select =3D qvirtio_mmio_queue_select, + .get_queue_size =3D qvirtio_mmio_get_queue_size, + .set_queue_address =3D qvirtio_mmio_set_queue_address, + .virtqueue_setup =3D qvirtio_mmio_virtqueue_setup, + .virtqueue_kick =3D qvirtio_mmio_virtqueue_kick, +}; + +QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page= _size) +{ + QVirtioMMIODevice *dev; + uint32_t magic; + dev =3D g_malloc0(sizeof(*dev)); + + magic =3D readl(addr + QVIRTIO_MMIO_MAGIC_VALUE); + g_assert(magic =3D=3D ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)); + + dev->addr =3D addr; + dev->page_size =3D page_size; + dev->vdev.device_type =3D readl(addr + QVIRTIO_MMIO_DEVICE_ID); + + writel(addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size); + + return dev; +} diff --git a/tests/libqos/virtio-mmio.h b/tests/libqos/virtio-mmio.h new file mode 100644 index 0000000..e3e52b9 --- /dev/null +++ b/tests/libqos/virtio-mmio.h @@ -0,0 +1,46 @@ +/* + * libqos virtio MMIO definitions + * + * Copyright (c) 2014 Marc Mar=C3=AD + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_VIRTIO_MMIO_H +#define LIBQOS_VIRTIO_MMIO_H + +#include "libqos/virtio.h" + +#define QVIRTIO_MMIO_MAGIC_VALUE 0x000 +#define QVIRTIO_MMIO_VERSION 0x004 +#define QVIRTIO_MMIO_DEVICE_ID 0x008 +#define QVIRTIO_MMIO_VENDOR_ID 0x00C +#define QVIRTIO_MMIO_HOST_FEATURES 0x010 +#define QVIRTIO_MMIO_HOST_FEATURES_SEL 0x014 +#define QVIRTIO_MMIO_GUEST_FEATURES 0x020 +#define QVIRTIO_MMIO_GUEST_FEATURES_SEL 0x024 +#define QVIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 +#define QVIRTIO_MMIO_QUEUE_SEL 0x030 +#define QVIRTIO_MMIO_QUEUE_NUM_MAX 0x034 +#define QVIRTIO_MMIO_QUEUE_NUM 0x038 +#define QVIRTIO_MMIO_QUEUE_ALIGN 0x03C +#define QVIRTIO_MMIO_QUEUE_PFN 0x040 +#define QVIRTIO_MMIO_QUEUE_NOTIFY 0x050 +#define QVIRTIO_MMIO_INTERRUPT_STATUS 0x060 +#define QVIRTIO_MMIO_INTERRUPT_ACK 0x064 +#define QVIRTIO_MMIO_DEVICE_STATUS 0x070 +#define QVIRTIO_MMIO_DEVICE_SPECIFIC 0x100 + +typedef struct QVirtioMMIODevice { + QVirtioDevice vdev; + uint64_t addr; + uint32_t page_size; + uint32_t features; /* As it cannot be read later, save it */ +} QVirtioMMIODevice; + +extern const QVirtioBus qvirtio_mmio; + +QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page= _size); + +#endif diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index fd54f58..82346e5 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -16,9 +16,11 @@ #include "libqtest.h" #include "libqos/virtio.h" #include "libqos/virtio-pci.h" +#include "libqos/virtio-mmio.h" #include "libqos/pci-pc.h" #include "libqos/malloc.h" #include "libqos/malloc-pc.h" +#include "libqos/malloc-generic.h" #include "qemu/bswap.h" =20 #define QVIRTIO_BLK_F_BARRIER 0x00000001 @@ -42,10 +44,14 @@ =20 #define TEST_IMAGE_SIZE (64 * 1024 * 1024) #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000) +#define PCI_SLOT_HP 0x06 #define PCI_SLOT 0x04 #define PCI_FN 0x00 =20 -#define PCI_SLOT_HP 0x06 +#define MMIO_PAGE_SIZE 4096 +#define MMIO_DEV_BASE_ADDR 0x0A003E00 +#define MMIO_RAM_ADDR 0x40000000 +#define MMIO_RAM_SIZE 0x20000000 =20 typedef struct QVirtioBlkReq { uint32_t type; @@ -90,6 +96,21 @@ static QPCIBus *pci_test_start(void) return qpci_init_pc(); } =20 +static void arm_test_start(void) +{ + char *cmdline; + char *tmp_path; + + tmp_path =3D drive_create(); + + cmdline =3D g_strdup_printf("-machine virt -drive if=3Dnone,id=3Ddri= ve0,file=3D%s " + "-device virtio-blk-device,drive=3Ddrive0", = tmp_path); + qtest_start(cmdline); + unlink(tmp_path); + g_free(tmp_path); + g_free(cmdline); +} + static void test_end(void) { qtest_end(); @@ -695,18 +716,64 @@ static void pci_hotplug(void) test_end(); } =20 +static void mmio_basic(void) +{ + QVirtioMMIODevice *dev; + QVirtQueue *vq; + QGuestAllocator *alloc; + int n_size =3D TEST_IMAGE_SIZE / 2; + uint64_t capacity; + + arm_test_start(); + + dev =3D qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE)= ; + g_assert(dev !=3D NULL); + g_assert_cmphex(dev->vdev.device_type, =3D=3D, QVIRTIO_BLK_DEVICE_ID= ); + + qvirtio_reset(&qvirtio_mmio, &dev->vdev); + qvirtio_set_acknowledge(&qvirtio_mmio, &dev->vdev); + qvirtio_set_driver(&qvirtio_mmio, &dev->vdev); + + alloc =3D generic_alloc_init(MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE= _SIZE); + vq =3D qvirtqueue_setup(&qvirtio_mmio, &dev->vdev, alloc, 0); + + test_basic(&qvirtio_mmio, &dev->vdev, alloc, vq, + QVIRTIO_MMIO_DEVICE_SPECIFIC); + + qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0',= " + " 'size': %d } }", n= _size); + + qvirtio_wait_queue_isr(&qvirtio_mmio, &dev->vdev, vq, + QVIRTIO_BLK_TIMEOUT_US); + + capacity =3D qvirtio_config_readq(&qvirtio_mmio, &dev->vdev, + QVIRTIO_MMIO_DEVICE_SPEC= IFIC); + g_assert_cmpint(capacity, =3D=3D, n_size / 512); + + /* End test */ + guest_free(alloc, vq->desc); + generic_alloc_uninit(alloc); + g_free(dev); + test_end(); +} + int main(int argc, char **argv) { int ret; + const char *arch =3D qtest_get_arch(); =20 g_test_init(&argc, &argv, NULL); =20 - g_test_add_func("/virtio/blk/pci/basic", pci_basic); - g_test_add_func("/virtio/blk/pci/indirect", pci_indirect); - g_test_add_func("/virtio/blk/pci/config", pci_config); - g_test_add_func("/virtio/blk/pci/msix", pci_msix); - g_test_add_func("/virtio/blk/pci/idx", pci_idx); - g_test_add_func("/virtio/blk/pci/hotplug", pci_hotplug); + if (strcmp(arch, "i386") =3D=3D 0 || strcmp(arch, "x86_64") =3D=3D 0= ) { + qtest_add_func("/virtio/blk/pci/basic", pci_basic); + qtest_add_func("/virtio/blk/pci/indirect", pci_indirect); + qtest_add_func("/virtio/blk/pci/config", pci_config); + qtest_add_func("/virtio/blk/pci/msix", pci_msix); + qtest_add_func("/virtio/blk/pci/idx", pci_idx); + qtest_add_func("/virtio/blk/pci/hotplug", pci_hotplug); + } else if (strcmp(arch, "arm") =3D=3D 0) { + qtest_add_func("/virtio/blk/mmio/basic", mmio_basic); + } =20 ret =3D g_test_run(); =20 --=20 2.1.0