From e49f827725d53d2fb1b8ec42db96c442d0caf6cd Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sat, 27 Aug 2016 16:34:14 -0400 Subject: tests: fix qvirtqueue_kick vq->avail.idx and vq->avail->ring[] are a 16bit values, so read and write them with readw()/writew() instead of readl()/writel(). To read/write a 16bit value with a 32bit accessor works fine on little-endian CPU but not on big endian CPU. [An equivalent patch for the writew() calls was also sent by Zhang Shuai . --Stefan] Signed-off-by: Laurent Vivier Message-id: 1472330054-22607-1-git-send-email-lvivier@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/libqos/virtio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index d8c2970de7..37ff860c16 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -257,16 +257,16 @@ void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head) { /* vq->avail->idx */ - uint16_t idx = readl(vq->avail + 2); + uint16_t idx = readw(vq->avail + 2); /* vq->used->flags */ uint16_t flags; /* vq->used->avail_event */ uint16_t avail_event; /* vq->avail->ring[idx % vq->size] */ - writel(vq->avail + 4 + (2 * (idx % vq->size)), free_head); + writew(vq->avail + 4 + (2 * (idx % vq->size)), free_head); /* vq->avail->idx */ - writel(vq->avail + 2, idx + 1); + writew(vq->avail + 2, idx + 1); /* Must read after idx is updated */ flags = readw(vq->avail); -- cgit v1.2.3 From 8d6ef7c9fe880c710dd55cfe7a0f076be475bede Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 13 Sep 2016 14:52:44 +0200 Subject: libqos: define SPAPR libqos functions Define spapr_alloc_init()/spapr_alloc_init_flags()/spapr_alloc_uninit() to allocate and use SPAPR guest memory Define qtest_spapr_vboot()/qtest_spapr_boot()/qtest_spapr_shutdown() to start SPAPR guest with QOSState initialized for it (memory management) Move qtest_irq_intercept_in() from generic part to PC part. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: David Gibson --- tests/libqos/libqos-pc.c | 2 ++ tests/libqos/libqos-spapr.c | 30 ++++++++++++++++++++++++++++++ tests/libqos/libqos-spapr.h | 10 ++++++++++ tests/libqos/libqos.c | 1 - tests/libqos/malloc-spapr.c | 38 ++++++++++++++++++++++++++++++++++++++ tests/libqos/malloc-spapr.h | 17 +++++++++++++++++ 6 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/libqos/libqos-spapr.c create mode 100644 tests/libqos/libqos-spapr.h create mode 100644 tests/libqos/malloc-spapr.c create mode 100644 tests/libqos/malloc-spapr.h (limited to 'tests/libqos') diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index 72b5e3ba09..df340928a6 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -21,6 +21,8 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); va_end(ap); + qtest_irq_intercept_in(global_qtest, "ioapic"); + return qs; } diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c new file mode 100644 index 0000000000..f19408be00 --- /dev/null +++ b/tests/libqos/libqos-spapr.c @@ -0,0 +1,30 @@ +#include "qemu/osdep.h" +#include "libqos/libqos-spapr.h" +#include "libqos/malloc-spapr.h" + +static QOSOps qos_ops = { + .init_allocator = spapr_alloc_init_flags, + .uninit_allocator = spapr_alloc_uninit +}; + +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) +{ + return qtest_vboot(&qos_ops, cmdline_fmt, ap); +} + +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) +{ + QOSState *qs; + va_list ap; + + va_start(ap, cmdline_fmt); + qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); + va_end(ap); + + return qs; +} + +void qtest_spapr_shutdown(QOSState *qs) +{ + return qtest_shutdown(qs); +} diff --git a/tests/libqos/libqos-spapr.h b/tests/libqos/libqos-spapr.h new file mode 100644 index 0000000000..dcb5c43ad3 --- /dev/null +++ b/tests/libqos/libqos-spapr.h @@ -0,0 +1,10 @@ +#ifndef LIBQOS_SPAPR_H +#define LIBQOS_SPAPR_H + +#include "libqos/libqos.h" + +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap); +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...); +void qtest_spapr_shutdown(QOSState *qs); + +#endif diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index c7ba441d0b..a852dc5f8e 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -20,7 +20,6 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qs->ops = ops; - qtest_irq_intercept_in(global_qtest, "ioapic"); if (ops && ops->init_allocator) { qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); } diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c new file mode 100644 index 0000000000..006404af33 --- /dev/null +++ b/tests/libqos/malloc-spapr.c @@ -0,0 +1,38 @@ +/* + * libqos malloc support for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqos/malloc-spapr.h" + +#include "qemu-common.h" + +#define PAGE_SIZE 4096 + +/* Memory must be a multiple of 256 MB, + * so we have at least 256MB + */ +#define SPAPR_MIN_SIZE 0x10000000 + +void spapr_alloc_uninit(QGuestAllocator *allocator) +{ + alloc_uninit(allocator); +} + +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags) +{ + QGuestAllocator *s; + + s = alloc_init_flags(flags, 1 << 20, SPAPR_MIN_SIZE); + alloc_set_page_size(s, PAGE_SIZE); + + return s; +} + +QGuestAllocator *spapr_alloc_init(void) +{ + return spapr_alloc_init_flags(ALLOC_NO_FLAGS); +} diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h new file mode 100644 index 0000000000..64d0e770d1 --- /dev/null +++ b/tests/libqos/malloc-spapr.h @@ -0,0 +1,17 @@ +/* + * libqos malloc support for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_MALLOC_SPAPR_H +#define LIBQOS_MALLOC_SPAPR_H + +#include "libqos/malloc.h" + +QGuestAllocator *spapr_alloc_init(void); +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags); +void spapr_alloc_uninit(QGuestAllocator *allocator); + +#endif -- cgit v1.2.3 From eeddd59f59626302cdb7db2602140ac9a076dec9 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 13 Sep 2016 14:52:45 +0200 Subject: tests: add RTAS command in the protocol Add a first test to validate the protocol: - rtas/get-time-of-day compares the time from the guest with the time from the host. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- tests/libqos/rtas.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/rtas.h | 11 +++++++++ 2 files changed, 82 insertions(+) create mode 100644 tests/libqos/rtas.c create mode 100644 tests/libqos/rtas.h (limited to 'tests/libqos') diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c new file mode 100644 index 0000000000..820321a3a7 --- /dev/null +++ b/tests/libqos/rtas.c @@ -0,0 +1,71 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/rtas.h" + +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs, + uint32_t *args) +{ + int i; + + for (i = 0; i < nargs; i++) { + writel(target_args + i * sizeof(uint32_t), args[i]); + } +} + +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret) +{ + int i; + + for (i = 0; i < nret; i++) { + ret[i] = readl(target_ret + i * sizeof(uint32_t)); + } +} + +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name, + uint32_t nargs, uint32_t *args, + uint32_t nret, uint32_t *ret) +{ + uint64_t res; + uint64_t target_args, target_ret; + + target_args = guest_alloc(alloc, nargs * sizeof(uint32_t)); + target_ret = guest_alloc(alloc, nret * sizeof(uint32_t)); + + qrtas_copy_args(target_args, nargs, args); + res = qtest_rtas_call(global_qtest, name, + nargs, target_args, nret, target_ret); + qrtas_copy_ret(target_ret, nret, ret); + + guest_free(alloc, target_ret); + guest_free(alloc, target_args); + + return res; +} + +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns) +{ + int res; + uint32_t ret[8]; + + res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret); + if (res != 0) { + return res; + } + + res = ret[0]; + memset(tm, 0, sizeof(*tm)); + tm->tm_year = ret[1] - 1900; + tm->tm_mon = ret[2] - 1; + tm->tm_mday = ret[3]; + tm->tm_hour = ret[4]; + tm->tm_min = ret[5]; + tm->tm_sec = ret[6]; + *ns = ret[7]; + + return res; +} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h new file mode 100644 index 0000000000..a1b60a8eb4 --- /dev/null +++ b/tests/libqos/rtas.h @@ -0,0 +1,11 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_RTAS_H +#define LIBQOS_RTAS_H +#include "libqos/malloc.h" + +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); +#endif /* LIBQOS_RTAS_H */ -- cgit v1.2.3 From 844c82296f8bd6ceff8d170f3740740f3ce84b73 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 26 Sep 2016 17:24:10 +0200 Subject: libqos: fix qvring_init() "vq->desc[i].addr" is a 64bit value, so write it with writeq(), not writew(). struct vring_desc { __virtio64 addr; __virtio32 len; __virtio16 flags; __virtio16 next; }; Signed-off-by: Laurent Vivier Message-id: 1474903450-9605-1-git-send-email-lvivier@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/libqos/virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/libqos') diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 37ff860c16..105bccecaa 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -147,7 +147,7 @@ void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr) for (i = 0; i < vq->size - 1; i++) { /* vq->desc[i].addr */ - writew(vq->desc + (16 * i), 0); + writeq(vq->desc + (16 * i), 0); /* vq->desc[i].next */ writew(vq->desc + (16 * i) + 14, i + 1); } -- cgit v1.2.3 From cf716b31cba278a6dbff585d58fa29d1ae2fe334 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 29 Sep 2016 12:32:44 +0200 Subject: libqos: add PPC64 PCI support Signed-off-by: Laurent Vivier [dwg: Fixed build problem on 32-bit hosts] Signed-off-by: David Gibson --- tests/libqos/pci-pc.c | 22 ---- tests/libqos/pci-spapr.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/pci-spapr.h | 17 +++ tests/libqos/pci.c | 22 +++- tests/libqos/rtas.c | 45 ++++++++ tests/libqos/rtas.h | 4 + 6 files changed, 375 insertions(+), 23 deletions(-) create mode 100644 tests/libqos/pci-spapr.c create mode 100644 tests/libqos/pci-spapr.h (limited to 'tests/libqos') diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 1ae2d3780f..82066b8531 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -255,28 +255,6 @@ void qpci_free_pc(QPCIBus *bus) g_free(s); } -void qpci_plug_device_test(const char *driver, const char *id, - uint8_t slot, const char *opts) -{ - QDict *response; - char *cmd; - - cmd = g_strdup_printf("{'execute': 'device_add'," - " 'arguments': {" - " 'driver': '%s'," - " 'addr': '%d'," - " %s%s" - " 'id': '%s'" - "}}", driver, slot, - opts ? opts : "", opts ? "," : "", - id); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - QDECREF(response); -} - void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) { QDict *response; diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c new file mode 100644 index 0000000000..2f73badfd9 --- /dev/null +++ b/tests/libqos/pci-spapr.c @@ -0,0 +1,288 @@ +/* + * libqos PCI bindings for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/pci-spapr.h" +#include "libqos/rtas.h" + +#include "hw/pci/pci_regs.h" + +#include "qemu-common.h" +#include "qemu/host-utils.h" + + +/* From include/hw/pci-host/spapr.h */ + +#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL + +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ + SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + +/* index is the phb index */ + +#define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index)) +#define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \ + (index) * SPAPR_PCI_WINDOW_SPACING) +#define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF) +#define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF) + +typedef struct QPCIBusSPAPR { + QPCIBus bus; + QGuestAllocator *alloc; + + uint64_t pci_hole_start; + uint64_t pci_hole_size; + uint64_t pci_hole_alloc; + + uint32_t pci_iohole_start; + uint32_t pci_iohole_size; + uint32_t pci_iohole_alloc; +} QPCIBusSPAPR; + +/* + * PCI devices are always little-endian + * SPAPR by default is big-endian + * so PCI accessors need to swap data endianness + */ + +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint8_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readb(IOBASE(0) + port); + } else { + v = readb(MMIOBASE(0) + port); + } + return v; +} + +static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint16_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readw(IOBASE(0) + port); + } else { + v = readw(MMIOBASE(0) + port); + } + return bswap16(v); +} + +static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint32_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readl(IOBASE(0) + port); + } else { + v = readl(MMIOBASE(0) + port); + } + return bswap32(v); +} + +static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) +{ + uint64_t port = (uintptr_t)addr; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writeb(IOBASE(0) + port, value); + } else { + writeb(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap16(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writew(IOBASE(0) + port, value); + } else { + writew(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap32(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writel(IOBASE(0) + port, value); + } else { + writel(MMIOBASE(0) + port, value); + } +} + +static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1); +} + +static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2); +} + +static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4); +} + +static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, + uint8_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1, value); +} + +static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, + uint16_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2, value); +} + +static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, + uint32_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4, value); +} + +static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, + uint64_t *sizeptr) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + static const int bar_reg_map[] = { + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, + }; + int bar_reg; + uint32_t addr; + uint64_t size; + uint32_t io_type; + + g_assert(barno >= 0 && barno <= 5); + bar_reg = bar_reg_map[barno]; + + qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); + addr = qpci_config_readl(dev, bar_reg); + + io_type = addr & PCI_BASE_ADDRESS_SPACE; + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + addr &= PCI_BASE_ADDRESS_IO_MASK; + } else { + addr &= PCI_BASE_ADDRESS_MEM_MASK; + } + + size = (1ULL << ctzl(addr)); + if (size == 0) { + return NULL; + } + if (sizeptr) { + *sizeptr = size; + } + + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + uint16_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size + <= s->pci_iohole_size); + s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); + loc = s->pci_iohole_start + s->pci_iohole_alloc; + s->pci_iohole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); + + return (void *)(unsigned long)loc; + } else { + uint64_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size + <= s->pci_hole_size); + s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); + loc = s->pci_hole_start + s->pci_hole_alloc; + s->pci_hole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc); + + return (void *)(unsigned long)loc; + } +} + +static void qpci_spapr_iounmap(QPCIBus *bus, void *data) +{ + /* FIXME */ +} + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) +{ + QPCIBusSPAPR *ret; + + ret = g_malloc(sizeof(*ret)); + + ret->alloc = alloc; + + ret->bus.io_readb = qpci_spapr_io_readb; + ret->bus.io_readw = qpci_spapr_io_readw; + ret->bus.io_readl = qpci_spapr_io_readl; + + ret->bus.io_writeb = qpci_spapr_io_writeb; + ret->bus.io_writew = qpci_spapr_io_writew; + ret->bus.io_writel = qpci_spapr_io_writel; + + ret->bus.config_readb = qpci_spapr_config_readb; + ret->bus.config_readw = qpci_spapr_config_readw; + ret->bus.config_readl = qpci_spapr_config_readl; + + ret->bus.config_writeb = qpci_spapr_config_writeb; + ret->bus.config_writew = qpci_spapr_config_writew; + ret->bus.config_writel = qpci_spapr_config_writel; + + ret->bus.iomap = qpci_spapr_iomap; + ret->bus.iounmap = qpci_spapr_iounmap; + + ret->pci_hole_start = 0xC0000000; + ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_alloc = 0; + + ret->pci_iohole_start = 0xc000; + ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE; + ret->pci_iohole_alloc = 0; + + return &ret->bus; +} + +void qpci_free_spapr(QPCIBus *bus) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + + g_free(s); +} diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h new file mode 100644 index 0000000000..4192126d86 --- /dev/null +++ b/tests/libqos/pci-spapr.h @@ -0,0 +1,17 @@ +/* + * libqos PCI bindings for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBQOS_PCI_SPAPR_H +#define LIBQOS_PCI_SPAPR_H + +#include "libqos/malloc.h" +#include "libqos/pci.h" + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc); +void qpci_free_spapr(QPCIBus *bus); + +#endif diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index ed78d91cea..c3f3382b7c 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -263,4 +263,24 @@ void qpci_iounmap(QPCIDevice *dev, void *data) dev->bus->iounmap(dev->bus, data); } - +void qpci_plug_device_test(const char *driver, const char *id, + uint8_t slot, const char *opts) +{ + QDict *response; + char *cmd; + + cmd = g_strdup_printf("{'execute': 'device_add'," + " 'arguments': {" + " 'driver': '%s'," + " 'addr': '%d'," + " %s%s" + " 'id': '%s'" + "}}", driver, slot, + opts ? opts : "", opts ? "," : "", + id); + response = qmp(cmd); + g_free(cmd); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c index 820321a3a7..0269803ce0 100644 --- a/tests/libqos/rtas.c +++ b/tests/libqos/rtas.c @@ -69,3 +69,48 @@ int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns) return res; } + +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size) +{ + int res; + uint32_t args[4], ret[2]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + res = qrtas_call(alloc, "ibm,read-pci-config", 4, args, 2, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return ret[1]; +} + +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val) +{ + int res; + uint32_t args[5], ret[1]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + args[4] = val; + res = qrtas_call(alloc, "ibm,write-pci-config", 5, args, 1, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return 0; +} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h index a1b60a8eb4..498eb19230 100644 --- a/tests/libqos/rtas.h +++ b/tests/libqos/rtas.h @@ -8,4 +8,8 @@ #include "libqos/malloc.h" int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size); +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val); #endif /* LIBQOS_RTAS_H */ -- cgit v1.2.3 From 2ecd7e2f25a57e8966a15ee50a0afacd4ec067da Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 29 Sep 2016 12:32:45 +0200 Subject: libqos: add PCI management in qtest_vboot()/qtest_shutdown() Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: David Gibson --- tests/libqos/ahci.c | 2 +- tests/libqos/libqos-pc.c | 5 ++++- tests/libqos/libqos-spapr.c | 5 ++++- tests/libqos/libqos.c | 21 ++++++++++++++++----- tests/libqos/libqos.h | 3 +++ tests/libqos/pci-pc.c | 2 +- tests/libqos/pci-pc.h | 3 ++- 7 files changed, 31 insertions(+), 10 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index f3be5500e1..716ab7939e 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -128,7 +128,7 @@ QPCIDevice *get_ahci_device(uint32_t *fingerprint) uint32_t ahci_fingerprint; QPCIBus *pcibus; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); /* Find the AHCI PCI device and verify it's the right one. */ ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index df340928a6..aa17c980d8 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -1,10 +1,13 @@ #include "qemu/osdep.h" #include "libqos/libqos-pc.h" #include "libqos/malloc-pc.h" +#include "libqos/pci-pc.h" static QOSOps qos_ops = { .init_allocator = pc_alloc_init_flags, - .uninit_allocator = pc_alloc_uninit + .uninit_allocator = pc_alloc_uninit, + .qpci_init = qpci_init_pc, + .qpci_free = qpci_free_pc, }; QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c index f19408be00..333e6fbb45 100644 --- a/tests/libqos/libqos-spapr.c +++ b/tests/libqos/libqos-spapr.c @@ -1,10 +1,13 @@ #include "qemu/osdep.h" #include "libqos/libqos-spapr.h" #include "libqos/malloc-spapr.h" +#include "libqos/pci-spapr.h" static QOSOps qos_ops = { .init_allocator = spapr_alloc_init_flags, - .uninit_allocator = spapr_alloc_uninit + .uninit_allocator = spapr_alloc_uninit, + .qpci_init = qpci_init_spapr, + .qpci_free = qpci_free_spapr, }; QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index a852dc5f8e..d842bf5126 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -20,8 +20,13 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qs->ops = ops; - if (ops && ops->init_allocator) { - qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + if (ops) { + if (ops->init_allocator) { + qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + } + if (ops->qpci_init && qs->alloc) { + qs->pcibus = ops->qpci_init(qs->alloc); + } } g_free(cmdline); @@ -49,9 +54,15 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) */ void qtest_shutdown(QOSState *qs) { - if (qs->alloc && qs->ops && qs->ops->uninit_allocator) { - qs->ops->uninit_allocator(qs->alloc); - qs->alloc = NULL; + if (qs->ops) { + if (qs->pcibus && qs->ops->qpci_free) { + qs->ops->qpci_free(qs->pcibus); + qs->pcibus = NULL; + } + if (qs->alloc && qs->ops->uninit_allocator) { + qs->ops->uninit_allocator(qs->alloc); + qs->alloc = NULL; + } } qtest_quit(qs->qts); g_free(qs); diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index 604980d125..a9f699019c 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -8,11 +8,14 @@ typedef struct QOSOps { QGuestAllocator *(*init_allocator)(QAllocOpts); void (*uninit_allocator)(QGuestAllocator *); + QPCIBus *(*qpci_init)(QGuestAllocator *alloc); + void (*qpci_free)(QPCIBus *bus); } QOSOps; typedef struct QOSState { QTestState *qts; QGuestAllocator *alloc; + QPCIBus *pcibus; QOSOps *ops; } QOSState; diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 82066b8531..9600ed6e41 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -212,7 +212,7 @@ static void qpci_pc_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -QPCIBus *qpci_init_pc(void) +QPCIBus *qpci_init_pc(QGuestAllocator *alloc) { QPCIBusPC *ret; diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h index 26211790cd..9479b51642 100644 --- a/tests/libqos/pci-pc.h +++ b/tests/libqos/pci-pc.h @@ -14,8 +14,9 @@ #define LIBQOS_PCI_PC_H #include "libqos/pci.h" +#include "libqos/malloc.h" -QPCIBus *qpci_init_pc(void); +QPCIBus *qpci_init_pc(QGuestAllocator *alloc); void qpci_free_pc(QPCIBus *bus); #endif -- cgit v1.2.3 From 61ae5cf3a2e1a7764a60fec69cd8731516d5fb83 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 29 Sep 2016 12:32:46 +0200 Subject: libqos: use generic qtest_shutdown() Machine specific shutdown function can be registered by the machine specific qtest_XXX_boot() if needed. So we will not have to test twice the architecture (on boot and on shutdown) if the test can be run on several architectures. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: David Gibson --- tests/libqos/libqos-pc.c | 3 ++- tests/libqos/libqos-spapr.c | 3 ++- tests/libqos/libqos.c | 11 ++++++++++- tests/libqos/libqos.h | 8 ++++++-- 4 files changed, 20 insertions(+), 5 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index aa17c980d8..b554758802 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -8,6 +8,7 @@ static QOSOps qos_ops = { .uninit_allocator = pc_alloc_uninit, .qpci_init = qpci_init_pc, .qpci_free = qpci_free_pc, + .shutdown = qtest_pc_shutdown, }; QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) @@ -31,5 +32,5 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) void qtest_pc_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c index 333e6fbb45..a37791e5d0 100644 --- a/tests/libqos/libqos-spapr.c +++ b/tests/libqos/libqos-spapr.c @@ -8,6 +8,7 @@ static QOSOps qos_ops = { .uninit_allocator = spapr_alloc_uninit, .qpci_init = qpci_init_spapr, .qpci_free = qpci_free_spapr, + .shutdown = qtest_spapr_shutdown, }; QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) @@ -29,5 +30,5 @@ QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) void qtest_spapr_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index d842bf5126..7abb48254e 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -52,7 +52,7 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) /** * Tear down the QEMU instance. */ -void qtest_shutdown(QOSState *qs) +void qtest_common_shutdown(QOSState *qs) { if (qs->ops) { if (qs->pcibus && qs->ops->qpci_free) { @@ -68,6 +68,15 @@ void qtest_shutdown(QOSState *qs) g_free(qs); } +void qtest_shutdown(QOSState *qs) +{ + if (qs->ops && qs->ops->shutdown) { + qs->ops->shutdown(qs); + } else { + qtest_common_shutdown(qs); + } +} + void set_context(QOSState *s) { global_qtest = s->qts; diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index a9f699019c..231969766f 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -5,22 +5,26 @@ #include "libqos/pci.h" #include "libqos/malloc-pc.h" +typedef struct QOSState QOSState; + typedef struct QOSOps { QGuestAllocator *(*init_allocator)(QAllocOpts); void (*uninit_allocator)(QGuestAllocator *); QPCIBus *(*qpci_init)(QGuestAllocator *alloc); void (*qpci_free)(QPCIBus *bus); + void (*shutdown)(QOSState *); } QOSOps; -typedef struct QOSState { +struct QOSState { QTestState *qts; QGuestAllocator *alloc; QPCIBus *pcibus; QOSOps *ops; -} QOSState; +}; QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); +void qtest_common_shutdown(QOSState *qs); void qtest_shutdown(QOSState *qs); bool have_qemu_img(void); void mkimg(const char *file, const char *fmt, unsigned size_mb); -- cgit v1.2.3 From 54ce6f22e86977b6e94692d90e13fce6fc9aa641 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 7 Oct 2016 12:14:27 +0200 Subject: qtest: ask endianness of the target in qtest_init() The target endianness is not deduced anymore from the architecture name but asked directly to the guest, using a new qtest command: "endianness". As it can't change (this is the value of TARGET_WORDS_BIGENDIAN), we store it to not have to ask every time we want to know if we have to byte-swap a value. Signed-off-by: Laurent Vivier CC: Greg Kurz CC: David Gibson CC: Peter Maydell Signed-off-by: David Gibson --- tests/libqos/virtio-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/libqos') diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index 18b92b95dc..6e005c1835 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -86,7 +86,7 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr) int i; uint64_t u64 = 0; - if (qtest_big_endian()) { + if (target_big_endian()) { for (i = 0; i < 8; ++i) { u64 |= (uint64_t)qpci_io_readb(dev->pdev, (void *)(uintptr_t)addr + i) << (7 - i) * 8; -- cgit v1.2.3 From cd1b354ec05035f84bb05f591cb632770ad36e7c Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2016 13:30:07 +1100 Subject: libqos: Isolate knowledge of spapr memory map to qpci_init_spapr() The libqos code for accessing PCI on the spapr machine type uses IOBASE() and MMIOBASE() macros to determine the address in the CPU memory map of the windows to PCI address space. This is a detail of the implementation of PCI in the machine type, it's not specified by the PAPR standard. Real guests would get the addresses of the PCI windows from the device tree. Finding the device tree in libqos would be awkward, but we can at least localize this knowledge of the implementation to the init function, saving it in the QPCIBusSPAPR structure for use by the accessors. That leaves only one place to fix if we alter the location of the PCI windows, as we're planning to do. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- tests/libqos/pci-spapr.c | 113 +++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 49 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 2f73badfd9..1765a54c80 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -18,30 +18,23 @@ /* From include/hw/pci-host/spapr.h */ -#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL - -#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL - -#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL -#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 -#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ - SPAPR_PCI_MEM_WIN_BUS_OFFSET) -#define SPAPR_PCI_IO_WIN_OFF 0x80000000 -#define SPAPR_PCI_IO_WIN_SIZE 0x10000 - -/* index is the phb index */ - -#define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index)) -#define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \ - (index) * SPAPR_PCI_WINDOW_SPACING) -#define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF) -#define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF) +typedef struct QPCIWindow { + uint64_t pci_base; /* window address in PCI space */ + uint64_t size; /* window size */ +} QPCIWindow; typedef struct QPCIBusSPAPR { QPCIBus bus; QGuestAllocator *alloc; + uint64_t buid; + + uint64_t pio_cpu_base; + QPCIWindow pio; + + uint64_t mmio_cpu_base; + QPCIWindow mmio; + uint64_t pci_hole_start; uint64_t pci_hole_size; uint64_t pci_hole_alloc; @@ -59,69 +52,75 @@ typedef struct QPCIBusSPAPR { static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; uint8_t v; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - v = readb(IOBASE(0) + port); + if (port < s->pio.size) { + v = readb(s->pio_cpu_base + port); } else { - v = readb(MMIOBASE(0) + port); + v = readb(s->mmio_cpu_base + port); } return v; } static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; uint16_t v; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - v = readw(IOBASE(0) + port); + if (port < s->pio.size) { + v = readw(s->pio_cpu_base + port); } else { - v = readw(MMIOBASE(0) + port); + v = readw(s->mmio_cpu_base + port); } return bswap16(v); } static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; uint32_t v; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - v = readl(IOBASE(0) + port); + if (port < s->pio.size) { + v = readl(s->pio_cpu_base + port); } else { - v = readl(MMIOBASE(0) + port); + v = readl(s->mmio_cpu_base + port); } return bswap32(v); } static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - writeb(IOBASE(0) + port, value); + if (port < s->pio.size) { + writeb(s->pio_cpu_base + port, value); } else { - writeb(MMIOBASE(0) + port, value); + writeb(s->mmio_cpu_base + port, value); } } static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; value = bswap16(value); - if (port < SPAPR_PCI_IO_WIN_SIZE) { - writew(IOBASE(0) + port, value); + if (port < s->pio.size) { + writew(s->pio_cpu_base + port, value); } else { - writew(MMIOBASE(0) + port, value); + writew(s->mmio_cpu_base + port, value); } } static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; value = bswap32(value); - if (port < SPAPR_PCI_IO_WIN_SIZE) { - writel(IOBASE(0) + port, value); + if (port < s->pio.size) { + writel(s->pio_cpu_base + port, value); } else { - writel(MMIOBASE(0) + port, value); + writel(s->mmio_cpu_base + port, value); } } @@ -129,24 +128,21 @@ static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), - config_addr, 1); + return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 1); } static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), - config_addr, 2); + return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 2); } static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), - config_addr, 4); + return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 4); } static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, @@ -154,8 +150,7 @@ static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), - config_addr, 1, value); + qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 1, value); } static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, @@ -163,8 +158,7 @@ static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), - config_addr, 2, value); + qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 2, value); } static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, @@ -172,8 +166,7 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), - config_addr, 4, value); + qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 4, value); } static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, @@ -242,6 +235,15 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data) /* FIXME */ } +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ + SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) { QPCIBusSPAPR *ret; @@ -269,6 +271,19 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->bus.iomap = qpci_spapr_iomap; ret->bus.iounmap = qpci_spapr_iounmap; + /* FIXME: We assume the default location of the PHB for now. + * Ideally we'd parse the device tree deposited in the guest to + * get the window locations */ + ret->buid = 0x800000020000000ULL; + + ret->pio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_IO_WIN_OFF; + ret->pio.pci_base = 0; + ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; + + ret->mmio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO_WIN_OFF; + ret->mmio.pci_base = SPAPR_PCI_MEM_WIN_BUS_OFFSET; + ret->mmio.size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_start = 0xC0000000; ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; ret->pci_hole_alloc = 0; -- cgit v1.2.3 From c711369087d5964ea77b0fd0e0ff1f268e1a67ee Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2016 13:38:25 +1100 Subject: libqos: Correct error in PCI hole sizing for spapr In pci-spapr.c (as in pci-pc.c from which it was derived), the pci_hole_start/pci_hole_size and pci_iohole_start/pci_iohole_size pairs[1] essentially define the region of PCI (not CPU) addresses in which MMIO or PIO BARs respectively will be allocated. The size value is relative to the start value. But in pci-spapr.c it is set to the entire size of the window supported by the (emulated) hardware, but the start values are *not* at the beginning of the emulated windows. That means if you tried to map enough PCI BARs, we'd messily overrun the IO windows, instead of failing in iomap as we should. This patch corrects this by calculating the hole sizes from the location of the window in PCI space and the hole start. [1] Those are bad names, but that's a problem for another time. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- tests/libqos/pci-spapr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 1765a54c80..3192903497 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -285,11 +285,13 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->mmio.size = SPAPR_PCI_MMIO_WIN_SIZE; ret->pci_hole_start = 0xC0000000; - ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_size = + ret->mmio.pci_base + ret->mmio.size - ret->pci_hole_start; ret->pci_hole_alloc = 0; ret->pci_iohole_start = 0xc000; - ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE; + ret->pci_iohole_size = + ret->pio.pci_base + ret->pio.size - ret->pci_iohole_start; ret->pci_iohole_alloc = 0; return &ret->bus; -- cgit v1.2.3 From 8360544a6d3a54df1fce80f55ba4ad075a8ded54 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2016 14:07:04 +1100 Subject: libqos: Limit spapr-pci to 32-bit MMIO for now Currently the functions in pci-spapr.c (like pci-pc.c on which it's based) don't distinguish between 32-bit and 64-bit PCI MMIO. At the moment, the qemu side implementation is a bit weird and has a single MMIO window straddling 32-bit and 64-bit regions, but we're likely to change that in future. In any case, pci-pc.c - and therefore the testcases using PCI - only handle 32-bit MMIOs for now. For spapr despite whatever changes might happen with the MMIO windows, the 32-bit window is likely to remain at 2..4 GiB in PCI space. So, explicitly limit pci-spapr.c to 32-bit MMIOs for now, we can add 64-bit MMIO support back in when and if we need it. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- tests/libqos/pci-spapr.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 3192903497..558dfc3bdc 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -32,8 +32,8 @@ typedef struct QPCIBusSPAPR { uint64_t pio_cpu_base; QPCIWindow pio; - uint64_t mmio_cpu_base; - QPCIWindow mmio; + uint64_t mmio32_cpu_base; + QPCIWindow mmio32; uint64_t pci_hole_start; uint64_t pci_hole_size; @@ -58,7 +58,7 @@ static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) if (port < s->pio.size) { v = readb(s->pio_cpu_base + port); } else { - v = readb(s->mmio_cpu_base + port); + v = readb(s->mmio32_cpu_base + port); } return v; } @@ -71,7 +71,7 @@ static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) if (port < s->pio.size) { v = readw(s->pio_cpu_base + port); } else { - v = readw(s->mmio_cpu_base + port); + v = readw(s->mmio32_cpu_base + port); } return bswap16(v); } @@ -84,7 +84,7 @@ static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) if (port < s->pio.size) { v = readl(s->pio_cpu_base + port); } else { - v = readl(s->mmio_cpu_base + port); + v = readl(s->mmio32_cpu_base + port); } return bswap32(v); } @@ -96,7 +96,7 @@ static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) if (port < s->pio.size) { writeb(s->pio_cpu_base + port, value); } else { - writeb(s->mmio_cpu_base + port, value); + writeb(s->mmio32_cpu_base + port, value); } } @@ -108,7 +108,7 @@ static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) if (port < s->pio.size) { writew(s->pio_cpu_base + port, value); } else { - writew(s->mmio_cpu_base + port, value); + writew(s->mmio32_cpu_base + port, value); } } @@ -120,7 +120,7 @@ static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) if (port < s->pio.size) { writel(s->pio_cpu_base + port, value); } else { - writel(s->mmio_cpu_base + port, value); + writel(s->mmio32_cpu_base + port, value); } } @@ -235,12 +235,9 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL #define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL -#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 -#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ - SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_MMIO32_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ #define SPAPR_PCI_IO_WIN_OFF 0x80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 @@ -280,13 +277,14 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->pio.pci_base = 0; ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; - ret->mmio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO_WIN_OFF; - ret->mmio.pci_base = SPAPR_PCI_MEM_WIN_BUS_OFFSET; - ret->mmio.size = SPAPR_PCI_MMIO_WIN_SIZE; + /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ + ret->mmio32_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO32_WIN_OFF; + ret->mmio32.pci_base = 0x80000000; /* 2 GiB */ + ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; ret->pci_hole_start = 0xC0000000; ret->pci_hole_size = - ret->mmio.pci_base + ret->mmio.size - ret->pci_hole_start; + ret->mmio32.pci_base + ret->mmio32.size - ret->pci_hole_start; ret->pci_hole_alloc = 0; ret->pci_iohole_start = 0xc000; -- cgit v1.2.3 From 357d1e3bc7d2d80e5271bc4f3ac8537e30dc8046 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 16 Oct 2016 12:04:15 +1100 Subject: spapr: Improved placement of PCI host bridges in guest memory map Currently, the MMIO space for accessing PCI on pseries guests begins at 1 TiB in guest address space. Each PCI host bridge (PHB) has a 64 GiB chunk of address space in which it places its outbound PIO and 32-bit and 64-bit MMIO windows. This scheme as several problems: - It limits guest RAM to 1 TiB (though we have a limited fix for this now) - It limits the total MMIO window to 64 GiB. This is not always enough for some of the large nVidia GPGPU cards - Putting all the windows into a single 64 GiB area means that naturally aligning things within there will waste more address space. In addition there was a miscalculation in some of the defaults, which meant that the MMIO windows for each PHB actually slightly overran the 64 GiB region for that PHB. We got away without nasty consequences because the overrun fit within an unused area at the beginning of the next PHB's region, but it's not pretty. This patch implements a new scheme which addresses those problems, and is also closer to what bare metal hardware and pHyp guests generally use. Because some guest versions (including most current distro kernels) can't access PCI MMIO above 64 TiB, we put all the PCI windows between 32 TiB and 64 TiB. This is broken into 1 TiB chunks. The first 1 TiB contains the PIO (64 kiB) and 32-bit MMIO (2 GiB) windows for all of the PHBs. Each subsequent TiB chunk contains a naturally aligned 64-bit MMIO window for one PHB each. This reduces the number of allowed PHBs (without full manual configuration of all the windows) from 256 to 31, but this should still be plenty in practice. We also change some of the default window sizes for manually configured PHBs to saner values. Finally we adjust some tests and libqos so that it correctly uses the new default locations. Ideally it would parse the device tree given to the guest, but that's a more complex problem for another time. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- tests/libqos/pci-spapr.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 558dfc3bdc..2eaaf9159a 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -235,10 +235,9 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_MMIO32_WIN_OFF 0xA0000000 +#define SPAPR_PCI_BASE (1ULL << 45) + #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ -#define SPAPR_PCI_IO_WIN_OFF 0x80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) @@ -273,12 +272,12 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) * get the window locations */ ret->buid = 0x800000020000000ULL; - ret->pio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_IO_WIN_OFF; + ret->pio_cpu_base = SPAPR_PCI_BASE; ret->pio.pci_base = 0; ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ - ret->mmio32_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO32_WIN_OFF; + ret->mmio32_cpu_base = SPAPR_PCI_BASE + SPAPR_PCI_MMIO32_WIN_SIZE; ret->mmio32.pci_base = 0x80000000; /* 2 GiB */ ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; -- cgit v1.2.3 From 458f3b2c953bdc7110896cb3691251023652523f Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 17 Oct 2016 12:30:20 +0200 Subject: tests: don't check if qtest_spapr_boot() returns NULL qtest_spapr_boot()/qtest_pc_boot()/qtest_boot() call qtest_vboot() and qtest_vboot() calls g_malloc(), and g_malloc() never fails: if memory allocation fails, the application is terminated. Signed-off-by: Laurent Vivier Reviewed-by: Thomas Huth Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- tests/libqos/libqos.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests/libqos') diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index 7abb48254e..6226546c28 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -10,6 +10,8 @@ /** * Launch QEMU with the given command line, * and then set up interrupts and our guest malloc interface. + * Never returns NULL: + * Terminates the application in case an error is encountered. */ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) { -- cgit v1.2.3 From 6b9cdf4cf1fd52c1a59a7640a02a718176bfd217 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 17 Oct 2016 12:30:21 +0200 Subject: tests: move QVirtioBus pointer into QVirtioDevice This allows to not have to pass bus and device for every virtio functions. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: Thomas Huth [dwg: Fix style nit] Signed-off-by: David Gibson --- tests/libqos/virtio-mmio.c | 1 + tests/libqos/virtio-pci.c | 2 ++ tests/libqos/virtio.c | 78 +++++++++++++++++++++------------------------- tests/libqos/virtio.h | 51 ++++++++++++++---------------- 4 files changed, 61 insertions(+), 71 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c index 0cab38f296..bced6803e6 100644 --- a/tests/libqos/virtio-mmio.c +++ b/tests/libqos/virtio-mmio.c @@ -199,6 +199,7 @@ QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size) dev->addr = addr; dev->page_size = page_size; dev->vdev.device_type = readl(addr + QVIRTIO_MMIO_DEVICE_ID); + dev->vdev.bus = &qvirtio_mmio; writel(addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size); diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index 6e005c1835..bbfed58dcf 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -286,6 +286,8 @@ QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type) QVirtioPCIDevice *dev = NULL; qvirtio_pci_foreach(bus, device_type, qvirtio_pci_assign_device, &dev); + dev->vdev.bus = &qvirtio_pci; + return dev; } diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 105bccecaa..ec30cb99b2 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -13,45 +13,40 @@ #include "standard-headers/linux/virtio_config.h" #include "standard-headers/linux/virtio_ring.h" -uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) +uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr) { - return bus->config_readb(d, addr); + return d->bus->config_readb(d, addr); } -uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) +uint16_t qvirtio_config_readw(QVirtioDevice *d, uint64_t addr) { - return bus->config_readw(d, addr); + return d->bus->config_readw(d, addr); } -uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) +uint32_t qvirtio_config_readl(QVirtioDevice *d, uint64_t addr) { - return bus->config_readl(d, addr); + return d->bus->config_readl(d, addr); } -uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr) +uint64_t qvirtio_config_readq(QVirtioDevice *d, uint64_t addr) { - return bus->config_readq(d, addr); + return d->bus->config_readq(d, addr); } -uint32_t qvirtio_get_features(const QVirtioBus *bus, QVirtioDevice *d) +uint32_t qvirtio_get_features(QVirtioDevice *d) { - return bus->get_features(d); + return d->bus->get_features(d); } -void qvirtio_set_features(const QVirtioBus *bus, QVirtioDevice *d, - uint32_t features) +void qvirtio_set_features(QVirtioDevice *d, uint32_t features) { - bus->set_features(d, features); + d->bus->set_features(d, features); } -QVirtQueue *qvirtqueue_setup(const QVirtioBus *bus, QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index) +QVirtQueue *qvirtqueue_setup(QVirtioDevice *d, + QGuestAllocator *alloc, uint16_t index) { - return bus->virtqueue_setup(d, alloc, index); + return d->bus->virtqueue_setup(d, alloc, index); } void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq, @@ -60,40 +55,40 @@ void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq, return bus->virtqueue_cleanup(vq, alloc); } -void qvirtio_reset(const QVirtioBus *bus, QVirtioDevice *d) +void qvirtio_reset(QVirtioDevice *d) { - bus->set_status(d, 0); - g_assert_cmphex(bus->get_status(d), ==, 0); + d->bus->set_status(d, 0); + g_assert_cmphex(d->bus->get_status(d), ==, 0); } -void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d) +void qvirtio_set_acknowledge(QVirtioDevice *d) { - bus->set_status(d, bus->get_status(d) | VIRTIO_CONFIG_S_ACKNOWLEDGE); - g_assert_cmphex(bus->get_status(d), ==, VIRTIO_CONFIG_S_ACKNOWLEDGE); + d->bus->set_status(d, d->bus->get_status(d) | VIRTIO_CONFIG_S_ACKNOWLEDGE); + g_assert_cmphex(d->bus->get_status(d), ==, VIRTIO_CONFIG_S_ACKNOWLEDGE); } -void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d) +void qvirtio_set_driver(QVirtioDevice *d) { - bus->set_status(d, bus->get_status(d) | VIRTIO_CONFIG_S_DRIVER); - g_assert_cmphex(bus->get_status(d), ==, + d->bus->set_status(d, d->bus->get_status(d) | VIRTIO_CONFIG_S_DRIVER); + g_assert_cmphex(d->bus->get_status(d), ==, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_ACKNOWLEDGE); } -void qvirtio_set_driver_ok(const QVirtioBus *bus, QVirtioDevice *d) +void qvirtio_set_driver_ok(QVirtioDevice *d) { - bus->set_status(d, bus->get_status(d) | VIRTIO_CONFIG_S_DRIVER_OK); - g_assert_cmphex(bus->get_status(d), ==, VIRTIO_CONFIG_S_DRIVER_OK | + d->bus->set_status(d, d->bus->get_status(d) | VIRTIO_CONFIG_S_DRIVER_OK); + g_assert_cmphex(d->bus->get_status(d), ==, VIRTIO_CONFIG_S_DRIVER_OK | VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_ACKNOWLEDGE); } -void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d, +void qvirtio_wait_queue_isr(QVirtioDevice *d, QVirtQueue *vq, gint64 timeout_us) { gint64 start_time = g_get_monotonic_time(); for (;;) { clock_step(100); - if (bus->get_queue_isr_status(d, vq)) { + if (d->bus->get_queue_isr_status(d, vq)) { return; } g_assert(g_get_monotonic_time() - start_time <= timeout_us); @@ -105,8 +100,7 @@ void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d, * The virtqueue interrupt must not be raised, making this useful for testing * event_index functionality. */ -uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus, - QVirtioDevice *d, +uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, QVirtQueue *vq, uint64_t addr, gint64 timeout_us) @@ -116,20 +110,19 @@ uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus, while ((val = readb(addr)) == 0xff) { clock_step(100); - g_assert(!bus->get_queue_isr_status(d, vq)); + g_assert(!d->bus->get_queue_isr_status(d, vq)); g_assert(g_get_monotonic_time() - start_time <= timeout_us); } return val; } -void qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d, - gint64 timeout_us) +void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us) { gint64 start_time = g_get_monotonic_time(); for (;;) { clock_step(100); - if (bus->get_config_isr_status(d)) { + if (d->bus->get_config_isr_status(d)) { return; } g_assert(g_get_monotonic_time() - start_time <= timeout_us); @@ -253,8 +246,7 @@ uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect) return vq->free_head++; /* Return and increase, in this order */ } -void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq, - uint32_t free_head) +void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head) { /* vq->avail->idx */ uint16_t idx = readw(vq->avail + 2); @@ -276,7 +268,7 @@ void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq, /* < 1 because we add elements to avail queue one by one */ if ((flags & VRING_USED_F_NO_NOTIFY) == 0 && (!vq->event || (uint16_t)(idx-avail_event) < 1)) { - bus->virtqueue_kick(d, vq); + d->bus->virtqueue_kick(d, vq); } } diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 0250842bf2..ac4669a11b 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -15,7 +15,10 @@ #define QVIRTIO_F_BAD_FEATURE 0x40000000 +typedef struct QVirtioBus QVirtioBus; + typedef struct QVirtioDevice { + const QVirtioBus *bus; /* Device type */ uint16_t device_type; } QVirtioDevice; @@ -39,7 +42,7 @@ typedef struct QVRingIndirectDesc { uint16_t elem; } QVRingIndirectDesc; -typedef struct QVirtioBus { +struct QVirtioBus { uint8_t (*config_readb)(QVirtioDevice *d, uint64_t addr); uint16_t (*config_readw)(QVirtioDevice *d, uint64_t addr); uint32_t (*config_readl)(QVirtioDevice *d, uint64_t addr); @@ -84,7 +87,7 @@ typedef struct QVirtioBus { /* Notify changes in virtqueue */ void (*virtqueue_kick)(QVirtioDevice *d, QVirtQueue *vq); -} QVirtioBus; +}; static inline uint32_t qvring_size(uint32_t num, uint32_t align) { @@ -93,34 +96,27 @@ static inline uint32_t qvring_size(uint32_t num, uint32_t align) + sizeof(uint16_t) * 3 + sizeof(struct vring_used_elem) * num; } -uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, - uint64_t addr); -uint32_t qvirtio_get_features(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_features(const QVirtioBus *bus, QVirtioDevice *d, - uint32_t features); - -void qvirtio_reset(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d); -void qvirtio_set_driver_ok(const QVirtioBus *bus, QVirtioDevice *d); - -void qvirtio_wait_queue_isr(const QVirtioBus *bus, QVirtioDevice *d, +uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr); +uint16_t qvirtio_config_readw(QVirtioDevice *d, uint64_t addr); +uint32_t qvirtio_config_readl(QVirtioDevice *d, uint64_t addr); +uint64_t qvirtio_config_readq(QVirtioDevice *d, uint64_t addr); +uint32_t qvirtio_get_features(QVirtioDevice *d); +void qvirtio_set_features(QVirtioDevice *d, uint32_t features); + +void qvirtio_reset(QVirtioDevice *d); +void qvirtio_set_acknowledge(QVirtioDevice *d); +void qvirtio_set_driver(QVirtioDevice *d); +void qvirtio_set_driver_ok(QVirtioDevice *d); + +void qvirtio_wait_queue_isr(QVirtioDevice *d, QVirtQueue *vq, gint64 timeout_us); -uint8_t qvirtio_wait_status_byte_no_isr(const QVirtioBus *bus, - QVirtioDevice *d, +uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, QVirtQueue *vq, uint64_t addr, gint64 timeout_us); -void qvirtio_wait_config_isr(const QVirtioBus *bus, QVirtioDevice *d, - gint64 timeout_us); -QVirtQueue *qvirtqueue_setup(const QVirtioBus *bus, QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t index); +void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us); +QVirtQueue *qvirtqueue_setup(QVirtioDevice *d, + QGuestAllocator *alloc, uint16_t index); void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq, QGuestAllocator *alloc); @@ -132,8 +128,7 @@ void qvring_indirect_desc_add(QVRingIndirectDesc *indirect, uint64_t data, uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, bool next); uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect); -void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq, - uint32_t free_head); +void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head); void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx); #endif -- cgit v1.2.3 From 8b4b80c37630e976f2dd02a7d42bd9bea1ce676e Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 17 Oct 2016 12:30:22 +0200 Subject: tests: rename target_big_endian() as qvirtio_is_big_endian() Move the definition to libqos/virtio.h as it must be used only with virtio functions. Add a QVirtioDevice parameter as it will be needed to know if the virtio device is using virtio 1.0 specification and thus is always little-endian (to do) Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: Thomas Huth Signed-off-by: David Gibson --- tests/libqos/virtio-pci.c | 2 +- tests/libqos/virtio.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'tests/libqos') diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index bbfed58dcf..7aa29b1a9c 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -86,7 +86,7 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr) int i; uint64_t u64 = 0; - if (target_big_endian()) { + if (qvirtio_is_big_endian(d)) { for (i = 0; i < 8; ++i) { u64 |= (uint64_t)qpci_io_readb(dev->pdev, (void *)(uintptr_t)addr + i) << (7 - i) * 8; diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index ac4669a11b..3397a080e9 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -89,6 +89,12 @@ struct QVirtioBus { void (*virtqueue_kick)(QVirtioDevice *d, QVirtQueue *vq); }; +static inline bool qvirtio_is_big_endian(QVirtioDevice *d) +{ + /* FIXME: virtio 1.0 is always little-endian */ + return qtest_big_endian(global_qtest); +} + static inline uint32_t qvring_size(uint32_t num, uint32_t align) { return ((sizeof(struct vring_desc) * num + sizeof(uint16_t) * (3 + num) -- cgit v1.2.3 From 30ca440eec9fe1d7eec5a48addac656438778278 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 17 Oct 2016 12:30:24 +0200 Subject: tests: enable virtio tests on SPAPR but disable MSI-X tests on SPAPR as we can't check the result (the memory region used on PC is not readable on SPAPR). Signed-off-by: Laurent Vivier Signed-off-by: David Gibson --- tests/libqos/virtio-pci.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index 7aa29b1a9c..7e60b3a427 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -68,16 +68,36 @@ static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t addr) return qpci_io_readb(dev->pdev, (void *)(uintptr_t)addr); } +/* PCI is always read in little-endian order + * but virtio ( < 1.0) is in guest order + * so with a big-endian guest the order has been reversed, + * reverse it again + * virtio-1.0 is always little-endian, like PCI, but this + * case will be managed inside qvirtio_is_big_endian() + */ + static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t addr) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readw(dev->pdev, (void *)(uintptr_t)addr); + uint16_t value; + + value = qpci_io_readw(dev->pdev, (void *)(uintptr_t)addr); + if (qvirtio_is_big_endian(d)) { + value = bswap16(value); + } + return value; } static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t addr) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readl(dev->pdev, (void *)(uintptr_t)addr); + uint32_t value; + + value = qpci_io_readl(dev->pdev, (void *)(uintptr_t)addr); + if (qvirtio_is_big_endian(d)) { + value = bswap32(value); + } + return value; } static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr) -- cgit v1.2.3 From 246fc0fb66cbf861b0e76320626b059e2d49ea12 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Oct 2016 14:08:07 +1100 Subject: libqos: Give qvirtio_config_read*() consistent semantics The 'addr' parameter to qvirtio_config_read*() doesn't have a consistent meaning: when using the virtio-pci versions, it's a full PCI space address, but for virtio-mmio, it's an offset from the device's base mmio address. This means that the callers need to do different things to calculate the addresses in the two cases, which rather defeats the purpose of function pointer backends. All the current users of these functions are using them to retrieve variables from the device specific portion of the virtio config space. So, this patch alters the semantics to always be an offset into that device specific config area. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier Reviewed-by: Greg Kurz --- tests/libqos/virtio-mmio.c | 16 ++++++++-------- tests/libqos/virtio-pci.c | 25 ++++++++++++++----------- 2 files changed, 22 insertions(+), 19 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c index bced6803e6..7aa8383338 100644 --- a/tests/libqos/virtio-mmio.c +++ b/tests/libqos/virtio-mmio.c @@ -15,28 +15,28 @@ #include "libqos/malloc-generic.h" #include "standard-headers/linux/virtio_ring.h" -static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t addr) +static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t off) { QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readb(dev->addr + addr); + return readb(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); } -static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t addr) +static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t off) { QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readw(dev->addr + addr); + return readw(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); } -static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t addr) +static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t off) { QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readl(dev->addr + addr); + return readl(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); } -static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t addr) +static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t off) { QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d; - return readq(dev->addr + addr); + return readq(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off); } static uint32_t qvirtio_mmio_get_features(QVirtioDevice *d) diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index 7e60b3a427..fa82132ab7 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -62,10 +62,13 @@ static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data) *vpcidev = (QVirtioPCIDevice *)d; } -static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t addr) +#define CONFIG_BASE(dev) \ + ((dev)->addr + VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled)) + +static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readb(dev->pdev, (void *)(uintptr_t)addr); + return qpci_io_readb(dev->pdev, CONFIG_BASE(dev) + off); } /* PCI is always read in little-endian order @@ -76,31 +79,31 @@ static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t addr) * case will be managed inside qvirtio_is_big_endian() */ -static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t addr) +static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t off) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; uint16_t value; - value = qpci_io_readw(dev->pdev, (void *)(uintptr_t)addr); + value = qpci_io_readw(dev->pdev, CONFIG_BASE(dev) + off); if (qvirtio_is_big_endian(d)) { value = bswap16(value); } return value; } -static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t addr) +static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t off) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; uint32_t value; - value = qpci_io_readl(dev->pdev, (void *)(uintptr_t)addr); + value = qpci_io_readl(dev->pdev, CONFIG_BASE(dev) + off); if (qvirtio_is_big_endian(d)) { value = bswap32(value); } return value; } -static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr) +static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; int i; @@ -108,13 +111,13 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr) if (qvirtio_is_big_endian(d)) { for (i = 0; i < 8; ++i) { - u64 |= (uint64_t)qpci_io_readb(dev->pdev, - (void *)(uintptr_t)addr + i) << (7 - i) * 8; + u64 |= (uint64_t)qpci_io_readb(dev->pdev, CONFIG_BASE(dev) + + off + i) << (7 - i) * 8; } } else { for (i = 0; i < 8; ++i) { - u64 |= (uint64_t)qpci_io_readb(dev->pdev, - (void *)(uintptr_t)addr + i) << i * 8; + u64 |= (uint64_t)qpci_io_readb(dev->pdev, CONFIG_BASE(dev) + + off + i) << i * 8; } } -- cgit v1.2.3 From a795fc08f2636013fe097e51bdac62d089ac505a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 18 Oct 2016 17:02:49 +1100 Subject: libqos: Handle PCI IO de-multiplexing in common code The PCI IO space (aka PIO, aka legacy IO) and PCI memory space (aka MMIO) are distinct address spaces by the PCI spec (although parts of one might be aliased to parts of the other in some cases). However, qpci_io_read*() and qpci_io_write*() can perform accesses to either space depending on parameter. That's convenient for test case drivers, since there are a fair few devices which can be controlled via either a PIO or MMIO BAR but with an otherwise identical driver. This is implemented by having addresses below 64kiB treated as PIO, and those above treated as MMIO. This works because low addresses in memory space are generally reserved for DMA rather than MMIO. At the moment, this demultiplexing must be handled by each PCI backend (pc and spapr, so far). There's no real reason for this - the current encoding is likely to work for all platforms, and even if it doesn't we can still use a more complex common encoding since the value returned from iomap are semi-opaque. This patch moves the demultiplexing into the common part of the libqos PCI code, with the backends having simpler, separate accessors for PIO and MMIO space. This also means we have a way of explicitly accessing either space if it's necessary for some special case. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier Reviewed-by: Greg Kurz --- tests/libqos/pci-pc.c | 107 ++++++++++++++++++++---------------------- tests/libqos/pci-spapr.c | 118 +++++++++++++++++++++++++---------------------- tests/libqos/pci.c | 49 +++++++++++++++++--- tests/libqos/pci.h | 22 ++++++--- 4 files changed, 170 insertions(+), 126 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 9600ed6e41..51dff8a7fa 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -36,79 +36,64 @@ typedef struct QPCIBusPC uint16_t pci_iohole_alloc; } QPCIBusPC; -static uint8_t qpci_pc_io_readb(QPCIBus *bus, void *addr) +static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) { - uintptr_t port = (uintptr_t)addr; - uint8_t value; - - if (port < 0x10000) { - value = inb(port); - } else { - value = readb(port); - } - - return value; + return inb(addr); } -static uint16_t qpci_pc_io_readw(QPCIBus *bus, void *addr) +static uint8_t qpci_pc_mmio_readb(QPCIBus *bus, uint32_t addr) { - uintptr_t port = (uintptr_t)addr; - uint16_t value; - - if (port < 0x10000) { - value = inw(port); - } else { - value = readw(port); - } + return readb(addr); +} - return value; +static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) +{ + outb(addr, val); } -static uint32_t qpci_pc_io_readl(QPCIBus *bus, void *addr) +static void qpci_pc_mmio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) { - uintptr_t port = (uintptr_t)addr; - uint32_t value; + writeb(addr, val); +} - if (port < 0x10000) { - value = inl(port); - } else { - value = readl(port); - } +static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) +{ + return inw(addr); +} - return value; +static uint16_t qpci_pc_mmio_readw(QPCIBus *bus, uint32_t addr) +{ + return readw(addr); } -static void qpci_pc_io_writeb(QPCIBus *bus, void *addr, uint8_t value) +static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) { - uintptr_t port = (uintptr_t)addr; + outw(addr, val); +} - if (port < 0x10000) { - outb(port, value); - } else { - writeb(port, value); - } +static void qpci_pc_mmio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) +{ + writew(addr, val); } -static void qpci_pc_io_writew(QPCIBus *bus, void *addr, uint16_t value) +static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) { - uintptr_t port = (uintptr_t)addr; + return inl(addr); +} - if (port < 0x10000) { - outw(port, value); - } else { - writew(port, value); - } +static uint32_t qpci_pc_mmio_readl(QPCIBus *bus, uint32_t addr) +{ + return readl(addr); } -static void qpci_pc_io_writel(QPCIBus *bus, void *addr, uint32_t value) +static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) { - uintptr_t port = (uintptr_t)addr; + outl(addr, val); +} - if (port < 0x10000) { - outl(port, value); - } else { - writel(port, value); - } +static void qpci_pc_mmio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) +{ + writel(addr, val); } static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) @@ -218,13 +203,21 @@ QPCIBus *qpci_init_pc(QGuestAllocator *alloc) ret = g_malloc(sizeof(*ret)); - ret->bus.io_readb = qpci_pc_io_readb; - ret->bus.io_readw = qpci_pc_io_readw; - ret->bus.io_readl = qpci_pc_io_readl; + ret->bus.pio_readb = qpci_pc_pio_readb; + ret->bus.pio_readw = qpci_pc_pio_readw; + ret->bus.pio_readl = qpci_pc_pio_readl; + + ret->bus.pio_writeb = qpci_pc_pio_writeb; + ret->bus.pio_writew = qpci_pc_pio_writew; + ret->bus.pio_writel = qpci_pc_pio_writel; + + ret->bus.mmio_readb = qpci_pc_mmio_readb; + ret->bus.mmio_readw = qpci_pc_mmio_readw; + ret->bus.mmio_readl = qpci_pc_mmio_readl; - ret->bus.io_writeb = qpci_pc_io_writeb; - ret->bus.io_writew = qpci_pc_io_writew; - ret->bus.io_writel = qpci_pc_io_writel; + ret->bus.mmio_writeb = qpci_pc_mmio_writeb; + ret->bus.mmio_writew = qpci_pc_mmio_writew; + ret->bus.mmio_writel = qpci_pc_mmio_writel; ret->bus.config_readb = qpci_pc_config_readb; ret->bus.config_readw = qpci_pc_config_readw; diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 2eaaf9159a..2d26a94dab 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -50,78 +50,76 @@ typedef struct QPCIBusSPAPR { * so PCI accessors need to swap data endianness */ -static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) +static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint64_t port = (uintptr_t)addr; - uint8_t v; - if (port < s->pio.size) { - v = readb(s->pio_cpu_base + port); - } else { - v = readb(s->mmio32_cpu_base + port); - } - return v; + return readb(s->pio_cpu_base + addr); } -static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) +static uint8_t qpci_spapr_mmio32_readb(QPCIBus *bus, uint32_t addr) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint64_t port = (uintptr_t)addr; - uint16_t v; - if (port < s->pio.size) { - v = readw(s->pio_cpu_base + port); - } else { - v = readw(s->mmio32_cpu_base + port); - } - return bswap16(v); + return readb(s->mmio32_cpu_base + addr); } -static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) +static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint64_t port = (uintptr_t)addr; - uint32_t v; - if (port < s->pio.size) { - v = readl(s->pio_cpu_base + port); - } else { - v = readl(s->mmio32_cpu_base + port); - } - return bswap32(v); + writeb(s->pio_cpu_base + addr, val); } -static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) +static void qpci_spapr_mmio32_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint64_t port = (uintptr_t)addr; - if (port < s->pio.size) { - writeb(s->pio_cpu_base + port, value); - } else { - writeb(s->mmio32_cpu_base + port, value); - } + writeb(s->mmio32_cpu_base + addr, val); } -static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) +static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint64_t port = (uintptr_t)addr; - value = bswap16(value); - if (port < s->pio.size) { - writew(s->pio_cpu_base + port, value); - } else { - writew(s->mmio32_cpu_base + port, value); - } + return bswap16(readw(s->pio_cpu_base + addr)); } -static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) +static uint16_t qpci_spapr_mmio32_readw(QPCIBus *bus, uint32_t addr) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - uint64_t port = (uintptr_t)addr; - value = bswap32(value); - if (port < s->pio.size) { - writel(s->pio_cpu_base + port, value); - } else { - writel(s->mmio32_cpu_base + port, value); - } + return bswap16(readw(s->mmio32_cpu_base + addr)); +} + +static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + writew(s->pio_cpu_base + addr, bswap16(val)); +} + +static void qpci_spapr_mmio32_writew(QPCIBus *bus, uint32_t addr, uint16_t val) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + writew(s->mmio32_cpu_base + addr, bswap16(val)); +} + +static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + return bswap32(readl(s->pio_cpu_base + addr)); +} + +static uint32_t qpci_spapr_mmio32_readl(QPCIBus *bus, uint32_t addr) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + return bswap32(readl(s->mmio32_cpu_base + addr)); +} + +static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + writel(s->pio_cpu_base + addr, bswap32(val)); +} + +static void qpci_spapr_mmio32_writel(QPCIBus *bus, uint32_t addr, uint32_t val) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + writel(s->mmio32_cpu_base + addr, bswap32(val)); } static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) @@ -248,13 +246,21 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->alloc = alloc; - ret->bus.io_readb = qpci_spapr_io_readb; - ret->bus.io_readw = qpci_spapr_io_readw; - ret->bus.io_readl = qpci_spapr_io_readl; + ret->bus.pio_readb = qpci_spapr_pio_readb; + ret->bus.pio_readw = qpci_spapr_pio_readw; + ret->bus.pio_readl = qpci_spapr_pio_readl; + + ret->bus.pio_writeb = qpci_spapr_pio_writeb; + ret->bus.pio_writew = qpci_spapr_pio_writew; + ret->bus.pio_writel = qpci_spapr_pio_writel; + + ret->bus.mmio_readb = qpci_spapr_mmio32_readb; + ret->bus.mmio_readw = qpci_spapr_mmio32_readw; + ret->bus.mmio_readl = qpci_spapr_mmio32_readl; - ret->bus.io_writeb = qpci_spapr_io_writeb; - ret->bus.io_writew = qpci_spapr_io_writew; - ret->bus.io_writel = qpci_spapr_io_writel; + ret->bus.mmio_writeb = qpci_spapr_mmio32_writeb; + ret->bus.mmio_writew = qpci_spapr_mmio32_writew; + ret->bus.mmio_writel = qpci_spapr_mmio32_writel; ret->bus.config_readb = qpci_spapr_config_readb; ret->bus.config_readw = qpci_spapr_config_readw; diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index c3f3382b7c..55b01df37b 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -224,33 +224,68 @@ void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value) uint8_t qpci_io_readb(QPCIDevice *dev, void *data) { - return dev->bus->io_readb(dev->bus, data); + uintptr_t addr = (uintptr_t)data; + + if (addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readb(dev->bus, addr); + } else { + return dev->bus->mmio_readb(dev->bus, addr); + } } uint16_t qpci_io_readw(QPCIDevice *dev, void *data) { - return dev->bus->io_readw(dev->bus, data); + uintptr_t addr = (uintptr_t)data; + + if (addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readw(dev->bus, addr); + } else { + return dev->bus->mmio_readw(dev->bus, addr); + } } uint32_t qpci_io_readl(QPCIDevice *dev, void *data) { - return dev->bus->io_readl(dev->bus, data); -} + uintptr_t addr = (uintptr_t)data; + if (addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readl(dev->bus, addr); + } else { + return dev->bus->mmio_readl(dev->bus, addr); + } +} void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value) { - dev->bus->io_writeb(dev->bus, data, value); + uintptr_t addr = (uintptr_t)data; + + if (addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writeb(dev->bus, addr, value); + } else { + dev->bus->mmio_writeb(dev->bus, addr, value); + } } void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value) { - dev->bus->io_writew(dev->bus, data, value); + uintptr_t addr = (uintptr_t)data; + + if (addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writew(dev->bus, addr, value); + } else { + dev->bus->mmio_writew(dev->bus, addr, value); + } } void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value) { - dev->bus->io_writel(dev->bus, data, value); + uintptr_t addr = (uintptr_t)data; + + if (addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writel(dev->bus, addr, value); + } else { + dev->bus->mmio_writel(dev->bus, addr, value); + } } void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index c06add8dbf..72a2245c05 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -15,6 +15,8 @@ #include "libqtest.h" +#define QPCI_PIO_LIMIT 0x10000 + #define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn)) typedef struct QPCIDevice QPCIDevice; @@ -22,13 +24,21 @@ typedef struct QPCIBus QPCIBus; struct QPCIBus { - uint8_t (*io_readb)(QPCIBus *bus, void *addr); - uint16_t (*io_readw)(QPCIBus *bus, void *addr); - uint32_t (*io_readl)(QPCIBus *bus, void *addr); + uint8_t (*pio_readb)(QPCIBus *bus, uint32_t addr); + uint16_t (*pio_readw)(QPCIBus *bus, uint32_t addr); + uint32_t (*pio_readl)(QPCIBus *bus, uint32_t addr); + + uint8_t (*mmio_readb)(QPCIBus *bus, uint32_t addr); + uint16_t (*mmio_readw)(QPCIBus *bus, uint32_t addr); + uint32_t (*mmio_readl)(QPCIBus *bus, uint32_t addr); + + void (*pio_writeb)(QPCIBus *bus, uint32_t addr, uint8_t value); + void (*pio_writew)(QPCIBus *bus, uint32_t addr, uint16_t value); + void (*pio_writel)(QPCIBus *bus, uint32_t addr, uint32_t value); - void (*io_writeb)(QPCIBus *bus, void *addr, uint8_t value); - void (*io_writew)(QPCIBus *bus, void *addr, uint16_t value); - void (*io_writel)(QPCIBus *bus, void *addr, uint32_t value); + void (*mmio_writeb)(QPCIBus *bus, uint32_t addr, uint8_t value); + void (*mmio_writew)(QPCIBus *bus, uint32_t addr, uint16_t value); + void (*mmio_writel)(QPCIBus *bus, uint32_t addr, uint32_t value); uint8_t (*config_readb)(QPCIBus *bus, int devfn, uint8_t offset); uint16_t (*config_readw)(QPCIBus *bus, int devfn, uint8_t offset); -- cgit v1.2.3 From b8cc4d0231b97c3dd7930d91ab91657b5a105b78 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 19 Oct 2016 14:06:51 +1100 Subject: libqos: Move BAR assignment to common code The PCI backends in libqos each supply an iomap() and iounmap() function which is used to set up a specified PCI BAR. But PCI BAR allocation takes place entirely within PCI space, so doesn't really need per-backend versions. For example, Linux includes generic BAR allocation code used on platforms where that isn't done by firmware. This patch merges the BAR allocation from the two existing backends into a single simplified copy. The back ends just need to set up some parameters describing the window of PCI IO and PCI memory addresses which are available for allocation. Like both the existing versions the new one uses a simple bump allocator. Note that (again like the existing versions) this doesn't really handle 64-bit memory BARs properly. It is actually used for such a BAR by the ivshmem test, and apparently the 32-bit MMIO BAR logic is close enough to work, as long as the BAR isn't too big. Fixing that to properly handle 64-bit BAR allocation is a problem for another time. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier Reviewed-by: Greg Kurz --- tests/libqos/pci-pc.c | 87 ++-------------------------------------------- tests/libqos/pci-spapr.c | 89 ++---------------------------------------------- tests/libqos/pci.c | 56 ++++++++++++++++++++++++++++-- tests/libqos/pci.h | 7 ++-- 4 files changed, 63 insertions(+), 176 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 51dff8a7fa..d0eb84a134 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -17,7 +17,6 @@ #include "hw/pci/pci_regs.h" #include "qemu-common.h" -#include "qemu/host-utils.h" #define ACPI_PCIHP_ADDR 0xae00 @@ -26,14 +25,6 @@ typedef struct QPCIBusPC { QPCIBus bus; - - uint32_t pci_hole_start; - uint32_t pci_hole_size; - uint32_t pci_hole_alloc; - - uint16_t pci_iohole_start; - uint16_t pci_iohole_size; - uint16_t pci_iohole_alloc; } QPCIBusPC; static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) @@ -132,71 +123,6 @@ static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint3 outl(0xcfc, value); } -static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *sizeptr) -{ - QPCIBusPC *s = container_of(bus, QPCIBusPC, bus); - static const int bar_reg_map[] = { - PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, - }; - int bar_reg; - uint32_t addr; - uint64_t size; - uint32_t io_type; - - g_assert(barno >= 0 && barno <= 5); - bar_reg = bar_reg_map[barno]; - - qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); - addr = qpci_config_readl(dev, bar_reg); - - io_type = addr & PCI_BASE_ADDRESS_SPACE; - if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { - addr &= PCI_BASE_ADDRESS_IO_MASK; - } else { - addr &= PCI_BASE_ADDRESS_MEM_MASK; - } - - size = (1ULL << ctzl(addr)); - if (size == 0) { - return NULL; - } - if (sizeptr) { - *sizeptr = size; - } - - if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { - uint16_t loc; - - g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size - <= s->pci_iohole_size); - s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); - loc = s->pci_iohole_start + s->pci_iohole_alloc; - s->pci_iohole_alloc += size; - - qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); - - return (void *)(intptr_t)loc; - } else { - uint64_t loc; - - g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size - <= s->pci_hole_size); - s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); - loc = s->pci_hole_start + s->pci_hole_alloc; - s->pci_hole_alloc += size; - - qpci_config_writel(dev, bar_reg, loc); - - return (void *)(intptr_t)loc; - } -} - -static void qpci_pc_iounmap(QPCIBus *bus, void *data) -{ - /* FIXME */ -} - QPCIBus *qpci_init_pc(QGuestAllocator *alloc) { QPCIBusPC *ret; @@ -227,16 +153,9 @@ QPCIBus *qpci_init_pc(QGuestAllocator *alloc) ret->bus.config_writew = qpci_pc_config_writew; ret->bus.config_writel = qpci_pc_config_writel; - ret->bus.iomap = qpci_pc_iomap; - ret->bus.iounmap = qpci_pc_iounmap; - - ret->pci_hole_start = 0xE0000000; - ret->pci_hole_size = 0x20000000; - ret->pci_hole_alloc = 0; - - ret->pci_iohole_start = 0xc000; - ret->pci_iohole_size = 0x4000; - ret->pci_iohole_alloc = 0; + ret->bus.pio_alloc_ptr = 0xc000; + ret->bus.mmio_alloc_ptr = 0xE0000000; + ret->bus.mmio_limit = 0x100000000ULL; return &ret->bus; } diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 2d26a94dab..70a24b5579 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -34,14 +34,6 @@ typedef struct QPCIBusSPAPR { uint64_t mmio32_cpu_base; QPCIWindow mmio32; - - uint64_t pci_hole_start; - uint64_t pci_hole_size; - uint64_t pci_hole_alloc; - - uint32_t pci_iohole_start; - uint32_t pci_iohole_size; - uint32_t pci_iohole_alloc; } QPCIBusSPAPR; /* @@ -167,72 +159,6 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 4, value); } -static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, - uint64_t *sizeptr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - static const int bar_reg_map[] = { - PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, - }; - int bar_reg; - uint32_t addr; - uint64_t size; - uint32_t io_type; - - g_assert(barno >= 0 && barno <= 5); - bar_reg = bar_reg_map[barno]; - - qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); - addr = qpci_config_readl(dev, bar_reg); - - io_type = addr & PCI_BASE_ADDRESS_SPACE; - if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { - addr &= PCI_BASE_ADDRESS_IO_MASK; - } else { - addr &= PCI_BASE_ADDRESS_MEM_MASK; - } - - size = (1ULL << ctzl(addr)); - if (size == 0) { - return NULL; - } - if (sizeptr) { - *sizeptr = size; - } - - if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { - uint16_t loc; - - g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size - <= s->pci_iohole_size); - s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); - loc = s->pci_iohole_start + s->pci_iohole_alloc; - s->pci_iohole_alloc += size; - - qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); - - return (void *)(unsigned long)loc; - } else { - uint64_t loc; - - g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size - <= s->pci_hole_size); - s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); - loc = s->pci_hole_start + s->pci_hole_alloc; - s->pci_hole_alloc += size; - - qpci_config_writel(dev, bar_reg, loc); - - return (void *)(unsigned long)loc; - } -} - -static void qpci_spapr_iounmap(QPCIBus *bus, void *data) -{ - /* FIXME */ -} - #define SPAPR_PCI_BASE (1ULL << 45) #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ @@ -270,9 +196,6 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->bus.config_writew = qpci_spapr_config_writew; ret->bus.config_writel = qpci_spapr_config_writel; - ret->bus.iomap = qpci_spapr_iomap; - ret->bus.iounmap = qpci_spapr_iounmap; - /* FIXME: We assume the default location of the PHB for now. * Ideally we'd parse the device tree deposited in the guest to * get the window locations */ @@ -287,15 +210,9 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->mmio32.pci_base = 0x80000000; /* 2 GiB */ ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; - ret->pci_hole_start = 0xC0000000; - ret->pci_hole_size = - ret->mmio32.pci_base + ret->mmio32.size - ret->pci_hole_start; - ret->pci_hole_alloc = 0; - - ret->pci_iohole_start = 0xc000; - ret->pci_iohole_size = - ret->pio.pci_base + ret->pio.size - ret->pci_iohole_start; - ret->pci_iohole_alloc = 0; + ret->bus.pio_alloc_ptr = 0xc000; + ret->bus.mmio_alloc_ptr = ret->mmio32.pci_base; + ret->bus.mmio_limit = ret->mmio32.pci_base + ret->mmio32.size; return &ret->bus; } diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index 55b01df37b..bf1c53240b 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -14,6 +14,7 @@ #include "libqos/pci.h" #include "hw/pci/pci_regs.h" +#include "qemu/host-utils.h" void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id, void (*func)(QPCIDevice *dev, int devfn, void *data), @@ -290,12 +291,63 @@ void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value) void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) { - return dev->bus->iomap(dev->bus, dev, barno, sizeptr); + QPCIBus *bus = dev->bus; + static const int bar_reg_map[] = { + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, + }; + int bar_reg; + uint32_t addr, size; + uint32_t io_type; + uint64_t loc; + + g_assert(barno >= 0 && barno <= 5); + bar_reg = bar_reg_map[barno]; + + qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); + addr = qpci_config_readl(dev, bar_reg); + + io_type = addr & PCI_BASE_ADDRESS_SPACE; + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + addr &= PCI_BASE_ADDRESS_IO_MASK; + } else { + addr &= PCI_BASE_ADDRESS_MEM_MASK; + } + + g_assert(addr); /* Must have *some* size bits */ + + size = 1U << ctz32(addr); + if (sizeptr) { + *sizeptr = size; + } + + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size); + + g_assert(loc >= bus->pio_alloc_ptr); + g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */ + + bus->pio_alloc_ptr = loc + size; + + qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); + } else { + loc = QEMU_ALIGN_UP(bus->mmio_alloc_ptr, size); + + /* Check for space */ + g_assert(loc >= bus->mmio_alloc_ptr); + g_assert(loc + size <= bus->mmio_limit); + + bus->mmio_alloc_ptr = loc + size; + + qpci_config_writel(dev, bar_reg, loc); + } + + return (void *)(uintptr_t)loc; } void qpci_iounmap(QPCIDevice *dev, void *data) { - dev->bus->iounmap(dev->bus, data); + /* FIXME */ } void qpci_plug_device_test(const char *driver, const char *id, diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index 72a2245c05..f6f916dca7 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -22,8 +22,7 @@ typedef struct QPCIDevice QPCIDevice; typedef struct QPCIBus QPCIBus; -struct QPCIBus -{ +struct QPCIBus { uint8_t (*pio_readb)(QPCIBus *bus, uint32_t addr); uint16_t (*pio_readw)(QPCIBus *bus, uint32_t addr); uint32_t (*pio_readl)(QPCIBus *bus, uint32_t addr); @@ -51,8 +50,8 @@ struct QPCIBus void (*config_writel)(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value); - void *(*iomap)(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *sizeptr); - void (*iounmap)(QPCIBus *bus, void *data); + uint16_t pio_alloc_ptr; + uint64_t mmio_alloc_ptr, mmio_limit; }; struct QPCIDevice -- cgit v1.2.3 From a7b85b60623a862e2c55d5a6cd2e17f5fc26b256 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 19 Oct 2016 17:43:42 +1100 Subject: libqos: Better handling of PCI legacy IO The usual model for PCI IO with libqos is to use qpci_iomap() to map a specific BAR for a PCI device, then perform IOs within that BAR using qpci_io_{read,write}*(). However, certain devices also have legacy PCI IO. In this case, instead of (or as well as) being accessed via PCI BARs, the device can be accessed via certain well-known, fixed addresses in PCI IO space. Two existing tests use legacy PCI IO, and take different flawed approaches to it: * tco-test manually constructs a tco_io_base value instead of calling qpci_iomap(), which assumes internal knowledge of the structure of the value it shouldn't have * ide-test uses direct in*() and out*() calls instead of using qpci_io_*() accessors, meaning it's not portable to non-x86 machine types. This patch implements a new qpci_iomap_legacy() interface which gets a handle in the same format as qpci_iomap() but refers to a region in the legacy PIO space. For a device which has the same registers available both in a BAR and in legacy space (quite common), this allows the same test code to test both options with just a different iomap() at the beginning. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier Reviewed-by: Greg Kurz --- tests/libqos/pci.c | 5 +++++ tests/libqos/pci.h | 1 + 2 files changed, 6 insertions(+) (limited to 'tests/libqos') diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index bf1c53240b..98a2e56569 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -350,6 +350,11 @@ void qpci_iounmap(QPCIDevice *dev, void *data) /* FIXME */ } +void *qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr) +{ + return (void *)(uintptr_t)addr; +} + void qpci_plug_device_test(const char *driver, const char *id, uint8_t slot, const char *opts) { diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index f6f916dca7..b6f855e3b6 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -94,6 +94,7 @@ void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value); void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr); void qpci_iounmap(QPCIDevice *dev, void *data); +void *qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr); void qpci_plug_device_test(const char *driver, const char *id, uint8_t slot, const char *opts); -- cgit v1.2.3 From 9a84f889471de50144632100109f93aabea68ff6 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 19 Oct 2016 14:19:47 +1100 Subject: libqos: Add streaming accessors for PCI MMIO Currently PCI memory (aka MMIO) space is accessed via a set of readb/writeb style accessors. This is what we want for accessing discrete registers of a certain size. However, there are a few cases where we instead need a "bag of bytes" style streaming interface to PCI MMIO space. This can be either for streaming data style registers or when there's actual memory rather than registers in PCI space, for example frame buffers or ivshmem. This patch adds backend callbacks, and libqos wrappers for this type of byte address order preserving accesses. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier Reviewed-by: Greg Kurz --- tests/libqos/pci-pc.c | 14 ++++++++++++++ tests/libqos/pci-spapr.c | 17 +++++++++++++++++ tests/libqos/pci.c | 16 ++++++++++++++++ tests/libqos/pci.h | 6 ++++++ 4 files changed, 53 insertions(+) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index d0eb84a134..84aee25350 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -87,6 +87,17 @@ static void qpci_pc_mmio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) writel(addr, val); } +static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) +{ + memread(addr, buf, len); +} + +static void qpci_pc_memwrite(QPCIBus *bus, uint32_t addr, + const void *buf, size_t len) +{ + memwrite(addr, buf, len); +} + static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) { outl(0xcf8, (1U << 31) | (devfn << 8) | offset); @@ -145,6 +156,9 @@ QPCIBus *qpci_init_pc(QGuestAllocator *alloc) ret->bus.mmio_writew = qpci_pc_mmio_writew; ret->bus.mmio_writel = qpci_pc_mmio_writel; + ret->bus.memread = qpci_pc_memread; + ret->bus.memwrite = qpci_pc_memwrite; + ret->bus.config_readb = qpci_pc_config_readb; ret->bus.config_readw = qpci_pc_config_readw; ret->bus.config_readl = qpci_pc_config_readl; diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 70a24b5579..ad12c2e582 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -114,6 +114,20 @@ static void qpci_spapr_mmio32_writel(QPCIBus *bus, uint32_t addr, uint32_t val) writel(s->mmio32_cpu_base + addr, bswap32(val)); } +static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, + void *buf, size_t len) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + memread(s->mmio32_cpu_base + addr, buf, len); +} + +static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr, + const void *buf, size_t len) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + memwrite(s->mmio32_cpu_base + addr, buf, len); +} + static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); @@ -188,6 +202,9 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->bus.mmio_writew = qpci_spapr_mmio32_writew; ret->bus.mmio_writel = qpci_spapr_mmio32_writel; + ret->bus.memread = qpci_spapr_memread; + ret->bus.memwrite = qpci_spapr_memwrite; + ret->bus.config_readb = qpci_spapr_config_readb; ret->bus.config_readw = qpci_spapr_config_readw; ret->bus.config_readl = qpci_spapr_config_readl; diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index 98a2e56569..146b06311c 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -289,6 +289,22 @@ void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value) } } +void qpci_memread(QPCIDevice *dev, void *data, void *buf, size_t len) +{ + uintptr_t addr = (uintptr_t)data; + + g_assert(addr >= QPCI_PIO_LIMIT); + dev->bus->memread(dev->bus, addr, buf, len); +} + +void qpci_memwrite(QPCIDevice *dev, void *data, const void *buf, size_t len) +{ + uintptr_t addr = (uintptr_t)data; + + g_assert(addr >= QPCI_PIO_LIMIT); + dev->bus->memwrite(dev->bus, addr, buf, len); +} + void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) { QPCIBus *bus = dev->bus; diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index b6f855e3b6..2b083624ef 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -39,6 +39,9 @@ struct QPCIBus { void (*mmio_writew)(QPCIBus *bus, uint32_t addr, uint16_t value); void (*mmio_writel)(QPCIBus *bus, uint32_t addr, uint32_t value); + void (*memread)(QPCIBus *bus, uint32_t addr, void *buf, size_t len); + void (*memwrite)(QPCIBus *bus, uint32_t addr, const void *buf, size_t len); + uint8_t (*config_readb)(QPCIBus *bus, int devfn, uint8_t offset); uint16_t (*config_readw)(QPCIBus *bus, int devfn, uint8_t offset); uint32_t (*config_readl)(QPCIBus *bus, int devfn, uint8_t offset); @@ -92,6 +95,9 @@ void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value); void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value); void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value); +void qpci_memread(QPCIDevice *bus, void *data, void *buf, size_t len); +void qpci_memwrite(QPCIDevice *bus, void *data, const void *buf, size_t len); + void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr); void qpci_iounmap(QPCIDevice *dev, void *data); void *qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr); -- cgit v1.2.3 From 352d664cce514a94228fbf6e05d03920b2d6bd69 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 19 Oct 2016 14:20:44 +1100 Subject: libqos: Implement mmio accessors in terms of mem{read,write} In the libqos PCI code we now have accessors both for registers (byte significance preserving) and for streaming data (byte address order preserving). These exist in both the interface for qtest drivers and in the machine specific backends. However, the register-style accessors aren't actually necessary in the backend. They can be implemented in terms of the byte address order preserving accessors by the libqos wrappers. This works because PCI is always little endian. This does assume that the back end byte address order preserving accessors will perform the equivalent of a single bus transaction for short lengths. This is the case, and in fact they currently end up using the same cpu_physical_memory_rw() implementation within the qtest accelerator. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier Reviewed-by: Greg Kurz --- tests/libqos/pci-pc.c | 38 -------------------------------------- tests/libqos/pci-spapr.c | 44 -------------------------------------------- tests/libqos/pci.c | 20 ++++++++++++++------ tests/libqos/pci.h | 8 -------- 4 files changed, 14 insertions(+), 96 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 84aee25350..849ea56da4 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -32,61 +32,31 @@ static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) return inb(addr); } -static uint8_t qpci_pc_mmio_readb(QPCIBus *bus, uint32_t addr) -{ - return readb(addr); -} - static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) { outb(addr, val); } -static void qpci_pc_mmio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) -{ - writeb(addr, val); -} - static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) { return inw(addr); } -static uint16_t qpci_pc_mmio_readw(QPCIBus *bus, uint32_t addr) -{ - return readw(addr); -} - static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) { outw(addr, val); } -static void qpci_pc_mmio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) -{ - writew(addr, val); -} - static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) { return inl(addr); } -static uint32_t qpci_pc_mmio_readl(QPCIBus *bus, uint32_t addr) -{ - return readl(addr); -} - static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) { outl(addr, val); } -static void qpci_pc_mmio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) -{ - writel(addr, val); -} - static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) { memread(addr, buf, len); @@ -148,14 +118,6 @@ QPCIBus *qpci_init_pc(QGuestAllocator *alloc) ret->bus.pio_writew = qpci_pc_pio_writew; ret->bus.pio_writel = qpci_pc_pio_writel; - ret->bus.mmio_readb = qpci_pc_mmio_readb; - ret->bus.mmio_readw = qpci_pc_mmio_readw; - ret->bus.mmio_readl = qpci_pc_mmio_readl; - - ret->bus.mmio_writeb = qpci_pc_mmio_writeb; - ret->bus.mmio_writew = qpci_pc_mmio_writew; - ret->bus.mmio_writel = qpci_pc_mmio_writel; - ret->bus.memread = qpci_pc_memread; ret->bus.memwrite = qpci_pc_memwrite; diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index ad12c2e582..f26488ae5e 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -48,72 +48,36 @@ static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr) return readb(s->pio_cpu_base + addr); } -static uint8_t qpci_spapr_mmio32_readb(QPCIBus *bus, uint32_t addr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - return readb(s->mmio32_cpu_base + addr); -} - static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); writeb(s->pio_cpu_base + addr, val); } -static void qpci_spapr_mmio32_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - writeb(s->mmio32_cpu_base + addr, val); -} - static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); return bswap16(readw(s->pio_cpu_base + addr)); } -static uint16_t qpci_spapr_mmio32_readw(QPCIBus *bus, uint32_t addr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - return bswap16(readw(s->mmio32_cpu_base + addr)); -} - static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); writew(s->pio_cpu_base + addr, bswap16(val)); } -static void qpci_spapr_mmio32_writew(QPCIBus *bus, uint32_t addr, uint16_t val) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - writew(s->mmio32_cpu_base + addr, bswap16(val)); -} - static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); return bswap32(readl(s->pio_cpu_base + addr)); } -static uint32_t qpci_spapr_mmio32_readl(QPCIBus *bus, uint32_t addr) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - return bswap32(readl(s->mmio32_cpu_base + addr)); -} - static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); writel(s->pio_cpu_base + addr, bswap32(val)); } -static void qpci_spapr_mmio32_writel(QPCIBus *bus, uint32_t addr, uint32_t val) -{ - QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); - writel(s->mmio32_cpu_base + addr, bswap32(val)); -} - static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) { @@ -194,14 +158,6 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->bus.pio_writew = qpci_spapr_pio_writew; ret->bus.pio_writel = qpci_spapr_pio_writel; - ret->bus.mmio_readb = qpci_spapr_mmio32_readb; - ret->bus.mmio_readw = qpci_spapr_mmio32_readw; - ret->bus.mmio_readl = qpci_spapr_mmio32_readl; - - ret->bus.mmio_writeb = qpci_spapr_mmio32_writeb; - ret->bus.mmio_writew = qpci_spapr_mmio32_writew; - ret->bus.mmio_writel = qpci_spapr_mmio32_writel; - ret->bus.memread = qpci_spapr_memread; ret->bus.memwrite = qpci_spapr_memwrite; diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index 146b06311c..bdffeb3ec2 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -230,7 +230,9 @@ uint8_t qpci_io_readb(QPCIDevice *dev, void *data) if (addr < QPCI_PIO_LIMIT) { return dev->bus->pio_readb(dev->bus, addr); } else { - return dev->bus->mmio_readb(dev->bus, addr); + uint8_t val; + dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + return val; } } @@ -241,7 +243,9 @@ uint16_t qpci_io_readw(QPCIDevice *dev, void *data) if (addr < QPCI_PIO_LIMIT) { return dev->bus->pio_readw(dev->bus, addr); } else { - return dev->bus->mmio_readw(dev->bus, addr); + uint16_t val; + dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + return le16_to_cpu(val); } } @@ -252,7 +256,9 @@ uint32_t qpci_io_readl(QPCIDevice *dev, void *data) if (addr < QPCI_PIO_LIMIT) { return dev->bus->pio_readl(dev->bus, addr); } else { - return dev->bus->mmio_readl(dev->bus, addr); + uint32_t val; + dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + return le32_to_cpu(val); } } @@ -263,7 +269,7 @@ void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value) if (addr < QPCI_PIO_LIMIT) { dev->bus->pio_writeb(dev->bus, addr, value); } else { - dev->bus->mmio_writeb(dev->bus, addr, value); + dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); } } @@ -274,7 +280,8 @@ void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value) if (addr < QPCI_PIO_LIMIT) { dev->bus->pio_writew(dev->bus, addr, value); } else { - dev->bus->mmio_writew(dev->bus, addr, value); + value = cpu_to_le16(value); + dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); } } @@ -285,7 +292,8 @@ void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value) if (addr < QPCI_PIO_LIMIT) { dev->bus->pio_writel(dev->bus, addr, value); } else { - dev->bus->mmio_writel(dev->bus, addr, value); + value = cpu_to_le32(value); + dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); } } diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index 2b083624ef..ce6ed08f2a 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -27,18 +27,10 @@ struct QPCIBus { uint16_t (*pio_readw)(QPCIBus *bus, uint32_t addr); uint32_t (*pio_readl)(QPCIBus *bus, uint32_t addr); - uint8_t (*mmio_readb)(QPCIBus *bus, uint32_t addr); - uint16_t (*mmio_readw)(QPCIBus *bus, uint32_t addr); - uint32_t (*mmio_readl)(QPCIBus *bus, uint32_t addr); - void (*pio_writeb)(QPCIBus *bus, uint32_t addr, uint8_t value); void (*pio_writew)(QPCIBus *bus, uint32_t addr, uint16_t value); void (*pio_writel)(QPCIBus *bus, uint32_t addr, uint32_t value); - void (*mmio_writeb)(QPCIBus *bus, uint32_t addr, uint8_t value); - void (*mmio_writew)(QPCIBus *bus, uint32_t addr, uint16_t value); - void (*mmio_writel)(QPCIBus *bus, uint32_t addr, uint32_t value); - void (*memread)(QPCIBus *bus, uint32_t addr, void *buf, size_t len); void (*memwrite)(QPCIBus *bus, uint32_t addr, const void *buf, size_t len); -- cgit v1.2.3 From f775f45ab866f8e2d26720de9cb3c8f0ba5684d3 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 19 Oct 2016 15:00:21 +1100 Subject: libqos: Add 64-bit PCI IO accessors Currently the libqos PCI layer includes accessor helpers for 8, 16 and 32 bit reads and writes. It's likely that we'll want 64-bit accesses in the future (plenty of modern peripherals will have 64-bit reigsters). This adds them. For PIO (not MMIO) accesses on the PC backend, this is implemented as two 32-bit ins or outs. That's not ideal but AFAICT x86 doesn't have 64-bit versions of in and out. This patch also converts the single current user of 64-bit accesses - virtio-pci.c to use the new mechanism, rather than a sequence of 8 byte reads. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier Reviewed-by: Greg Kurz --- tests/libqos/pci-pc.c | 13 +++++++++++++ tests/libqos/pci-spapr.c | 14 ++++++++++++++ tests/libqos/pci.c | 25 +++++++++++++++++++++++++ tests/libqos/pci.h | 4 ++++ tests/libqos/virtio-pci.c | 16 ++++------------ 5 files changed, 60 insertions(+), 12 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 849ea56da4..ded1c54c06 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -57,6 +57,17 @@ static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) outl(addr, val); } +static uint64_t qpci_pc_pio_readq(QPCIBus *bus, uint32_t addr) +{ + return (uint64_t)inl(addr) + ((uint64_t)inl(addr + 4) << 32); +} + +static void qpci_pc_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) +{ + outl(addr, val & 0xffffffff); + outl(addr + 4, val >> 32); +} + static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) { memread(addr, buf, len); @@ -113,10 +124,12 @@ QPCIBus *qpci_init_pc(QGuestAllocator *alloc) ret->bus.pio_readb = qpci_pc_pio_readb; ret->bus.pio_readw = qpci_pc_pio_readw; ret->bus.pio_readl = qpci_pc_pio_readl; + ret->bus.pio_readq = qpci_pc_pio_readq; ret->bus.pio_writeb = qpci_pc_pio_writeb; ret->bus.pio_writew = qpci_pc_pio_writew; ret->bus.pio_writel = qpci_pc_pio_writel; + ret->bus.pio_writeq = qpci_pc_pio_writeq; ret->bus.memread = qpci_pc_memread; ret->bus.memwrite = qpci_pc_memwrite; diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index f26488ae5e..1e5d015bd4 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -78,6 +78,18 @@ static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) writel(s->pio_cpu_base + addr, bswap32(val)); } +static uint64_t qpci_spapr_pio_readq(QPCIBus *bus, uint32_t addr) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + return bswap64(readq(s->pio_cpu_base + addr)); +} + +static void qpci_spapr_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + writeq(s->pio_cpu_base + addr, bswap64(val)); +} + static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) { @@ -153,10 +165,12 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->bus.pio_readb = qpci_spapr_pio_readb; ret->bus.pio_readw = qpci_spapr_pio_readw; ret->bus.pio_readl = qpci_spapr_pio_readl; + ret->bus.pio_readq = qpci_spapr_pio_readq; ret->bus.pio_writeb = qpci_spapr_pio_writeb; ret->bus.pio_writew = qpci_spapr_pio_writew; ret->bus.pio_writel = qpci_spapr_pio_writel; + ret->bus.pio_writeq = qpci_spapr_pio_writeq; ret->bus.memread = qpci_spapr_memread; ret->bus.memwrite = qpci_spapr_memwrite; diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index bdffeb3ec2..3021651ee4 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -262,6 +262,19 @@ uint32_t qpci_io_readl(QPCIDevice *dev, void *data) } } +uint64_t qpci_io_readq(QPCIDevice *dev, void *data) +{ + uintptr_t addr = (uintptr_t)data; + + if (addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readq(dev->bus, addr); + } else { + uint64_t val; + dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + return le64_to_cpu(val); + } +} + void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value) { uintptr_t addr = (uintptr_t)data; @@ -297,6 +310,18 @@ void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value) } } +void qpci_io_writeq(QPCIDevice *dev, void *data, uint64_t value) +{ + uintptr_t addr = (uintptr_t)data; + + if (addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writeq(dev->bus, addr, value); + } else { + value = cpu_to_le64(value); + dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); + } +} + void qpci_memread(QPCIDevice *dev, void *data, void *buf, size_t len) { uintptr_t addr = (uintptr_t)data; diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index ce6ed08f2a..531e3f79e9 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -26,10 +26,12 @@ struct QPCIBus { uint8_t (*pio_readb)(QPCIBus *bus, uint32_t addr); uint16_t (*pio_readw)(QPCIBus *bus, uint32_t addr); uint32_t (*pio_readl)(QPCIBus *bus, uint32_t addr); + uint64_t (*pio_readq)(QPCIBus *bus, uint32_t addr); void (*pio_writeb)(QPCIBus *bus, uint32_t addr, uint8_t value); void (*pio_writew)(QPCIBus *bus, uint32_t addr, uint16_t value); void (*pio_writel)(QPCIBus *bus, uint32_t addr, uint32_t value); + void (*pio_writeq)(QPCIBus *bus, uint32_t addr, uint64_t value); void (*memread)(QPCIBus *bus, uint32_t addr, void *buf, size_t len); void (*memwrite)(QPCIBus *bus, uint32_t addr, const void *buf, size_t len); @@ -82,10 +84,12 @@ void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value); uint8_t qpci_io_readb(QPCIDevice *dev, void *data); uint16_t qpci_io_readw(QPCIDevice *dev, void *data); uint32_t qpci_io_readl(QPCIDevice *dev, void *data); +uint64_t qpci_io_readq(QPCIDevice *dev, void *data); void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value); void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value); void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value); +void qpci_io_writeq(QPCIDevice *dev, void *data, uint64_t value); void qpci_memread(QPCIDevice *bus, void *data, void *buf, size_t len); void qpci_memwrite(QPCIDevice *bus, void *data, const void *buf, size_t len); diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index fa82132ab7..c69d09ddb2 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -106,22 +106,14 @@ static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t off) static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - int i; - uint64_t u64 = 0; + uint64_t val; + val = qpci_io_readq(dev->pdev, CONFIG_BASE(dev) + off); if (qvirtio_is_big_endian(d)) { - for (i = 0; i < 8; ++i) { - u64 |= (uint64_t)qpci_io_readb(dev->pdev, CONFIG_BASE(dev) - + off + i) << (7 - i) * 8; - } - } else { - for (i = 0; i < 8; ++i) { - u64 |= (uint64_t)qpci_io_readb(dev->pdev, CONFIG_BASE(dev) - + off + i) << i * 8; - } + val = bswap64(val); } - return u64; + return val; } static uint32_t qvirtio_pci_get_features(QVirtioDevice *d) -- cgit v1.2.3 From e7c8526b2a1482a9b14319fda9f8ad4bfda5b958 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 24 Oct 2016 15:50:22 +1100 Subject: tests: Don't assume structure of PCI IO base in ahci-test In a couple of places ahci-test makes assumptions about how the tokens returned from qpci_iomap() are formatted in ways it probably shouldn't. First in verify_state() it uses a non-NULL token to indicate that the AHCI device has been enabled (part of enabling is to iomap()). This changes it to use an explicit 'enabled' flag instead. Second, it uses the fact that the token contains a PCI address, stored when the BAR is mapped during initialization to check that the BAR has the same value after a migration. This changes it to explicitly read the BAR register before and after the migration and compare. Together, these changes will make the test more robust against changes to the internals of the libqos PCI layer. Signed-off-by: David Gibson Reviewed-by: John Snow Reviewed-by: Greg Kurz --- tests/libqos/ahci.c | 1 + tests/libqos/ahci.h | 1 + 2 files changed, 2 insertions(+) (limited to 'tests/libqos') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 716ab7939e..8e789d8407 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -351,6 +351,7 @@ void ahci_hba_enable(AHCIQState *ahci) reg = ahci_rreg(ahci, AHCI_GHC); ASSERT_BIT_SET(reg, AHCI_GHC_IE); + ahci->enabled = true; /* TODO: The device should now be idling and waiting for commands. * In the future, a small test-case to inspect the Register D2H FIS * and clear the initial interrupts might be good. */ diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index c69fb5ae90..9b0c1d705b 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -327,6 +327,7 @@ typedef struct AHCIQState { uint32_t cap; uint32_t cap2; AHCIPortQState port[32]; + bool enabled; } AHCIQState; /** -- cgit v1.2.3 From b4ba67d9a702507793c2724e56f98e9b0f7be02b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 24 Oct 2016 15:52:06 +1100 Subject: libqos: Change PCI accessors to take opaque BAR handle The usual use model for the libqos PCI functions is to map a specific PCI BAR using qpci_iomap() then pass the returned token into IO accessor functions. This, and the fact that iomap() returns a (void *) which actually contains a PCI space address, kind of suggests that the return value from iomap is supposed to be an opaque token. ..except that the callers expect to be able to add offsets to it. Which also assumes the compiler will support pointer arithmetic on a (void *), and treat it as working with byte offsets. To clarify this situation change iomap() and the IO accessors to take a definitely opaque BAR handle (enforced with a wrapper struct) along with an offset within the BAR. This changes both the functions and all the callers. There were a number of places that checked if iomap() returned non-NULL, and or initialized it to NULL before hand. Since iomap() already assert()s if it fails to map the BAR, these tests were mostly pointless and are removed. Signed-off-by: David Gibson Reviewed-by: Greg Kurz --- tests/libqos/ahci.c | 3 +- tests/libqos/ahci.h | 6 +- tests/libqos/pci.c | 149 +++++++++++++++++++++------------------------- tests/libqos/pci.h | 46 ++++++++------ tests/libqos/usb.c | 6 +- tests/libqos/usb.h | 2 +- tests/libqos/virtio-pci.c | 101 ++++++++++++++++--------------- tests/libqos/virtio-pci.h | 2 +- 8 files changed, 157 insertions(+), 158 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 8e789d8407..5180d65279 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -210,8 +210,7 @@ void ahci_pci_enable(AHCIQState *ahci) void start_ahci_device(AHCIQState *ahci) { /* Map AHCI's ABAR (BAR5) */ - ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize); - g_assert(ahci->hba_base); + ahci->hba_bar = qpci_iomap(ahci->dev, 5, &ahci->barsize); /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ qpci_device_enable(ahci->dev); diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 9b0c1d705b..caaafe3fdf 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -321,7 +321,7 @@ typedef struct AHCIPortQState { typedef struct AHCIQState { QOSState *parent; QPCIDevice *dev; - void *hba_base; + QPCIBar hba_bar; uint64_t barsize; uint32_t fingerprint; uint32_t cap; @@ -489,12 +489,12 @@ typedef struct AHCIOpts { static inline uint32_t ahci_mread(AHCIQState *ahci, size_t offset) { - return qpci_io_readl(ahci->dev, ahci->hba_base + offset); + return qpci_io_readl(ahci->dev, ahci->hba_bar, offset); } static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value) { - qpci_io_writel(ahci->dev, ahci->hba_base + offset, value); + qpci_io_writel(ahci->dev, ahci->hba_bar, offset, value); } static inline uint32_t ahci_rreg(AHCIQState *ahci, uint32_t reg_num) diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index 3021651ee4..2dcdeade2a 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -104,7 +104,6 @@ void qpci_msix_enable(QPCIDevice *dev) uint32_t table; uint8_t bir_table; uint8_t bir_pba; - void *offset; addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX); g_assert_cmphex(addr, !=, 0); @@ -114,18 +113,16 @@ void qpci_msix_enable(QPCIDevice *dev) table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE); bir_table = table & PCI_MSIX_FLAGS_BIRMASK; - offset = qpci_iomap(dev, bir_table, NULL); - dev->msix_table = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK); + dev->msix_table_bar = qpci_iomap(dev, bir_table, NULL); + dev->msix_table_off = table & ~PCI_MSIX_FLAGS_BIRMASK; table = qpci_config_readl(dev, addr + PCI_MSIX_PBA); bir_pba = table & PCI_MSIX_FLAGS_BIRMASK; if (bir_pba != bir_table) { - offset = qpci_iomap(dev, bir_pba, NULL); + dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL); } - dev->msix_pba = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK); + dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK; - g_assert(dev->msix_table != NULL); - g_assert(dev->msix_pba != NULL); dev->msix_enabled = true; } @@ -141,22 +138,23 @@ void qpci_msix_disable(QPCIDevice *dev) qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val & ~PCI_MSIX_FLAGS_ENABLE); - qpci_iounmap(dev, dev->msix_table); - qpci_iounmap(dev, dev->msix_pba); + qpci_iounmap(dev, dev->msix_table_bar); + qpci_iounmap(dev, dev->msix_pba_bar); dev->msix_enabled = 0; - dev->msix_table = NULL; - dev->msix_pba = NULL; + dev->msix_table_off = 0; + dev->msix_pba_off = 0; } bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry) { uint32_t pba_entry; uint8_t bit_n = entry % 32; - void *addr = dev->msix_pba + (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4; + uint64_t off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4; g_assert(dev->msix_enabled); - pba_entry = qpci_io_readl(dev, addr); - qpci_io_writel(dev, addr, pba_entry & ~(1 << bit_n)); + pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off); + qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off, + pba_entry & ~(1 << bit_n)); return (pba_entry & (1 << bit_n)) != 0; } @@ -164,7 +162,7 @@ bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry) { uint8_t addr; uint16_t val; - void *vector_addr = dev->msix_table + (entry * PCI_MSIX_ENTRY_SIZE); + uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE; g_assert(dev->msix_enabled); addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX); @@ -174,8 +172,9 @@ bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry) if (val & PCI_MSIX_FLAGS_MASKALL) { return true; } else { - return (qpci_io_readl(dev, vector_addr + PCI_MSIX_ENTRY_VECTOR_CTRL) - & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0; + return (qpci_io_readl(dev, dev->msix_table_bar, + vector_off + PCI_MSIX_ENTRY_VECTOR_CTRL) + & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0; } } @@ -222,129 +221,115 @@ void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value) dev->bus->config_writel(dev->bus, dev->devfn, offset, value); } - -uint8_t qpci_io_readb(QPCIDevice *dev, void *data) +uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readb(dev->bus, addr); + if (token.addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readb(dev->bus, token.addr + off); } else { uint8_t val; - dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return val; } } -uint16_t qpci_io_readw(QPCIDevice *dev, void *data) +uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readw(dev->bus, addr); + if (token.addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readw(dev->bus, token.addr + off); } else { uint16_t val; - dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return le16_to_cpu(val); } } -uint32_t qpci_io_readl(QPCIDevice *dev, void *data) +uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readl(dev->bus, addr); + if (token.addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readl(dev->bus, token.addr + off); } else { uint32_t val; - dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return le32_to_cpu(val); } } -uint64_t qpci_io_readq(QPCIDevice *dev, void *data) +uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - return dev->bus->pio_readq(dev->bus, addr); + if (token.addr < QPCI_PIO_LIMIT) { + return dev->bus->pio_readq(dev->bus, token.addr + off); } else { uint64_t val; - dev->bus->memread(dev->bus, addr, &val, sizeof(val)); + dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val)); return le64_to_cpu(val); } } -void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value) +void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint8_t value) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeb(dev->bus, addr, value); + if (token.addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writeb(dev->bus, token.addr + off, value); } else { - dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); + dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); } } -void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value) +void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint16_t value) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writew(dev->bus, addr, value); + if (token.addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writew(dev->bus, token.addr + off, value); } else { value = cpu_to_le16(value); - dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); + dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); } } -void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value) +void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint32_t value) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writel(dev->bus, addr, value); + if (token.addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writel(dev->bus, token.addr + off, value); } else { value = cpu_to_le32(value); - dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); + dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); } } -void qpci_io_writeq(QPCIDevice *dev, void *data, uint64_t value) +void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint64_t value) { - uintptr_t addr = (uintptr_t)data; - - if (addr < QPCI_PIO_LIMIT) { - dev->bus->pio_writeq(dev->bus, addr, value); + if (token.addr < QPCI_PIO_LIMIT) { + dev->bus->pio_writeq(dev->bus, token.addr + off, value); } else { value = cpu_to_le64(value); - dev->bus->memwrite(dev->bus, addr, &value, sizeof(value)); + dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value)); } } -void qpci_memread(QPCIDevice *dev, void *data, void *buf, size_t len) +void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off, + void *buf, size_t len) { - uintptr_t addr = (uintptr_t)data; - - g_assert(addr >= QPCI_PIO_LIMIT); - dev->bus->memread(dev->bus, addr, buf, len); + g_assert(token.addr >= QPCI_PIO_LIMIT); + dev->bus->memread(dev->bus, token.addr + off, buf, len); } -void qpci_memwrite(QPCIDevice *dev, void *data, const void *buf, size_t len) +void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off, + const void *buf, size_t len) { - uintptr_t addr = (uintptr_t)data; - - g_assert(addr >= QPCI_PIO_LIMIT); - dev->bus->memwrite(dev->bus, addr, buf, len); + g_assert(token.addr >= QPCI_PIO_LIMIT); + dev->bus->memwrite(dev->bus, token.addr + off, buf, len); } -void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) +QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) { QPCIBus *bus = dev->bus; static const int bar_reg_map[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, }; + QPCIBar bar; int bar_reg; uint32_t addr, size; uint32_t io_type; @@ -391,17 +376,19 @@ void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr) qpci_config_writel(dev, bar_reg, loc); } - return (void *)(uintptr_t)loc; + bar.addr = loc; + return bar; } -void qpci_iounmap(QPCIDevice *dev, void *data) +void qpci_iounmap(QPCIDevice *dev, QPCIBar bar) { /* FIXME */ } -void *qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr) +QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr) { - return (void *)(uintptr_t)addr; + QPCIBar bar = { .addr = addr }; + return bar; } void qpci_plug_device_test(const char *driver, const char *id, diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h index 531e3f79e9..ed480614ff 100644 --- a/tests/libqos/pci.h +++ b/tests/libqos/pci.h @@ -21,6 +21,7 @@ typedef struct QPCIDevice QPCIDevice; typedef struct QPCIBus QPCIBus; +typedef struct QPCIBar QPCIBar; struct QPCIBus { uint8_t (*pio_readb)(QPCIBus *bus, uint32_t addr); @@ -51,13 +52,17 @@ struct QPCIBus { uint64_t mmio_alloc_ptr, mmio_limit; }; +struct QPCIBar { + uint64_t addr; +}; + struct QPCIDevice { QPCIBus *bus; int devfn; bool msix_enabled; - void *msix_table; - void *msix_pba; + QPCIBar msix_table_bar, msix_pba_bar; + uint64_t msix_table_off, msix_pba_off; }; void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id, @@ -81,22 +86,27 @@ void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value); void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value); void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value); -uint8_t qpci_io_readb(QPCIDevice *dev, void *data); -uint16_t qpci_io_readw(QPCIDevice *dev, void *data); -uint32_t qpci_io_readl(QPCIDevice *dev, void *data); -uint64_t qpci_io_readq(QPCIDevice *dev, void *data); - -void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value); -void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value); -void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value); -void qpci_io_writeq(QPCIDevice *dev, void *data, uint64_t value); - -void qpci_memread(QPCIDevice *bus, void *data, void *buf, size_t len); -void qpci_memwrite(QPCIDevice *bus, void *data, const void *buf, size_t len); - -void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr); -void qpci_iounmap(QPCIDevice *dev, void *data); -void *qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr); +uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off); +uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off); +uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off); +uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off); + +void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint8_t value); +void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint16_t value); +void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint32_t value); +void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off, + uint64_t value); + +void qpci_memread(QPCIDevice *bus, QPCIBar token, uint64_t off, + void *buf, size_t len); +void qpci_memwrite(QPCIDevice *bus, QPCIBar token, uint64_t off, + const void *buf, size_t len); +QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr); +void qpci_iounmap(QPCIDevice *dev, QPCIBar addr); +QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr); void qpci_plug_device_test(const char *driver, const char *id, uint8_t slot, const char *opts); diff --git a/tests/libqos/usb.c b/tests/libqos/usb.c index f794d92da5..72d7a961fe 100644 --- a/tests/libqos/usb.c +++ b/tests/libqos/usb.c @@ -21,14 +21,12 @@ void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc, uint32_t devfn, int bar) hc->dev = qpci_device_find(pcibus, devfn); g_assert(hc->dev != NULL); qpci_device_enable(hc->dev); - hc->base = qpci_iomap(hc->dev, bar, NULL); - g_assert(hc->base != NULL); + hc->bar = qpci_iomap(hc->dev, bar, NULL); } void uhci_port_test(struct qhc *hc, int port, uint16_t expect) { - void *addr = hc->base + 0x10 + 2 * port; - uint16_t value = qpci_io_readw(hc->dev, addr); + uint16_t value = qpci_io_readw(hc->dev, hc->bar, 0x10 + 2 * port); uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1); g_assert((value & mask) == (expect & mask)); diff --git a/tests/libqos/usb.h b/tests/libqos/usb.h index 8fe56872b7..423dcfd82f 100644 --- a/tests/libqos/usb.h +++ b/tests/libqos/usb.h @@ -5,7 +5,7 @@ struct qhc { QPCIDevice *dev; - void *base; + QPCIBar bar; }; void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc, diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index c69d09ddb2..d4bf841f23 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -62,13 +62,12 @@ static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data) *vpcidev = (QVirtioPCIDevice *)d; } -#define CONFIG_BASE(dev) \ - ((dev)->addr + VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled)) +#define CONFIG_BASE(dev) (VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled)) static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readb(dev->pdev, CONFIG_BASE(dev) + off); + return qpci_io_readb(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); } /* PCI is always read in little-endian order @@ -84,7 +83,7 @@ static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t off) QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; uint16_t value; - value = qpci_io_readw(dev->pdev, CONFIG_BASE(dev) + off); + value = qpci_io_readw(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); if (qvirtio_is_big_endian(d)) { value = bswap16(value); } @@ -96,7 +95,7 @@ static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t off) QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; uint32_t value; - value = qpci_io_readl(dev->pdev, CONFIG_BASE(dev) + off); + value = qpci_io_readl(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); if (qvirtio_is_big_endian(d)) { value = bswap32(value); } @@ -108,7 +107,7 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off) QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; uint64_t val; - val = qpci_io_readq(dev->pdev, CONFIG_BASE(dev) + off); + val = qpci_io_readq(dev->pdev, dev->bar, CONFIG_BASE(dev) + off); if (qvirtio_is_big_endian(d)) { val = bswap64(val); } @@ -119,31 +118,31 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off) static uint32_t qvirtio_pci_get_features(QVirtioDevice *d) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readl(dev->pdev, dev->addr + VIRTIO_PCI_HOST_FEATURES); + return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_HOST_FEATURES); } static void qvirtio_pci_set_features(QVirtioDevice *d, uint32_t features) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writel(dev->pdev, dev->addr + VIRTIO_PCI_GUEST_FEATURES, features); + qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES, features); } static uint32_t qvirtio_pci_get_guest_features(QVirtioDevice *d) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readl(dev->pdev, dev->addr + VIRTIO_PCI_GUEST_FEATURES); + return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES); } static uint8_t qvirtio_pci_get_status(QVirtioDevice *d) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readb(dev->pdev, dev->addr + VIRTIO_PCI_STATUS); + return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS); } static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writeb(dev->pdev, dev->addr + VIRTIO_PCI_STATUS, status); + qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS, status); } static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) @@ -167,7 +166,7 @@ static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) } } } else { - return qpci_io_readb(dev->pdev, dev->addr + VIRTIO_PCI_ISR) & 1; + return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 1; } } @@ -191,26 +190,26 @@ static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d) } } } else { - return qpci_io_readb(dev->pdev, dev->addr + VIRTIO_PCI_ISR) & 2; + return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 2; } } static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writeb(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_SEL, index); + qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_SEL, index); } static uint16_t qvirtio_pci_get_queue_size(QVirtioDevice *d) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - return qpci_io_readw(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_NUM); + return qpci_io_readw(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NUM); } static void qvirtio_pci_set_queue_address(QVirtioDevice *d, uint32_t pfn) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writel(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_PFN, pfn); + qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_PFN, pfn); } static QVirtQueue *qvirtio_pci_virtqueue_setup(QVirtioDevice *d, @@ -262,7 +261,7 @@ static void qvirtio_pci_virtqueue_cleanup(QVirtQueue *vq, static void qvirtio_pci_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq) { QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; - qpci_io_writew(dev->pdev, dev->addr + VIRTIO_PCI_QUEUE_NOTIFY, vq->index); + qpci_io_writew(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NOTIFY, vq->index); } const QVirtioBus qvirtio_pci = { @@ -309,14 +308,12 @@ QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type) void qvirtio_pci_device_enable(QVirtioPCIDevice *d) { qpci_device_enable(d->pdev); - d->addr = qpci_iomap(d->pdev, 0, NULL); - g_assert(d->addr != NULL); + d->bar = qpci_iomap(d->pdev, 0, NULL); } void qvirtio_pci_device_disable(QVirtioPCIDevice *d) { - qpci_iounmap(d->pdev, d->addr); - d->addr = NULL; + qpci_iounmap(d->pdev, d->bar); } void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci, @@ -324,29 +321,33 @@ void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci, { uint16_t vector; uint32_t control; - void *addr; + uint64_t off; g_assert(d->pdev->msix_enabled); - addr = d->pdev->msix_table + (entry * 16); + off = d->pdev->msix_table_off + (entry * 16); g_assert_cmpint(entry, >=, 0); g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev)); vqpci->msix_entry = entry; vqpci->msix_addr = guest_alloc(alloc, 4); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_LOWER_ADDR, - vqpci->msix_addr & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_UPPER_ADDR, - (vqpci->msix_addr >> 32) & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_DATA, vqpci->msix_data); - - control = qpci_io_readl(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL, - control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_LOWER_ADDR, vqpci->msix_addr & ~0UL); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_UPPER_ADDR, + (vqpci->msix_addr >> 32) & ~0UL); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_DATA, vqpci->msix_data); + + control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_VECTOR_CTRL); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_VECTOR_CTRL, + control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); qvirtio_pci_queue_select(&d->vdev, vqpci->vq.index); - qpci_io_writew(d->pdev, d->addr + VIRTIO_MSI_QUEUE_VECTOR, entry); - vector = qpci_io_readw(d->pdev, d->addr + VIRTIO_MSI_QUEUE_VECTOR); + qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR, entry); + vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR); g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR); } @@ -355,10 +356,10 @@ void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d, { uint16_t vector; uint32_t control; - void *addr; + uint64_t off; g_assert(d->pdev->msix_enabled); - addr = d->pdev->msix_table + (entry * 16); + off = d->pdev->msix_table_off + (entry * 16); g_assert_cmpint(entry, >=, 0); g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev)); @@ -367,17 +368,21 @@ void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d, d->config_msix_data = 0x12345678; d->config_msix_addr = guest_alloc(alloc, 4); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_LOWER_ADDR, - d->config_msix_addr & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_UPPER_ADDR, - (d->config_msix_addr >> 32) & ~0UL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_DATA, d->config_msix_data); - - control = qpci_io_readl(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL); - qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL, - control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); - - qpci_io_writew(d->pdev, d->addr + VIRTIO_MSI_CONFIG_VECTOR, entry); - vector = qpci_io_readw(d->pdev, d->addr + VIRTIO_MSI_CONFIG_VECTOR); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_LOWER_ADDR, d->config_msix_addr & ~0UL); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_UPPER_ADDR, + (d->config_msix_addr >> 32) & ~0UL); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_DATA, d->config_msix_data); + + control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_VECTOR_CTRL); + qpci_io_writel(d->pdev, d->pdev->msix_table_bar, + off + PCI_MSIX_ENTRY_VECTOR_CTRL, + control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT); + + qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR, entry); + vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR); g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR); } diff --git a/tests/libqos/virtio-pci.h b/tests/libqos/virtio-pci.h index efcac2d3de..38c54c63ea 100644 --- a/tests/libqos/virtio-pci.h +++ b/tests/libqos/virtio-pci.h @@ -16,7 +16,7 @@ typedef struct QVirtioPCIDevice { QVirtioDevice vdev; QPCIDevice *pdev; - void *addr; + QPCIBar bar; uint16_t config_msix_entry; uint64_t config_msix_addr; uint32_t config_msix_data; -- cgit v1.2.3 From ebde93bf9a13f2e0a853eac8fb4f33c9ecd74baf Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Nov 2016 11:15:54 -0500 Subject: ahci-test: test atapi read_cd with bcl, nb_sectors = 0 Commit 9ef2e93f introduced the concept of tagging ATAPI commands as NONDATA, but this introduced a regression for certain commands better described as CONDDATA. read_cd is such a command that both requires a non-zero BCL if a transfer size is set, but is perfectly content to accept a zero BCL if the transfer size is 0. This test adds a regression test for the case where BCL and nb_sectors are both 0. Flesh out the CDROM tests by: (1) Allowing the test to specify a BCL (2) Allowing the buffer comparison test to compare a 0-size buffer (3) Fix the BCL specification in libqos (It is LE, not BE) (4) Add a nice human-readable message for future SCSI command additions Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-id: 1477970211-25754-4-git-send-email-jsnow@redhat.com [Line length edit --js] Signed-off-by: John Snow --- tests/libqos/ahci.c | 28 +++++++++++++++++++++------- tests/libqos/ahci.h | 17 ++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 5180d65279..0e9354bf13 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -633,7 +633,8 @@ void ahci_exec(AHCIQState *ahci, uint8_t port, /* Command creation */ if (opts->atapi) { - cmd = ahci_atapi_command_create(op); + uint16_t bcl = opts->set_bcl ? opts->bcl : ATAPI_SECTOR_SIZE; + cmd = ahci_atapi_command_create(op, bcl); if (opts->atapi_dma) { ahci_command_enable_atapi_dma(cmd); } @@ -864,16 +865,12 @@ AHCICommand *ahci_command_create(uint8_t command_name) return cmd; } -AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd) +AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl) { AHCICommand *cmd = ahci_command_create(CMD_PACKET); cmd->atapi_cmd = g_malloc0(16); cmd->atapi_cmd[0] = scsi_cmd; - /* ATAPI needs a PIO transfer chunk size set inside of the LBA registers. - * The block/sector size is a natural default. */ - cmd->fis.lba_lo[1] = ATAPI_SECTOR_SIZE >> 8 & 0xFF; - cmd->fis.lba_lo[2] = ATAPI_SECTOR_SIZE & 0xFF; - + stw_le_p(&cmd->fis.lba_lo[1], bcl); return cmd; } @@ -901,12 +898,17 @@ static void ahci_atapi_command_set_offset(AHCICommand *cmd, uint64_t lba) switch (cbd[0]) { case CMD_ATAPI_READ_10: + case CMD_ATAPI_READ_CD: g_assert_cmpuint(lba, <=, UINT32_MAX); stl_be_p(&cbd[2], lba); break; default: /* SCSI doesn't have uniform packet formats, * so you have to add support for it manually. Sorry! */ + fprintf(stderr, "The Libqos AHCI driver does not support the " + "set_offset operation for ATAPI command 0x%02x, " + "please add support.\n", + cbd[0]); g_assert_not_reached(); } } @@ -951,6 +953,7 @@ static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes) { unsigned char *cbd = cmd->atapi_cmd; uint64_t nsectors = xbytes / 2048; + uint32_t tmp; g_assert(cbd); switch (cbd[0]) { @@ -958,9 +961,20 @@ static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes) g_assert_cmpuint(nsectors, <=, UINT16_MAX); stw_be_p(&cbd[7], nsectors); break; + case CMD_ATAPI_READ_CD: + /* 24bit BE store */ + g_assert_cmpuint(nsectors, <, 1ULL << 24); + tmp = nsectors; + cbd[6] = (tmp & 0xFF0000) >> 16; + cbd[7] = (tmp & 0xFF00) >> 8; + cbd[8] = (tmp & 0xFF); + break; default: /* SCSI doesn't have uniform packet formats, * so you have to add support for it manually. Sorry! */ + fprintf(stderr, "The Libqos AHCI driver does not support the set_size " + "operation for ATAPI command 0x%02x, please add support.\n", + cbd[0]); g_assert_not_reached(); } } diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index caaafe3fdf..f144fab37a 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -288,6 +288,7 @@ enum { /* ATAPI Commands */ enum { CMD_ATAPI_READ_10 = 0x28, + CMD_ATAPI_READ_CD = 0xbe, }; /* AHCI Command Header Flags & Masks*/ @@ -462,12 +463,14 @@ typedef struct AHCICommand AHCICommand; /* Options to ahci_exec */ typedef struct AHCIOpts { - size_t size; - unsigned prd_size; - uint64_t lba; - uint64_t buffer; - bool atapi; - bool atapi_dma; + size_t size; /* Size of transfer */ + unsigned prd_size; /* Size per-each PRD */ + bool set_bcl; /* Override the default BCL of ATAPI_SECTOR_SIZE */ + unsigned bcl; /* Byte Count Limit, for ATAPI PIO */ + uint64_t lba; /* Starting LBA offset */ + uint64_t buffer; /* Pointer to source or destination guest buffer */ + bool atapi; /* ATAPI command? */ + bool atapi_dma; /* Use DMA for ATAPI? */ bool error; int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); @@ -599,7 +602,7 @@ void ahci_exec(AHCIQState *ahci, uint8_t port, /* Command: Fine-grained lifecycle */ AHCICommand *ahci_command_create(uint8_t command_name); -AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd); +AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl); void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port); void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd); -- cgit v1.2.3 From f697b0edea426da261bff7541a66f36266d8edb0 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Nov 2016 11:15:54 -0500 Subject: libqos/ahci: Support expected errors Sometimes we know we'll get back an error, so let's have the test framework understand that. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-id: 1478553214-497-4-git-send-email-jsnow@redhat.com Signed-off-by: John Snow --- tests/libqos/ahci.c | 16 ++++++++++++---- tests/libqos/ahci.h | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 0e9354bf13..99e85d5b31 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -86,6 +86,7 @@ struct AHCICommand { uint8_t name; uint8_t port; uint8_t slot; + uint8_t errors; uint32_t interrupts; uint64_t xbytes; uint32_t prd_size; @@ -402,12 +403,14 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port) /** * Check a port for errors. */ -void ahci_port_check_error(AHCIQState *ahci, uint8_t port) +void ahci_port_check_error(AHCIQState *ahci, uint8_t port, + uint32_t imask, uint8_t emask) { uint32_t reg; /* The upper 9 bits of the IS register all indicate errors. */ reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); + reg &= ~imask; reg >>= 23; g_assert_cmphex(reg, ==, 0); @@ -417,8 +420,13 @@ void ahci_port_check_error(AHCIQState *ahci, uint8_t port) /* The TFD also has two error sections. */ reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); + if (!emask) { + ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); + } else { + ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_ERR); + } + ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR & (~emask << 8)); + ASSERT_BIT_SET(reg, AHCI_PX_TFD_ERR & (emask << 8)); } void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, @@ -1119,7 +1127,7 @@ void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd) uint8_t slot = cmd->slot; uint8_t port = cmd->port; - ahci_port_check_error(ahci, port); + ahci_port_check_error(ahci, port, cmd->interrupts, cmd->errors); ahci_port_check_interrupts(ahci, port, cmd->interrupts); ahci_port_check_nonbusy(ahci, port, slot); ahci_port_check_cmd_sanity(ahci, cmd); diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index f144fab37a..bbe04f834a 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -576,7 +576,8 @@ void ahci_set_command_header(AHCIQState *ahci, uint8_t port, void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); /* AHCI sanity check routines */ -void ahci_port_check_error(AHCIQState *ahci, uint8_t port); +void ahci_port_check_error(AHCIQState *ahci, uint8_t port, + uint32_t imask, uint8_t emask); void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, uint32_t intr_mask); void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot); -- cgit v1.2.3 From 48cde0913203079036f2785b6bb274873a1a1db2 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Nov 2016 11:15:55 -0500 Subject: libqos/ahci: Add ATAPI tray macros (1) Add START_STOP_UNIT command to ahci-test suite (2) Add eject/start macro commands; this is not a data transfer command so it is not well-served by the existing generic pipeline. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-id: 1478553214-497-5-git-send-email-jsnow@redhat.com Signed-off-by: John Snow --- tests/libqos/ahci.c | 30 ++++++++++++++++++++++++++++++ tests/libqos/ahci.h | 7 +++++-- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'tests/libqos') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 99e85d5b31..79398b4085 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -882,6 +882,30 @@ AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl) return cmd; } +void ahci_atapi_eject(AHCIQState *ahci, uint8_t port) +{ + AHCICommand *cmd = ahci_atapi_command_create(CMD_ATAPI_START_STOP_UNIT, 0); + ahci_command_set_size(cmd, 0); + + cmd->atapi_cmd[4] = 0x02; /* loej = true */ + ahci_command_commit(ahci, cmd, port); + ahci_command_issue(ahci, cmd); + ahci_command_verify(ahci, cmd); + ahci_command_free(cmd); +} + +void ahci_atapi_load(AHCIQState *ahci, uint8_t port) +{ + AHCICommand *cmd = ahci_atapi_command_create(CMD_ATAPI_START_STOP_UNIT, 0); + ahci_command_set_size(cmd, 0); + + cmd->atapi_cmd[4] = 0x03; /* loej,start = true */ + ahci_command_commit(ahci, cmd, port); + ahci_command_issue(ahci, cmd); + ahci_command_verify(ahci, cmd); + ahci_command_free(cmd); +} + void ahci_command_free(AHCICommand *cmd) { g_free(cmd->atapi_cmd); @@ -910,6 +934,9 @@ static void ahci_atapi_command_set_offset(AHCICommand *cmd, uint64_t lba) g_assert_cmpuint(lba, <=, UINT32_MAX); stl_be_p(&cbd[2], lba); break; + case CMD_ATAPI_START_STOP_UNIT: + g_assert_cmpuint(lba, ==, 0x00); + break; default: /* SCSI doesn't have uniform packet formats, * so you have to add support for it manually. Sorry! */ @@ -977,6 +1004,9 @@ static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes) cbd[7] = (tmp & 0xFF00) >> 8; cbd[8] = (tmp & 0xFF); break; + case CMD_ATAPI_START_STOP_UNIT: + g_assert_cmpuint(xbytes, ==, 0); + break; default: /* SCSI doesn't have uniform packet formats, * so you have to add support for it manually. Sorry! */ diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index bbe04f834a..05ce3de47f 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -287,8 +287,9 @@ enum { /* ATAPI Commands */ enum { - CMD_ATAPI_READ_10 = 0x28, - CMD_ATAPI_READ_CD = 0xbe, + CMD_ATAPI_START_STOP_UNIT = 0x1b, + CMD_ATAPI_READ_10 = 0x28, + CMD_ATAPI_READ_CD = 0xbe, }; /* AHCI Command Header Flags & Masks*/ @@ -600,6 +601,8 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void *buffer, size_t bufsize, uint64_t sector); void ahci_exec(AHCIQState *ahci, uint8_t port, uint8_t op, const AHCIOpts *opts); +void ahci_atapi_eject(AHCIQState *ahci, uint8_t port); +void ahci_atapi_load(AHCIQState *ahci, uint8_t port); /* Command: Fine-grained lifecycle */ AHCICommand *ahci_command_create(uint8_t command_name); -- cgit v1.2.3 From e0a4cb2c7da23c2f0e6364214de5d84f35ce4d5d Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Nov 2016 11:15:55 -0500 Subject: libqos/ahci: Add get_sense and test_ready Required for tray tests once a medium may have changed. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Message-id: 1478553214-497-6-git-send-email-jsnow@redhat.com [Line length edit --js] Signed-off-by: John Snow --- tests/libqos/ahci.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/ahci.h | 17 +++++++++++++++++ 2 files changed, 67 insertions(+) (limited to 'tests/libqos') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 79398b4085..1ca7f456b5 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -882,6 +882,49 @@ AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd, uint16_t bcl) return cmd; } +void ahci_atapi_test_ready(AHCIQState *ahci, uint8_t port, + bool ready, uint8_t expected_sense) +{ + AHCICommand *cmd = ahci_atapi_command_create(CMD_ATAPI_TEST_UNIT_READY, 0); + ahci_command_set_size(cmd, 0); + if (!ready) { + cmd->interrupts |= AHCI_PX_IS_TFES; + cmd->errors |= expected_sense << 4; + } + ahci_command_commit(ahci, cmd, port); + ahci_command_issue(ahci, cmd); + ahci_command_verify(ahci, cmd); + ahci_command_free(cmd); +} + +static int copy_buffer(AHCIQState *ahci, AHCICommand *cmd, + const AHCIOpts *opts) +{ + unsigned char *rx = opts->opaque; + bufread(opts->buffer, rx, opts->size); + return 0; +} + +void ahci_atapi_get_sense(AHCIQState *ahci, uint8_t port, + uint8_t *sense, uint8_t *asc) +{ + unsigned char *rx; + AHCIOpts opts = { + .size = 18, + .atapi = true, + .post_cb = copy_buffer, + }; + rx = g_malloc(18); + opts.opaque = rx; + + ahci_exec(ahci, port, CMD_ATAPI_REQUEST_SENSE, &opts); + + *sense = rx[2]; + *asc = rx[12]; + + g_free(rx); +} + void ahci_atapi_eject(AHCIQState *ahci, uint8_t port) { AHCICommand *cmd = ahci_atapi_command_create(CMD_ATAPI_START_STOP_UNIT, 0); @@ -934,6 +977,8 @@ static void ahci_atapi_command_set_offset(AHCICommand *cmd, uint64_t lba) g_assert_cmpuint(lba, <=, UINT32_MAX); stl_be_p(&cbd[2], lba); break; + case CMD_ATAPI_REQUEST_SENSE: + case CMD_ATAPI_TEST_UNIT_READY: case CMD_ATAPI_START_STOP_UNIT: g_assert_cmpuint(lba, ==, 0x00); break; @@ -1004,6 +1049,11 @@ static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes) cbd[7] = (tmp & 0xFF00) >> 8; cbd[8] = (tmp & 0xFF); break; + case CMD_ATAPI_REQUEST_SENSE: + g_assert_cmpuint(xbytes, <=, UINT8_MAX); + cbd[4] = (uint8_t)xbytes; + break; + case CMD_ATAPI_TEST_UNIT_READY: case CMD_ATAPI_START_STOP_UNIT: g_assert_cmpuint(xbytes, ==, 0); break; diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 05ce3de47f..5f9627bb0f 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -287,11 +287,24 @@ enum { /* ATAPI Commands */ enum { + CMD_ATAPI_TEST_UNIT_READY = 0x00, + CMD_ATAPI_REQUEST_SENSE = 0x03, CMD_ATAPI_START_STOP_UNIT = 0x1b, CMD_ATAPI_READ_10 = 0x28, CMD_ATAPI_READ_CD = 0xbe, }; +enum { + SENSE_NO_SENSE = 0x00, + SENSE_NOT_READY = 0x02, + SENSE_UNIT_ATTENTION = 0x06, +}; + +enum { + ASC_MEDIUM_MAY_HAVE_CHANGED = 0x28, + ASC_MEDIUM_NOT_PRESENT = 0x3a, +}; + /* AHCI Command Header Flags & Masks*/ #define CMDH_CFL (0x1F) #define CMDH_ATAPI (0x20) @@ -601,6 +614,10 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void *buffer, size_t bufsize, uint64_t sector); void ahci_exec(AHCIQState *ahci, uint8_t port, uint8_t op, const AHCIOpts *opts); +void ahci_atapi_test_ready(AHCIQState *ahci, uint8_t port, bool ready, + uint8_t expected_sense); +void ahci_atapi_get_sense(AHCIQState *ahci, uint8_t port, + uint8_t *sense, uint8_t *asc); void ahci_atapi_eject(AHCIQState *ahci, uint8_t port); void ahci_atapi_load(AHCIQState *ahci, uint8_t port); -- cgit v1.2.3