All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64
@ 2016-09-28 18:51 Laurent Vivier
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 1/6] libqos: add PPC64 PCI support Laurent Vivier
                   ` (7 more replies)
  0 siblings, 8 replies; 34+ messages in thread
From: Laurent Vivier @ 2016-09-28 18:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: dgibson, thuth, qemu-ppc, Gerd Hoffmann, Greg Kurz, Laurent Vivier

This series enables USB tests on PPC64, and for
that implements libqos SPAPR PCI support.

v3:
- rebase
- minor fixes (commas, comments)
- add Greg's R-b

v2:
- rebase
- revert order in qtest_common_shutdown() to release
  PCI and then memory allocator
- remove useless byte-swapping in qpci-spapr.c
- compute machine endianness on qtest_init()
- introduce target_cpu_to_leXX()/target_cpu_to_beXX()
            target_leXX_to_cpu()/target_beXX_to_cpu()

Laurent Vivier (6):
  libqos: add PPC64 PCI support
  libqos: add PCI management in qtest_vboot()/qtest_shutdown()
  libqos: use generic qtest_shutdown()
  qtest: evaluate endianness of the target in qtest_init()
  qtest: define target cpu endianness conversion functions
  tests: enable ohci/uhci/xhci tests on PPC64

 tests/Makefile.include      |   9 +-
 tests/e1000e-test.c         |   2 +-
 tests/i440fx-test.c         |   2 +-
 tests/ide-test.c            |   2 +-
 tests/ivshmem-test.c        |   2 +-
 tests/libqos/ahci.c         |   2 +-
 tests/libqos/libqos-pc.c    |   8 +-
 tests/libqos/libqos-spapr.c |   8 +-
 tests/libqos/libqos.c       |  32 ++++-
 tests/libqos/libqos.h       |  11 +-
 tests/libqos/pci-pc.c       |  24 +---
 tests/libqos/pci-pc.h       |   3 +-
 tests/libqos/pci-spapr.c    | 280 ++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/pci-spapr.h    |  17 +++
 tests/libqos/pci.c          |  22 +++-
 tests/libqos/rtas.c         |  45 +++++++
 tests/libqos/rtas.h         |   4 +
 tests/libqos/usb.c          |   2 +-
 tests/libqos/virtio-pci.c   |   2 +-
 tests/libqtest.c            |  96 ++++++++-------
 tests/libqtest.h            |  71 ++++++++++-
 tests/q35-test.c            |   2 +-
 tests/rtas-test.c           |   2 +-
 tests/rtl8139-test.c        |   2 +-
 tests/tco-test.c            |   2 +-
 tests/usb-hcd-ehci-test.c   |   2 +-
 tests/usb-hcd-uhci-test.c   |  24 ++--
 tests/vhost-user-test.c     |   4 +-
 tests/virtio-9p-test.c      |   2 +-
 tests/virtio-blk-test.c     |   4 +-
 tests/virtio-net-test.c     |   2 +-
 tests/virtio-scsi-test.c    |   2 +-
 32 files changed, 580 insertions(+), 112 deletions(-)
 create mode 100644 tests/libqos/pci-spapr.c
 create mode 100644 tests/libqos/pci-spapr.h

-- 
2.5.5

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
@ 2016-09-28 18:51 ` Laurent Vivier
  2016-09-29  5:27   ` [Qemu-devel] [Qemu-ppc] " David Gibson
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 2/6] libqos: add PCI management in qtest_vboot()/qtest_shutdown() Laurent Vivier
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 34+ messages in thread
From: Laurent Vivier @ 2016-09-28 18:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: dgibson, thuth, qemu-ppc, Gerd Hoffmann, Greg Kurz, Laurent Vivier

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
 tests/Makefile.include   |   1 +
 tests/libqos/pci-pc.c    |  22 ----
 tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/pci-spapr.h |  17 +++
 tests/libqos/pci.c       |  22 +++-
 tests/libqos/rtas.c      |  45 ++++++++
 tests/libqos/rtas.h      |   4 +
 7 files changed, 368 insertions(+), 23 deletions(-)
 create mode 100644 tests/libqos/pci-spapr.c
 create mode 100644 tests/libqos/pci-spapr.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8162f6f..92c82d8 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
 libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
 libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
 libqos-spapr-obj-y += tests/libqos/rtas.o
+libqos-spapr-obj-y += tests/libqos/pci-spapr.o
 libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
 libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 1ae2d37..82066b8 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 0000000..78df823
--- /dev/null
+++ b/tests/libqos/pci-spapr.c
@@ -0,0 +1,280 @@
+/*
+ * 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;
+
+static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
+{
+    uint64_t port = (uint64_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 = (uint64_t)addr;
+    uint16_t v;
+    if (port < SPAPR_PCI_IO_WIN_SIZE) {
+        v = readw(IOBASE(0) + port);
+    } else {
+        v = readw(MMIOBASE(0) + port);
+    }
+    return v;
+}
+
+static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr)
+{
+    uint64_t port = (uint64_t)addr;
+    uint32_t v;
+    if (port < SPAPR_PCI_IO_WIN_SIZE) {
+        v = readl(IOBASE(0) + port);
+    } else {
+        v = readl(MMIOBASE(0) + port);
+    }
+    return v;
+}
+
+static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
+{
+    uint64_t port = (uint64_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 = (uint64_t)addr;
+    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 = (uint64_t)addr;
+    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 0000000..4192126
--- /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 ed78d91..c3f3382 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 820321a..0269803 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 a1b60a8..498eb19 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 */
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v3 2/6] libqos: add PCI management in qtest_vboot()/qtest_shutdown()
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 1/6] libqos: add PPC64 PCI support Laurent Vivier
@ 2016-09-28 18:51 ` Laurent Vivier
  2016-09-29  5:30   ` [Qemu-devel] [Qemu-ppc] " David Gibson
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 3/6] libqos: use generic qtest_shutdown() Laurent Vivier
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 34+ messages in thread
From: Laurent Vivier @ 2016-09-28 18:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: dgibson, thuth, qemu-ppc, Gerd Hoffmann, Greg Kurz, Laurent Vivier

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 tests/e1000e-test.c         |  2 +-
 tests/i440fx-test.c         |  2 +-
 tests/ide-test.c            |  2 +-
 tests/ivshmem-test.c        |  2 +-
 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 ++-
 tests/q35-test.c            |  2 +-
 tests/rtl8139-test.c        |  2 +-
 tests/tco-test.c            |  2 +-
 tests/usb-hcd-ehci-test.c   |  2 +-
 tests/usb-hcd-uhci-test.c   |  2 +-
 tests/vhost-user-test.c     |  4 ++--
 tests/virtio-9p-test.c      |  2 +-
 tests/virtio-blk-test.c     |  2 +-
 tests/virtio-net-test.c     |  2 +-
 tests/virtio-scsi-test.c    |  2 +-
 21 files changed, 46 insertions(+), 25 deletions(-)

diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index d497b08..3979b20 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -390,7 +390,7 @@ static void data_test_init(e1000e_device *d)
     qtest_start(cmdline);
     g_free(cmdline);
 
-    test_bus = qpci_init_pc();
+    test_bus = qpci_init_pc(NULL);
     g_assert_nonnull(test_bus);
 
     test_alloc = pc_alloc_init();
diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
index 3542ad1..da2d5a5 100644
--- a/tests/i440fx-test.c
+++ b/tests/i440fx-test.c
@@ -38,7 +38,7 @@ static QPCIBus *test_start_get_bus(const TestData *s)
     cmdline = g_strdup_printf("-smp %d", s->num_cpus);
     qtest_start(cmdline);
     g_free(cmdline);
-    return qpci_init_pc();
+    return qpci_init_pc(NULL);
 }
 
 static void test_i440fx_defaults(gconstpointer opaque)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 1e51af2..a8a4081 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -143,7 +143,7 @@ static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
     uint16_t vendor_id, device_id;
 
     if (!pcibus) {
-        pcibus = qpci_init_pc();
+        pcibus = qpci_init_pc(NULL);
     }
 
     /* Find PCI device and verify it's the right one */
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index 0957ee7..f36bfe7 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -105,7 +105,7 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
     uint64_t barsize;
 
     s->qtest = qtest_start(cmd);
-    s->pcibus = qpci_init_pc();
+    s->pcibus = qpci_init_pc(NULL);
     s->dev = get_device(s->pcibus);
 
     s->reg_base = qpci_iomap(s->dev, 0, &barsize);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index f3be550..716ab79 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 df34092..aa17c98 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 f19408b..333e6fb 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 a852dc5..d842bf5 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 604980d..a9f6990 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 82066b8..9600ed6 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 2621179..9479b51 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
diff --git a/tests/q35-test.c b/tests/q35-test.c
index 71538fc..763fe3d 100644
--- a/tests/q35-test.c
+++ b/tests/q35-test.c
@@ -42,7 +42,7 @@ static void test_smram_lock(void)
     QPCIDevice *pcidev;
     QDict *response;
 
-    pcibus = qpci_init_pc();
+    pcibus = qpci_init_pc(NULL);
     g_assert(pcibus != NULL);
 
     pcidev = qpci_device_find(pcibus, 0);
diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
index 13de7ee..c2f601a 100644
--- a/tests/rtl8139-test.c
+++ b/tests/rtl8139-test.c
@@ -35,7 +35,7 @@ static QPCIDevice *get_device(void)
 {
     QPCIDevice *dev;
 
-    pcibus = qpci_init_pc();
+    pcibus = qpci_init_pc(NULL);
     qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
     g_assert(dev != NULL);
 
diff --git a/tests/tco-test.c b/tests/tco-test.c
index 0d13aa8..0d201b1 100644
--- a/tests/tco-test.c
+++ b/tests/tco-test.c
@@ -57,7 +57,7 @@ static void test_init(TestData *d)
     qtest_irq_intercept_in(qs, "ioapic");
     g_free(s);
 
-    bus = qpci_init_pc();
+    bus = qpci_init_pc(NULL);
     d->dev = qpci_device_find(bus, QPCI_DEVFN(0x1f, 0x00));
     g_assert(d->dev != NULL);
 
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
index eb247ad..a4ceeaa 100644
--- a/tests/usb-hcd-ehci-test.c
+++ b/tests/usb-hcd-ehci-test.c
@@ -56,7 +56,7 @@ static void pci_init(void)
     if (pcibus) {
         return;
     }
-    pcibus = qpci_init_pc();
+    pcibus = qpci_init_pc(NULL);
     g_assert(pcibus != NULL);
 
     qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
index 5cd59ad..c24063e 100644
--- a/tests/usb-hcd-uhci-test.c
+++ b/tests/usb-hcd-uhci-test.c
@@ -23,7 +23,7 @@ static void test_port(int port)
     struct qhc uhci;
 
     g_assert(port > 0);
-    pcibus = qpci_init_pc();
+    pcibus = qpci_init_pc(NULL);
     g_assert(pcibus != NULL);
     qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
     uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index a39846e..d7c48c5 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -163,7 +163,7 @@ static void init_virtio_dev(TestServer *s)
     QVirtioPCIDevice *dev;
     uint32_t features;
 
-    bus = qpci_init_pc();
+    bus = qpci_init_pc(NULL);
     g_assert_nonnull(bus);
 
     dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
@@ -884,7 +884,7 @@ static void test_multiqueue(void)
     qtest_start(cmd);
     g_free(cmd);
 
-    bus = qpci_init_pc();
+    bus = qpci_init_pc(NULL);
     dev = virtio_net_pci_init(bus, PCI_SLOT);
 
     alloc = pc_alloc_init();
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index b8fb6cd..e8b2196 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -63,7 +63,7 @@ static QVirtIO9P *qvirtio_9p_pci_init(void)
 
     v9p = g_new0(QVirtIO9P, 1);
     v9p->alloc = pc_alloc_init();
-    v9p->bus = qpci_init_pc();
+    v9p->bus = qpci_init_pc(NULL);
 
     dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P);
     g_assert_nonnull(dev);
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 811cf75..3c4fecc 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -75,7 +75,7 @@ static QPCIBus *pci_test_start(void)
     g_free(tmp_path);
     g_free(cmdline);
 
-    return qpci_init_pc();
+    return qpci_init_pc(NULL);
 }
 
 static void arm_test_start(void)
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index 361506f..a343a6b 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -62,7 +62,7 @@ static QPCIBus *pci_test_start(int socket)
     qtest_start(cmdline);
     g_free(cmdline);
 
-    return qpci_init_pc();
+    return qpci_init_pc(NULL);
 }
 
 static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev)
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index f1489e6..79088bb 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -146,7 +146,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
 
     vs = g_new0(QVirtIOSCSI, 1);
     vs->alloc = pc_alloc_init();
-    vs->bus = qpci_init_pc();
+    vs->bus = qpci_init_pc(NULL);
 
     dev = qvirtio_pci_device_find(vs->bus, VIRTIO_ID_SCSI);
     vs->dev = (QVirtioDevice *)dev;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v3 3/6] libqos: use generic qtest_shutdown()
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 1/6] libqos: add PPC64 PCI support Laurent Vivier
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 2/6] libqos: add PCI management in qtest_vboot()/qtest_shutdown() Laurent Vivier
@ 2016-09-28 18:51 ` Laurent Vivier
  2016-09-29  5:31   ` [Qemu-devel] [Qemu-ppc] " David Gibson
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 4/6] qtest: evaluate endianness of the target in qtest_init() Laurent Vivier
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 34+ messages in thread
From: Laurent Vivier @ 2016-09-28 18:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: dgibson, thuth, qemu-ppc, Gerd Hoffmann, Greg Kurz, Laurent Vivier

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 <lvivier@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 tests/libqos/libqos-pc.c    |  3 ++-
 tests/libqos/libqos-spapr.c |  3 ++-
 tests/libqos/libqos.c       | 11 ++++++++++-
 tests/libqos/libqos.h       |  8 ++++++--
 tests/rtas-test.c           |  2 +-
 5 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
index aa17c98..b554758 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 333e6fb..a37791e 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 d842bf5..7abb482 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 a9f6990..2319697 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);
diff --git a/tests/rtas-test.c b/tests/rtas-test.c
index 73c7803..ba0867a 100644
--- a/tests/rtas-test.c
+++ b/tests/rtas-test.c
@@ -22,7 +22,7 @@ static void test_rtas_get_time_of_day(void)
     t2 = mktimegm(&tm);
     g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
 
-    qtest_spapr_shutdown(qs);
+    qtest_shutdown(qs);
 }
 
 int main(int argc, char *argv[])
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v3 4/6] qtest: evaluate endianness of the target in qtest_init()
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
                   ` (2 preceding siblings ...)
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 3/6] libqos: use generic qtest_shutdown() Laurent Vivier
@ 2016-09-28 18:51 ` Laurent Vivier
  2016-09-29  5:31   ` [Qemu-devel] [Qemu-ppc] " David Gibson
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions Laurent Vivier
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 34+ messages in thread
From: Laurent Vivier @ 2016-09-28 18:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: dgibson, thuth, qemu-ppc, Gerd Hoffmann, Greg Kurz, Laurent Vivier

This allows to store it and not have to rescan the list
each time we need it.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 tests/libqos/virtio-pci.c |  2 +-
 tests/libqtest.c          | 96 +++++++++++++++++++++++++----------------------
 tests/libqtest.h          | 16 ++++++--
 tests/virtio-blk-test.c   |  2 +-
 4 files changed, 66 insertions(+), 50 deletions(-)

diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 18b92b9..6e005c1 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;
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 6f6bdf1..aa4bc9e 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -37,6 +37,7 @@ struct QTestState
     bool irq_level[MAX_IRQ];
     GString *rx;
     pid_t qemu_pid;  /* our child QEMU process */
+    bool big_endian;
 };
 
 static GHookList abrt_hooks;
@@ -146,6 +147,52 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data)
     g_hook_prepend(&abrt_hooks, hook);
 }
 
+static bool arch_is_big_endian(const char *arch)
+{
+    int i;
+    static const struct {
+        const char *arch;
+        bool big_endian;
+    } endianness[] = {
+        { "aarch64", false },
+        { "alpha", false },
+        { "arm", false },
+        { "cris", false },
+        { "i386", false },
+        { "lm32", true },
+        { "m68k", true },
+        { "microblaze", true },
+        { "microblazeel", false },
+        { "mips", true },
+        { "mips64", true },
+        { "mips64el", false },
+        { "mipsel", false },
+        { "moxie", true },
+        { "or32", true },
+        { "ppc", true },
+        { "ppc64", true },
+        { "ppcemb", true },
+        { "s390x", true },
+        { "sh4", false },
+        { "sh4eb", true },
+        { "sparc", true },
+        { "sparc64", true },
+        { "unicore32", false },
+        { "x86_64", false },
+        { "xtensa", false },
+        { "xtensaeb", true },
+        { "tricore", false },
+        {},
+    };
+
+    for (i = 0; endianness[i].arch; i++) {
+        if (strcmp(endianness[i].arch, arch) == 0) {
+            return endianness[i].big_endian;
+        }
+    }
+    g_assert_not_reached();
+}
+
 QTestState *qtest_init(const char *extra_args)
 {
     QTestState *s;
@@ -209,6 +256,8 @@ QTestState *qtest_init(const char *extra_args)
         kill(s->qemu_pid, SIGSTOP);
     }
 
+    s->big_endian = arch_is_big_endian(qtest_get_arch());
+
     return s;
 }
 
@@ -886,50 +935,7 @@ char *hmp(const char *fmt, ...)
     return ret;
 }
 
-bool qtest_big_endian(void)
+bool qtest_big_endian(QTestState *s)
 {
-    const char *arch = qtest_get_arch();
-    int i;
-
-    static const struct {
-        const char *arch;
-        bool big_endian;
-    } endianness[] = {
-        { "aarch64", false },
-        { "alpha", false },
-        { "arm", false },
-        { "cris", false },
-        { "i386", false },
-        { "lm32", true },
-        { "m68k", true },
-        { "microblaze", true },
-        { "microblazeel", false },
-        { "mips", true },
-        { "mips64", true },
-        { "mips64el", false },
-        { "mipsel", false },
-        { "moxie", true },
-        { "or32", true },
-        { "ppc", true },
-        { "ppc64", true },
-        { "ppcemb", true },
-        { "s390x", true },
-        { "sh4", false },
-        { "sh4eb", true },
-        { "sparc", true },
-        { "sparc64", true },
-        { "unicore32", false },
-        { "x86_64", false },
-        { "xtensa", false },
-        { "xtensaeb", true },
-        {},
-    };
-
-    for (i = 0; endianness[i].arch; i++) {
-        if (strcmp(endianness[i].arch, arch) == 0) {
-            return endianness[i].big_endian;
-        }
-    }
-
-    return false;
+    return s->big_endian;
 }
diff --git a/tests/libqtest.h b/tests/libqtest.h
index f7402e0..4be1f77 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -410,6 +410,14 @@ int64_t qtest_clock_step(QTestState *s, int64_t step);
 int64_t qtest_clock_set(QTestState *s, int64_t val);
 
 /**
+ * qtest_big_endian:
+ * @s: QTestState instance to operate on.
+ *
+ * Returns: True if the architecture under test has a big endian configuration.
+ */
+bool qtest_big_endian(QTestState *s);
+
+/**
  * qtest_get_arch:
  *
  * Returns: The architecture for the QEMU executable under test.
@@ -874,12 +882,14 @@ static inline int64_t clock_set(int64_t val)
 }
 
 /**
- * qtest_big_endian:
+ * target_big_endian:
  *
  * Returns: True if the architecture under test has a big endian configuration.
  */
-bool qtest_big_endian(void);
-
+static inline bool target_big_endian(void)
+{
+    return qtest_big_endian(global_qtest);
+}
 
 QDict *qmp_fd_receive(int fd);
 void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 3c4fecc..0506917 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -125,7 +125,7 @@ static inline void virtio_blk_fix_request(QVirtioBlkReq *req)
     bool host_endian = false;
 #endif
 
-    if (qtest_big_endian() != host_endian) {
+    if (target_big_endian() != host_endian) {
         req->type = bswap32(req->type);
         req->ioprio = bswap32(req->ioprio);
         req->sector = bswap64(req->sector);
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
                   ` (3 preceding siblings ...)
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 4/6] qtest: evaluate endianness of the target in qtest_init() Laurent Vivier
@ 2016-09-28 18:51 ` Laurent Vivier
  2016-09-29  5:33   ` [Qemu-devel] [Qemu-ppc] " David Gibson
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 6/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 34+ messages in thread
From: Laurent Vivier @ 2016-09-28 18:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: dgibson, thuth, qemu-ppc, Gerd Hoffmann, Greg Kurz, Laurent Vivier

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
 tests/libqtest.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/tests/libqtest.h b/tests/libqtest.h
index 4be1f77..b3ac7d8 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -17,6 +17,7 @@
 #ifndef LIBQTEST_H
 #define LIBQTEST_H
 
+#include "qemu/bswap.h"
 #include "qapi/qmp/qdict.h"
 
 typedef struct QTestState QTestState;
@@ -891,6 +892,62 @@ static inline bool target_big_endian(void)
     return qtest_big_endian(global_qtest);
 }
 
+/* Endianness conversion function between target cpu and specified endianess
+ *
+ * uint16_t target_le16_to_cpu(uint16_t v);
+ * uint32_t target_le32_to_cpu(uint32_t v);
+ * uint64_t target_le64_to_cpu(uint64_t v);
+ * uint16_t target_be16_to_cpu(uint16_t v);
+ * uint32_t target_be32_to_cpu(uint32_t v);
+ * uint64_t target_be64_to_cpu(uint64_t v);
+ *
+ * Convert the value @v from the specified format to the native
+ * endianness of the target CPU by byteswapping if necessary, and
+ * return the converted value.
+ *
+ * uint16_t target_cpu_to_le16(uint16_t v);
+ * uint32_t target_cpu_to_le32(uint32_t v);
+ * uint64_t target_cpu_to_le64(uint64_t v);
+ * uint16_t target_cpu_to_be16(uint16_t v);
+ * uint32_t target_cpu_to_be32(uint32_t v);
+ * uint64_t target_cpu_to_be64(uint64_t v);
+ *
+ * Convert the value @v from the native endianness of the target CPU to
+ * the specified format by byteswapping if necessary, and return
+ * the converted value.
+ *
+ * Both target_X_to_cpu() and target_cpu_to_X() perform the same operation; you
+ * should use whichever one is better documenting of the function your
+ * code is performing.
+ *
+ */
+
+#define le_bswap(s, v, size) (qtest_big_endian(s) ? bswap ## size(v) : (v))
+#define be_bswap(s, v, size) (qtest_big_endian(s) ? (v) : bswap ## size(v))
+
+#define TARGET_CPU_CONVERT(endian, size, type)\
+static inline type target_ ## endian ## size ## _to_cpu(type v)\
+{\
+    return glue(endian, _bswap)(global_qtest, v, size);\
+} \
+\
+static inline type target_cpu_to_ ## endian ## size(type v)\
+{\
+    return glue(endian, _bswap)(global_qtest, v, size);\
+}
+
+TARGET_CPU_CONVERT(be, 16, uint16_t)
+TARGET_CPU_CONVERT(be, 32, uint32_t)
+TARGET_CPU_CONVERT(be, 64, uint64_t)
+
+TARGET_CPU_CONVERT(le, 16, uint16_t)
+TARGET_CPU_CONVERT(le, 32, uint32_t)
+TARGET_CPU_CONVERT(le, 64, uint64_t)
+
+#undef TARGET_CPU_CONVERT
+#undef be_bswap
+#undef le_bswap
+
 QDict *qmp_fd_receive(int fd);
 void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
 void qmp_fd_send(int fd, const char *fmt, ...);
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [Qemu-devel] [PATCH v3 6/6] tests: enable ohci/uhci/xhci tests on PPC64
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
                   ` (4 preceding siblings ...)
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions Laurent Vivier
@ 2016-09-28 18:51 ` Laurent Vivier
  2016-10-04 13:20   ` [Qemu-devel] [Qemu-ppc] " Thomas Huth
  2016-09-28 19:24 ` [Qemu-devel] [PATCH v3 0/6] " no-reply
  2016-09-29  5:35 ` [Qemu-devel] [Qemu-ppc] " David Gibson
  7 siblings, 1 reply; 34+ messages in thread
From: Laurent Vivier @ 2016-09-28 18:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: dgibson, thuth, qemu-ppc, Gerd Hoffmann, Greg Kurz, Laurent Vivier

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
 tests/Makefile.include    |  8 +++++++-
 tests/libqos/usb.c        |  2 +-
 tests/usb-hcd-uhci-test.c | 24 ++++++++++++++++--------
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 92c82d8..30c4e9e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -271,6 +271,12 @@ check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
 check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
 check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
 check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
+check-qtest-ppc64-y += tests/usb-hcd-ohci-test$(EXESUF)
+gcov-files-ppc64-y += hw/usb/hcd-ohci.c
+check-qtest-ppc64-y += tests/usb-hcd-uhci-test$(EXESUF)
+gcov-files-ppc64-y += hw/usb/hcd-uhci.c
+check-qtest-ppc64-y += tests/usb-hcd-xhci-test$(EXESUF)
+gcov-files-ppc64-y += hw/usb/hcd-xhci.c
 
 check-qtest-sh4-y = tests/endianness-test$(EXESUF)
 
@@ -596,7 +602,7 @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
 libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
-libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
+libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
 
 tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
diff --git a/tests/libqos/usb.c b/tests/libqos/usb.c
index f794d92..25e5f38 100644
--- a/tests/libqos/usb.c
+++ b/tests/libqos/usb.c
@@ -28,7 +28,7 @@ void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc, uint32_t devfn, int bar)
 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 = target_le16_to_cpu(qpci_io_readw(hc->dev, addr));
     uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
 
     g_assert((value & mask) == (expect & mask));
diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
index c24063e..4b951ce 100644
--- a/tests/usb-hcd-uhci-test.c
+++ b/tests/usb-hcd-uhci-test.c
@@ -9,9 +9,13 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/libqos.h"
 #include "libqos/usb.h"
+#include "libqos/libqos-pc.h"
+#include "libqos/libqos-spapr.h"
 #include "hw/usb/uhci-regs.h"
 
+static QOSState *qs;
 
 static void test_uhci_init(void)
 {
@@ -19,13 +23,10 @@ static void test_uhci_init(void)
 
 static void test_port(int port)
 {
-    QPCIBus *pcibus;
     struct qhc uhci;
 
     g_assert(port > 0);
-    pcibus = qpci_init_pc(NULL);
-    g_assert(pcibus != NULL);
-    qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
+    qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
     uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
 }
 
@@ -75,6 +76,7 @@ static void test_usb_storage_hotplug(void)
 
 int main(int argc, char **argv)
 {
+    const char *arch = qtest_get_arch();
     int ret;
 
     g_test_init(&argc, &argv, NULL);
@@ -84,11 +86,17 @@ int main(int argc, char **argv)
     qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug);
     qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
 
-    qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0"
-                " -drive id=drive0,if=none,file=/dev/null,format=raw"
-                " -device usb-tablet,bus=uhci.0,port=1");
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
+                           " -drive id=drive0,if=none,file=/dev/null,format=raw"
+                           " -device usb-tablet,bus=uhci.0,port=1");
+    } else if (strcmp(arch, "ppc64") == 0) {
+        qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
+                           " -drive id=drive0,if=none,file=/dev/null,format=raw"
+                           " -device usb-tablet,bus=uhci.0,port=1");
+    }
     ret = g_test_run();
-    qtest_end();
+    qtest_shutdown(qs);
 
     return ret;
 }
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
                   ` (5 preceding siblings ...)
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 6/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
@ 2016-09-28 19:24 ` no-reply
  2016-09-29  5:35 ` [Qemu-devel] [Qemu-ppc] " David Gibson
  7 siblings, 0 replies; 34+ messages in thread
From: no-reply @ 2016-09-28 19:24 UTC (permalink / raw)
  To: lvivier; +Cc: famz, qemu-devel, thuth, groug, qemu-ppc, kraxel, dgibson

Hi,

Your series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 1475088693-29091-1-git-send-email-lvivier@redhat.com
Subject: [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

# Useful git options
git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git show --no-patch --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]         patchew/1475088693-29091-1-git-send-email-lvivier@redhat.com -> patchew/1475088693-29091-1-git-send-email-lvivier@redhat.com
Switched to a new branch 'test'
16102fa tests: enable ohci/uhci/xhci tests on PPC64
5401f55 qtest: define target cpu endianness conversion functions
d59bad7 qtest: evaluate endianness of the target in qtest_init()
6c93deb libqos: use generic qtest_shutdown()
6f269e3 libqos: add PCI management in qtest_vboot()/qtest_shutdown()
0f72509 libqos: add PPC64 PCI support

=== OUTPUT BEGIN ===
Checking PATCH 1/6: libqos: add PPC64 PCI support...
Checking PATCH 2/6: libqos: add PCI management in qtest_vboot()/qtest_shutdown()...
Checking PATCH 3/6: libqos: use generic qtest_shutdown()...
Checking PATCH 4/6: qtest: evaluate endianness of the target in qtest_init()...
Checking PATCH 5/6: qtest: define target cpu endianness conversion functions...
ERROR: Macros with multiple statements should be enclosed in a do - while loop
#58: FILE: tests/libqtest.h:928:
+#define TARGET_CPU_CONVERT(endian, size, type)\
+static inline type target_ ## endian ## size ## _to_cpu(type v)\
+{\
+    return glue(endian, _bswap)(global_qtest, v, size);\
+} \
+\
+static inline type target_cpu_to_ ## endian ## size(type v)\
+{\
+    return glue(endian, _bswap)(global_qtest, v, size);\
+}

total: 1 errors, 0 warnings, 69 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 6/6: tests: enable ohci/uhci/xhci tests on PPC64...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 1/6] libqos: add PPC64 PCI support Laurent Vivier
@ 2016-09-29  5:27   ` David Gibson
  2016-10-03 11:23     ` Cédric Le Goater
  0 siblings, 1 reply; 34+ messages in thread
From: David Gibson @ 2016-09-29  5:27 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 17020 bytes --]

On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> ---
>  tests/Makefile.include   |   1 +
>  tests/libqos/pci-pc.c    |  22 ----
>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
>  tests/libqos/pci-spapr.h |  17 +++
>  tests/libqos/pci.c       |  22 +++-
>  tests/libqos/rtas.c      |  45 ++++++++
>  tests/libqos/rtas.h      |   4 +
>  7 files changed, 368 insertions(+), 23 deletions(-)
>  create mode 100644 tests/libqos/pci-spapr.c
>  create mode 100644 tests/libqos/pci-spapr.h
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 8162f6f..92c82d8 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>  libqos-spapr-obj-y += tests/libqos/rtas.o
> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>  libqos-pc-obj-y += tests/libqos/ahci.o
> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> index 1ae2d37..82066b8 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 0000000..78df823
> --- /dev/null
> +++ b/tests/libqos/pci-spapr.c
> @@ -0,0 +1,280 @@
> +/*
> + * 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;
> +
> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> +{
> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> +    uint16_t v;
> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> +        v = readw(IOBASE(0) + port);
> +    } else {
> +        v = readw(MMIOBASE(0) + port);
> +    }

Ok, so, I've looked through the qtest stuff in more detail now, and
I've got a better idea of how the endianness works.  Some of my
earlier comments were confused about which pieces were in the test
case side and which were on the qtest accel stub side.

So, what I think you need is an unconditional byteswap in each of the
spapr pci IO functions.  Why?

   * The plain readw() etc. functions return values read from memory
     assuming guest endianness.  For guest native values in memory, so
     far so good.
   * Generic users of the pci read/write functions in qtest expect to
     get native values.
   * But PCI devices are always LE, not guest endian

The guest endianness of spapr (as far as tswap() etc. are concerned)
is BE, even though that's not really true in practice these days, so
to correct for the PCI registers being read as BE when they should be
LE we always need a swap.

That should remove the need for swaps further up the test stack.

Of course, "guest endianness" is a poorly defined concept, so longer
term it might be better to completely replace the "readw" etc. qtest
operations with explicit "readw_le" and "readw_be" ops.

> +    return v;
> +}
> +
> +static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr)
> +{
> +    uint64_t port = (uint64_t)addr;
> +    uint32_t v;
> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> +        v = readl(IOBASE(0) + port);
> +    } else {
> +        v = readl(MMIOBASE(0) + port);
> +    }
> +    return v;
> +}
> +
> +static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
> +{
> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> +    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 = (uint64_t)addr;
> +    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 0000000..4192126
> --- /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 ed78d91..c3f3382 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 820321a..0269803 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 a1b60a8..498eb19 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 */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 2/6] libqos: add PCI management in qtest_vboot()/qtest_shutdown()
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 2/6] libqos: add PCI management in qtest_vboot()/qtest_shutdown() Laurent Vivier
@ 2016-09-29  5:30   ` David Gibson
  0 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2016-09-29  5:30 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 12549 bytes --]

On Wed, Sep 28, 2016 at 08:51:29PM +0200, Laurent Vivier wrote:
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> Reviewed-by: Greg Kurz <groug@kaod.org>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  tests/e1000e-test.c         |  2 +-
>  tests/i440fx-test.c         |  2 +-
>  tests/ide-test.c            |  2 +-
>  tests/ivshmem-test.c        |  2 +-
>  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 ++-
>  tests/q35-test.c            |  2 +-
>  tests/rtl8139-test.c        |  2 +-
>  tests/tco-test.c            |  2 +-
>  tests/usb-hcd-ehci-test.c   |  2 +-
>  tests/usb-hcd-uhci-test.c   |  2 +-
>  tests/vhost-user-test.c     |  4 ++--
>  tests/virtio-9p-test.c      |  2 +-
>  tests/virtio-blk-test.c     |  2 +-
>  tests/virtio-net-test.c     |  2 +-
>  tests/virtio-scsi-test.c    |  2 +-
>  21 files changed, 46 insertions(+), 25 deletions(-)
> 
> diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
> index d497b08..3979b20 100644
> --- a/tests/e1000e-test.c
> +++ b/tests/e1000e-test.c
> @@ -390,7 +390,7 @@ static void data_test_init(e1000e_device *d)
>      qtest_start(cmdline);
>      g_free(cmdline);
>  
> -    test_bus = qpci_init_pc();
> +    test_bus = qpci_init_pc(NULL);
>      g_assert_nonnull(test_bus);
>  
>      test_alloc = pc_alloc_init();
> diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
> index 3542ad1..da2d5a5 100644
> --- a/tests/i440fx-test.c
> +++ b/tests/i440fx-test.c
> @@ -38,7 +38,7 @@ static QPCIBus *test_start_get_bus(const TestData *s)
>      cmdline = g_strdup_printf("-smp %d", s->num_cpus);
>      qtest_start(cmdline);
>      g_free(cmdline);
> -    return qpci_init_pc();
> +    return qpci_init_pc(NULL);
>  }
>  
>  static void test_i440fx_defaults(gconstpointer opaque)
> diff --git a/tests/ide-test.c b/tests/ide-test.c
> index 1e51af2..a8a4081 100644
> --- a/tests/ide-test.c
> +++ b/tests/ide-test.c
> @@ -143,7 +143,7 @@ static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
>      uint16_t vendor_id, device_id;
>  
>      if (!pcibus) {
> -        pcibus = qpci_init_pc();
> +        pcibus = qpci_init_pc(NULL);
>      }
>  
>      /* Find PCI device and verify it's the right one */
> diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
> index 0957ee7..f36bfe7 100644
> --- a/tests/ivshmem-test.c
> +++ b/tests/ivshmem-test.c
> @@ -105,7 +105,7 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
>      uint64_t barsize;
>  
>      s->qtest = qtest_start(cmd);
> -    s->pcibus = qpci_init_pc();
> +    s->pcibus = qpci_init_pc(NULL);
>      s->dev = get_device(s->pcibus);
>  
>      s->reg_base = qpci_iomap(s->dev, 0, &barsize);
> diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
> index f3be550..716ab79 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 df34092..aa17c98 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 f19408b..333e6fb 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 a852dc5..d842bf5 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 604980d..a9f6990 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 82066b8..9600ed6 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 2621179..9479b51 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
> diff --git a/tests/q35-test.c b/tests/q35-test.c
> index 71538fc..763fe3d 100644
> --- a/tests/q35-test.c
> +++ b/tests/q35-test.c
> @@ -42,7 +42,7 @@ static void test_smram_lock(void)
>      QPCIDevice *pcidev;
>      QDict *response;
>  
> -    pcibus = qpci_init_pc();
> +    pcibus = qpci_init_pc(NULL);
>      g_assert(pcibus != NULL);
>  
>      pcidev = qpci_device_find(pcibus, 0);
> diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
> index 13de7ee..c2f601a 100644
> --- a/tests/rtl8139-test.c
> +++ b/tests/rtl8139-test.c
> @@ -35,7 +35,7 @@ static QPCIDevice *get_device(void)
>  {
>      QPCIDevice *dev;
>  
> -    pcibus = qpci_init_pc();
> +    pcibus = qpci_init_pc(NULL);
>      qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
>      g_assert(dev != NULL);
>  
> diff --git a/tests/tco-test.c b/tests/tco-test.c
> index 0d13aa8..0d201b1 100644
> --- a/tests/tco-test.c
> +++ b/tests/tco-test.c
> @@ -57,7 +57,7 @@ static void test_init(TestData *d)
>      qtest_irq_intercept_in(qs, "ioapic");
>      g_free(s);
>  
> -    bus = qpci_init_pc();
> +    bus = qpci_init_pc(NULL);
>      d->dev = qpci_device_find(bus, QPCI_DEVFN(0x1f, 0x00));
>      g_assert(d->dev != NULL);
>  
> diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
> index eb247ad..a4ceeaa 100644
> --- a/tests/usb-hcd-ehci-test.c
> +++ b/tests/usb-hcd-ehci-test.c
> @@ -56,7 +56,7 @@ static void pci_init(void)
>      if (pcibus) {
>          return;
>      }
> -    pcibus = qpci_init_pc();
> +    pcibus = qpci_init_pc(NULL);
>      g_assert(pcibus != NULL);
>  
>      qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
> diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
> index 5cd59ad..c24063e 100644
> --- a/tests/usb-hcd-uhci-test.c
> +++ b/tests/usb-hcd-uhci-test.c
> @@ -23,7 +23,7 @@ static void test_port(int port)
>      struct qhc uhci;
>  
>      g_assert(port > 0);
> -    pcibus = qpci_init_pc();
> +    pcibus = qpci_init_pc(NULL);
>      g_assert(pcibus != NULL);
>      qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
>      uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
> diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
> index a39846e..d7c48c5 100644
> --- a/tests/vhost-user-test.c
> +++ b/tests/vhost-user-test.c
> @@ -163,7 +163,7 @@ static void init_virtio_dev(TestServer *s)
>      QVirtioPCIDevice *dev;
>      uint32_t features;
>  
> -    bus = qpci_init_pc();
> +    bus = qpci_init_pc(NULL);
>      g_assert_nonnull(bus);
>  
>      dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
> @@ -884,7 +884,7 @@ static void test_multiqueue(void)
>      qtest_start(cmd);
>      g_free(cmd);
>  
> -    bus = qpci_init_pc();
> +    bus = qpci_init_pc(NULL);
>      dev = virtio_net_pci_init(bus, PCI_SLOT);
>  
>      alloc = pc_alloc_init();
> diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
> index b8fb6cd..e8b2196 100644
> --- a/tests/virtio-9p-test.c
> +++ b/tests/virtio-9p-test.c
> @@ -63,7 +63,7 @@ static QVirtIO9P *qvirtio_9p_pci_init(void)
>  
>      v9p = g_new0(QVirtIO9P, 1);
>      v9p->alloc = pc_alloc_init();
> -    v9p->bus = qpci_init_pc();
> +    v9p->bus = qpci_init_pc(NULL);
>  
>      dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P);
>      g_assert_nonnull(dev);
> diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
> index 811cf75..3c4fecc 100644
> --- a/tests/virtio-blk-test.c
> +++ b/tests/virtio-blk-test.c
> @@ -75,7 +75,7 @@ static QPCIBus *pci_test_start(void)
>      g_free(tmp_path);
>      g_free(cmdline);
>  
> -    return qpci_init_pc();
> +    return qpci_init_pc(NULL);
>  }
>  
>  static void arm_test_start(void)
> diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
> index 361506f..a343a6b 100644
> --- a/tests/virtio-net-test.c
> +++ b/tests/virtio-net-test.c
> @@ -62,7 +62,7 @@ static QPCIBus *pci_test_start(int socket)
>      qtest_start(cmdline);
>      g_free(cmdline);
>  
> -    return qpci_init_pc();
> +    return qpci_init_pc(NULL);
>  }
>  
>  static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev)
> diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
> index f1489e6..79088bb 100644
> --- a/tests/virtio-scsi-test.c
> +++ b/tests/virtio-scsi-test.c
> @@ -146,7 +146,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
>  
>      vs = g_new0(QVirtIOSCSI, 1);
>      vs->alloc = pc_alloc_init();
> -    vs->bus = qpci_init_pc();
> +    vs->bus = qpci_init_pc(NULL);
>  
>      dev = qvirtio_pci_device_find(vs->bus, VIRTIO_ID_SCSI);
>      vs->dev = (QVirtioDevice *)dev;

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 3/6] libqos: use generic qtest_shutdown()
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 3/6] libqos: use generic qtest_shutdown() Laurent Vivier
@ 2016-09-29  5:31   ` David Gibson
  0 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2016-09-29  5:31 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 4616 bytes --]

On Wed, Sep 28, 2016 at 08:51:30PM +0200, Laurent Vivier wrote:
> 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 <lvivier@redhat.com>
> Reviewed-by: Greg Kurz <groug@kaod.org>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  tests/libqos/libqos-pc.c    |  3 ++-
>  tests/libqos/libqos-spapr.c |  3 ++-
>  tests/libqos/libqos.c       | 11 ++++++++++-
>  tests/libqos/libqos.h       |  8 ++++++--
>  tests/rtas-test.c           |  2 +-
>  5 files changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
> index aa17c98..b554758 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 333e6fb..a37791e 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 d842bf5..7abb482 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 a9f6990..2319697 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);
> diff --git a/tests/rtas-test.c b/tests/rtas-test.c
> index 73c7803..ba0867a 100644
> --- a/tests/rtas-test.c
> +++ b/tests/rtas-test.c
> @@ -22,7 +22,7 @@ static void test_rtas_get_time_of_day(void)
>      t2 = mktimegm(&tm);
>      g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
>  
> -    qtest_spapr_shutdown(qs);
> +    qtest_shutdown(qs);
>  }
>  
>  int main(int argc, char *argv[])

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 4/6] qtest: evaluate endianness of the target in qtest_init()
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 4/6] qtest: evaluate endianness of the target in qtest_init() Laurent Vivier
@ 2016-09-29  5:31   ` David Gibson
  0 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2016-09-29  5:31 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 6635 bytes --]

On Wed, Sep 28, 2016 at 08:51:31PM +0200, Laurent Vivier wrote:
> This allows to store it and not have to rescan the list
> each time we need it.
> 
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> Reviewed-by: Greg Kurz <groug@kaod.org>

With the changes I've suggested to patch 1/6, I think this patch and
the next become unnecessary.

> ---
>  tests/libqos/virtio-pci.c |  2 +-
>  tests/libqtest.c          | 96 +++++++++++++++++++++++++----------------------
>  tests/libqtest.h          | 16 ++++++--
>  tests/virtio-blk-test.c   |  2 +-
>  4 files changed, 66 insertions(+), 50 deletions(-)
> 
> diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
> index 18b92b9..6e005c1 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;
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index 6f6bdf1..aa4bc9e 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -37,6 +37,7 @@ struct QTestState
>      bool irq_level[MAX_IRQ];
>      GString *rx;
>      pid_t qemu_pid;  /* our child QEMU process */
> +    bool big_endian;
>  };
>  
>  static GHookList abrt_hooks;
> @@ -146,6 +147,52 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data)
>      g_hook_prepend(&abrt_hooks, hook);
>  }
>  
> +static bool arch_is_big_endian(const char *arch)
> +{
> +    int i;
> +    static const struct {
> +        const char *arch;
> +        bool big_endian;
> +    } endianness[] = {
> +        { "aarch64", false },
> +        { "alpha", false },
> +        { "arm", false },
> +        { "cris", false },
> +        { "i386", false },
> +        { "lm32", true },
> +        { "m68k", true },
> +        { "microblaze", true },
> +        { "microblazeel", false },
> +        { "mips", true },
> +        { "mips64", true },
> +        { "mips64el", false },
> +        { "mipsel", false },
> +        { "moxie", true },
> +        { "or32", true },
> +        { "ppc", true },
> +        { "ppc64", true },
> +        { "ppcemb", true },
> +        { "s390x", true },
> +        { "sh4", false },
> +        { "sh4eb", true },
> +        { "sparc", true },
> +        { "sparc64", true },
> +        { "unicore32", false },
> +        { "x86_64", false },
> +        { "xtensa", false },
> +        { "xtensaeb", true },
> +        { "tricore", false },
> +        {},
> +    };
> +
> +    for (i = 0; endianness[i].arch; i++) {
> +        if (strcmp(endianness[i].arch, arch) == 0) {
> +            return endianness[i].big_endian;
> +        }
> +    }
> +    g_assert_not_reached();
> +}
> +
>  QTestState *qtest_init(const char *extra_args)
>  {
>      QTestState *s;
> @@ -209,6 +256,8 @@ QTestState *qtest_init(const char *extra_args)
>          kill(s->qemu_pid, SIGSTOP);
>      }
>  
> +    s->big_endian = arch_is_big_endian(qtest_get_arch());
> +
>      return s;
>  }
>  
> @@ -886,50 +935,7 @@ char *hmp(const char *fmt, ...)
>      return ret;
>  }
>  
> -bool qtest_big_endian(void)
> +bool qtest_big_endian(QTestState *s)
>  {
> -    const char *arch = qtest_get_arch();
> -    int i;
> -
> -    static const struct {
> -        const char *arch;
> -        bool big_endian;
> -    } endianness[] = {
> -        { "aarch64", false },
> -        { "alpha", false },
> -        { "arm", false },
> -        { "cris", false },
> -        { "i386", false },
> -        { "lm32", true },
> -        { "m68k", true },
> -        { "microblaze", true },
> -        { "microblazeel", false },
> -        { "mips", true },
> -        { "mips64", true },
> -        { "mips64el", false },
> -        { "mipsel", false },
> -        { "moxie", true },
> -        { "or32", true },
> -        { "ppc", true },
> -        { "ppc64", true },
> -        { "ppcemb", true },
> -        { "s390x", true },
> -        { "sh4", false },
> -        { "sh4eb", true },
> -        { "sparc", true },
> -        { "sparc64", true },
> -        { "unicore32", false },
> -        { "x86_64", false },
> -        { "xtensa", false },
> -        { "xtensaeb", true },
> -        {},
> -    };
> -
> -    for (i = 0; endianness[i].arch; i++) {
> -        if (strcmp(endianness[i].arch, arch) == 0) {
> -            return endianness[i].big_endian;
> -        }
> -    }
> -
> -    return false;
> +    return s->big_endian;
>  }
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index f7402e0..4be1f77 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -410,6 +410,14 @@ int64_t qtest_clock_step(QTestState *s, int64_t step);
>  int64_t qtest_clock_set(QTestState *s, int64_t val);
>  
>  /**
> + * qtest_big_endian:
> + * @s: QTestState instance to operate on.
> + *
> + * Returns: True if the architecture under test has a big endian configuration.
> + */
> +bool qtest_big_endian(QTestState *s);
> +
> +/**
>   * qtest_get_arch:
>   *
>   * Returns: The architecture for the QEMU executable under test.
> @@ -874,12 +882,14 @@ static inline int64_t clock_set(int64_t val)
>  }
>  
>  /**
> - * qtest_big_endian:
> + * target_big_endian:
>   *
>   * Returns: True if the architecture under test has a big endian configuration.
>   */
> -bool qtest_big_endian(void);
> -
> +static inline bool target_big_endian(void)
> +{
> +    return qtest_big_endian(global_qtest);
> +}
>  
>  QDict *qmp_fd_receive(int fd);
>  void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
> diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
> index 3c4fecc..0506917 100644
> --- a/tests/virtio-blk-test.c
> +++ b/tests/virtio-blk-test.c
> @@ -125,7 +125,7 @@ static inline void virtio_blk_fix_request(QVirtioBlkReq *req)
>      bool host_endian = false;
>  #endif
>  
> -    if (qtest_big_endian() != host_endian) {
> +    if (target_big_endian() != host_endian) {
>          req->type = bswap32(req->type);
>          req->ioprio = bswap32(req->ioprio);
>          req->sector = bswap64(req->sector);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions Laurent Vivier
@ 2016-09-29  5:33   ` David Gibson
  2016-09-29  7:23     ` Laurent Vivier
  0 siblings, 1 reply; 34+ messages in thread
From: David Gibson @ 2016-09-29  5:33 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 3355 bytes --]

On Wed, Sep 28, 2016 at 08:51:32PM +0200, Laurent Vivier wrote:
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>

So, I think the right place to do the necessary endianness conversion
is the PCI accessor helpers, as noted elsewhere.

However, even ignoring that, I can't actually see anything in your
series that uses these new functions.

> ---
>  tests/libqtest.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index 4be1f77..b3ac7d8 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -17,6 +17,7 @@
>  #ifndef LIBQTEST_H
>  #define LIBQTEST_H
>  
> +#include "qemu/bswap.h"
>  #include "qapi/qmp/qdict.h"
>  
>  typedef struct QTestState QTestState;
> @@ -891,6 +892,62 @@ static inline bool target_big_endian(void)
>      return qtest_big_endian(global_qtest);
>  }
>  
> +/* Endianness conversion function between target cpu and specified endianess
> + *
> + * uint16_t target_le16_to_cpu(uint16_t v);
> + * uint32_t target_le32_to_cpu(uint32_t v);
> + * uint64_t target_le64_to_cpu(uint64_t v);
> + * uint16_t target_be16_to_cpu(uint16_t v);
> + * uint32_t target_be32_to_cpu(uint32_t v);
> + * uint64_t target_be64_to_cpu(uint64_t v);
> + *
> + * Convert the value @v from the specified format to the native
> + * endianness of the target CPU by byteswapping if necessary, and
> + * return the converted value.
> + *
> + * uint16_t target_cpu_to_le16(uint16_t v);
> + * uint32_t target_cpu_to_le32(uint32_t v);
> + * uint64_t target_cpu_to_le64(uint64_t v);
> + * uint16_t target_cpu_to_be16(uint16_t v);
> + * uint32_t target_cpu_to_be32(uint32_t v);
> + * uint64_t target_cpu_to_be64(uint64_t v);
> + *
> + * Convert the value @v from the native endianness of the target CPU to
> + * the specified format by byteswapping if necessary, and return
> + * the converted value.
> + *
> + * Both target_X_to_cpu() and target_cpu_to_X() perform the same operation; you
> + * should use whichever one is better documenting of the function your
> + * code is performing.
> + *
> + */
> +
> +#define le_bswap(s, v, size) (qtest_big_endian(s) ? bswap ## size(v) : (v))
> +#define be_bswap(s, v, size) (qtest_big_endian(s) ? (v) : bswap ## size(v))
> +
> +#define TARGET_CPU_CONVERT(endian, size, type)\
> +static inline type target_ ## endian ## size ## _to_cpu(type v)\
> +{\
> +    return glue(endian, _bswap)(global_qtest, v, size);\
> +} \
> +\
> +static inline type target_cpu_to_ ## endian ## size(type v)\
> +{\
> +    return glue(endian, _bswap)(global_qtest, v, size);\
> +}
> +
> +TARGET_CPU_CONVERT(be, 16, uint16_t)
> +TARGET_CPU_CONVERT(be, 32, uint32_t)
> +TARGET_CPU_CONVERT(be, 64, uint64_t)
> +
> +TARGET_CPU_CONVERT(le, 16, uint16_t)
> +TARGET_CPU_CONVERT(le, 32, uint32_t)
> +TARGET_CPU_CONVERT(le, 64, uint64_t)
> +
> +#undef TARGET_CPU_CONVERT
> +#undef be_bswap
> +#undef le_bswap
> +
>  QDict *qmp_fd_receive(int fd);
>  void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
>  void qmp_fd_send(int fd, const char *fmt, ...);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64
  2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
                   ` (6 preceding siblings ...)
  2016-09-28 19:24 ` [Qemu-devel] [PATCH v3 0/6] " no-reply
@ 2016-09-29  5:35 ` David Gibson
  7 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2016-09-29  5:35 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 2892 bytes --]

On Wed, Sep 28, 2016 at 08:51:27PM +0200, Laurent Vivier wrote:
> This series enables USB tests on PPC64, and for
> that implements libqos SPAPR PCI support.

These look good, except I still think the endianness is a bit
confused.  A more detailed analysis in response to patch 1.

Also, I'm afraid this is going to need another rebase, due to things
I've merged in ppc-for-2.8 today.

> 
> v3:
> - rebase
> - minor fixes (commas, comments)
> - add Greg's R-b
> 
> v2:
> - rebase
> - revert order in qtest_common_shutdown() to release
>   PCI and then memory allocator
> - remove useless byte-swapping in qpci-spapr.c
> - compute machine endianness on qtest_init()
> - introduce target_cpu_to_leXX()/target_cpu_to_beXX()
>             target_leXX_to_cpu()/target_beXX_to_cpu()
> 
> Laurent Vivier (6):
>   libqos: add PPC64 PCI support
>   libqos: add PCI management in qtest_vboot()/qtest_shutdown()
>   libqos: use generic qtest_shutdown()
>   qtest: evaluate endianness of the target in qtest_init()
>   qtest: define target cpu endianness conversion functions
>   tests: enable ohci/uhci/xhci tests on PPC64
> 
>  tests/Makefile.include      |   9 +-
>  tests/e1000e-test.c         |   2 +-
>  tests/i440fx-test.c         |   2 +-
>  tests/ide-test.c            |   2 +-
>  tests/ivshmem-test.c        |   2 +-
>  tests/libqos/ahci.c         |   2 +-
>  tests/libqos/libqos-pc.c    |   8 +-
>  tests/libqos/libqos-spapr.c |   8 +-
>  tests/libqos/libqos.c       |  32 ++++-
>  tests/libqos/libqos.h       |  11 +-
>  tests/libqos/pci-pc.c       |  24 +---
>  tests/libqos/pci-pc.h       |   3 +-
>  tests/libqos/pci-spapr.c    | 280 ++++++++++++++++++++++++++++++++++++++++++++
>  tests/libqos/pci-spapr.h    |  17 +++
>  tests/libqos/pci.c          |  22 +++-
>  tests/libqos/rtas.c         |  45 +++++++
>  tests/libqos/rtas.h         |   4 +
>  tests/libqos/usb.c          |   2 +-
>  tests/libqos/virtio-pci.c   |   2 +-
>  tests/libqtest.c            |  96 ++++++++-------
>  tests/libqtest.h            |  71 ++++++++++-
>  tests/q35-test.c            |   2 +-
>  tests/rtas-test.c           |   2 +-
>  tests/rtl8139-test.c        |   2 +-
>  tests/tco-test.c            |   2 +-
>  tests/usb-hcd-ehci-test.c   |   2 +-
>  tests/usb-hcd-uhci-test.c   |  24 ++--
>  tests/vhost-user-test.c     |   4 +-
>  tests/virtio-9p-test.c      |   2 +-
>  tests/virtio-blk-test.c     |   4 +-
>  tests/virtio-net-test.c     |   2 +-
>  tests/virtio-scsi-test.c    |   2 +-
>  32 files changed, 580 insertions(+), 112 deletions(-)
>  create mode 100644 tests/libqos/pci-spapr.c
>  create mode 100644 tests/libqos/pci-spapr.h
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions
  2016-09-29  5:33   ` [Qemu-devel] [Qemu-ppc] " David Gibson
@ 2016-09-29  7:23     ` Laurent Vivier
  2016-09-29  7:27       ` David Gibson
  0 siblings, 1 reply; 34+ messages in thread
From: Laurent Vivier @ 2016-09-29  7:23 UTC (permalink / raw)
  To: David Gibson
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson



On 29/09/2016 07:33, David Gibson wrote:
> On Wed, Sep 28, 2016 at 08:51:32PM +0200, Laurent Vivier wrote:
>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> 
> So, I think the right place to do the necessary endianness conversion
> is the PCI accessor helpers, as noted elsewhere.

Reworking my series I came to the same conclusion: I'm going to rework
that and send a new series.

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions
  2016-09-29  7:23     ` Laurent Vivier
@ 2016-09-29  7:27       ` David Gibson
  0 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2016-09-29  7:27 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: qemu-devel, thuth, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 707 bytes --]

On Thu, Sep 29, 2016 at 09:23:51AM +0200, Laurent Vivier wrote:
> 
> 
> On 29/09/2016 07:33, David Gibson wrote:
> > On Wed, Sep 28, 2016 at 08:51:32PM +0200, Laurent Vivier wrote:
> >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > 
> > So, I think the right place to do the necessary endianness conversion
> > is the PCI accessor helpers, as noted elsewhere.
> 
> Reworking my series I came to the same conclusion: I'm going to rework
> that and send a new series.

Sounds good, thanks.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-09-29  5:27   ` [Qemu-devel] [Qemu-ppc] " David Gibson
@ 2016-10-03 11:23     ` Cédric Le Goater
  2016-10-03 11:37       ` Laurent Vivier
                         ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Cédric Le Goater @ 2016-10-03 11:23 UTC (permalink / raw)
  To: David Gibson, Laurent Vivier
  Cc: thuth, qemu-devel, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

On 09/29/2016 07:27 AM, David Gibson wrote:
> On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:
>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>> ---
>>  tests/Makefile.include   |   1 +
>>  tests/libqos/pci-pc.c    |  22 ----
>>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
>>  tests/libqos/pci-spapr.h |  17 +++
>>  tests/libqos/pci.c       |  22 +++-
>>  tests/libqos/rtas.c      |  45 ++++++++
>>  tests/libqos/rtas.h      |   4 +
>>  7 files changed, 368 insertions(+), 23 deletions(-)
>>  create mode 100644 tests/libqos/pci-spapr.c
>>  create mode 100644 tests/libqos/pci-spapr.h
>>
>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>> index 8162f6f..92c82d8 100644
>> --- a/tests/Makefile.include
>> +++ b/tests/Makefile.include
>> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>>  libqos-spapr-obj-y += tests/libqos/rtas.o
>> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
>>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>>  libqos-pc-obj-y += tests/libqos/ahci.o
>> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
>> index 1ae2d37..82066b8 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 0000000..78df823
>> --- /dev/null
>> +++ b/tests/libqos/pci-spapr.c
>> @@ -0,0 +1,280 @@
>> +/*
>> + * 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;
>> +
>> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
>> +{
>> +    uint64_t port = (uint64_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 = (uint64_t)addr;
>> +    uint16_t v;
>> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
>> +        v = readw(IOBASE(0) + port);
>> +    } else {
>> +        v = readw(MMIOBASE(0) + port);
>> +    }
> 
> Ok, so, I've looked through the qtest stuff in more detail now, and
> I've got a better idea of how the endianness works.  Some of my
> earlier comments were confused about which pieces were in the test
> case side and which were on the qtest accel stub side.
> 
> So, what I think you need is an unconditional byteswap in each of the
> spapr pci IO functions.  Why?
> 
>    * The plain readw() etc. functions return values read from memory
>      assuming guest endianness.  For guest native values in memory, so
>      far so good.
>    * Generic users of the pci read/write functions in qtest expect to
>      get native values.
>    * But PCI devices are always LE, not guest endian
> 
> The guest endianness of spapr (as far as tswap() etc. are concerned)
> is BE, even though that's not really true in practice these days, so
> to correct for the PCI registers being read as BE when they should be
> LE we always need a swap.
> 
> That should remove the need for swaps further up the test stack.
> 
> Of course, "guest endianness" is a poorly defined concept, so longer
> term it might be better to completely replace the "readw" etc. qtest
> operations with explicit "readw_le" and "readw_be" ops.


I have a similar need for a unit test of the AST2400 flash controller. 

The flash module is accessible through a memory window and, when in 
SPI mode, the commands are sent to the slave by writing at the beginning 
of the region. Addresses are necessarily BE to be understood by the SPI
flash module. So, sequences like

    writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
    writeb(AST2400_FLASH_BASE, READ);
    writel(AST2400_FLASH_BASE, cpu_to_be32(addr));

will just fail under a BE host as an extra swap is done by the qtest
layer. I have used memwrite to have endian-agnostic mem accessors. 
Maybe something like below would be helpful in libqtest.h


+/*
+ * Generic read/write helpers for a BE region
+ */
+static inline void writew_be(uint64_t addr, uint16_t value)
+{
+    value = cpu_to_be16(value);
+    memwrite(addr, &value, sizeof(value));
+}
+
+static inline uint16_t readw_be(uint64_t addr)
+{
+    uint16_t value;
+
+    memread(addr, &value, sizeof(value));
+    return be16_to_cpu(value);
+}
+
+static inline void writel_be(uint64_t addr, uint32_t value)
+{
+    value = cpu_to_be32(value);
+    memwrite(addr, &value, sizeof(value));
+}
+
+static inline uint32_t readl_be(uint64_t addr)
+{
+    uint32_t value;
+
+    memread(addr, &value, sizeof(value));
+    return be32_to_cpu(value);
+}

If this is correct, I can add the LE equivalents and send a patch.

Cheers,

C.










>> +    return v;
>> +}
>> +
>> +static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr)
>> +{
>> +    uint64_t port = (uint64_t)addr;
>> +    uint32_t v;
>> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
>> +        v = readl(IOBASE(0) + port);
>> +    } else {
>> +        v = readl(MMIOBASE(0) + port);
>> +    }
>> +    return v;
>> +}
>> +
>> +static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
>> +{
>> +    uint64_t port = (uint64_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 = (uint64_t)addr;
>> +    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 = (uint64_t)addr;
>> +    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 0000000..4192126
>> --- /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 ed78d91..c3f3382 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 820321a..0269803 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 a1b60a8..498eb19 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 */
> 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-03 11:23     ` Cédric Le Goater
@ 2016-10-03 11:37       ` Laurent Vivier
  2016-10-03 14:03       ` Greg Kurz
  2016-10-04  0:22       ` David Gibson
  2 siblings, 0 replies; 34+ messages in thread
From: Laurent Vivier @ 2016-10-03 11:37 UTC (permalink / raw)
  To: Cédric Le Goater, David Gibson
  Cc: thuth, qemu-devel, Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson



On 03/10/2016 13:23, Cédric Le Goater wrote:
> On 09/29/2016 07:27 AM, David Gibson wrote:
>> On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:
>>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>>> ---
>>>  tests/Makefile.include   |   1 +
>>>  tests/libqos/pci-pc.c    |  22 ----
>>>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
>>>  tests/libqos/pci-spapr.h |  17 +++
>>>  tests/libqos/pci.c       |  22 +++-
>>>  tests/libqos/rtas.c      |  45 ++++++++
>>>  tests/libqos/rtas.h      |   4 +
>>>  7 files changed, 368 insertions(+), 23 deletions(-)
>>>  create mode 100644 tests/libqos/pci-spapr.c
>>>  create mode 100644 tests/libqos/pci-spapr.h
>>>
>>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>>> index 8162f6f..92c82d8 100644
>>> --- a/tests/Makefile.include
>>> +++ b/tests/Makefile.include
>>> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>>>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>>>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>>>  libqos-spapr-obj-y += tests/libqos/rtas.o
>>> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
>>>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>>>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>>>  libqos-pc-obj-y += tests/libqos/ahci.o
>>> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
>>> index 1ae2d37..82066b8 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 0000000..78df823
>>> --- /dev/null
>>> +++ b/tests/libqos/pci-spapr.c
>>> @@ -0,0 +1,280 @@
>>> +/*
>>> + * 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;
>>> +
>>> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
>>> +{
>>> +    uint64_t port = (uint64_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 = (uint64_t)addr;
>>> +    uint16_t v;
>>> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
>>> +        v = readw(IOBASE(0) + port);
>>> +    } else {
>>> +        v = readw(MMIOBASE(0) + port);
>>> +    }
>>
>> Ok, so, I've looked through the qtest stuff in more detail now, and
>> I've got a better idea of how the endianness works.  Some of my
>> earlier comments were confused about which pieces were in the test
>> case side and which were on the qtest accel stub side.
>>
>> So, what I think you need is an unconditional byteswap in each of the
>> spapr pci IO functions.  Why?
>>
>>    * The plain readw() etc. functions return values read from memory
>>      assuming guest endianness.  For guest native values in memory, so
>>      far so good.
>>    * Generic users of the pci read/write functions in qtest expect to
>>      get native values.
>>    * But PCI devices are always LE, not guest endian
>>
>> The guest endianness of spapr (as far as tswap() etc. are concerned)
>> is BE, even though that's not really true in practice these days, so
>> to correct for the PCI registers being read as BE when they should be
>> LE we always need a swap.
>>
>> That should remove the need for swaps further up the test stack.
>>
>> Of course, "guest endianness" is a poorly defined concept, so longer
>> term it might be better to completely replace the "readw" etc. qtest
>> operations with explicit "readw_le" and "readw_be" ops.
> 
> 
> I have a similar need for a unit test of the AST2400 flash controller. 
> 
> The flash module is accessible through a memory window and, when in 
> SPI mode, the commands are sent to the slave by writing at the beginning 
> of the region. Addresses are necessarily BE to be understood by the SPI
> flash module. So, sequences like
> 
>     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
>     writeb(AST2400_FLASH_BASE, READ);
>     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> 
> will just fail under a BE host as an extra swap is done by the qtest
> layer. I have used memwrite to have endian-agnostic mem accessors. 
> Maybe something like below would be helpful in libqtest.h
> 
> 
> +/*
> + * Generic read/write helpers for a BE region
> + */
> +static inline void writew_be(uint64_t addr, uint16_t value)
> +{
> +    value = cpu_to_be16(value);
> +    memwrite(addr, &value, sizeof(value));
> +}
> +
> +static inline uint16_t readw_be(uint64_t addr)
> +{
> +    uint16_t value;
> +
> +    memread(addr, &value, sizeof(value));
> +    return be16_to_cpu(value);
> +}
> +
> +static inline void writel_be(uint64_t addr, uint32_t value)
> +{
> +    value = cpu_to_be32(value);
> +    memwrite(addr, &value, sizeof(value));
> +}
> +
> +static inline uint32_t readl_be(uint64_t addr)
> +{
> +    uint32_t value;
> +
> +    memread(addr, &value, sizeof(value));
> +    return be32_to_cpu(value);
> +}
> 
> If this is correct, I can add the LE equivalents and send a patch.
> 

Yes, I think it's a good idea, but add also the functions with the
QTestState parameter as it is done with the others:

libqtest.c:

uint32_t qtest_readl_be(QTestState *s, uint64_t addr)
{
    uint32_t value;

    qtest_memread(s, addr, &value, sizeof(value));

    return be32_to_cpu(value);
}

libqtest.h:

static inline uint32_t readl_be(uint64_t addr)
{
    return qtest_readl_be(global_qtest, addr);
}

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-03 11:23     ` Cédric Le Goater
  2016-10-03 11:37       ` Laurent Vivier
@ 2016-10-03 14:03       ` Greg Kurz
  2016-10-03 14:14         ` Cédric Le Goater
                           ` (2 more replies)
  2016-10-04  0:22       ` David Gibson
  2 siblings, 3 replies; 34+ messages in thread
From: Greg Kurz @ 2016-10-03 14:03 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: David Gibson, Laurent Vivier, thuth, qemu-devel, qemu-ppc,
	Gerd Hoffmann, dgibson

On Mon, 3 Oct 2016 13:23:27 +0200
Cédric Le Goater <clg@kaod.org> wrote:

> On 09/29/2016 07:27 AM, David Gibson wrote:
> > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:  
> >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> >> ---
> >>  tests/Makefile.include   |   1 +
> >>  tests/libqos/pci-pc.c    |  22 ----
> >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  tests/libqos/pci-spapr.h |  17 +++
> >>  tests/libqos/pci.c       |  22 +++-
> >>  tests/libqos/rtas.c      |  45 ++++++++
> >>  tests/libqos/rtas.h      |   4 +
> >>  7 files changed, 368 insertions(+), 23 deletions(-)
> >>  create mode 100644 tests/libqos/pci-spapr.c
> >>  create mode 100644 tests/libqos/pci-spapr.h
> >>
> >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> >> index 8162f6f..92c82d8 100644
> >> --- a/tests/Makefile.include
> >> +++ b/tests/Makefile.include
> >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> >>  libqos-pc-obj-y += tests/libqos/ahci.o
> >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> >> index 1ae2d37..82066b8 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 0000000..78df823
> >> --- /dev/null
> >> +++ b/tests/libqos/pci-spapr.c
> >> @@ -0,0 +1,280 @@
> >> +/*
> >> + * 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;
> >> +
> >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> >> +{
> >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> >> +    uint16_t v;
> >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> >> +        v = readw(IOBASE(0) + port);
> >> +    } else {
> >> +        v = readw(MMIOBASE(0) + port);
> >> +    }  
> > 
> > Ok, so, I've looked through the qtest stuff in more detail now, and
> > I've got a better idea of how the endianness works.  Some of my
> > earlier comments were confused about which pieces were in the test
> > case side and which were on the qtest accel stub side.
> > 
> > So, what I think you need is an unconditional byteswap in each of the
> > spapr pci IO functions.  Why?
> > 
> >    * The plain readw() etc. functions return values read from memory
> >      assuming guest endianness.  For guest native values in memory, so
> >      far so good.
> >    * Generic users of the pci read/write functions in qtest expect to
> >      get native values.
> >    * But PCI devices are always LE, not guest endian
> > 
> > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > is BE, even though that's not really true in practice these days, so
> > to correct for the PCI registers being read as BE when they should be
> > LE we always need a swap.
> > 
> > That should remove the need for swaps further up the test stack.
> > 
> > Of course, "guest endianness" is a poorly defined concept, so longer
> > term it might be better to completely replace the "readw" etc. qtest
> > operations with explicit "readw_le" and "readw_be" ops.  
> 
> 
> I have a similar need for a unit test of the AST2400 flash controller. 
> 
> The flash module is accessible through a memory window and, when in 
> SPI mode, the commands are sent to the slave by writing at the beginning 
> of the region. Addresses are necessarily BE to be understood by the SPI
> flash module. So, sequences like
> 
>     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
>     writeb(AST2400_FLASH_BASE, READ);
>     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> 
> will just fail under a BE host as an extra swap is done by the qtest

cpu_to_be32() is indeed what a real guest does... but the real guest runs
with the target endianness, whereas the qtest program runs with the host
endianness... so cpu_to_be32() looks wrong here.

> layer. I have used memwrite to have endian-agnostic mem accessors. 
> Maybe something like below would be helpful in libqtest.h
> 
> 
> +/*
> + * Generic read/write helpers for a BE region
> + */
> +static inline void writew_be(uint64_t addr, uint16_t value)
> +{
> +    value = cpu_to_be16(value);
> +    memwrite(addr, &value, sizeof(value));
> +}
> +
> +static inline uint16_t readw_be(uint64_t addr)
> +{
> +    uint16_t value;
> +
> +    memread(addr, &value, sizeof(value));
> +    return be16_to_cpu(value);
> +}
> +
> +static inline void writel_be(uint64_t addr, uint32_t value)
> +{
> +    value = cpu_to_be32(value);
> +    memwrite(addr, &value, sizeof(value));
> +}
> +
> +static inline uint32_t readl_be(uint64_t addr)
> +{
> +    uint32_t value;
> +
> +    memread(addr, &value, sizeof(value));
> +    return be32_to_cpu(value);
> +}
> 
> If this is correct, I can add the LE equivalents and send a patch.
> 

The API is correct, but the implementation has the same issue: it uses
cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
the target endianness is totally ignored.

Let's suppose that a similar AST2400 platform exists with a BE processor:
would the same test program work for both LE and BE cases ?

Both the test program and QEMU run with the host endianness acutally,
but only QEMU knows about the target endianness. So I guess, the qtest
protocol should provide explicit BE/LE operations: the test program
would ask for an access with a specific endianness and the qtest
accelerator in QEMU would do the swap based on the target endianness.

> Cheers,
> 
> C.
> 

Cheers.

--
Greg

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-03 14:03       ` Greg Kurz
@ 2016-10-03 14:14         ` Cédric Le Goater
  2016-10-03 17:30         ` Cédric Le Goater
  2016-10-04  0:24         ` David Gibson
  2 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2016-10-03 14:14 UTC (permalink / raw)
  To: Greg Kurz
  Cc: David Gibson, Laurent Vivier, thuth, qemu-devel, qemu-ppc,
	Gerd Hoffmann, dgibson

On 10/03/2016 04:03 PM, Greg Kurz wrote:
> On Mon, 3 Oct 2016 13:23:27 +0200
> Cédric Le Goater <clg@kaod.org> wrote:
> 
>> On 09/29/2016 07:27 AM, David Gibson wrote:
>>> On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:  
>>>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>>>> ---
>>>>  tests/Makefile.include   |   1 +
>>>>  tests/libqos/pci-pc.c    |  22 ----
>>>>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>  tests/libqos/pci-spapr.h |  17 +++
>>>>  tests/libqos/pci.c       |  22 +++-
>>>>  tests/libqos/rtas.c      |  45 ++++++++
>>>>  tests/libqos/rtas.h      |   4 +
>>>>  7 files changed, 368 insertions(+), 23 deletions(-)
>>>>  create mode 100644 tests/libqos/pci-spapr.c
>>>>  create mode 100644 tests/libqos/pci-spapr.h
>>>>
>>>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>>>> index 8162f6f..92c82d8 100644
>>>> --- a/tests/Makefile.include
>>>> +++ b/tests/Makefile.include
>>>> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>>>>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>>>>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>>>>  libqos-spapr-obj-y += tests/libqos/rtas.o
>>>> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
>>>>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>>>>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>>>>  libqos-pc-obj-y += tests/libqos/ahci.o
>>>> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
>>>> index 1ae2d37..82066b8 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 0000000..78df823
>>>> --- /dev/null
>>>> +++ b/tests/libqos/pci-spapr.c
>>>> @@ -0,0 +1,280 @@
>>>> +/*
>>>> + * 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;
>>>> +
>>>> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
>>>> +{
>>>> +    uint64_t port = (uint64_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 = (uint64_t)addr;
>>>> +    uint16_t v;
>>>> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
>>>> +        v = readw(IOBASE(0) + port);
>>>> +    } else {
>>>> +        v = readw(MMIOBASE(0) + port);
>>>> +    }  
>>>
>>> Ok, so, I've looked through the qtest stuff in more detail now, and
>>> I've got a better idea of how the endianness works.  Some of my
>>> earlier comments were confused about which pieces were in the test
>>> case side and which were on the qtest accel stub side.
>>>
>>> So, what I think you need is an unconditional byteswap in each of the
>>> spapr pci IO functions.  Why?
>>>
>>>    * The plain readw() etc. functions return values read from memory
>>>      assuming guest endianness.  For guest native values in memory, so
>>>      far so good.
>>>    * Generic users of the pci read/write functions in qtest expect to
>>>      get native values.
>>>    * But PCI devices are always LE, not guest endian
>>>
>>> The guest endianness of spapr (as far as tswap() etc. are concerned)
>>> is BE, even though that's not really true in practice these days, so
>>> to correct for the PCI registers being read as BE when they should be
>>> LE we always need a swap.
>>>
>>> That should remove the need for swaps further up the test stack.
>>>
>>> Of course, "guest endianness" is a poorly defined concept, so longer
>>> term it might be better to completely replace the "readw" etc. qtest
>>> operations with explicit "readw_le" and "readw_be" ops.  
>>
>>
>> I have a similar need for a unit test of the AST2400 flash controller. 
>>
>> The flash module is accessible through a memory window and, when in 
>> SPI mode, the commands are sent to the slave by writing at the beginning 
>> of the region. Addresses are necessarily BE to be understood by the SPI
>> flash module. So, sequences like
>>
>>     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
>>     writeb(AST2400_FLASH_BASE, READ);
>>     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
>>
>> will just fail under a BE host as an extra swap is done by the qtest
> 
> cpu_to_be32() is indeed what a real guest does... but the real guest runs
> with the target endianness, whereas the qtest program runs with the host
> endianness... so cpu_to_be32() looks wrong here.

yes clearly.

>> layer. I have used memwrite to have endian-agnostic mem accessors. 
>> Maybe something like below would be helpful in libqtest.h
>>
>>
>> +/*
>> + * Generic read/write helpers for a BE region
>> + */
>> +static inline void writew_be(uint64_t addr, uint16_t value)
>> +{
>> +    value = cpu_to_be16(value);
>> +    memwrite(addr, &value, sizeof(value));
>> +}
>> +
>> +static inline uint16_t readw_be(uint64_t addr)
>> +{
>> +    uint16_t value;
>> +
>> +    memread(addr, &value, sizeof(value));
>> +    return be16_to_cpu(value);
>> +}
>> +
>> +static inline void writel_be(uint64_t addr, uint32_t value)
>> +{
>> +    value = cpu_to_be32(value);
>> +    memwrite(addr, &value, sizeof(value));
>> +}
>> +
>> +static inline uint32_t readl_be(uint64_t addr)
>> +{
>> +    uint32_t value;
>> +
>> +    memread(addr, &value, sizeof(value));
>> +    return be32_to_cpu(value);
>> +}
>>
>> If this is correct, I can add the LE equivalents and send a patch.
>>
> 
> The API is correct, but the implementation has the same issue: it uses
> cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> the target endianness is totally ignored.
>
> Let's suppose that a similar AST2400 platform exists with a BE processor:
> would the same test program work for both LE and BE cases ?
>
> Both the test program and QEMU run with the host endianness acutally,
> but only QEMU knows about the target endianness. So I guess, the qtest
> protocol should provide explicit BE/LE operations: the test program
> would ask for an access with a specific endianness and the qtest
> accelerator in QEMU would do the swap based on the target endianness.

yes. it is better to go that way and extend the qtest set of operations 
on  memory regions.

Thanks,

C.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-03 14:03       ` Greg Kurz
  2016-10-03 14:14         ` Cédric Le Goater
@ 2016-10-03 17:30         ` Cédric Le Goater
  2016-10-04  0:24         ` David Gibson
  2 siblings, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2016-10-03 17:30 UTC (permalink / raw)
  To: Greg Kurz
  Cc: David Gibson, Laurent Vivier, thuth, qemu-devel, qemu-ppc,
	Gerd Hoffmann, dgibson

On 10/03/2016 04:03 PM, Greg Kurz wrote:
> On Mon, 3 Oct 2016 13:23:27 +0200
> Cédric Le Goater <clg@kaod.org> wrote:
> 
>> On 09/29/2016 07:27 AM, David Gibson wrote:
>>> On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:  
>>>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>>>> ---
>>>>  tests/Makefile.include   |   1 +
>>>>  tests/libqos/pci-pc.c    |  22 ----
>>>>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>  tests/libqos/pci-spapr.h |  17 +++
>>>>  tests/libqos/pci.c       |  22 +++-
>>>>  tests/libqos/rtas.c      |  45 ++++++++
>>>>  tests/libqos/rtas.h      |   4 +
>>>>  7 files changed, 368 insertions(+), 23 deletions(-)
>>>>  create mode 100644 tests/libqos/pci-spapr.c
>>>>  create mode 100644 tests/libqos/pci-spapr.h
>>>>
>>>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>>>> index 8162f6f..92c82d8 100644
>>>> --- a/tests/Makefile.include
>>>> +++ b/tests/Makefile.include
>>>> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>>>>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>>>>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>>>>  libqos-spapr-obj-y += tests/libqos/rtas.o
>>>> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
>>>>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>>>>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>>>>  libqos-pc-obj-y += tests/libqos/ahci.o
>>>> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
>>>> index 1ae2d37..82066b8 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 0000000..78df823
>>>> --- /dev/null
>>>> +++ b/tests/libqos/pci-spapr.c
>>>> @@ -0,0 +1,280 @@
>>>> +/*
>>>> + * 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;
>>>> +
>>>> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
>>>> +{
>>>> +    uint64_t port = (uint64_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 = (uint64_t)addr;
>>>> +    uint16_t v;
>>>> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
>>>> +        v = readw(IOBASE(0) + port);
>>>> +    } else {
>>>> +        v = readw(MMIOBASE(0) + port);
>>>> +    }  
>>>
>>> Ok, so, I've looked through the qtest stuff in more detail now, and
>>> I've got a better idea of how the endianness works.  Some of my
>>> earlier comments were confused about which pieces were in the test
>>> case side and which were on the qtest accel stub side.
>>>
>>> So, what I think you need is an unconditional byteswap in each of the
>>> spapr pci IO functions.  Why?
>>>
>>>    * The plain readw() etc. functions return values read from memory
>>>      assuming guest endianness.  For guest native values in memory, so
>>>      far so good.
>>>    * Generic users of the pci read/write functions in qtest expect to
>>>      get native values.
>>>    * But PCI devices are always LE, not guest endian
>>>
>>> The guest endianness of spapr (as far as tswap() etc. are concerned)
>>> is BE, even though that's not really true in practice these days, so
>>> to correct for the PCI registers being read as BE when they should be
>>> LE we always need a swap.
>>>
>>> That should remove the need for swaps further up the test stack.
>>>
>>> Of course, "guest endianness" is a poorly defined concept, so longer
>>> term it might be better to completely replace the "readw" etc. qtest
>>> operations with explicit "readw_le" and "readw_be" ops.  
>>
>>
>> I have a similar need for a unit test of the AST2400 flash controller. 
>>
>> The flash module is accessible through a memory window and, when in 
>> SPI mode, the commands are sent to the slave by writing at the beginning 
>> of the region. Addresses are necessarily BE to be understood by the SPI
>> flash module. So, sequences like
>>
>>     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
>>     writeb(AST2400_FLASH_BASE, READ);
>>     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
>>
>> will just fail under a BE host as an extra swap is done by the qtest
> 
> cpu_to_be32() is indeed what a real guest does... but the real guest runs
> with the target endianness, whereas the qtest program runs with the host
> endianness... so cpu_to_be32() looks wrong here.
> 
>> layer. I have used memwrite to have endian-agnostic mem accessors. 
>> Maybe something like below would be helpful in libqtest.h
>>
>>
>> +/*
>> + * Generic read/write helpers for a BE region
>> + */
>> +static inline void writew_be(uint64_t addr, uint16_t value)
>> +{
>> +    value = cpu_to_be16(value);
>> +    memwrite(addr, &value, sizeof(value));
>> +}
>> +
>> +static inline uint16_t readw_be(uint64_t addr)
>> +{
>> +    uint16_t value;
>> +
>> +    memread(addr, &value, sizeof(value));
>> +    return be16_to_cpu(value);
>> +}
>> +
>> +static inline void writel_be(uint64_t addr, uint32_t value)
>> +{
>> +    value = cpu_to_be32(value);
>> +    memwrite(addr, &value, sizeof(value));
>> +}
>> +
>> +static inline uint32_t readl_be(uint64_t addr)
>> +{
>> +    uint32_t value;
>> +
>> +    memread(addr, &value, sizeof(value));
>> +    return be32_to_cpu(value);
>> +}
>>
>> If this is correct, I can add the LE equivalents and send a patch.
>>
> 
> The API is correct, but the implementation has the same issue: it uses
> cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> the target endianness is totally ignored.
> 
> Let's suppose that a similar AST2400 platform exists with a BE processor:
> would the same test program work for both LE and BE cases ?
> 
> Both the test program and QEMU run with the host endianness acutally,
> but only QEMU knows about the target endianness. So I guess, the qtest
> protocol should provide explicit BE/LE operations: the test program
> would ask for an access with a specific endianness and the qtest
> accelerator in QEMU would do the swap based on the target endianness.

Here is a RFC below, tested on a BE and LE host for a BE region.

Thanks,
C. 


From: Cédric Le Goater <clg@kaod.org>
Subject: [PATCH] qtest: add an endianness parameter to read/write accessors
Date: Mon, 03 Oct 2016 16:52:48 +0200
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This adds {read,write}{w,l,q}_{be,le} routines to access guest memory
using a specific endianness. The protocol is simply extented to pass
"be", "le", "native".

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 qtest.c          |   73 +++++++++++++++++++++++++++++++++++++++++-----
 tests/libqtest.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++--------
 tests/libqtest.h |   68 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 207 insertions(+), 20 deletions(-)

Index: qemu-aspeed.git/tests/libqtest.h
===================================================================
--- qemu-aspeed.git.orig/tests/libqtest.h
+++ qemu-aspeed.git/tests/libqtest.h
@@ -888,4 +888,72 @@ void qmp_fd_send(int fd, const char *fmt
 QDict *qmp_fdv(int fd, const char *fmt, va_list ap);
 QDict *qmp_fd(int fd, const char *fmt, ...);
 
+uint16_t qtest_readw_be(QTestState *s, uint64_t addr);
+uint32_t qtest_readl_be(QTestState *s, uint64_t addr);
+uint64_t qtest_readq_be(QTestState *s, uint64_t addr);
+
+static inline uint16_t readw_be(uint64_t addr)
+{
+    return qtest_readw_be(global_qtest, addr);
+}
+static inline uint32_t readl_be(uint64_t addr)
+{
+    return qtest_readl_be(global_qtest, addr);
+}
+static inline uint64_t readq_be(uint64_t addr)
+{
+    return qtest_readq_be(global_qtest, addr);
+}
+
+void qtest_writew_be(QTestState *s, uint64_t addr, uint16_t value);
+void qtest_writel_be(QTestState *s, uint64_t addr, uint32_t value);
+void qtest_writeq_be(QTestState *s, uint64_t addr, uint64_t value);
+
+static inline void writew_be(uint64_t addr, uint16_t value)
+{
+    qtest_writew_be(global_qtest, addr, value);
+}
+static inline void writel_be(uint64_t addr, uint32_t value)
+{
+    qtest_writel_be(global_qtest, addr, value);
+}
+static inline void writeq_be(uint64_t addr, uint64_t value)
+{
+    qtest_writeq_be(global_qtest, addr, value);
+}
+
+uint16_t qtest_readw_le(QTestState *s, uint64_t addr);
+uint32_t qtest_readl_le(QTestState *s, uint64_t addr);
+uint64_t qtest_readq_le(QTestState *s, uint64_t addr);
+
+static inline uint16_t readw_le(uint64_t addr)
+{
+    return qtest_readw_le(global_qtest, addr);
+}
+static inline uint32_t readl_le(uint64_t addr)
+{
+    return qtest_readl_le(global_qtest, addr);
+}
+static inline uint64_t readq_le(uint64_t addr)
+{
+    return qtest_readq_le(global_qtest, addr);
+}
+
+void qtest_writew_le(QTestState *s, uint64_t addr, uint16_t value);
+void qtest_writel_le(QTestState *s, uint64_t addr, uint32_t value);
+void qtest_writeq_le(QTestState *s, uint64_t addr, uint64_t value);
+
+static inline void writew_le(uint64_t addr, uint16_t value)
+{
+    qtest_writew_le(global_qtest, addr, value);
+}
+static inline void writel_le(uint64_t addr, uint32_t value)
+{
+    qtest_writel_le(global_qtest, addr, value);
+}
+static inline void writeq_le(uint64_t addr, uint64_t value)
+{
+    qtest_writeq_le(global_qtest, addr, value);
+}
+
 #endif
Index: qemu-aspeed.git/qtest.c
===================================================================
--- qemu-aspeed.git.orig/qtest.c
+++ qemu-aspeed.git/qtest.c
@@ -257,6 +257,63 @@ static void qtest_irq_handler(void *opaq
     }
 }
 
+static inline bool is_target_big_endian(void)
+{
+#if defined(TARGET_WORDS_BIGENDIAN)
+    return true;
+#else
+    return false;
+#endif
+}
+
+static void qtest_tswap16s(uint16_t *s, gchar *endianness)
+{
+    if (endianness[0] != 'n') {
+        bool big_endian = (endianness[0] == 'b');
+
+        if (is_target_big_endian() != big_endian) {
+            bswap16s(s);
+        }
+    }
+    tswap16s(s);
+}
+
+static uint16_t qtest_tswap16(uint16_t s, gchar *endianness)
+{
+    qtest_tswap16s(&s, endianness);
+    return s;
+}
+
+static void qtest_tswap32s(uint32_t *s, gchar *endianness)
+{
+    if (endianness[0] != 'n') {
+        bool big_endian = (endianness[0] == 'b');
+
+        if (is_target_big_endian() != big_endian) {
+            bswap32s(s);
+        }
+    }
+    tswap32s(s);
+}
+
+static uint32_t qtest_tswap32(uint32_t s, gchar *endianness)
+{
+    qtest_tswap32s(&s, endianness);
+    return s;
+}
+
+static void qtest_tswap64s(uint64_t *s, gchar *endianness)
+{
+    if (endianness[0] != 'n') {
+        bool big_endian = (endianness[0] == 'b');
+
+        if (is_target_big_endian() != big_endian) {
+            bswap64s(s);
+        }
+    }
+    tswap64s(s);
+}
+
 static void qtest_process_command(CharDriverState *chr, gchar **words)
 {
     const gchar *command;
@@ -372,7 +429,7 @@ static void qtest_process_command(CharDr
         uint64_t addr;
         uint64_t value;
 
-        g_assert(words[1] && words[2]);
+        g_assert(words[1] && words[2] && words[3]);
         g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
         g_assert(qemu_strtoull(words[2], NULL, 0, &value) == 0);
 
@@ -381,15 +438,15 @@ static void qtest_process_command(CharDr
             cpu_physical_memory_write(addr, &data, 1);
         } else if (words[0][5] == 'w') {
             uint16_t data = value;
-            tswap16s(&data);
+            qtest_tswap16s(&data, words[3]);
             cpu_physical_memory_write(addr, &data, 2);
         } else if (words[0][5] == 'l') {
             uint32_t data = value;
-            tswap32s(&data);
+            qtest_tswap32s(&data, words[3]);
             cpu_physical_memory_write(addr, &data, 4);
         } else if (words[0][5] == 'q') {
             uint64_t data = value;
-            tswap64s(&data);
+            qtest_tswap64s(&data, words[3]);
             cpu_physical_memory_write(addr, &data, 8);
         }
         qtest_send_prefix(chr);
@@ -401,7 +458,7 @@ static void qtest_process_command(CharDr
         uint64_t addr;
         uint64_t value = UINT64_C(-1);
 
-        g_assert(words[1]);
+        g_assert(words[1] && words[2]);
         g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 
         if (words[0][4] == 'b') {
@@ -411,14 +468,14 @@ static void qtest_process_command(CharDr
         } else if (words[0][4] == 'w') {
             uint16_t data;
             cpu_physical_memory_read(addr, &data, 2);
-            value = tswap16(data);
+            value = qtest_tswap16(data, words[2]);
         } else if (words[0][4] == 'l') {
             uint32_t data;
             cpu_physical_memory_read(addr, &data, 4);
-            value = tswap32(data);
+            value = qtest_tswap32(data, words[2]);
         } else if (words[0][4] == 'q') {
             cpu_physical_memory_read(addr, &value, 8);
-            tswap64s(&value);
+            qtest_tswap64s(&value, words[2]);
         }
         qtest_send_prefix(chr);
         qtest_sendf(chr, "OK 0x%016" PRIx64 "\n", value);
Index: qemu-aspeed.git/tests/libqtest.c
===================================================================
--- qemu-aspeed.git.orig/tests/libqtest.c
+++ qemu-aspeed.git/tests/libqtest.c
@@ -663,38 +663,70 @@ uint32_t qtest_inl(QTestState *s, uint16
 }
 
 static void qtest_write(QTestState *s, const char *cmd, uint64_t addr,
-                        uint64_t value)
+                        uint64_t value, const char *endianness)
 {
-    qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64 "\n", cmd, addr, value);
+    qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64  " %s\n", cmd, addr, value,
+                endianness);
     qtest_rsp(s, 0);
 }
 
 void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value)
 {
-    qtest_write(s, "writeb", addr, value);
+    qtest_write(s, "writeb", addr, value, "native");
 }
 
 void qtest_writew(QTestState *s, uint64_t addr, uint16_t value)
 {
-    qtest_write(s, "writew", addr, value);
+    qtest_write(s, "writew", addr, value, "native");
 }
 
 void qtest_writel(QTestState *s, uint64_t addr, uint32_t value)
 {
-    qtest_write(s, "writel", addr, value);
+    qtest_write(s, "writel", addr, value, "native");
 }
 
 void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)
 {
-    qtest_write(s, "writeq", addr, value);
+    qtest_write(s, "writeq", addr, value, "native");
 }
 
-static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr)
+void qtest_writew_be(QTestState *s, uint64_t addr, uint16_t value)
+{
+    qtest_write(s, "writew", addr, value, "be");
+}
+
+void qtest_writel_be(QTestState *s, uint64_t addr, uint32_t value)
+{
+    qtest_write(s, "writel", addr, value, "be");
+}
+
+void qtest_writeq_be(QTestState *s, uint64_t addr, uint64_t value)
+{
+    qtest_write(s, "writeq", addr, value, "be");
+}
+
+void qtest_writew_le(QTestState *s, uint64_t addr, uint16_t value)
+{
+    qtest_write(s, "writew", addr, value, "le");
+}
+
+void qtest_writel_le(QTestState *s, uint64_t addr, uint32_t value)
+{
+    qtest_write(s, "writel", addr, value, "le");
+}
+
+void qtest_writeq_le(QTestState *s, uint64_t addr, uint64_t value)
+{
+    qtest_write(s, "writeq", addr, value, "le");
+}
+
+static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr,
+                           const char *endianness)
 {
     gchar **args;
     uint64_t value;
 
-    qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr);
+    qtest_sendf(s, "%s 0x%" PRIx64 " %s\n", cmd, addr, endianness);
     args = qtest_rsp(s, 2);
     value = strtoull(args[1], NULL, 0);
     g_strfreev(args);
@@ -704,22 +736,52 @@ static uint64_t qtest_read(QTestState *s
 
 uint8_t qtest_readb(QTestState *s, uint64_t addr)
 {
-    return qtest_read(s, "readb", addr);
+    return qtest_read(s, "readb", addr, "native");
 }
 
 uint16_t qtest_readw(QTestState *s, uint64_t addr)
 {
-    return qtest_read(s, "readw", addr);
+    return qtest_read(s, "readw", addr, "native");
 }
 
 uint32_t qtest_readl(QTestState *s, uint64_t addr)
 {
-    return qtest_read(s, "readl", addr);
+    return qtest_read(s, "readl", addr, "native");
 }
 
 uint64_t qtest_readq(QTestState *s, uint64_t addr)
 {
-    return qtest_read(s, "readq", addr);
+    return qtest_read(s, "readq", addr, "native");
+}
+
+uint16_t qtest_readw_be(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readw", addr, "be");
+}
+
+uint32_t qtest_readl_be(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readl", addr, "be");
+}
+
+uint64_t qtest_readq_be(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readq", addr, "be");
+}
+
+uint16_t qtest_readw_le(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readw", addr, "le");
+}
+
+uint32_t qtest_readl_le(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readl", addr, "le");
+}
+
+uint64_t qtest_readq_le(QTestState *s, uint64_t addr)
+{
+    return qtest_read(s, "readq", addr, "le");
 }
 
 static int hex2nib(char ch)

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-03 11:23     ` Cédric Le Goater
  2016-10-03 11:37       ` Laurent Vivier
  2016-10-03 14:03       ` Greg Kurz
@ 2016-10-04  0:22       ` David Gibson
  2016-10-04  6:44         ` Greg Kurz
  2016-10-04  6:45         ` Cédric Le Goater
  2 siblings, 2 replies; 34+ messages in thread
From: David Gibson @ 2016-10-04  0:22 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Laurent Vivier, thuth, qemu-devel, Greg Kurz, qemu-ppc,
	Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 8677 bytes --]

On Mon, Oct 03, 2016 at 01:23:27PM +0200, Cédric Le Goater wrote:
> On 09/29/2016 07:27 AM, David Gibson wrote:
> > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:
> >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> >> ---
> >>  tests/Makefile.include   |   1 +
> >>  tests/libqos/pci-pc.c    |  22 ----
> >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  tests/libqos/pci-spapr.h |  17 +++
> >>  tests/libqos/pci.c       |  22 +++-
> >>  tests/libqos/rtas.c      |  45 ++++++++
> >>  tests/libqos/rtas.h      |   4 +
> >>  7 files changed, 368 insertions(+), 23 deletions(-)
> >>  create mode 100644 tests/libqos/pci-spapr.c
> >>  create mode 100644 tests/libqos/pci-spapr.h
> >>
> >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> >> index 8162f6f..92c82d8 100644
> >> --- a/tests/Makefile.include
> >> +++ b/tests/Makefile.include
> >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> >>  libqos-pc-obj-y += tests/libqos/ahci.o
> >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> >> index 1ae2d37..82066b8 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 0000000..78df823
> >> --- /dev/null
> >> +++ b/tests/libqos/pci-spapr.c
> >> @@ -0,0 +1,280 @@
> >> +/*
> >> + * 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;
> >> +
> >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> >> +{
> >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> >> +    uint16_t v;
> >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> >> +        v = readw(IOBASE(0) + port);
> >> +    } else {
> >> +        v = readw(MMIOBASE(0) + port);
> >> +    }
> > 
> > Ok, so, I've looked through the qtest stuff in more detail now, and
> > I've got a better idea of how the endianness works.  Some of my
> > earlier comments were confused about which pieces were in the test
> > case side and which were on the qtest accel stub side.
> > 
> > So, what I think you need is an unconditional byteswap in each of the
> > spapr pci IO functions.  Why?
> > 
> >    * The plain readw() etc. functions return values read from memory
> >      assuming guest endianness.  For guest native values in memory, so
> >      far so good.
> >    * Generic users of the pci read/write functions in qtest expect to
> >      get native values.
> >    * But PCI devices are always LE, not guest endian
> > 
> > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > is BE, even though that's not really true in practice these days, so
> > to correct for the PCI registers being read as BE when they should be
> > LE we always need a swap.
> > 
> > That should remove the need for swaps further up the test stack.
> > 
> > Of course, "guest endianness" is a poorly defined concept, so longer
> > term it might be better to completely replace the "readw" etc. qtest
> > operations with explicit "readw_le" and "readw_be" ops.
> 
> 
> I have a similar need for a unit test of the AST2400 flash controller. 
> 
> The flash module is accessible through a memory window and, when in 
> SPI mode, the commands are sent to the slave by writing at the beginning 
> of the region. Addresses are necessarily BE to be understood by the SPI
> flash module. So, sequences like
> 
>     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
>     writeb(AST2400_FLASH_BASE, READ);
>     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> 
> will just fail under a BE host as an extra swap is done by the qtest
> layer. I have used memwrite to have endian-agnostic mem accessors. 

Right.  You could fix this by writing tswap32(cpu_to_be32(addr)), of
course but it's starting to get ugly.

> Maybe something like below would be helpful in libqtest.h



> 
> 
> +/*
> + * Generic read/write helpers for a BE region
> + */
> +static inline void writew_be(uint64_t addr, uint16_t value)
> +{
> +    value = cpu_to_be16(value);
> +    memwrite(addr, &value, sizeof(value));
> +}
> +
> +static inline uint16_t readw_be(uint64_t addr)
> +{
> +    uint16_t value;
> +
> +    memread(addr, &value, sizeof(value));
> +    return be16_to_cpu(value);
> +}
> +
> +static inline void writel_be(uint64_t addr, uint32_t value)
> +{
> +    value = cpu_to_be32(value);
> +    memwrite(addr, &value, sizeof(value));
> +}
> +
> +static inline uint32_t readl_be(uint64_t addr)
> +{
> +    uint32_t value;
> +
> +    memread(addr, &value, sizeof(value));
> +    return be32_to_cpu(value);
> +}
> 
> If this is correct, I can add the LE equivalents and send a patch.

I like the idea, but we probably need buy in from some more people.


-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-03 14:03       ` Greg Kurz
  2016-10-03 14:14         ` Cédric Le Goater
  2016-10-03 17:30         ` Cédric Le Goater
@ 2016-10-04  0:24         ` David Gibson
  2016-10-04  6:58           ` Greg Kurz
  2 siblings, 1 reply; 34+ messages in thread
From: David Gibson @ 2016-10-04  0:24 UTC (permalink / raw)
  To: Greg Kurz
  Cc: Cédric Le Goater, Laurent Vivier, thuth, qemu-devel,
	qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 10266 bytes --]

On Mon, Oct 03, 2016 at 04:03:14PM +0200, Greg Kurz wrote:
> On Mon, 3 Oct 2016 13:23:27 +0200
> Cédric Le Goater <clg@kaod.org> wrote:
> 
> > On 09/29/2016 07:27 AM, David Gibson wrote:
> > > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:  
> > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > >> ---
> > >>  tests/Makefile.include   |   1 +
> > >>  tests/libqos/pci-pc.c    |  22 ----
> > >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> > >>  tests/libqos/pci-spapr.h |  17 +++
> > >>  tests/libqos/pci.c       |  22 +++-
> > >>  tests/libqos/rtas.c      |  45 ++++++++
> > >>  tests/libqos/rtas.h      |   4 +
> > >>  7 files changed, 368 insertions(+), 23 deletions(-)
> > >>  create mode 100644 tests/libqos/pci-spapr.c
> > >>  create mode 100644 tests/libqos/pci-spapr.h
> > >>
> > >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> > >> index 8162f6f..92c82d8 100644
> > >> --- a/tests/Makefile.include
> > >> +++ b/tests/Makefile.include
> > >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> > >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> > >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> > >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> > >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> > >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> > >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> > >>  libqos-pc-obj-y += tests/libqos/ahci.o
> > >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> > >> index 1ae2d37..82066b8 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 0000000..78df823
> > >> --- /dev/null
> > >> +++ b/tests/libqos/pci-spapr.c
> > >> @@ -0,0 +1,280 @@
> > >> +/*
> > >> + * 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;
> > >> +
> > >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> > >> +{
> > >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> > >> +    uint16_t v;
> > >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> > >> +        v = readw(IOBASE(0) + port);
> > >> +    } else {
> > >> +        v = readw(MMIOBASE(0) + port);
> > >> +    }  
> > > 
> > > Ok, so, I've looked through the qtest stuff in more detail now, and
> > > I've got a better idea of how the endianness works.  Some of my
> > > earlier comments were confused about which pieces were in the test
> > > case side and which were on the qtest accel stub side.
> > > 
> > > So, what I think you need is an unconditional byteswap in each of the
> > > spapr pci IO functions.  Why?
> > > 
> > >    * The plain readw() etc. functions return values read from memory
> > >      assuming guest endianness.  For guest native values in memory, so
> > >      far so good.
> > >    * Generic users of the pci read/write functions in qtest expect to
> > >      get native values.
> > >    * But PCI devices are always LE, not guest endian
> > > 
> > > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > > is BE, even though that's not really true in practice these days, so
> > > to correct for the PCI registers being read as BE when they should be
> > > LE we always need a swap.
> > > 
> > > That should remove the need for swaps further up the test stack.
> > > 
> > > Of course, "guest endianness" is a poorly defined concept, so longer
> > > term it might be better to completely replace the "readw" etc. qtest
> > > operations with explicit "readw_le" and "readw_be" ops.  
> > 
> > 
> > I have a similar need for a unit test of the AST2400 flash controller. 
> > 
> > The flash module is accessible through a memory window and, when in 
> > SPI mode, the commands are sent to the slave by writing at the beginning 
> > of the region. Addresses are necessarily BE to be understood by the SPI
> > flash module. So, sequences like
> > 
> >     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
> >     writeb(AST2400_FLASH_BASE, READ);
> >     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> > 
> > will just fail under a BE host as an extra swap is done by the qtest
> 
> cpu_to_be32() is indeed what a real guest does... but the real guest runs
> with the target endianness, whereas the qtest program runs with the host
> endianness... so cpu_to_be32() looks wrong here.
> 
> > layer. I have used memwrite to have endian-agnostic mem accessors. 
> > Maybe something like below would be helpful in libqtest.h
> > 
> > 
> > +/*
> > + * Generic read/write helpers for a BE region
> > + */
> > +static inline void writew_be(uint64_t addr, uint16_t value)
> > +{
> > +    value = cpu_to_be16(value);
> > +    memwrite(addr, &value, sizeof(value));
> > +}
> > +
> > +static inline uint16_t readw_be(uint64_t addr)
> > +{
> > +    uint16_t value;
> > +
> > +    memread(addr, &value, sizeof(value));
> > +    return be16_to_cpu(value);
> > +}
> > +
> > +static inline void writel_be(uint64_t addr, uint32_t value)
> > +{
> > +    value = cpu_to_be32(value);
> > +    memwrite(addr, &value, sizeof(value));
> > +}
> > +
> > +static inline uint32_t readl_be(uint64_t addr)
> > +{
> > +    uint32_t value;
> > +
> > +    memread(addr, &value, sizeof(value));
> > +    return be32_to_cpu(value);
> > +}
> > 
> > If this is correct, I can add the LE equivalents and send a patch.
> > 
> 
> The API is correct, but the implementation has the same issue: it uses
> cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> the target endianness is totally ignored.

Yes, this is precisely the intended result.

The target endianness is not well defined, and simply an extra point
of confusion for qtest code.

> Let's suppose that a similar AST2400 platform exists with a BE processor:
> would the same test program work for both LE and BE cases ?

Yes, that's the idea - assuming the AST2400 has the same IO endianness
in either case, which would be usual for most IO devices.

> Both the test program and QEMU run with the host endianness acutally,
> but only QEMU knows about the target endianness. So I guess, the qtest
> protocol should provide explicit BE/LE operations: the test program
> would ask for an access with a specific endianness and the qtest
> accelerator in QEMU would do the swap based on the target endianness.

Half right.  The target endiannness need not enter into this.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-04  0:22       ` David Gibson
@ 2016-10-04  6:44         ` Greg Kurz
  2016-10-04  6:45         ` Cédric Le Goater
  1 sibling, 0 replies; 34+ messages in thread
From: Greg Kurz @ 2016-10-04  6:44 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, Laurent Vivier, thuth, qemu-devel,
	qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 9122 bytes --]

On Tue, 4 Oct 2016 11:22:23 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> On Mon, Oct 03, 2016 at 01:23:27PM +0200, Cédric Le Goater wrote:
> > On 09/29/2016 07:27 AM, David Gibson wrote:  
> > > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:  
> > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > >> ---
> > >>  tests/Makefile.include   |   1 +
> > >>  tests/libqos/pci-pc.c    |  22 ----
> > >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> > >>  tests/libqos/pci-spapr.h |  17 +++
> > >>  tests/libqos/pci.c       |  22 +++-
> > >>  tests/libqos/rtas.c      |  45 ++++++++
> > >>  tests/libqos/rtas.h      |   4 +
> > >>  7 files changed, 368 insertions(+), 23 deletions(-)
> > >>  create mode 100644 tests/libqos/pci-spapr.c
> > >>  create mode 100644 tests/libqos/pci-spapr.h
> > >>
> > >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> > >> index 8162f6f..92c82d8 100644
> > >> --- a/tests/Makefile.include
> > >> +++ b/tests/Makefile.include
> > >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> > >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> > >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> > >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> > >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> > >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> > >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> > >>  libqos-pc-obj-y += tests/libqos/ahci.o
> > >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> > >> index 1ae2d37..82066b8 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 0000000..78df823
> > >> --- /dev/null
> > >> +++ b/tests/libqos/pci-spapr.c
> > >> @@ -0,0 +1,280 @@
> > >> +/*
> > >> + * 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;
> > >> +
> > >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> > >> +{
> > >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> > >> +    uint16_t v;
> > >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> > >> +        v = readw(IOBASE(0) + port);
> > >> +    } else {
> > >> +        v = readw(MMIOBASE(0) + port);
> > >> +    }  
> > > 
> > > Ok, so, I've looked through the qtest stuff in more detail now, and
> > > I've got a better idea of how the endianness works.  Some of my
> > > earlier comments were confused about which pieces were in the test
> > > case side and which were on the qtest accel stub side.
> > > 
> > > So, what I think you need is an unconditional byteswap in each of the
> > > spapr pci IO functions.  Why?
> > > 
> > >    * The plain readw() etc. functions return values read from memory
> > >      assuming guest endianness.  For guest native values in memory, so
> > >      far so good.
> > >    * Generic users of the pci read/write functions in qtest expect to
> > >      get native values.
> > >    * But PCI devices are always LE, not guest endian
> > > 
> > > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > > is BE, even though that's not really true in practice these days, so
> > > to correct for the PCI registers being read as BE when they should be
> > > LE we always need a swap.
> > > 
> > > That should remove the need for swaps further up the test stack.
> > > 
> > > Of course, "guest endianness" is a poorly defined concept, so longer
> > > term it might be better to completely replace the "readw" etc. qtest
> > > operations with explicit "readw_le" and "readw_be" ops.  
> > 
> > 
> > I have a similar need for a unit test of the AST2400 flash controller. 
> > 
> > The flash module is accessible through a memory window and, when in 
> > SPI mode, the commands are sent to the slave by writing at the beginning 
> > of the region. Addresses are necessarily BE to be understood by the SPI
> > flash module. So, sequences like
> > 
> >     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
> >     writeb(AST2400_FLASH_BASE, READ);
> >     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> > 
> > will just fail under a BE host as an extra swap is done by the qtest
> > layer. I have used memwrite to have endian-agnostic mem accessors.   
> 
> Right.  You could fix this by writing tswap32(cpu_to_be32(addr)), of
> course but it's starting to get ugly.
> 

And it would require to have per-target qtest, which is a no go I guess.

> > Maybe something like below would be helpful in libqtest.h  
> 
> 
> 
> > 
> > 
> > +/*
> > + * Generic read/write helpers for a BE region
> > + */
> > +static inline void writew_be(uint64_t addr, uint16_t value)
> > +{
> > +    value = cpu_to_be16(value);
> > +    memwrite(addr, &value, sizeof(value));
> > +}
> > +
> > +static inline uint16_t readw_be(uint64_t addr)
> > +{
> > +    uint16_t value;
> > +
> > +    memread(addr, &value, sizeof(value));
> > +    return be16_to_cpu(value);
> > +}
> > +
> > +static inline void writel_be(uint64_t addr, uint32_t value)
> > +{
> > +    value = cpu_to_be32(value);
> > +    memwrite(addr, &value, sizeof(value));
> > +}
> > +
> > +static inline uint32_t readl_be(uint64_t addr)
> > +{
> > +    uint32_t value;
> > +
> > +    memread(addr, &value, sizeof(value));
> > +    return be32_to_cpu(value);
> > +}
> > 
> > If this is correct, I can add the LE equivalents and send a patch.  
> 
> I like the idea, but we probably need buy in from some more people.
> 
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-04  0:22       ` David Gibson
  2016-10-04  6:44         ` Greg Kurz
@ 2016-10-04  6:45         ` Cédric Le Goater
  1 sibling, 0 replies; 34+ messages in thread
From: Cédric Le Goater @ 2016-10-04  6:45 UTC (permalink / raw)
  To: David Gibson
  Cc: Laurent Vivier, thuth, qemu-devel, Greg Kurz, qemu-ppc,
	Gerd Hoffmann, dgibson

On 10/04/2016 02:22 AM, David Gibson wrote:
> On Mon, Oct 03, 2016 at 01:23:27PM +0200, Cédric Le Goater wrote:
>> On 09/29/2016 07:27 AM, David Gibson wrote:
>>> On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:
>>>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>>>> ---
>>>>  tests/Makefile.include   |   1 +
>>>>  tests/libqos/pci-pc.c    |  22 ----
>>>>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>  tests/libqos/pci-spapr.h |  17 +++
>>>>  tests/libqos/pci.c       |  22 +++-
>>>>  tests/libqos/rtas.c      |  45 ++++++++
>>>>  tests/libqos/rtas.h      |   4 +
>>>>  7 files changed, 368 insertions(+), 23 deletions(-)
>>>>  create mode 100644 tests/libqos/pci-spapr.c
>>>>  create mode 100644 tests/libqos/pci-spapr.h
>>>>
>>>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>>>> index 8162f6f..92c82d8 100644
>>>> --- a/tests/Makefile.include
>>>> +++ b/tests/Makefile.include
>>>> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>>>>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>>>>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>>>>  libqos-spapr-obj-y += tests/libqos/rtas.o
>>>> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
>>>>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>>>>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>>>>  libqos-pc-obj-y += tests/libqos/ahci.o
>>>> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
>>>> index 1ae2d37..82066b8 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 0000000..78df823
>>>> --- /dev/null
>>>> +++ b/tests/libqos/pci-spapr.c
>>>> @@ -0,0 +1,280 @@
>>>> +/*
>>>> + * 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;
>>>> +
>>>> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
>>>> +{
>>>> +    uint64_t port = (uint64_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 = (uint64_t)addr;
>>>> +    uint16_t v;
>>>> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
>>>> +        v = readw(IOBASE(0) + port);
>>>> +    } else {
>>>> +        v = readw(MMIOBASE(0) + port);
>>>> +    }
>>>
>>> Ok, so, I've looked through the qtest stuff in more detail now, and
>>> I've got a better idea of how the endianness works.  Some of my
>>> earlier comments were confused about which pieces were in the test
>>> case side and which were on the qtest accel stub side.
>>>
>>> So, what I think you need is an unconditional byteswap in each of the
>>> spapr pci IO functions.  Why?
>>>
>>>    * The plain readw() etc. functions return values read from memory
>>>      assuming guest endianness.  For guest native values in memory, so
>>>      far so good.
>>>    * Generic users of the pci read/write functions in qtest expect to
>>>      get native values.
>>>    * But PCI devices are always LE, not guest endian
>>>
>>> The guest endianness of spapr (as far as tswap() etc. are concerned)
>>> is BE, even though that's not really true in practice these days, so
>>> to correct for the PCI registers being read as BE when they should be
>>> LE we always need a swap.
>>>
>>> That should remove the need for swaps further up the test stack.
>>>
>>> Of course, "guest endianness" is a poorly defined concept, so longer
>>> term it might be better to completely replace the "readw" etc. qtest
>>> operations with explicit "readw_le" and "readw_be" ops.
>>
>>
>> I have a similar need for a unit test of the AST2400 flash controller. 
>>
>> The flash module is accessible through a memory window and, when in 
>> SPI mode, the commands are sent to the slave by writing at the beginning 
>> of the region. Addresses are necessarily BE to be understood by the SPI
>> flash module. So, sequences like
>>
>>     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
>>     writeb(AST2400_FLASH_BASE, READ);
>>     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
>>
>> will just fail under a BE host as an extra swap is done by the qtest
>> layer. I have used memwrite to have endian-agnostic mem accessors. 
> 
> Right.  You could fix this by writing tswap32(cpu_to_be32(addr)), of
> course but it's starting to get ugly.
> 
>> Maybe something like below would be helpful in libqtest.h
> 
> 
> 
>>
>>
>> +/*
>> + * Generic read/write helpers for a BE region
>> + */
>> +static inline void writew_be(uint64_t addr, uint16_t value)
>> +{
>> +    value = cpu_to_be16(value);
>> +    memwrite(addr, &value, sizeof(value));
>> +}
>> +
>> +static inline uint16_t readw_be(uint64_t addr)
>> +{
>> +    uint16_t value;
>> +
>> +    memread(addr, &value, sizeof(value));
>> +    return be16_to_cpu(value);
>> +}
>> +
>> +static inline void writel_be(uint64_t addr, uint32_t value)
>> +{
>> +    value = cpu_to_be32(value);
>> +    memwrite(addr, &value, sizeof(value));
>> +}
>> +
>> +static inline uint32_t readl_be(uint64_t addr)
>> +{
>> +    uint32_t value;
>> +
>> +    memread(addr, &value, sizeof(value));
>> +    return be32_to_cpu(value);
>> +}
>>
>> If this is correct, I can add the LE equivalents and send a patch.
> 
> I like the idea, but we probably need buy in from some more people.

Yes. I should be sending the latest patch as an RFC but I need to test 
the  LE read/write first. 

Thanks,

C. 
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-04  0:24         ` David Gibson
@ 2016-10-04  6:58           ` Greg Kurz
  2016-10-04  7:36             ` Greg Kurz
  2016-10-05  1:14             ` David Gibson
  0 siblings, 2 replies; 34+ messages in thread
From: Greg Kurz @ 2016-10-04  6:58 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, Laurent Vivier, thuth, qemu-devel,
	qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 11011 bytes --]

On Tue, 4 Oct 2016 11:24:54 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> On Mon, Oct 03, 2016 at 04:03:14PM +0200, Greg Kurz wrote:
> > On Mon, 3 Oct 2016 13:23:27 +0200
> > Cédric Le Goater <clg@kaod.org> wrote:
> >   
> > > On 09/29/2016 07:27 AM, David Gibson wrote:  
> > > > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:    
> > > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > > >> ---
> > > >>  tests/Makefile.include   |   1 +
> > > >>  tests/libqos/pci-pc.c    |  22 ----
> > > >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> > > >>  tests/libqos/pci-spapr.h |  17 +++
> > > >>  tests/libqos/pci.c       |  22 +++-
> > > >>  tests/libqos/rtas.c      |  45 ++++++++
> > > >>  tests/libqos/rtas.h      |   4 +
> > > >>  7 files changed, 368 insertions(+), 23 deletions(-)
> > > >>  create mode 100644 tests/libqos/pci-spapr.c
> > > >>  create mode 100644 tests/libqos/pci-spapr.h
> > > >>
> > > >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> > > >> index 8162f6f..92c82d8 100644
> > > >> --- a/tests/Makefile.include
> > > >> +++ b/tests/Makefile.include
> > > >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> > > >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> > > >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> > > >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> > > >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> > > >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> > > >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> > > >>  libqos-pc-obj-y += tests/libqos/ahci.o
> > > >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> > > >> index 1ae2d37..82066b8 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 0000000..78df823
> > > >> --- /dev/null
> > > >> +++ b/tests/libqos/pci-spapr.c
> > > >> @@ -0,0 +1,280 @@
> > > >> +/*
> > > >> + * 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;
> > > >> +
> > > >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> > > >> +{
> > > >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> > > >> +    uint16_t v;
> > > >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> > > >> +        v = readw(IOBASE(0) + port);
> > > >> +    } else {
> > > >> +        v = readw(MMIOBASE(0) + port);
> > > >> +    }    
> > > > 
> > > > Ok, so, I've looked through the qtest stuff in more detail now, and
> > > > I've got a better idea of how the endianness works.  Some of my
> > > > earlier comments were confused about which pieces were in the test
> > > > case side and which were on the qtest accel stub side.
> > > > 
> > > > So, what I think you need is an unconditional byteswap in each of the
> > > > spapr pci IO functions.  Why?
> > > > 
> > > >    * The plain readw() etc. functions return values read from memory
> > > >      assuming guest endianness.  For guest native values in memory, so
> > > >      far so good.
> > > >    * Generic users of the pci read/write functions in qtest expect to
> > > >      get native values.
> > > >    * But PCI devices are always LE, not guest endian
> > > > 
> > > > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > > > is BE, even though that's not really true in practice these days, so
> > > > to correct for the PCI registers being read as BE when they should be
> > > > LE we always need a swap.
> > > > 
> > > > That should remove the need for swaps further up the test stack.
> > > > 
> > > > Of course, "guest endianness" is a poorly defined concept, so longer
> > > > term it might be better to completely replace the "readw" etc. qtest
> > > > operations with explicit "readw_le" and "readw_be" ops.    
> > > 
> > > 
> > > I have a similar need for a unit test of the AST2400 flash controller. 
> > > 
> > > The flash module is accessible through a memory window and, when in 
> > > SPI mode, the commands are sent to the slave by writing at the beginning 
> > > of the region. Addresses are necessarily BE to be understood by the SPI
> > > flash module. So, sequences like
> > > 
> > >     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
> > >     writeb(AST2400_FLASH_BASE, READ);
> > >     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> > > 
> > > will just fail under a BE host as an extra swap is done by the qtest  
> > 
> > cpu_to_be32() is indeed what a real guest does... but the real guest runs
> > with the target endianness, whereas the qtest program runs with the host
> > endianness... so cpu_to_be32() looks wrong here.
> >   
> > > layer. I have used memwrite to have endian-agnostic mem accessors. 
> > > Maybe something like below would be helpful in libqtest.h
> > > 
> > > 
> > > +/*
> > > + * Generic read/write helpers for a BE region
> > > + */
> > > +static inline void writew_be(uint64_t addr, uint16_t value)
> > > +{
> > > +    value = cpu_to_be16(value);
> > > +    memwrite(addr, &value, sizeof(value));
> > > +}
> > > +
> > > +static inline uint16_t readw_be(uint64_t addr)
> > > +{
> > > +    uint16_t value;
> > > +
> > > +    memread(addr, &value, sizeof(value));
> > > +    return be16_to_cpu(value);
> > > +}
> > > +
> > > +static inline void writel_be(uint64_t addr, uint32_t value)
> > > +{
> > > +    value = cpu_to_be32(value);
> > > +    memwrite(addr, &value, sizeof(value));
> > > +}
> > > +
> > > +static inline uint32_t readl_be(uint64_t addr)
> > > +{
> > > +    uint32_t value;
> > > +
> > > +    memread(addr, &value, sizeof(value));
> > > +    return be32_to_cpu(value);
> > > +}
> > > 
> > > If this is correct, I can add the LE equivalents and send a patch.
> > >   
> > 
> > The API is correct, but the implementation has the same issue: it uses
> > cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> > the target endianness is totally ignored.  
> 
> Yes, this is precisely the intended result.
> 
> The target endianness is not well defined, and simply an extra point
> of confusion for qtest code.
> 

I agree that target endianness is confusing in the test program code but
tswap32() I'm referring to is the one in qtest.c.

> > Let's suppose that a similar AST2400 platform exists with a BE processor:
> > would the same test program work for both LE and BE cases ?  
> 
> Yes, that's the idea - assuming the AST2400 has the same IO endianness
> in either case, which would be usual for most IO devices.
> 
> > Both the test program and QEMU run with the host endianness acutally,
> > but only QEMU knows about the target endianness. So I guess, the qtest
> > protocol should provide explicit BE/LE operations: the test program
> > would ask for an access with a specific endianness and the qtest
> > accelerator in QEMU would do the swap based on the target endianness.  
> 
> Half right.  The target endiannness need not enter into this.
> 

I'm lost here... are you saying that the qtest accelerator does not need
to care for the target endianness when accessing the guest memory ? What
about the tswap*() call sites in qtest.c then ?

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-04  6:58           ` Greg Kurz
@ 2016-10-04  7:36             ` Greg Kurz
  2016-10-05  1:15               ` David Gibson
  2016-10-05  1:14             ` David Gibson
  1 sibling, 1 reply; 34+ messages in thread
From: Greg Kurz @ 2016-10-04  7:36 UTC (permalink / raw)
  To: David Gibson
  Cc: Laurent Vivier, thuth, qemu-devel, qemu-ppc, Gerd Hoffmann,
	dgibson, Cédric Le Goater

[-- Attachment #1: Type: text/plain, Size: 11973 bytes --]

On Tue, 4 Oct 2016 08:58:35 +0200
Greg Kurz <groug@kaod.org> wrote:

> On Tue, 4 Oct 2016 11:24:54 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
> 
> > On Mon, Oct 03, 2016 at 04:03:14PM +0200, Greg Kurz wrote:  
> > > On Mon, 3 Oct 2016 13:23:27 +0200
> > > Cédric Le Goater <clg@kaod.org> wrote:
> > >     
> > > > On 09/29/2016 07:27 AM, David Gibson wrote:    
> > > > > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:      
> > > > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > > > >> ---
> > > > >>  tests/Makefile.include   |   1 +
> > > > >>  tests/libqos/pci-pc.c    |  22 ----
> > > > >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> > > > >>  tests/libqos/pci-spapr.h |  17 +++
> > > > >>  tests/libqos/pci.c       |  22 +++-
> > > > >>  tests/libqos/rtas.c      |  45 ++++++++
> > > > >>  tests/libqos/rtas.h      |   4 +
> > > > >>  7 files changed, 368 insertions(+), 23 deletions(-)
> > > > >>  create mode 100644 tests/libqos/pci-spapr.c
> > > > >>  create mode 100644 tests/libqos/pci-spapr.h
> > > > >>
> > > > >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> > > > >> index 8162f6f..92c82d8 100644
> > > > >> --- a/tests/Makefile.include
> > > > >> +++ b/tests/Makefile.include
> > > > >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> > > > >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> > > > >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> > > > >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> > > > >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> > > > >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> > > > >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> > > > >>  libqos-pc-obj-y += tests/libqos/ahci.o
> > > > >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> > > > >> index 1ae2d37..82066b8 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 0000000..78df823
> > > > >> --- /dev/null
> > > > >> +++ b/tests/libqos/pci-spapr.c
> > > > >> @@ -0,0 +1,280 @@
> > > > >> +/*
> > > > >> + * 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;
> > > > >> +
> > > > >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> > > > >> +{
> > > > >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> > > > >> +    uint16_t v;
> > > > >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> > > > >> +        v = readw(IOBASE(0) + port);
> > > > >> +    } else {
> > > > >> +        v = readw(MMIOBASE(0) + port);
> > > > >> +    }      
> > > > > 
> > > > > Ok, so, I've looked through the qtest stuff in more detail now, and
> > > > > I've got a better idea of how the endianness works.  Some of my
> > > > > earlier comments were confused about which pieces were in the test
> > > > > case side and which were on the qtest accel stub side.
> > > > > 
> > > > > So, what I think you need is an unconditional byteswap in each of the
> > > > > spapr pci IO functions.  Why?
> > > > > 
> > > > >    * The plain readw() etc. functions return values read from memory
> > > > >      assuming guest endianness.  For guest native values in memory, so
> > > > >      far so good.
> > > > >    * Generic users of the pci read/write functions in qtest expect to
> > > > >      get native values.
> > > > >    * But PCI devices are always LE, not guest endian
> > > > > 
> > > > > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > > > > is BE, even though that's not really true in practice these days, so
> > > > > to correct for the PCI registers being read as BE when they should be
> > > > > LE we always need a swap.
> > > > > 
> > > > > That should remove the need for swaps further up the test stack.
> > > > > 
> > > > > Of course, "guest endianness" is a poorly defined concept, so longer
> > > > > term it might be better to completely replace the "readw" etc. qtest
> > > > > operations with explicit "readw_le" and "readw_be" ops.      
> > > > 
> > > > 
> > > > I have a similar need for a unit test of the AST2400 flash controller. 
> > > > 
> > > > The flash module is accessible through a memory window and, when in 
> > > > SPI mode, the commands are sent to the slave by writing at the beginning 
> > > > of the region. Addresses are necessarily BE to be understood by the SPI
> > > > flash module. So, sequences like
> > > > 
> > > >     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
> > > >     writeb(AST2400_FLASH_BASE, READ);
> > > >     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> > > > 
> > > > will just fail under a BE host as an extra swap is done by the qtest    
> > > 
> > > cpu_to_be32() is indeed what a real guest does... but the real guest runs
> > > with the target endianness, whereas the qtest program runs with the host
> > > endianness... so cpu_to_be32() looks wrong here.
> > >     
> > > > layer. I have used memwrite to have endian-agnostic mem accessors. 
> > > > Maybe something like below would be helpful in libqtest.h
> > > > 
> > > > 
> > > > +/*
> > > > + * Generic read/write helpers for a BE region
> > > > + */
> > > > +static inline void writew_be(uint64_t addr, uint16_t value)
> > > > +{
> > > > +    value = cpu_to_be16(value);
> > > > +    memwrite(addr, &value, sizeof(value));
> > > > +}
> > > > +
> > > > +static inline uint16_t readw_be(uint64_t addr)
> > > > +{
> > > > +    uint16_t value;
> > > > +
> > > > +    memread(addr, &value, sizeof(value));
> > > > +    return be16_to_cpu(value);
> > > > +}
> > > > +
> > > > +static inline void writel_be(uint64_t addr, uint32_t value)
> > > > +{
> > > > +    value = cpu_to_be32(value);
> > > > +    memwrite(addr, &value, sizeof(value));
> > > > +}
> > > > +
> > > > +static inline uint32_t readl_be(uint64_t addr)
> > > > +{
> > > > +    uint32_t value;
> > > > +
> > > > +    memread(addr, &value, sizeof(value));
> > > > +    return be32_to_cpu(value);
> > > > +}
> > > > 
> > > > If this is correct, I can add the LE equivalents and send a patch.
> > > >     
> > > 
> > > The API is correct, but the implementation has the same issue: it uses
> > > cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> > > the target endianness is totally ignored.    
> > 
> > Yes, this is precisely the intended result.
> > 
> > The target endianness is not well defined, and simply an extra point
> > of confusion for qtest code.
> >   
> 
> I agree that target endianness is confusing in the test program code but
> tswap32() I'm referring to is the one in qtest.c.
> 
> > > Let's suppose that a similar AST2400 platform exists with a BE processor:
> > > would the same test program work for both LE and BE cases ?    
> > 
> > Yes, that's the idea - assuming the AST2400 has the same IO endianness
> > in either case, which would be usual for most IO devices.
> >   
> > > Both the test program and QEMU run with the host endianness acutally,
> > > but only QEMU knows about the target endianness. So I guess, the qtest
> > > protocol should provide explicit BE/LE operations: the test program
> > > would ask for an access with a specific endianness and the qtest
> > > accelerator in QEMU would do the swap based on the target endianness.    
> > 
> > Half right.  The target endiannness need not enter into this.
> >   
> 
> I'm lost here... are you saying that the qtest accelerator does not need
> to care for the target endianness when accessing the guest memory ? What
> about the tswap*() call sites in qtest.c then ?

Ohh... maybe I see now: if the test program says I'm writing BE or LE, then
it needs to call cpu_to_*() and then we just want qtest.c to copy the value
to guest memory without modifying it again. That's basically what Cedric's
accessors ^^ do.

Th tswap*() in qtest.c only makes sense when accessing memory in native
endianness.

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 6/6] tests: enable ohci/uhci/xhci tests on PPC64
  2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 6/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
@ 2016-10-04 13:20   ` Thomas Huth
  2016-10-04 13:36     ` Laurent Vivier
  0 siblings, 1 reply; 34+ messages in thread
From: Thomas Huth @ 2016-10-04 13:20 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel; +Cc: Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson

On 28.09.2016 20:51, Laurent Vivier wrote:
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>

Meta-question: Do we need to test UHCI on ppc at all? AFAIK most (all?)
ppc-based machines were rather based on OHCI instead...

> ---
>  tests/Makefile.include    |  8 +++++++-
>  tests/libqos/usb.c        |  2 +-
>  tests/usb-hcd-uhci-test.c | 24 ++++++++++++++++--------
>  3 files changed, 24 insertions(+), 10 deletions(-)
[...]
> diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
> index c24063e..4b951ce 100644
> --- a/tests/usb-hcd-uhci-test.c
> +++ b/tests/usb-hcd-uhci-test.c
> @@ -9,9 +9,13 @@
>  
>  #include "qemu/osdep.h"
>  #include "libqtest.h"
> +#include "libqos/libqos.h"
>  #include "libqos/usb.h"
> +#include "libqos/libqos-pc.h"
> +#include "libqos/libqos-spapr.h"
>  #include "hw/usb/uhci-regs.h"
>  
> +static QOSState *qs;
>  
>  static void test_uhci_init(void)
>  {
> @@ -19,13 +23,10 @@ static void test_uhci_init(void)
>  
>  static void test_port(int port)
>  {
> -    QPCIBus *pcibus;
>      struct qhc uhci;
>  
>      g_assert(port > 0);
> -    pcibus = qpci_init_pc(NULL);
> -    g_assert(pcibus != NULL);
> -    qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
> +    qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
>      uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
>  }
>  
> @@ -75,6 +76,7 @@ static void test_usb_storage_hotplug(void)
>  
>  int main(int argc, char **argv)
>  {
> +    const char *arch = qtest_get_arch();
>      int ret;
>  
>      g_test_init(&argc, &argv, NULL);
> @@ -84,11 +86,17 @@ int main(int argc, char **argv)
>      qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug);
>      qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
>  
> -    qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0"
> -                " -drive id=drive0,if=none,file=/dev/null,format=raw"
> -                " -device usb-tablet,bus=uhci.0,port=1");
> +    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
> +        qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
> +                           " -drive id=drive0,if=none,file=/dev/null,format=raw"
> +                           " -device usb-tablet,bus=uhci.0,port=1");
> +    } else if (strcmp(arch, "ppc64") == 0) {
> +        qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
> +                           " -drive id=drive0,if=none,file=/dev/null,format=raw"
> +                           " -device usb-tablet,bus=uhci.0,port=1");
> +    }

The "-device ..." string looks the same for both machine types ... so
IMHO it would be somewhat nicer to define this only once and then use
the common string for both machine instead of specifying it here twice.

 Thomas

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 6/6] tests: enable ohci/uhci/xhci tests on PPC64
  2016-10-04 13:20   ` [Qemu-devel] [Qemu-ppc] " Thomas Huth
@ 2016-10-04 13:36     ` Laurent Vivier
  0 siblings, 0 replies; 34+ messages in thread
From: Laurent Vivier @ 2016-10-04 13:36 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Greg Kurz, qemu-ppc, Gerd Hoffmann, dgibson



On 04/10/2016 15:20, Thomas Huth wrote:
> On 28.09.2016 20:51, Laurent Vivier wrote:
>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> 
> Meta-question: Do we need to test UHCI on ppc at all? AFAIK most (all?)
> ppc-based machines were rather based on OHCI instead...

No, but this is the only test using PCI. OHCI test tests only if we can
plug and hotplug a device.

> 
>> ---
>>  tests/Makefile.include    |  8 +++++++-
>>  tests/libqos/usb.c        |  2 +-
>>  tests/usb-hcd-uhci-test.c | 24 ++++++++++++++++--------
>>  3 files changed, 24 insertions(+), 10 deletions(-)
> [...]
>> diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
>> index c24063e..4b951ce 100644
>> --- a/tests/usb-hcd-uhci-test.c
>> +++ b/tests/usb-hcd-uhci-test.c
>> @@ -9,9 +9,13 @@
>>  
>>  #include "qemu/osdep.h"
>>  #include "libqtest.h"
>> +#include "libqos/libqos.h"
>>  #include "libqos/usb.h"
>> +#include "libqos/libqos-pc.h"
>> +#include "libqos/libqos-spapr.h"
>>  #include "hw/usb/uhci-regs.h"
>>  
>> +static QOSState *qs;
>>  
>>  static void test_uhci_init(void)
>>  {
>> @@ -19,13 +23,10 @@ static void test_uhci_init(void)
>>  
>>  static void test_port(int port)
>>  {
>> -    QPCIBus *pcibus;
>>      struct qhc uhci;
>>  
>>      g_assert(port > 0);
>> -    pcibus = qpci_init_pc(NULL);
>> -    g_assert(pcibus != NULL);
>> -    qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
>> +    qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
>>      uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
>>  }
>>  
>> @@ -75,6 +76,7 @@ static void test_usb_storage_hotplug(void)
>>  
>>  int main(int argc, char **argv)
>>  {
>> +    const char *arch = qtest_get_arch();
>>      int ret;
>>  
>>      g_test_init(&argc, &argv, NULL);
>> @@ -84,11 +86,17 @@ int main(int argc, char **argv)
>>      qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug);
>>      qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
>>  
>> -    qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0"
>> -                " -drive id=drive0,if=none,file=/dev/null,format=raw"
>> -                " -device usb-tablet,bus=uhci.0,port=1");
>> +    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
>> +        qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
>> +                           " -drive id=drive0,if=none,file=/dev/null,format=raw"
>> +                           " -device usb-tablet,bus=uhci.0,port=1");
>> +    } else if (strcmp(arch, "ppc64") == 0) {
>> +        qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0"
>> +                           " -drive id=drive0,if=none,file=/dev/null,format=raw"
>> +                           " -device usb-tablet,bus=uhci.0,port=1");
>> +    }
> 
> The "-device ..." string looks the same for both machine types ... so
> IMHO it would be somewhat nicer to define this only once and then use
> the common string for both machine instead of specifying it here twice.

yes.

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-04  6:58           ` Greg Kurz
  2016-10-04  7:36             ` Greg Kurz
@ 2016-10-05  1:14             ` David Gibson
  2016-10-05  7:34               ` Greg Kurz
  1 sibling, 1 reply; 34+ messages in thread
From: David Gibson @ 2016-10-05  1:14 UTC (permalink / raw)
  To: Greg Kurz
  Cc: Cédric Le Goater, Laurent Vivier, thuth, qemu-devel,
	qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 12604 bytes --]

On Tue, Oct 04, 2016 at 08:58:35AM +0200, Greg Kurz wrote:
> On Tue, 4 Oct 2016 11:24:54 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
> 
> > On Mon, Oct 03, 2016 at 04:03:14PM +0200, Greg Kurz wrote:
> > > On Mon, 3 Oct 2016 13:23:27 +0200
> > > Cédric Le Goater <clg@kaod.org> wrote:
> > >   
> > > > On 09/29/2016 07:27 AM, David Gibson wrote:  
> > > > > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:    
> > > > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > > > >> ---
> > > > >>  tests/Makefile.include   |   1 +
> > > > >>  tests/libqos/pci-pc.c    |  22 ----
> > > > >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> > > > >>  tests/libqos/pci-spapr.h |  17 +++
> > > > >>  tests/libqos/pci.c       |  22 +++-
> > > > >>  tests/libqos/rtas.c      |  45 ++++++++
> > > > >>  tests/libqos/rtas.h      |   4 +
> > > > >>  7 files changed, 368 insertions(+), 23 deletions(-)
> > > > >>  create mode 100644 tests/libqos/pci-spapr.c
> > > > >>  create mode 100644 tests/libqos/pci-spapr.h
> > > > >>
> > > > >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> > > > >> index 8162f6f..92c82d8 100644
> > > > >> --- a/tests/Makefile.include
> > > > >> +++ b/tests/Makefile.include
> > > > >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> > > > >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> > > > >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> > > > >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> > > > >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> > > > >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> > > > >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> > > > >>  libqos-pc-obj-y += tests/libqos/ahci.o
> > > > >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> > > > >> index 1ae2d37..82066b8 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 0000000..78df823
> > > > >> --- /dev/null
> > > > >> +++ b/tests/libqos/pci-spapr.c
> > > > >> @@ -0,0 +1,280 @@
> > > > >> +/*
> > > > >> + * 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;
> > > > >> +
> > > > >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> > > > >> +{
> > > > >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> > > > >> +    uint16_t v;
> > > > >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> > > > >> +        v = readw(IOBASE(0) + port);
> > > > >> +    } else {
> > > > >> +        v = readw(MMIOBASE(0) + port);
> > > > >> +    }    
> > > > > 
> > > > > Ok, so, I've looked through the qtest stuff in more detail now, and
> > > > > I've got a better idea of how the endianness works.  Some of my
> > > > > earlier comments were confused about which pieces were in the test
> > > > > case side and which were on the qtest accel stub side.
> > > > > 
> > > > > So, what I think you need is an unconditional byteswap in each of the
> > > > > spapr pci IO functions.  Why?
> > > > > 
> > > > >    * The plain readw() etc. functions return values read from memory
> > > > >      assuming guest endianness.  For guest native values in memory, so
> > > > >      far so good.
> > > > >    * Generic users of the pci read/write functions in qtest expect to
> > > > >      get native values.
> > > > >    * But PCI devices are always LE, not guest endian
> > > > > 
> > > > > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > > > > is BE, even though that's not really true in practice these days, so
> > > > > to correct for the PCI registers being read as BE when they should be
> > > > > LE we always need a swap.
> > > > > 
> > > > > That should remove the need for swaps further up the test stack.
> > > > > 
> > > > > Of course, "guest endianness" is a poorly defined concept, so longer
> > > > > term it might be better to completely replace the "readw" etc. qtest
> > > > > operations with explicit "readw_le" and "readw_be" ops.    
> > > > 
> > > > 
> > > > I have a similar need for a unit test of the AST2400 flash controller. 
> > > > 
> > > > The flash module is accessible through a memory window and, when in 
> > > > SPI mode, the commands are sent to the slave by writing at the beginning 
> > > > of the region. Addresses are necessarily BE to be understood by the SPI
> > > > flash module. So, sequences like
> > > > 
> > > >     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
> > > >     writeb(AST2400_FLASH_BASE, READ);
> > > >     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> > > > 
> > > > will just fail under a BE host as an extra swap is done by the qtest  
> > > 
> > > cpu_to_be32() is indeed what a real guest does... but the real guest runs
> > > with the target endianness, whereas the qtest program runs with the host
> > > endianness... so cpu_to_be32() looks wrong here.
> > >   
> > > > layer. I have used memwrite to have endian-agnostic mem accessors. 
> > > > Maybe something like below would be helpful in libqtest.h
> > > > 
> > > > 
> > > > +/*
> > > > + * Generic read/write helpers for a BE region
> > > > + */
> > > > +static inline void writew_be(uint64_t addr, uint16_t value)
> > > > +{
> > > > +    value = cpu_to_be16(value);
> > > > +    memwrite(addr, &value, sizeof(value));
> > > > +}
> > > > +
> > > > +static inline uint16_t readw_be(uint64_t addr)
> > > > +{
> > > > +    uint16_t value;
> > > > +
> > > > +    memread(addr, &value, sizeof(value));
> > > > +    return be16_to_cpu(value);
> > > > +}
> > > > +
> > > > +static inline void writel_be(uint64_t addr, uint32_t value)
> > > > +{
> > > > +    value = cpu_to_be32(value);
> > > > +    memwrite(addr, &value, sizeof(value));
> > > > +}
> > > > +
> > > > +static inline uint32_t readl_be(uint64_t addr)
> > > > +{
> > > > +    uint32_t value;
> > > > +
> > > > +    memread(addr, &value, sizeof(value));
> > > > +    return be32_to_cpu(value);
> > > > +}
> > > > 
> > > > If this is correct, I can add the LE equivalents and send a patch.
> > > >   
> > > 
> > > The API is correct, but the implementation has the same issue: it uses
> > > cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> > > the target endianness is totally ignored.  
> > 
> > Yes, this is precisely the intended result.
> > 
> > The target endianness is not well defined, and simply an extra point
> > of confusion for qtest code.
> > 
> 
> I agree that target endianness is confusing in the test program code but
> tswap32() I'm referring to is the one in qtest.c.

Yes, that's the one I'm referring to as well.  Bypassing it is
*precisely* the intention of this patch.

> > > Let's suppose that a similar AST2400 platform exists with a BE processor:
> > > would the same test program work for both LE and BE cases ?  
> > 
> > Yes, that's the idea - assuming the AST2400 has the same IO endianness
> > in either case, which would be usual for most IO devices.
> > 
> > > Both the test program and QEMU run with the host endianness acutally,
> > > but only QEMU knows about the target endianness. So I guess, the qtest
> > > protocol should provide explicit BE/LE operations: the test program
> > > would ask for an access with a specific endianness and the qtest
> > > accelerator in QEMU would do the swap based on the target endianness.  
> > 
> > Half right.  The target endiannness need not enter into this.
> > 
> 
> I'm lost here... are you saying that the qtest accelerator does not need
> to care for the target endianness when accessing the guest memory ? What
> about the tswap*() call sites in qtest.c then ?

Bad idea from the start as far as I can tell.

Well.. maybe.  For accessing IO devices we certainly want to bypass it
- they have their own endianness independent from the target cpu.  For
accessing guest RAM, possibly we want target endianness accessors.


Even then, though, I don't see much call for it.  If it's some
hardware protocol (e.g. DMA buffers), the peripheral hardware still
defines the endianness independent of the target cpu.  If it's just
for communication between pieces of our test, then we control both
sides so it doesn't matter what we choose, as long as we're
consistent.  Might as well make it universally consistent instead of
arbitrarily varying based on target cpu.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-04  7:36             ` Greg Kurz
@ 2016-10-05  1:15               ` David Gibson
  0 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2016-10-05  1:15 UTC (permalink / raw)
  To: Greg Kurz
  Cc: Laurent Vivier, thuth, qemu-devel, qemu-ppc, Gerd Hoffmann,
	dgibson, Cédric Le Goater

[-- Attachment #1: Type: text/plain, Size: 12991 bytes --]

On Tue, Oct 04, 2016 at 09:36:30AM +0200, Greg Kurz wrote:
> On Tue, 4 Oct 2016 08:58:35 +0200
> Greg Kurz <groug@kaod.org> wrote:
> 
> > On Tue, 4 Oct 2016 11:24:54 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> > 
> > > On Mon, Oct 03, 2016 at 04:03:14PM +0200, Greg Kurz wrote:  
> > > > On Mon, 3 Oct 2016 13:23:27 +0200
> > > > Cédric Le Goater <clg@kaod.org> wrote:
> > > >     
> > > > > On 09/29/2016 07:27 AM, David Gibson wrote:    
> > > > > > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:      
> > > > > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > > > > >> ---
> > > > > >>  tests/Makefile.include   |   1 +
> > > > > >>  tests/libqos/pci-pc.c    |  22 ----
> > > > > >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> > > > > >>  tests/libqos/pci-spapr.h |  17 +++
> > > > > >>  tests/libqos/pci.c       |  22 +++-
> > > > > >>  tests/libqos/rtas.c      |  45 ++++++++
> > > > > >>  tests/libqos/rtas.h      |   4 +
> > > > > >>  7 files changed, 368 insertions(+), 23 deletions(-)
> > > > > >>  create mode 100644 tests/libqos/pci-spapr.c
> > > > > >>  create mode 100644 tests/libqos/pci-spapr.h
> > > > > >>
> > > > > >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> > > > > >> index 8162f6f..92c82d8 100644
> > > > > >> --- a/tests/Makefile.include
> > > > > >> +++ b/tests/Makefile.include
> > > > > >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> > > > > >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> > > > > >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> > > > > >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> > > > > >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> > > > > >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> > > > > >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> > > > > >>  libqos-pc-obj-y += tests/libqos/ahci.o
> > > > > >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> > > > > >> index 1ae2d37..82066b8 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 0000000..78df823
> > > > > >> --- /dev/null
> > > > > >> +++ b/tests/libqos/pci-spapr.c
> > > > > >> @@ -0,0 +1,280 @@
> > > > > >> +/*
> > > > > >> + * 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;
> > > > > >> +
> > > > > >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> > > > > >> +{
> > > > > >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> > > > > >> +    uint16_t v;
> > > > > >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> > > > > >> +        v = readw(IOBASE(0) + port);
> > > > > >> +    } else {
> > > > > >> +        v = readw(MMIOBASE(0) + port);
> > > > > >> +    }      
> > > > > > 
> > > > > > Ok, so, I've looked through the qtest stuff in more detail now, and
> > > > > > I've got a better idea of how the endianness works.  Some of my
> > > > > > earlier comments were confused about which pieces were in the test
> > > > > > case side and which were on the qtest accel stub side.
> > > > > > 
> > > > > > So, what I think you need is an unconditional byteswap in each of the
> > > > > > spapr pci IO functions.  Why?
> > > > > > 
> > > > > >    * The plain readw() etc. functions return values read from memory
> > > > > >      assuming guest endianness.  For guest native values in memory, so
> > > > > >      far so good.
> > > > > >    * Generic users of the pci read/write functions in qtest expect to
> > > > > >      get native values.
> > > > > >    * But PCI devices are always LE, not guest endian
> > > > > > 
> > > > > > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > > > > > is BE, even though that's not really true in practice these days, so
> > > > > > to correct for the PCI registers being read as BE when they should be
> > > > > > LE we always need a swap.
> > > > > > 
> > > > > > That should remove the need for swaps further up the test stack.
> > > > > > 
> > > > > > Of course, "guest endianness" is a poorly defined concept, so longer
> > > > > > term it might be better to completely replace the "readw" etc. qtest
> > > > > > operations with explicit "readw_le" and "readw_be" ops.      
> > > > > 
> > > > > 
> > > > > I have a similar need for a unit test of the AST2400 flash controller. 
> > > > > 
> > > > > The flash module is accessible through a memory window and, when in 
> > > > > SPI mode, the commands are sent to the slave by writing at the beginning 
> > > > > of the region. Addresses are necessarily BE to be understood by the SPI
> > > > > flash module. So, sequences like
> > > > > 
> > > > >     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
> > > > >     writeb(AST2400_FLASH_BASE, READ);
> > > > >     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> > > > > 
> > > > > will just fail under a BE host as an extra swap is done by the qtest    
> > > > 
> > > > cpu_to_be32() is indeed what a real guest does... but the real guest runs
> > > > with the target endianness, whereas the qtest program runs with the host
> > > > endianness... so cpu_to_be32() looks wrong here.
> > > >     
> > > > > layer. I have used memwrite to have endian-agnostic mem accessors. 
> > > > > Maybe something like below would be helpful in libqtest.h
> > > > > 
> > > > > 
> > > > > +/*
> > > > > + * Generic read/write helpers for a BE region
> > > > > + */
> > > > > +static inline void writew_be(uint64_t addr, uint16_t value)
> > > > > +{
> > > > > +    value = cpu_to_be16(value);
> > > > > +    memwrite(addr, &value, sizeof(value));
> > > > > +}
> > > > > +
> > > > > +static inline uint16_t readw_be(uint64_t addr)
> > > > > +{
> > > > > +    uint16_t value;
> > > > > +
> > > > > +    memread(addr, &value, sizeof(value));
> > > > > +    return be16_to_cpu(value);
> > > > > +}
> > > > > +
> > > > > +static inline void writel_be(uint64_t addr, uint32_t value)
> > > > > +{
> > > > > +    value = cpu_to_be32(value);
> > > > > +    memwrite(addr, &value, sizeof(value));
> > > > > +}
> > > > > +
> > > > > +static inline uint32_t readl_be(uint64_t addr)
> > > > > +{
> > > > > +    uint32_t value;
> > > > > +
> > > > > +    memread(addr, &value, sizeof(value));
> > > > > +    return be32_to_cpu(value);
> > > > > +}
> > > > > 
> > > > > If this is correct, I can add the LE equivalents and send a patch.
> > > > >     
> > > > 
> > > > The API is correct, but the implementation has the same issue: it uses
> > > > cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> > > > the target endianness is totally ignored.    
> > > 
> > > Yes, this is precisely the intended result.
> > > 
> > > The target endianness is not well defined, and simply an extra point
> > > of confusion for qtest code.
> > >   
> > 
> > I agree that target endianness is confusing in the test program code but
> > tswap32() I'm referring to is the one in qtest.c.
> > 
> > > > Let's suppose that a similar AST2400 platform exists with a BE processor:
> > > > would the same test program work for both LE and BE cases ?    
> > > 
> > > Yes, that's the idea - assuming the AST2400 has the same IO endianness
> > > in either case, which would be usual for most IO devices.
> > >   
> > > > Both the test program and QEMU run with the host endianness acutally,
> > > > but only QEMU knows about the target endianness. So I guess, the qtest
> > > > protocol should provide explicit BE/LE operations: the test program
> > > > would ask for an access with a specific endianness and the qtest
> > > > accelerator in QEMU would do the swap based on the target endianness.    
> > > 
> > > Half right.  The target endiannness need not enter into this.
> > >   
> > 
> > I'm lost here... are you saying that the qtest accelerator does not need
> > to care for the target endianness when accessing the guest memory ? What
> > about the tswap*() call sites in qtest.c then ?
> 
> Ohh... maybe I see now: if the test program says I'm writing BE or LE, then
> it needs to call cpu_to_*() and then we just want qtest.c to copy the value
> to guest memory without modifying it again. That's basically what Cedric's
> accessors ^^ do.
> 
> Th tswap*() in qtest.c only makes sense when accessing memory in native
> endianness.

s/native/guest native/, yes.  Except that guest native endianness is
vague to begin with CPUs that support both modes, and completely
meaningless when we've essentially replaced the guest cpu with the
qtest stub.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-05  1:14             ` David Gibson
@ 2016-10-05  7:34               ` Greg Kurz
  2016-10-05 19:33                 ` Greg Kurz
  0 siblings, 1 reply; 34+ messages in thread
From: Greg Kurz @ 2016-10-05  7:34 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, Laurent Vivier, thuth, qemu-devel,
	qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 13218 bytes --]

On Wed, 5 Oct 2016 12:14:05 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> On Tue, Oct 04, 2016 at 08:58:35AM +0200, Greg Kurz wrote:
> > On Tue, 4 Oct 2016 11:24:54 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >   
> > > On Mon, Oct 03, 2016 at 04:03:14PM +0200, Greg Kurz wrote:  
> > > > On Mon, 3 Oct 2016 13:23:27 +0200
> > > > Cédric Le Goater <clg@kaod.org> wrote:
> > > >     
> > > > > On 09/29/2016 07:27 AM, David Gibson wrote:    
> > > > > > On Wed, Sep 28, 2016 at 08:51:28PM +0200, Laurent Vivier wrote:      
> > > > > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> > > > > >> ---
> > > > > >>  tests/Makefile.include   |   1 +
> > > > > >>  tests/libqos/pci-pc.c    |  22 ----
> > > > > >>  tests/libqos/pci-spapr.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++
> > > > > >>  tests/libqos/pci-spapr.h |  17 +++
> > > > > >>  tests/libqos/pci.c       |  22 +++-
> > > > > >>  tests/libqos/rtas.c      |  45 ++++++++
> > > > > >>  tests/libqos/rtas.h      |   4 +
> > > > > >>  7 files changed, 368 insertions(+), 23 deletions(-)
> > > > > >>  create mode 100644 tests/libqos/pci-spapr.c
> > > > > >>  create mode 100644 tests/libqos/pci-spapr.h
> > > > > >>
> > > > > >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> > > > > >> index 8162f6f..92c82d8 100644
> > > > > >> --- a/tests/Makefile.include
> > > > > >> +++ b/tests/Makefile.include
> > > > > >> @@ -590,6 +590,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> > > > > >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> > > > > >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> > > > > >>  libqos-spapr-obj-y += tests/libqos/rtas.o
> > > > > >> +libqos-spapr-obj-y += tests/libqos/pci-spapr.o
> > > > > >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> > > > > >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> > > > > >>  libqos-pc-obj-y += tests/libqos/ahci.o
> > > > > >> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> > > > > >> index 1ae2d37..82066b8 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 0000000..78df823
> > > > > >> --- /dev/null
> > > > > >> +++ b/tests/libqos/pci-spapr.c
> > > > > >> @@ -0,0 +1,280 @@
> > > > > >> +/*
> > > > > >> + * 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;
> > > > > >> +
> > > > > >> +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
> > > > > >> +{
> > > > > >> +    uint64_t port = (uint64_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 = (uint64_t)addr;
> > > > > >> +    uint16_t v;
> > > > > >> +    if (port < SPAPR_PCI_IO_WIN_SIZE) {
> > > > > >> +        v = readw(IOBASE(0) + port);
> > > > > >> +    } else {
> > > > > >> +        v = readw(MMIOBASE(0) + port);
> > > > > >> +    }      
> > > > > > 
> > > > > > Ok, so, I've looked through the qtest stuff in more detail now, and
> > > > > > I've got a better idea of how the endianness works.  Some of my
> > > > > > earlier comments were confused about which pieces were in the test
> > > > > > case side and which were on the qtest accel stub side.
> > > > > > 
> > > > > > So, what I think you need is an unconditional byteswap in each of the
> > > > > > spapr pci IO functions.  Why?
> > > > > > 
> > > > > >    * The plain readw() etc. functions return values read from memory
> > > > > >      assuming guest endianness.  For guest native values in memory, so
> > > > > >      far so good.
> > > > > >    * Generic users of the pci read/write functions in qtest expect to
> > > > > >      get native values.
> > > > > >    * But PCI devices are always LE, not guest endian
> > > > > > 
> > > > > > The guest endianness of spapr (as far as tswap() etc. are concerned)
> > > > > > is BE, even though that's not really true in practice these days, so
> > > > > > to correct for the PCI registers being read as BE when they should be
> > > > > > LE we always need a swap.
> > > > > > 
> > > > > > That should remove the need for swaps further up the test stack.
> > > > > > 
> > > > > > Of course, "guest endianness" is a poorly defined concept, so longer
> > > > > > term it might be better to completely replace the "readw" etc. qtest
> > > > > > operations with explicit "readw_le" and "readw_be" ops.      
> > > > > 
> > > > > 
> > > > > I have a similar need for a unit test of the AST2400 flash controller. 
> > > > > 
> > > > > The flash module is accessible through a memory window and, when in 
> > > > > SPI mode, the commands are sent to the slave by writing at the beginning 
> > > > > of the region. Addresses are necessarily BE to be understood by the SPI
> > > > > flash module. So, sequences like
> > > > > 
> > > > >     writeb(AST2400_FLASH_BASE, EN_4BYTE_ADDR);
> > > > >     writeb(AST2400_FLASH_BASE, READ);
> > > > >     writel(AST2400_FLASH_BASE, cpu_to_be32(addr));
> > > > > 
> > > > > will just fail under a BE host as an extra swap is done by the qtest    
> > > > 
> > > > cpu_to_be32() is indeed what a real guest does... but the real guest runs
> > > > with the target endianness, whereas the qtest program runs with the host
> > > > endianness... so cpu_to_be32() looks wrong here.
> > > >     
> > > > > layer. I have used memwrite to have endian-agnostic mem accessors. 
> > > > > Maybe something like below would be helpful in libqtest.h
> > > > > 
> > > > > 
> > > > > +/*
> > > > > + * Generic read/write helpers for a BE region
> > > > > + */
> > > > > +static inline void writew_be(uint64_t addr, uint16_t value)
> > > > > +{
> > > > > +    value = cpu_to_be16(value);
> > > > > +    memwrite(addr, &value, sizeof(value));
> > > > > +}
> > > > > +
> > > > > +static inline uint16_t readw_be(uint64_t addr)
> > > > > +{
> > > > > +    uint16_t value;
> > > > > +
> > > > > +    memread(addr, &value, sizeof(value));
> > > > > +    return be16_to_cpu(value);
> > > > > +}
> > > > > +
> > > > > +static inline void writel_be(uint64_t addr, uint32_t value)
> > > > > +{
> > > > > +    value = cpu_to_be32(value);
> > > > > +    memwrite(addr, &value, sizeof(value));
> > > > > +}
> > > > > +
> > > > > +static inline uint32_t readl_be(uint64_t addr)
> > > > > +{
> > > > > +    uint32_t value;
> > > > > +
> > > > > +    memread(addr, &value, sizeof(value));
> > > > > +    return be32_to_cpu(value);
> > > > > +}
> > > > > 
> > > > > If this is correct, I can add the LE equivalents and send a patch.
> > > > >     
> > > > 
> > > > The API is correct, but the implementation has the same issue: it uses
> > > > cpu_to_be32() and bypasses the tswap32() in qtest... the result is that
> > > > the target endianness is totally ignored.    
> > > 
> > > Yes, this is precisely the intended result.
> > > 
> > > The target endianness is not well defined, and simply an extra point
> > > of confusion for qtest code.
> > >   
> > 
> > I agree that target endianness is confusing in the test program code but
> > tswap32() I'm referring to is the one in qtest.c.  
> 
> Yes, that's the one I'm referring to as well.  Bypassing it is
> *precisely* the intention of this patch.
> 
> > > > Let's suppose that a similar AST2400 platform exists with a BE processor:
> > > > would the same test program work for both LE and BE cases ?    
> > > 
> > > Yes, that's the idea - assuming the AST2400 has the same IO endianness
> > > in either case, which would be usual for most IO devices.
> > >   
> > > > Both the test program and QEMU run with the host endianness acutally,
> > > > but only QEMU knows about the target endianness. So I guess, the qtest
> > > > protocol should provide explicit BE/LE operations: the test program
> > > > would ask for an access with a specific endianness and the qtest
> > > > accelerator in QEMU would do the swap based on the target endianness.    
> > > 
> > > Half right.  The target endiannness need not enter into this.
> > >   
> > 
> > I'm lost here... are you saying that the qtest accelerator does not need
> > to care for the target endianness when accessing the guest memory ? What
> > about the tswap*() call sites in qtest.c then ?  
> 
> Bad idea from the start as far as I can tell.
> 
> Well.. maybe.  For accessing IO devices we certainly want to bypass it
> - they have their own endianness independent from the target cpu.  For
> accessing guest RAM, possibly we want target endianness accessors.
> 
> 
> Even then, though, I don't see much call for it.  If it's some
> hardware protocol (e.g. DMA buffers), the peripheral hardware still
> defines the endianness independent of the target cpu.  If it's just
> for communication between pieces of our test, then we control both
> sides so it doesn't matter what we choose, as long as we're
> consistent.  Might as well make it universally consistent instead of
> arbitrarily varying based on target cpu.
> 

You convinced me. The tswaps in qtest.c are toxic and should be removed.

Thanks for the clarification.

--
Greg

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-05  7:34               ` Greg Kurz
@ 2016-10-05 19:33                 ` Greg Kurz
  2016-10-06  3:53                   ` David Gibson
  0 siblings, 1 reply; 34+ messages in thread
From: Greg Kurz @ 2016-10-05 19:33 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, Laurent Vivier, thuth, qemu-devel,
	qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 1253 bytes --]

On Wed, 5 Oct 2016 09:34:05 +0200
Greg Kurz <groug@kaod.org> wrote:
> On Wed, 5 Oct 2016 12:14:05 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
> [...]
> You convinced me. The tswaps in qtest.c are toxic and should be removed.
> 
> Thanks for the clarification.
> 

Rewind. Cedric and I spent the whole day thinking about that, based on
Peter's inputs. The conclusion is: the qtest accelerator replaces the
real world CPU and and the test program simulates what the CPU actually
does when running the guest driver code in a specific situation.

If the guest driver performs a store to the device, and the CPU and
device have different endianness, cpu_to_xxYY() in the driver code
boils down to bswapYY(). Doing things like writel(cpu_to_beYY()) in
the test program is thus wrong since it involves the host endianness,
and the test program no longer simulates what the real CPU would do.
The test program must hence do writel(bswapYY()) and send that to qtest.

If the host endianness differs from the simulated CPU, the value is in
wrong order and must be byteswapped before being handed over to the memory
layer.

This explains why qtest calls tswapYY() before cpu_physical_memory_write().

Cheers.

--
Greg

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v3 1/6] libqos: add PPC64 PCI support
  2016-10-05 19:33                 ` Greg Kurz
@ 2016-10-06  3:53                   ` David Gibson
  0 siblings, 0 replies; 34+ messages in thread
From: David Gibson @ 2016-10-06  3:53 UTC (permalink / raw)
  To: Greg Kurz
  Cc: Cédric Le Goater, Laurent Vivier, thuth, qemu-devel,
	qemu-ppc, Gerd Hoffmann, dgibson

[-- Attachment #1: Type: text/plain, Size: 2463 bytes --]

On Wed, Oct 05, 2016 at 09:33:06PM +0200, Greg Kurz wrote:
> On Wed, 5 Oct 2016 09:34:05 +0200
> Greg Kurz <groug@kaod.org> wrote:
> > On Wed, 5 Oct 2016 12:14:05 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> > [...]
> > You convinced me. The tswaps in qtest.c are toxic and should be removed.
> > 
> > Thanks for the clarification.
> > 
> 
> Rewind. Cedric and I spent the whole day thinking about that, based on
> Peter's inputs. The conclusion is: the qtest accelerator replaces the
> real world CPU and and the test program simulates what the CPU actually
> does when running the guest driver code in a specific situation.

No, I still think Peter is dead wrong, as you can see in my various
replies

"What the CPU actually does" depends on a number of factors which
simply aren't modelled when qtest replaces the cpu, so it's not a
meaningful concept.

> If the guest driver performs a store to the device, and the CPU and
> device have different endianness, cpu_to_xxYY() in the driver code
> boils down to bswapYY(). Doing things like writel(cpu_to_beYY()) in
> the test program is thus wrong since it involves the host endianness,
> and the test program no longer simulates what the real CPU would do.
> The test program must hence do writel(bswapYY()) and send that to
> qtest.

Except that the bswap has to be conditional on whether the guest CPU's
notional endianness is the same as the device or not.  So, for say an
LE device that can appear on several platforms what we actually need
writel(guestcpu_to_le32(val)).  Except that if host and guest
(notional) endianness are different the result of that conversion
won't *actually* be LE32, it will be a swapped value in anticipation
of the swap back to guest endianness within the writel().

Why not just say what you actually want.  We want to write to an LE
device, so writel_le(val);

> If the host endianness differs from the simulated CPU, the value is in
> wrong order and must be byteswapped before being handed over to the memory
> layer.
> 
> This explains why qtest calls tswapYY() before cpu_physical_memory_write().

Yes, the tswap() correctly implements an operation with semantics that
are approximately never what you want.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2016-10-06  3:53 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-28 18:51 [Qemu-devel] [PATCH v3 0/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 1/6] libqos: add PPC64 PCI support Laurent Vivier
2016-09-29  5:27   ` [Qemu-devel] [Qemu-ppc] " David Gibson
2016-10-03 11:23     ` Cédric Le Goater
2016-10-03 11:37       ` Laurent Vivier
2016-10-03 14:03       ` Greg Kurz
2016-10-03 14:14         ` Cédric Le Goater
2016-10-03 17:30         ` Cédric Le Goater
2016-10-04  0:24         ` David Gibson
2016-10-04  6:58           ` Greg Kurz
2016-10-04  7:36             ` Greg Kurz
2016-10-05  1:15               ` David Gibson
2016-10-05  1:14             ` David Gibson
2016-10-05  7:34               ` Greg Kurz
2016-10-05 19:33                 ` Greg Kurz
2016-10-06  3:53                   ` David Gibson
2016-10-04  0:22       ` David Gibson
2016-10-04  6:44         ` Greg Kurz
2016-10-04  6:45         ` Cédric Le Goater
2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 2/6] libqos: add PCI management in qtest_vboot()/qtest_shutdown() Laurent Vivier
2016-09-29  5:30   ` [Qemu-devel] [Qemu-ppc] " David Gibson
2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 3/6] libqos: use generic qtest_shutdown() Laurent Vivier
2016-09-29  5:31   ` [Qemu-devel] [Qemu-ppc] " David Gibson
2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 4/6] qtest: evaluate endianness of the target in qtest_init() Laurent Vivier
2016-09-29  5:31   ` [Qemu-devel] [Qemu-ppc] " David Gibson
2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 5/6] qtest: define target cpu endianness conversion functions Laurent Vivier
2016-09-29  5:33   ` [Qemu-devel] [Qemu-ppc] " David Gibson
2016-09-29  7:23     ` Laurent Vivier
2016-09-29  7:27       ` David Gibson
2016-09-28 18:51 ` [Qemu-devel] [PATCH v3 6/6] tests: enable ohci/uhci/xhci tests on PPC64 Laurent Vivier
2016-10-04 13:20   ` [Qemu-devel] [Qemu-ppc] " Thomas Huth
2016-10-04 13:36     ` Laurent Vivier
2016-09-28 19:24 ` [Qemu-devel] [PATCH v3 0/6] " no-reply
2016-09-29  5:35 ` [Qemu-devel] [Qemu-ppc] " David Gibson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.