All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework
@ 2018-12-03 15:32 Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file Paolo Bonzini
                   ` (73 more replies)
  0 siblings, 74 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Patches 1-14 are actually a refactoring of vhost and vhost-user-test so
that it can be "qtested" on all targets that support virtio-net.

Patches 15-18 are other small refactorings to the libqos library and fixes
to the Makefile.

Patch 19 is the framework, including unit tests, while the rest is conversions
of existing tests.  We tried to pick tests that used a mix of features of
qtest, and that cover as many use cases as possible within qgraph. 
In particular:

- sdhci-test was the motivating example for the duplication between
  PCI and MMIO versions of the same devices, so it come first

- all virtio tests were converted, since they also have both MMIO and
  PCI variants and they taught us a lot about modeling devices within
  qgraph

- all PCI devices that had "nop" tests only were converted, so that they
  can avoid defining their copy of the test, and can instead use a
  common test

- finally, three more PCI devices were converted as an example - e1000e,
  nvme and megasas

This submission includes quite a few changes and cleanups that we did
not manage to complete before Emanuele restarted classes, but this
is almost entirely his baby; don't be fooled by the number of patches
authored by him vs. myself.  I have noted my changes to the framework
in the commit message to patch 19, to help people that followed the
previous submissions; apart from that my changes consist of porting
vhost-user-test and turning the nop tests into generic PCI and virtio
tests (even though Emanuele had done the conversion to qgraph, he had
left the tests in the nodes due to lack of time).

Thanks,

Paolo

Based-on: <1543513531-1151-1-git-send-email-pbonzini@redhat.com>

Emanuele Giuseppe Esposito (45):
  tests/libqos: introduce virtio_start_device
  tests/libqos: rename qpci_init_pc and qpci_init_spapr functions
  tests: qgraph API for the qtest driver framework
  tests/libqos: pci-pc driver and interface nodes
  tests/libqos: x86_64/pc machine node
  tests/libqos: sdhci driver and interface nodes
  tests/libqos: arm/raspi2 machine node
  tests/libqos: arm/smdkc210 machine node
  tests/libqos: arm/sabrelite machine node
  tests/libqos: arm/xilinx-zynq-a9 machine node
  tests/libqos: aarch64/xlnx-zcu102 machine node
  qos-test: sdhci test node
  tests/libqos: pci-spapr driver and interface nodes
  tests/qgraph: ppc64/pseries machine node
  tests/libqos: has_buggy_msi flag
  tests/libqos: e1000e driver and interface nodes
  qos-test: e1000e test node
  tests/libqos: virtio-pci driver and interface nodes
  tests/libqos: virtio-mmio driver and interface nodes
  tests/libqos: arm/virt machine node
  tests/libqos: virtio-serial driver and interface nodes
  qos-test: virtio-console and virtio-serial test node
  tests/libqos: virtio-9p driver and interface nodes
  qos-test: virtio-9p test node
  tests/libqos: virtio-balloon driver and interface nodes
  tests/qgraph: remove virtio-balloon-test
  tests/libqos: virtio-rng driver and interface nodes
  qos-test: virtio-rng test node
  tests/libqos: virtio-blk driver and interface nodes
  tests/libqos: virtio-net driver and interface nodes
  qos-test: virtio-net test node
  tests/libqos: virtio-scsi driver and interface nodes
  qos-test: virtio-scsi test node
  qos-test: ac97 test node
  qos-test: tpci200 test node
  qos-test: ipoctal232 test node
  qos-test: ne2k_pci test node
  qos-test: nvme test node
  qos-test: pcnet test node
  qos-test: spapr-phb test node
  qos-test: usb-hcd-ohci test node
  qos-test: vmxnet3 test node
  qos-test: es1370 test node
  qos-test: eepro100 test node
  qos-test: e1000 test node

Paolo Bonzini (26):
  vhost-net: move stubs to a separate file
  vhost-net-user: add stubs for when no virtio-net device is present
  vhost: restrict Linux dependency to kernel vhost
  vhost-net: compile it on all targets that have virtio-net.
  vhost-net: revamp configure logic
  vhost-user-test: use g_cond_broadcast
  vhost-user-test: signal data_cond when s->rings changes
  vhost-user: support cross-endian vnet headers
  vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
  vhost-user-test: skip if there is no memory at address 0
  vhost-user-test: reduce usage of global_qtest
  vhost-user-test: create a main loop per TestServer
  vhost-user-test: small changes to init_hugepagefs
  vhost-user-test: create a temporary directory per TestServer
  tests: remove rule for nonexisting qdev-monitor-test
  tests/libqos: embed allocators instead of malloc-ing them
  tests/qgraph: add generic PCI testcases
  tests/libqos: remove global_qtest from virtio endianness checks
  tests/qgraph: add generic virtio testcases
  qos-test: virtio-blk test node
  tests/libqos: support multiqueue for virtio-net
  vhost-user-test: always use 256 MiB of guest memory
  qos-test: vhost-user test node
  tests/libqos: remove pre-qgraph QVirtioPCIDevice API
  tests: move virtio entirely to qos-test
  qos-test: megasas test node

 backends/Makefile.objs                     |   5 +-
 configure                                  | 104 ++--
 default-configs/virtio.mak                 |   4 +-
 hw/net/Makefile.objs                       |   4 +-
 hw/net/vhost_net-stub.c                    |  95 ++++
 hw/net/vhost_net.c                         |  78 +--
 hw/virtio/Makefile.objs                    |   5 +-
 hw/virtio/vhost-backend.c                  |  11 +-
 include/exec/poison.h                      |   1 -
 include/qemu/module.h                      |   2 +
 net/Makefile.objs                          |   4 +-
 net/net.c                                  |   2 +-
 net/vhost-user-stub.c                      |  23 +
 net/vhost-user.c                           |  13 +
 tests/Makefile.include                     | 133 +++--
 tests/ac97-test.c                          |  47 +-
 tests/ahci-test.c                          |   6 +-
 tests/drive_del-test.c                     |  25 +-
 tests/e1000-test.c                         |  64 ++-
 tests/e1000e-test.c                        | 358 +++-----------
 tests/eepro100-test.c                      |  65 ++-
 tests/es1370-test.c                        |  46 +-
 tests/i440fx-test.c                        |   2 +-
 tests/ide-test.c                           |  19 +-
 tests/ipoctal232-test.c                    |  35 +-
 tests/libqos/aarch64-xlnx-zcu102-machine.c |  93 ++++
 tests/libqos/ahci.c                        |   2 +-
 tests/libqos/arm-raspi2-machine.c          |  91 ++++
 tests/libqos/arm-sabrelite-machine.c       |  91 ++++
 tests/libqos/arm-smdkc210-machine.c        |  91 ++++
 tests/libqos/arm-virt-machine.c            |  90 ++++
 tests/libqos/arm-xilinx-zynq-a9-machine.c  |  94 ++++
 tests/libqos/e1000e.c                      | 260 ++++++++++
 tests/libqos/e1000e.h                      |  53 ++
 tests/libqos/libqos-pc.c                   |   5 +-
 tests/libqos/libqos-spapr.c                |   5 +-
 tests/libqos/libqos.c                      |  13 +-
 tests/libqos/libqos.h                      |  13 +-
 tests/libqos/malloc-generic.c              |  39 --
 tests/libqos/malloc-generic.h              |  21 -
 tests/libqos/malloc-pc.c                   |  18 +-
 tests/libqos/malloc-pc.h                   |   4 +-
 tests/libqos/malloc-spapr.c                |  19 +-
 tests/libqos/malloc-spapr.h                |   4 +-
 tests/libqos/malloc.c                      |  41 +-
 tests/libqos/malloc.h                      |  21 +-
 tests/libqos/pci-pc.c                      |  86 ++--
 tests/libqos/pci-pc.h                      |  22 +-
 tests/libqos/pci-spapr.c                   | 119 +++--
 tests/libqos/pci-spapr.h                   |  26 +-
 tests/libqos/pci.c                         |  46 +-
 tests/libqos/pci.h                         |  16 +
 tests/libqos/ppc64_pseries-machine.c       | 111 +++++
 tests/libqos/qgraph.c                      | 760 +++++++++++++++++++++++++++++
 tests/libqos/qgraph.h                      | 575 ++++++++++++++++++++++
 tests/libqos/qgraph_internal.h             | 264 ++++++++++
 tests/libqos/sdhci.c                       | 163 +++++++
 tests/libqos/sdhci.h                       |  70 +++
 tests/libqos/tpci200.c                     |  65 +++
 tests/libqos/virtio-9p.c                   | 173 +++++++
 tests/libqos/virtio-9p.h                   |  42 ++
 tests/libqos/virtio-balloon.c              | 113 +++++
 tests/libqos/virtio-balloon.h              |  39 ++
 tests/libqos/virtio-blk.c                  | 124 +++++
 tests/libqos/virtio-blk.h                  |  40 ++
 tests/libqos/virtio-mmio.c                 | 116 +++--
 tests/libqos/virtio-mmio.h                 |   6 +-
 tests/libqos/virtio-net.c                  | 195 ++++++++
 tests/libqos/virtio-net.h                  |  41 ++
 tests/libqos/virtio-pci.c                  | 187 ++++---
 tests/libqos/virtio-pci.h                  |  18 +-
 tests/libqos/virtio-rng.c                  | 110 +++++
 tests/libqos/virtio-rng.h                  |  39 ++
 tests/libqos/virtio-scsi.c                 | 117 +++++
 tests/libqos/virtio-scsi.h                 |  39 ++
 tests/libqos/virtio-serial.c               | 110 +++++
 tests/libqos/virtio-serial.h               |  39 ++
 tests/libqos/virtio.c                      |  24 +-
 tests/libqos/virtio.h                      |  11 +-
 tests/libqos/x86_64_pc-machine.c           | 110 +++++
 tests/libqtest.h                           |   6 +
 tests/megasas-test.c                       |  80 +--
 tests/ne2000-test.c                        |  46 +-
 tests/nvme-test.c                          |  78 +--
 tests/pci-test.c                           |  25 +
 tests/pcnet-test.c                         |  46 +-
 tests/q35-test.c                           |   4 +-
 tests/qos-test.c                           | 470 ++++++++++++++++++
 tests/rtas-test.c                          |   2 +-
 tests/rtl8139-test.c                       |   2 +-
 tests/sdhci-test.c                         | 185 +------
 tests/spapr-phb-test.c                     |  32 +-
 tests/tco-test.c                           |   2 +-
 tests/test-qgraph.c                        | 434 ++++++++++++++++
 tests/tpci200-test.c                       |  31 --
 tests/usb-hcd-ehci-test.c                  |   2 +-
 tests/usb-hcd-ohci-test.c                  |  54 +-
 tests/vhost-user-test.c                    | 516 +++++++++-----------
 tests/virtio-9p-test.c                     | 220 +++------
 tests/virtio-balloon-test.c                |  33 --
 tests/virtio-blk-test.c                    | 471 +++++++-----------
 tests/virtio-console-test.c                |  38 --
 tests/virtio-net-test.c                    | 167 ++-----
 tests/virtio-rng-test.c                    |  27 +-
 tests/virtio-scsi-test.c                   | 145 +++---
 tests/virtio-serial-test.c                 |  27 +-
 tests/virtio-test.c                        |  25 +
 tests/vmxnet3-test.c                       |  46 +-
 108 files changed, 7084 insertions(+), 2365 deletions(-)
 create mode 100644 hw/net/vhost_net-stub.c
 create mode 100644 net/vhost-user-stub.c
 create mode 100644 tests/libqos/aarch64-xlnx-zcu102-machine.c
 create mode 100644 tests/libqos/arm-raspi2-machine.c
 create mode 100644 tests/libqos/arm-sabrelite-machine.c
 create mode 100644 tests/libqos/arm-smdkc210-machine.c
 create mode 100644 tests/libqos/arm-virt-machine.c
 create mode 100644 tests/libqos/arm-xilinx-zynq-a9-machine.c
 create mode 100644 tests/libqos/e1000e.c
 create mode 100644 tests/libqos/e1000e.h
 delete mode 100644 tests/libqos/malloc-generic.c
 delete mode 100644 tests/libqos/malloc-generic.h
 create mode 100644 tests/libqos/ppc64_pseries-machine.c
 create mode 100644 tests/libqos/qgraph.c
 create mode 100644 tests/libqos/qgraph.h
 create mode 100644 tests/libqos/qgraph_internal.h
 create mode 100644 tests/libqos/sdhci.c
 create mode 100644 tests/libqos/sdhci.h
 create mode 100644 tests/libqos/tpci200.c
 create mode 100644 tests/libqos/virtio-9p.c
 create mode 100644 tests/libqos/virtio-9p.h
 create mode 100644 tests/libqos/virtio-balloon.c
 create mode 100644 tests/libqos/virtio-balloon.h
 create mode 100644 tests/libqos/virtio-blk.c
 create mode 100644 tests/libqos/virtio-blk.h
 create mode 100644 tests/libqos/virtio-net.c
 create mode 100644 tests/libqos/virtio-net.h
 create mode 100644 tests/libqos/virtio-rng.c
 create mode 100644 tests/libqos/virtio-rng.h
 create mode 100644 tests/libqos/virtio-scsi.c
 create mode 100644 tests/libqos/virtio-scsi.h
 create mode 100644 tests/libqos/virtio-serial.c
 create mode 100644 tests/libqos/virtio-serial.h
 create mode 100644 tests/libqos/x86_64_pc-machine.c
 create mode 100644 tests/pci-test.c
 create mode 100644 tests/qos-test.c
 create mode 100644 tests/test-qgraph.c
 delete mode 100644 tests/tpci200-test.c
 delete mode 100644 tests/virtio-balloon-test.c
 delete mode 100644 tests/virtio-console-test.c
 create mode 100644 tests/virtio-test.c

-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 21:10   ` Eric Blake
  2018-12-04 16:04   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 02/71] vhost-net-user: add stubs for when no virtio-net device is present Paolo Bonzini
                   ` (72 subsequent siblings)
  73 siblings, 2 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

There is no reason for CONFIG_VHOST_NET to be specific to a single target;
it is a host feature that can be add to all targets, as long as they support
the virtio-net device.  Currently CONFIG_VHOST_NET depends on CONFIG_KVM,
but ioeventfd support is present in the core memory API and works with
other accelerators as well.

As a first step, move the vhost-net stubs to a separate file.  Later, they
will become conditional on CONFIG_VIRTIO_NET, which is not available in .c
files.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/net/Makefile.objs    |  4 ++-
 hw/net/vhost_net-stub.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/net/vhost_net.c      | 74 --------------------------------------
 3 files changed, 98 insertions(+), 75 deletions(-)
 create mode 100644 hw/net/vhost_net-stub.c

diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index fa461d4..c2705e6 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -37,7 +37,9 @@ obj-$(CONFIG_PSERIES) += spapr_llan.o
 obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
 
 obj-$(CONFIG_VIRTIO_NET) += virtio-net.o
-obj-y += vhost_net.o
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+common-obj-$(call lnot,$(CONFIG_VHOST_NET)) += vhost_net-stub.o
+common-obj-$(CONFIG_ALL) += vhost_net-stub.o
 
 obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
 			fsl_etsec/rings.o fsl_etsec/miim.o
diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c
new file mode 100644
index 0000000..4de1dfb
--- /dev/null
+++ b/hw/net/vhost_net-stub.c
@@ -0,0 +1,95 @@
+/*
+ * vhost-net support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "net/net.h"
+#include "net/tap.h"
+#include "net/vhost-user.h"
+
+#include "hw/virtio/virtio-net.h"
+#include "net/vhost_net.h"
+#include "qemu/error-report.h"
+
+
+uint64_t vhost_net_get_max_queues(VHostNetState *net)
+{
+    return 1;
+}
+
+struct vhost_net *vhost_net_init(VhostNetOptions *options)
+{
+    error_report("vhost-net support is not compiled in");
+    return NULL;
+}
+
+int vhost_net_start(VirtIODevice *dev,
+                    NetClientState *ncs,
+                    int total_queues)
+{
+    return -ENOSYS;
+}
+void vhost_net_stop(VirtIODevice *dev,
+                    NetClientState *ncs,
+                    int total_queues)
+{
+}
+
+void vhost_net_cleanup(struct vhost_net *net)
+{
+}
+
+uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
+{
+    return features;
+}
+
+void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
+{
+}
+
+uint64_t vhost_net_get_acked_features(VHostNetState *net)
+{
+    return 0;
+}
+
+bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
+{
+    return false;
+}
+
+void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
+                              int idx, bool mask)
+{
+}
+
+int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
+{
+    return -1;
+}
+
+VHostNetState *get_vhost_net(NetClientState *nc)
+{
+    return 0;
+}
+
+int vhost_set_vring_enable(NetClientState *nc, int enable)
+{
+    return 0;
+}
+
+int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
+{
+    return 0;
+}
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index e037db6..b901306 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -23,7 +23,6 @@
 #include "qemu/error-report.h"
 
 
-#ifdef CONFIG_VHOST_NET
 #include <linux/vhost.h>
 #include <sys/socket.h>
 #include <linux/kvm.h>
@@ -449,76 +448,3 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
 
     return vhost_ops->vhost_net_set_mtu(&net->dev, mtu);
 }
-
-#else
-uint64_t vhost_net_get_max_queues(VHostNetState *net)
-{
-    return 1;
-}
-
-struct vhost_net *vhost_net_init(VhostNetOptions *options)
-{
-    error_report("vhost-net support is not compiled in");
-    return NULL;
-}
-
-int vhost_net_start(VirtIODevice *dev,
-                    NetClientState *ncs,
-                    int total_queues)
-{
-    return -ENOSYS;
-}
-void vhost_net_stop(VirtIODevice *dev,
-                    NetClientState *ncs,
-                    int total_queues)
-{
-}
-
-void vhost_net_cleanup(struct vhost_net *net)
-{
-}
-
-uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
-{
-    return features;
-}
-
-void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
-{
-}
-
-uint64_t vhost_net_get_acked_features(VHostNetState *net)
-{
-    return 0;
-}
-
-bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
-{
-    return false;
-}
-
-void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
-                              int idx, bool mask)
-{
-}
-
-int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
-{
-    return -1;
-}
-
-VHostNetState *get_vhost_net(NetClientState *nc)
-{
-    return 0;
-}
-
-int vhost_set_vring_enable(NetClientState *nc, int enable)
-{
-    return 0;
-}
-
-int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
-{
-    return 0;
-}
-#endif
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 02/71] vhost-net-user: add stubs for when no virtio-net device is present
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-06 13:29   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 03/71] vhost: restrict Linux dependency to kernel vhost Paolo Bonzini
                   ` (71 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

hw/net/vhost_net.c needs functions that are declared in net/vhost-user.c: the
vhost-user code is always compiled into QEMU, only the constructor
net_init_vhost_user is unreachable.  Also, net/vhost-user.c needs functions
declared in hw/virtio/vhost-stub.c even if no virtio device exists.

Break this dependency.  First, add a minimal version of net/vhost-user.c,
with no functionality and no dependency on vhost code.  Second, #ifdef out
the calls back to net/vhost-user.c from hw/net/vhost_net.c.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 configure             |  2 +-
 hw/net/vhost_net.c    |  4 ++++
 net/Makefile.objs     |  4 +++-
 net/net.c             |  2 +-
 net/vhost-user-stub.c | 23 +++++++++++++++++++++++
 5 files changed, 32 insertions(+), 3 deletions(-)
 create mode 100644 net/vhost-user-stub.c

diff --git a/configure b/configure
index 0a3c6a7..cda17ef 100755
--- a/configure
+++ b/configure
@@ -6513,7 +6513,7 @@ if test "$vhost_scsi" = "yes" ; then
   echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
 fi
 if test "$vhost_net" = "yes" -a "$vhost_user" = "yes"; then
-  echo "CONFIG_VHOST_NET_USED=y" >> $config_host_mak
+  echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak
 fi
 if test "$vhost_crypto" = "yes" ; then
   echo "CONFIG_VHOST_CRYPTO=y" >> $config_host_mak
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index b901306..fe6202a 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -193,6 +193,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
     }
 
     /* Set sane init value. Override when guest acks. */
+#ifdef CONFIG_VHOST_USER
     if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
         features = vhost_user_get_acked_features(net->nc);
         if (~net->dev.features & features) {
@@ -202,6 +203,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
             goto fail;
         }
     }
+#endif
 
     vhost_net_ack_features(net, features);
 
@@ -413,10 +415,12 @@ VHostNetState *get_vhost_net(NetClientState *nc)
     case NET_CLIENT_DRIVER_TAP:
         vhost_net = tap_get_vhost_net(nc);
         break;
+#ifdef CONFIG_VHOST_NET_USER
     case NET_CLIENT_DRIVER_VHOST_USER:
         vhost_net = vhost_user_get_vhost_net(nc);
         assert(vhost_net);
         break;
+#endif
     default:
         break;
     }
diff --git a/net/Makefile.objs b/net/Makefile.objs
index b2bf88a..df2b409 100644
--- a/net/Makefile.objs
+++ b/net/Makefile.objs
@@ -3,7 +3,9 @@ common-obj-y += socket.o
 common-obj-y += dump.o
 common-obj-y += eth.o
 common-obj-$(CONFIG_L2TPV3) += l2tpv3.o
-common-obj-$(CONFIG_POSIX) += vhost-user.o
+common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-user.o
+common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o
+common-obj-$(CONFIG_ALL) += vhost-user-stub.o
 common-obj-$(CONFIG_SLIRP) += slirp.o
 common-obj-$(CONFIG_VDE) += vde.o
 common-obj-$(CONFIG_NETMAP) += netmap.o
diff --git a/net/net.c b/net/net.c
index 07c194a..95a74ad 100644
--- a/net/net.c
+++ b/net/net.c
@@ -955,7 +955,7 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
         [NET_CLIENT_DRIVER_BRIDGE]    = net_init_bridge,
 #endif
         [NET_CLIENT_DRIVER_HUBPORT]   = net_init_hubport,
-#ifdef CONFIG_VHOST_NET_USED
+#ifdef CONFIG_VHOST_NET_USER
         [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user,
 #endif
 #ifdef CONFIG_L2TPV3
diff --git a/net/vhost-user-stub.c b/net/vhost-user-stub.c
new file mode 100644
index 0000000..52ab4e1
--- /dev/null
+++ b/net/vhost-user-stub.c
@@ -0,0 +1,23 @@
+/*
+ * vhost-user-stub.c
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * 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 "clients.h"
+#include "net/vhost_net.h"
+#include "net/vhost-user.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+int net_init_vhost_user(const Netdev *netdev, const char *name,
+                        NetClientState *peer, Error **errp)
+{
+    error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
+    return -1;
+}
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 03/71] vhost: restrict Linux dependency to kernel vhost
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 02/71] vhost-net-user: add stubs for when no virtio-net device is present Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-06 13:36   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 04/71] vhost-net: compile it on all targets that have virtio-net Paolo Bonzini
                   ` (70 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

vhost-user does not depend on Linux; it can run on any POSIX system.  Restrict
vhost-kernel to Linux in hw/virtio/vhost-backend.c, everything else can be
compiled on all POSIX systems.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/Makefile.objs     |  5 ++---
 default-configs/virtio.mak |  4 ++--
 hw/net/vhost_net.c         |  2 +-
 hw/virtio/Makefile.objs    |  5 +++--
 hw/virtio/vhost-backend.c  | 11 +++++++++--
 5 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 717fcbd..ff619d3 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -9,10 +9,9 @@ common-obj-$(CONFIG_POSIX) += hostmem-file.o
 common-obj-y += cryptodev.o
 common-obj-y += cryptodev-builtin.o
 
-ifeq ($(CONFIG_VIRTIO),y)
+ifeq ($(CONFIG_VIRTIO_CRYPTO),y)
 common-obj-y += cryptodev-vhost.o
-common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) += \
-    cryptodev-vhost-user.o
+common-obj-$(CONFIG_VHOST_CRYPTO) += cryptodev-vhost-user.o
 endif
 
 common-obj-$(CONFIG_LINUX) += hostmem-memfd.o
diff --git a/default-configs/virtio.mak b/default-configs/virtio.mak
index 1304849..340050a 100644
--- a/default-configs/virtio.mak
+++ b/default-configs/virtio.mak
@@ -1,5 +1,5 @@
-CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
-CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
+CONFIG_VHOST_USER_SCSI=$(CONFIG_VHOST_USER)
+CONFIG_VHOST_USER_BLK=$(CONFIG_VHOST_USER)
 CONFIG_VIRTIO=y
 CONFIG_VIRTIO_9P=y
 CONFIG_VIRTIO_BALLOON=y
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index fe6202a..2a300ee 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -193,7 +193,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
     }
 
     /* Set sane init value. Override when guest acks. */
-#ifdef CONFIG_VHOST_USER
+#ifdef CONFIG_VHOST_NET_USER
     if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
         features = vhost_user_get_acked_features(net->nc);
         if (~net->dev.features & features) {
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index 1b2799c..e8eff80 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -9,9 +9,10 @@ obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon.o
 obj-$(CONFIG_VIRTIO_CRYPTO) += virtio-crypto.o
 obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-pci.o
 
-obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
+obj-$(CONFIG_VHOST_USER) += vhost-user.o
 obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
+obj-$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) += vhost.o vhost-backend.o
+common-obj-$(call lnot,$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))) += vhost-stub.o
 endif
 
-common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o
 common-obj-$(CONFIG_ALL) += vhost-stub.o
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 7f09efa..b5d2e30 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -9,12 +9,14 @@
  */
 
 #include "qemu/osdep.h"
-#include <linux/vhost.h>
-#include <sys/ioctl.h>
 #include "hw/virtio/vhost.h"
 #include "hw/virtio/vhost-backend.h"
 #include "qemu/error-report.h"
 
+#ifdef CONFIG_LINUX
+#include <linux/vhost.h>
+#include <sys/ioctl.h>
+
 static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request,
                              void *arg)
 {
@@ -265,18 +267,23 @@ static const VhostOps kernel_ops = {
         .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
         .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
 };
+#endif
 
 int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
 {
     int r = 0;
 
     switch (backend_type) {
+#ifdef CONFIG_LINUX
     case VHOST_BACKEND_TYPE_KERNEL:
         dev->vhost_ops = &kernel_ops;
         break;
+#endif
+#ifdef CONFIG_VHOST_USER
     case VHOST_BACKEND_TYPE_USER:
         dev->vhost_ops = &user_ops;
         break;
+#endif
     default:
         error_report("Unknown vhost backend type");
         r = -1;
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 04/71] vhost-net: compile it on all targets that have virtio-net.
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (2 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 03/71] vhost: restrict Linux dependency to kernel vhost Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-06 13:45   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 05/71] vhost-net: revamp configure logic Paolo Bonzini
                   ` (69 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

This shows a preexisting bug: if a KVM target did not have virtio-net enabled,
it would fail with undefined symbols when vhost was enabled.  This must now
be fixed, lest targets that have no virtio-net fail to compile.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 configure              | 11 ++++-------
 hw/net/Makefile.objs   |  4 ++--
 include/exec/poison.h  |  1 -
 tests/Makefile.include |  5 +----
 4 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/configure b/configure
index cda17ef..b3b4464 100755
--- a/configure
+++ b/configure
@@ -6512,7 +6512,10 @@ fi
 if test "$vhost_scsi" = "yes" ; then
   echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
 fi
-if test "$vhost_net" = "yes" -a "$vhost_user" = "yes"; then
+if test "$vhost_net" = "yes" ; then
+  echo "CONFIG_VHOST_NET=y" >> $config_host_mak
+fi
+if test "$vhost_net_user" = "yes" ; then
   echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak
 fi
 if test "$vhost_crypto" = "yes" ; then
@@ -7275,12 +7278,6 @@ if supported_xen_target $target; then
 fi
 if supported_kvm_target $target; then
     echo "CONFIG_KVM=y" >> $config_target_mak
-    if test "$vhost_net" = "yes" ; then
-        echo "CONFIG_VHOST_NET=y" >> $config_target_mak
-        if test "$vhost_user" = "yes" ; then
-            echo "CONFIG_VHOST_USER_NET_TEST_$target_name=y" >> $config_host_mak
-        fi
-    fi
 fi
 if supported_hax_target $target; then
     echo "CONFIG_HAX=y" >> $config_target_mak
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index c2705e6..2d7ee0a 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -37,8 +37,8 @@ obj-$(CONFIG_PSERIES) += spapr_llan.o
 obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
 
 obj-$(CONFIG_VIRTIO_NET) += virtio-net.o
-obj-$(CONFIG_VHOST_NET) += vhost_net.o
-common-obj-$(call lnot,$(CONFIG_VHOST_NET)) += vhost_net-stub.o
+common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET)) += vhost_net.o
+common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET))) += vhost_net-stub.o
 common-obj-$(CONFIG_ALL) += vhost_net-stub.o
 
 obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 32d5378..b158632 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -85,7 +85,6 @@
 #pragma GCC poison CONFIG_XTENSA_DIS
 
 #pragma GCC poison CONFIG_LINUX_USER
-#pragma GCC poison CONFIG_VHOST_NET
 #pragma GCC poison CONFIG_KVM
 #pragma GCC poison CONFIG_SOFTMMU
 
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8e882ed..3e3b16b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -204,10 +204,7 @@ check-qtest-i386-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF)
 check-qtest-i386-y += tests/cpu-plug-test$(EXESUF)
 check-qtest-i386-y += tests/q35-test$(EXESUF)
 check-qtest-i386-y += tests/vmgenid-test$(EXESUF)
-check-qtest-i386-$(CONFIG_VHOST_USER_NET_TEST_i386) += tests/vhost-user-test$(EXESUF)
-ifeq ($(CONFIG_VHOST_USER_NET_TEST_i386),)
-check-qtest-x86_64-$(CONFIG_VHOST_USER_NET_TEST_x86_64) += tests/vhost-user-test$(EXESUF)
-endif
+check-qtest-i386-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF)
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 05/71] vhost-net: revamp configure logic
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (3 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 04/71] vhost-net: compile it on all targets that have virtio-net Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-06 16:12   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 06/71] vhost-user-test: use g_cond_broadcast Paolo Bonzini
                   ` (68 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Detect all invalid configurations (e.g. mingw32 with vhost-user,
non-Linux with vhost-kernel).  As a collateral benefit, all vhost-kernel
backends can be now disabled if one wants to reduce the attack surface.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 configure                 | 89 +++++++++++++++++++++++++++++++----------------
 hw/virtio/Makefile.objs   |  4 +--
 hw/virtio/vhost-backend.c |  4 +--
 3 files changed, 63 insertions(+), 34 deletions(-)

diff --git a/configure b/configure
index b3b4464..d2c0fd3 100755
--- a/configure
+++ b/configure
@@ -366,10 +366,10 @@ libattr=""
 xfs=""
 tcg="yes"
 membarrier=""
-vhost_net="no"
-vhost_crypto="no"
-vhost_scsi="no"
-vhost_vsock="no"
+vhost_net=""
+vhost_crypto=""
+vhost_scsi=""
+vhost_vsock=""
 vhost_user=""
 kvm="no"
 hax="no"
@@ -774,6 +774,7 @@ case $targetos in
 MINGW32*)
   mingw32="yes"
   hax="yes"
+  vhost_user="no"
   audio_possible_drivers="dsound sdl"
   if check_include dsound.h; then
     audio_drv_list="dsound"
@@ -874,10 +875,6 @@ Linux)
   linux="yes"
   linux_user="yes"
   kvm="yes"
-  vhost_net="yes"
-  vhost_crypto="yes"
-  vhost_scsi="yes"
-  vhost_vsock="yes"
   QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$PWD/linux-headers $QEMU_INCLUDES"
   supported_os="yes"
   libudev="yes"
@@ -1258,11 +1255,7 @@ for opt do
   ;;
   --disable-vhost-crypto) vhost_crypto="no"
   ;;
-  --enable-vhost-crypto)
-      vhost_crypto="yes"
-      if test "$mingw32" = "yes"; then
-          error_exit "vhost-crypto isn't available on win32"
-      fi
+  --enable-vhost-crypto) vhost_crypto="yes"
   ;;
   --disable-vhost-scsi) vhost_scsi="no"
   ;;
@@ -1463,11 +1456,11 @@ for opt do
   ;;
   --disable-vhost-user) vhost_user="no"
   ;;
-  --enable-vhost-user)
-      vhost_user="yes"
-      if test "$mingw32" = "yes"; then
-          error_exit "vhost-user isn't available on win32"
-      fi
+  --enable-vhost-user) vhost_user="yes"
+  ;;
+  --disable-vhost-kernel) vhost_kernel="no"
+  ;;
+  --enable-vhost-kernel) vhost_kernel="yes"
   ;;
   --disable-capstone) capstone="no"
   ;;
@@ -1499,14 +1492,6 @@ for opt do
   esac
 done
 
-if test "$vhost_user" = ""; then
-    if test "$mingw32" = "yes"; then
-        vhost_user="no"
-    else
-        vhost_user="yes"
-    fi
-fi
-
 case "$cpu" in
     ppc)
            CPU_CFLAGS="-m32"
@@ -1731,8 +1716,12 @@ disabled with --disable-FEATURE, default is enabled if available:
   linux-aio       Linux AIO support
   cap-ng          libcap-ng support
   attr            attr and xattr support
-  vhost-net       vhost-net acceleration support
-  vhost-crypto    vhost-crypto acceleration support
+  vhost-net       vhost-net kernel acceleration support
+  vhost-vsock     virtio sockets device support
+  vhost-scsi      vhost-scsi kernel target support
+  vhost-crypto    vhost-user-crypto backend support
+  vhost-kernel    vhost kernel backend support
+  vhost-user      vhost-user backend support
   spice           spice
   rbd             rados block device (rbd)
   libiscsi        iscsi support
@@ -1756,7 +1745,6 @@ disabled with --disable-FEATURE, default is enabled if available:
   jemalloc        jemalloc support
   avx2            AVX2 optimization support
   replication     replication support
-  vhost-vsock     virtio sockets device support
   opengl          opengl support
   virglrenderer   virgl rendering support
   xfsctl          xfsctl support
@@ -1773,7 +1761,6 @@ disabled with --disable-FEATURE, default is enabled if available:
   parallels       parallels image format support
   sheepdog        sheepdog block driver support
   crypto-afalg    Linux AF_ALG crypto backend driver
-  vhost-user      vhost-user support
   capstone        capstone disassembler support
   debug-mutex     mutex debugging support
   libpmem         libpmem support
@@ -2150,6 +2137,45 @@ else
   l2tpv3=no
 fi
 
+#########################################
+# vhost interdependencies and host support
+
+# vhost backends
+test "$vhost_user" = "" && vhost_user=yes
+if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then
+  error_exit "vhost-user isn't available on win32"
+fi
+test "$vhost_kernel" = "" && vhost_kernel=$linux
+if test "$vhost_kernel" = "yes" && test "$linux" != "yes"; then
+  error_exit "vhost-kernel is only available on Linux"
+fi
+
+# vhost-kernel devices
+test "$vhost_scsi" = "" && vhost_scsi=$vhost_kernel
+if test "$vhost_scsi" = "yes" && test "$vhost_kernel" != "yes"; then
+  error_exit "--enable-vhost-scsi requires --enable-vhost-kernel"
+fi
+test "$vhost_vsock" = "" && vhost_vsock=$vhost_kernel
+if test "$vhost_vsock" = "yes" && test "$vhost_kernel" != "yes"; then
+  error_exit "--enable-vhost-vsock requires --enable-vhost-kernel"
+fi
+
+# vhost-user backends
+test "$vhost_net_user" = "" && vhost_net_user=$vhost_user
+if test "$vhost_net_user" = "yes" && test "$vhost_user" = "no"; then
+  error_exit "--enable-vhost-net-user requires --enable-vhost-user"
+fi
+test "$vhost_crypto" = "" && vhost_crypto=$vhost_user
+if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then
+  error_exit "--enable-vhost-crypto requires --enable-vhost-user"
+fi
+
+# OR the vhost-kernel and vhost-user values for simplicity
+if test "$vhost_net" = ""; then
+  test "$vhost_net_user" = "yes" && vhost_net=yes
+  test "$vhost_kernel" = "yes" && vhost_net=yes
+fi
+
 ##########################################
 # MinGW / Mingw-w64 localtime_r/gmtime_r check
 
@@ -6524,6 +6550,9 @@ fi
 if test "$vhost_vsock" = "yes" ; then
   echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak
 fi
+if test "$vhost_kernel" = "yes" ; then
+  echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak
+fi
 if test "$vhost_user" = "yes" ; then
   echo "CONFIG_VHOST_USER=y" >> $config_host_mak
 fi
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index e8eff80..87402d1 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -11,8 +11,8 @@ obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-p
 
 obj-$(CONFIG_VHOST_USER) += vhost-user.o
 obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
-obj-$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) += vhost.o vhost-backend.o
-common-obj-$(call lnot,$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))) += vhost-stub.o
+obj-$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_VHOST_KERNEL)) += vhost.o vhost-backend.o
+common-obj-$(call lnot,$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_VHOST_KERNEL))) += vhost-stub.o
 endif
 
 common-obj-$(CONFIG_ALL) += vhost-stub.o
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index b5d2e30..46d388b 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -13,7 +13,7 @@
 #include "hw/virtio/vhost-backend.h"
 #include "qemu/error-report.h"
 
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_VHOST_KERNEL
 #include <linux/vhost.h>
 #include <sys/ioctl.h>
 
@@ -274,7 +274,7 @@ int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
     int r = 0;
 
     switch (backend_type) {
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_VHOST_KERNEL
     case VHOST_BACKEND_TYPE_KERNEL:
         dev->vhost_ops = &kernel_ops;
         break;
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 06/71] vhost-user-test: use g_cond_broadcast
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (4 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 05/71] vhost-net: revamp configure logic Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 07/71] vhost-user-test: signal data_cond when s->rings changes Paolo Bonzini
                   ` (67 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

g_cond_signal is rarely the right thing to do, it works now because
vhost-user-test only has two threads but it is not correct in general.
Fix it before adding more calls.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 45d58d8..656e519 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -393,7 +393,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
                                             G_N_ELEMENTS(s->fds));
 
         /* signal the test that it can continue */
-        g_cond_signal(&s->data_cond);
+        g_cond_broadcast(&s->data_cond);
         break;
 
     case VHOST_USER_SET_VRING_KICK:
@@ -419,7 +419,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
         p = (uint8_t *) &msg;
         qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
 
-        g_cond_signal(&s->data_cond);
+        g_cond_broadcast(&s->data_cond);
         break;
 
     case VHOST_USER_SET_VRING_BASE:
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 07/71] vhost-user-test: signal data_cond when s->rings changes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (5 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 06/71] vhost-user-test: use g_cond_broadcast Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 08/71] vhost-user: support cross-endian vnet headers Paolo Bonzini
                   ` (66 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

This speeds up wait_for_rings_started, which currently is just waiting for
the timeout before checking s->rings.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 656e519..6a805e6 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -384,6 +384,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
 
         assert(msg.payload.state.index < s->queues * 2);
         s->rings &= ~(0x1ULL << msg.payload.state.index);
+        g_cond_broadcast(&s->data_cond);
         break;
 
     case VHOST_USER_SET_MEM_TABLE:
@@ -425,6 +426,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     case VHOST_USER_SET_VRING_BASE:
         assert(msg.payload.state.index < s->queues * 2);
         s->rings |= 0x1ULL << msg.payload.state.index;
+        g_cond_broadcast(&s->data_cond);
         break;
 
     case VHOST_USER_GET_QUEUE_NUM:
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 08/71] vhost-user: support cross-endian vnet headers
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (6 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 07/71] vhost-user-test: signal data_cond when s->rings changes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN Paolo Bonzini
                   ` (65 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

vhost-user already has a way to communicate the endianness of the guest
via the vring endianness messages.  The vring endianness always matches
the vnet header endianness so there is no need to do anything else in
the backend.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 net/vhost-user.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/net/vhost-user.c b/net/vhost-user.c
index a39f9c9..cd9659d 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -172,6 +172,17 @@ static void net_vhost_user_cleanup(NetClientState *nc)
     qemu_purge_queued_packets(nc);
 }
 
+static int vhost_user_set_vnet_endianness(NetClientState *nc,
+                                          bool enable)
+{
+    /* Nothing to do.  If the server supports
+     * VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, it will get the
+     * vnet header endianness from there.  If it doesn't, negotiation
+     * fails.
+     */
+    return 0;
+}
+
 static bool vhost_user_has_vnet_hdr(NetClientState *nc)
 {
     assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
@@ -193,6 +204,8 @@ static NetClientInfo net_vhost_user_info = {
         .cleanup = net_vhost_user_cleanup,
         .has_vnet_hdr = vhost_user_has_vnet_hdr,
         .has_ufo = vhost_user_has_ufo,
+        .set_vnet_be = vhost_user_set_vnet_endianness,
+        .set_vnet_le = vhost_user_set_vnet_endianness,
 };
 
 static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (7 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 08/71] vhost-user: support cross-endian vnet headers Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-06 16:15   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 10/71] vhost-user-test: skip if there is no memory at address 0 Paolo Bonzini
                   ` (64 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

This will be useful to run the qtest for ppc64 targets on (for example)
x86_64 hosts.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 6a805e6..82fc6c5 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -51,6 +51,7 @@
 #define VHOST_USER_F_PROTOCOL_FEATURES 30
 #define VHOST_USER_PROTOCOL_F_MQ 0
 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
+#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
 
 #define VHOST_LOG_PAGE 0x1000
 
@@ -251,7 +252,7 @@ static void wait_for_fds(TestServer *s)
 
 static void read_guest_mem_server(TestServer *s)
 {
-    uint32_t *guest_mem;
+    uint8_t *guest_mem;
     int i, j;
     size_t size;
 
@@ -278,8 +279,8 @@ static void read_guest_mem_server(TestServer *s)
         g_assert(guest_mem != MAP_FAILED);
         guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
 
-        for (j = 0; j < 256; j++) {
-            uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
+        for (j = 0; j < 1024; j++) {
+            uint32_t a = readb(s->memory.regions[i].guest_phys_addr + j);
             uint32_t b = guest_mem[j];
 
             g_assert_cmpint(a, ==, b);
@@ -367,6 +368,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
         msg.flags |= VHOST_USER_REPLY_MASK;
         msg.size = sizeof(m.payload.u64);
         msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
+        msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN;
         if (s->queues > 1) {
             msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
         }
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 10/71] vhost-user-test: skip if there is no memory at address 0
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (8 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-06 16:26   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 11/71] vhost-user-test: reduce usage of global_qtest Paolo Bonzini
                   ` (63 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

The virt machine cannot run the vhost-user qtests because they hardcode
the presence of memory at address 0.  Report the tests as a skip so that
they can be converted to use qgraph.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 58 ++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 45 insertions(+), 13 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 82fc6c5..59e1aec 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -228,9 +228,11 @@ static void uninit_virtio_dev(TestServer *s)
     qvirtio_pci_device_free(s->dev);
 }
 
-static void wait_for_fds(TestServer *s)
+static bool wait_for_fds(TestServer *s)
 {
     gint64 end_time;
+    bool got_region;
+    int i;
 
     g_mutex_lock(&s->data_mutex);
 
@@ -248,6 +250,19 @@ static void wait_for_fds(TestServer *s)
     g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
 
     g_mutex_unlock(&s->data_mutex);
+
+    got_region = false;
+    for (i = 0; i < s->memory.nregions; ++i) {
+        VhostUserMemoryRegion *reg = &s->memory.regions[i];
+        if (reg->guest_phys_addr == 0) {
+            got_region = true;
+            break;
+        }
+    }
+    if (!got_region) {
+        g_test_skip("No memory at address 0x0");
+    }
+    return got_region;
 }
 
 static void read_guest_mem_server(TestServer *s)
@@ -256,8 +271,6 @@ static void read_guest_mem_server(TestServer *s)
     int i, j;
     size_t size;
 
-    wait_for_fds(s);
-
     g_mutex_lock(&s->data_mutex);
 
     /* iterate all regions */
@@ -577,8 +590,6 @@ static void write_guest_mem(TestServer *s, uint32_t seed)
     int i, j;
     size_t size;
 
-    wait_for_fds(s);
-
     /* iterate all regions */
     for (i = 0; i < s->fds_num; i++) {
 
@@ -661,8 +672,13 @@ static void test_read_guest_mem(const void *arg)
 
     init_virtio_dev(server, 1u << VIRTIO_NET_F_MAC);
 
+    if (!wait_for_fds(server)) {
+        goto exit;
+    }
+
     read_guest_mem_server(server);
 
+exit:
     uninit_virtio_dev(server);
 
     qtest_quit(s);
@@ -689,8 +705,10 @@ static void test_migrate(void)
     g_free(cmd);
 
     init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
-    init_virtio_dev(dest, 1u << VIRTIO_NET_F_MAC);
-    wait_for_fds(s);
+    if (!wait_for_fds(s)) {
+        goto exit;
+    }
+
     size = get_log_size(s);
     g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
 
@@ -699,6 +717,7 @@ static void test_migrate(void)
     g_free(tmp);
     to = qtest_init(cmd);
     g_free(cmd);
+    init_virtio_dev(dest, 1u << VIRTIO_NET_F_MAC);
 
     source = g_source_new(&test_migrate_source_funcs,
                           sizeof(TestMigrateSource));
@@ -738,15 +757,18 @@ static void test_migrate(void)
     global_qtest = to;
     qmp_eventwait("RESUME");
 
+    g_assert(wait_for_fds(s));
     read_guest_mem_server(dest);
 
-    uninit_virtio_dev(s);
     uninit_virtio_dev(dest);
+    qtest_quit(to);
 
     g_source_destroy(source);
     g_source_unref(source);
 
-    qtest_quit(to);
+exit:
+    uninit_virtio_dev(s);
+
     test_server_free(dest);
     qtest_quit(from);
     test_server_free(s);
@@ -810,16 +832,20 @@ static void test_reconnect_subprocess(void)
     g_free(cmd);
 
     init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
-    wait_for_fds(s);
+    if (!wait_for_fds(s)) {
+        goto exit;
+    }
+
     wait_for_rings_started(s, 2);
 
     /* reconnect */
     s->fds_num = 0;
     s->rings = 0;
     g_idle_add(reconnect_cb, s);
-    wait_for_fds(s);
+    g_assert(wait_for_fds(s));
     wait_for_rings_started(s, 2);
 
+exit:
     uninit_virtio_dev(s);
 
     qtest_end();
@@ -848,9 +874,12 @@ static void test_connect_fail_subprocess(void)
     g_free(cmd);
 
     init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
-    wait_for_fds(s);
+    if (!wait_for_fds(s)) {
+        goto exit;
+    }
     wait_for_rings_started(s, 2);
 
+exit:
     uninit_virtio_dev(s);
 
     qtest_end();
@@ -878,9 +907,12 @@ static void test_flags_mismatch_subprocess(void)
     g_free(cmd);
 
     init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
-    wait_for_fds(s);
+    if (!wait_for_fds(s)) {
+        goto exit;
+    }
     wait_for_rings_started(s, 2);
 
+exit:
     uninit_virtio_dev(s);
 
     qtest_end();
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 11/71] vhost-user-test: reduce usage of global_qtest
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (9 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 10/71] vhost-user-test: skip if there is no memory at address 0 Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-06 16:36   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 12/71] vhost-user-test: create a main loop per TestServer Paolo Bonzini
                   ` (62 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Whenever the code can run on multiple QTestStates, use them explicitly instead of
global_qtest.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 38 +++++++++++++++++---------------------
 1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 59e1aec..c3a8af3 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -187,12 +187,12 @@ static char *get_qemu_cmd(TestServer *s,
     }
 }
 
-static void init_virtio_dev(TestServer *s, uint32_t features_mask)
+static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_mask)
 {
     uint32_t features;
     int i;
 
-    s->bus = qpci_init_pc(global_qtest, NULL);
+    s->bus = qpci_init_pc(qts, NULL);
     g_assert_nonnull(s->bus);
 
     s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
@@ -203,7 +203,7 @@ static void init_virtio_dev(TestServer *s, uint32_t features_mask)
     qvirtio_set_acknowledge(&s->dev->vdev);
     qvirtio_set_driver(&s->dev->vdev);
 
-    s->alloc = pc_alloc_init(global_qtest);
+    s->alloc = pc_alloc_init(qts);
 
     for (i = 0; i < s->queues * 2; i++) {
         s->vq[i] = qvirtqueue_setup(&s->dev->vdev, s->alloc, i);
@@ -265,7 +265,7 @@ static bool wait_for_fds(TestServer *s)
     return got_region;
 }
 
-static void read_guest_mem_server(TestServer *s)
+static void read_guest_mem_server(QTestState *qts, TestServer *s)
 {
     uint8_t *guest_mem;
     int i, j;
@@ -293,7 +293,7 @@ static void read_guest_mem_server(TestServer *s)
         guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
 
         for (j = 0; j < 1024; j++) {
-            uint32_t a = readb(s->memory.regions[i].guest_phys_addr + j);
+            uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);
             uint32_t b = guest_mem[j];
 
             g_assert_cmpint(a, ==, b);
@@ -670,13 +670,13 @@ static void test_read_guest_mem(const void *arg)
     s = qtest_start(qemu_cmd);
     g_free(qemu_cmd);
 
-    init_virtio_dev(server, 1u << VIRTIO_NET_F_MAC);
+    init_virtio_dev(global_qtest, server, 1u << VIRTIO_NET_F_MAC);
 
     if (!wait_for_fds(server)) {
         goto exit;
     }
 
-    read_guest_mem_server(server);
+    read_guest_mem_server(global_qtest, server);
 
 exit:
     uninit_virtio_dev(server);
@@ -690,7 +690,7 @@ static void test_migrate(void)
     TestServer *s = test_server_new("src");
     TestServer *dest = test_server_new("dest");
     char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
-    QTestState *global = global_qtest, *from, *to;
+    QTestState *from, *to;
     GSource *source;
     gchar *cmd, *tmp;
     QDict *rsp;
@@ -704,7 +704,7 @@ static void test_migrate(void)
     from = qtest_start(cmd);
     g_free(cmd);
 
-    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
+    init_virtio_dev(from, s, 1u << VIRTIO_NET_F_MAC);
     if (!wait_for_fds(s)) {
         goto exit;
     }
@@ -717,7 +717,7 @@ static void test_migrate(void)
     g_free(tmp);
     to = qtest_init(cmd);
     g_free(cmd);
-    init_virtio_dev(dest, 1u << VIRTIO_NET_F_MAC);
+    init_virtio_dev(to, dest, 1u << VIRTIO_NET_F_MAC);
 
     source = g_source_new(&test_migrate_source_funcs,
                           sizeof(TestMigrateSource));
@@ -753,12 +753,10 @@ static void test_migrate(void)
     qobject_unref(rsp);
 
     qmp_eventwait("STOP");
+    qtest_qmp_eventwait(to, "RESUME");
 
-    global_qtest = to;
-    qmp_eventwait("RESUME");
-
-    g_assert(wait_for_fds(s));
-    read_guest_mem_server(dest);
+    g_assert(wait_for_fds(dest));
+    read_guest_mem_server(to, dest);
 
     uninit_virtio_dev(dest);
     qtest_quit(to);
@@ -773,8 +771,6 @@ exit:
     qtest_quit(from);
     test_server_free(s);
     g_free(uri);
-
-    global_qtest = global;
 }
 
 static void wait_for_rings_started(TestServer *s, size_t count)
@@ -831,7 +827,7 @@ static void test_reconnect_subprocess(void)
     qtest_start(cmd);
     g_free(cmd);
 
-    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
+    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
     if (!wait_for_fds(s)) {
         goto exit;
     }
@@ -873,7 +869,7 @@ static void test_connect_fail_subprocess(void)
     qtest_start(cmd);
     g_free(cmd);
 
-    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
+    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
     if (!wait_for_fds(s)) {
         goto exit;
     }
@@ -906,7 +902,7 @@ static void test_flags_mismatch_subprocess(void)
     qtest_start(cmd);
     g_free(cmd);
 
-    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
+    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
     if (!wait_for_fds(s)) {
         goto exit;
     }
@@ -957,7 +953,7 @@ static void test_multiqueue(void)
     qtest_start(cmd);
     g_free(cmd);
 
-    init_virtio_dev(s, features_mask);
+    init_virtio_dev(global_qtest, s, features_mask);
 
     wait_for_rings_started(s, s->queues * 2);
 
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 12/71] vhost-user-test: create a main loop per TestServer
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (10 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 11/71] vhost-user-test: reduce usage of global_qtest Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 13/71] vhost-user-test: small changes to init_hugepagefs Paolo Bonzini
                   ` (61 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

This makes the tests more independent and removes the need to defer test_server_free
via an idle event source.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 38 ++++++++++++++++----------------------
 1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index c3a8af3..93d5157 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -143,6 +143,8 @@ typedef struct TestServer {
     int fds_num;
     int fds[VHOST_MEMORY_MAX_NREGIONS];
     VhostUserMemory memory;
+    GMainLoop *loop;
+    GThread *thread;
     GMutex data_mutex;
     GCond data_cond;
     int log_fd;
@@ -490,6 +492,10 @@ static TestServer *test_server_new(const gchar *name)
 {
     TestServer *server = g_new0(TestServer, 1);
 
+    server->loop = g_main_loop_new(NULL, FALSE);
+    /* run the main loop thread so the chardev may operate */
+    server->thread = g_thread_new(NULL, thread_function, server->loop);
+
     server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
     server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
     server->chr_name = g_strdup_printf("chr-%s", name);
@@ -533,9 +539,18 @@ static void test_server_listen(TestServer *server)
     test_server_create_chr(server, ",server,nowait");
 }
 
-static gboolean _test_server_free(TestServer *server)
+static void test_server_free(TestServer *server)
 {
     int i;
+    int ret;
+
+    /* finish the helper thread and dispatch pending sources */
+    g_main_loop_quit(server->loop);
+    g_thread_join(server->thread);
+    while (g_main_context_pending(NULL)) {
+        g_main_context_iteration (NULL, TRUE);
+    }
+    g_main_loop_unref(server->loop);
 
     qemu_chr_fe_deinit(&server->chr, true);
 
@@ -558,13 +573,6 @@ static gboolean _test_server_free(TestServer *server)
     qpci_free_pc(server->bus);
 
     g_free(server);
-
-    return FALSE;
-}
-
-static void test_server_free(TestServer *server)
-{
-    g_idle_add((GSourceFunc)_test_server_free, server);
 }
 
 static void wait_for_log_fd(TestServer *s)
@@ -969,8 +977,6 @@ int main(int argc, char **argv)
     const char *hugefs;
     int ret;
     char template[] = "/tmp/vhost-test-XXXXXX";
-    GMainLoop *loop;
-    GThread *thread;
 
     g_test_init(&argc, &argv, NULL);
 
@@ -991,10 +997,6 @@ int main(int argc, char **argv)
         root = tmpfs;
     }
 
-    loop = g_main_loop_new(NULL, FALSE);
-    /* run the main loop thread so the chardev may operate */
-    thread = g_thread_new(NULL, thread_function, loop);
-
     if (qemu_memfd_check(0)) {
         qtest_add_data_func("/vhost-user/read-guest-mem/memfd",
                             GINT_TO_POINTER(TEST_MEMFD_YES),
@@ -1022,14 +1024,6 @@ int main(int argc, char **argv)
 
     /* cleanup */
 
-    /* finish the helper thread and dispatch pending sources */
-    g_main_loop_quit(loop);
-    g_thread_join(thread);
-    while (g_main_context_pending(NULL)) {
-        g_main_context_iteration (NULL, TRUE);
-    }
-    g_main_loop_unref(loop);
-
     ret = rmdir(tmpfs);
     if (ret != 0) {
         g_test_message("unable to rmdir: path (%s): %s\n",
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 13/71] vhost-user-test: small changes to init_hugepagefs
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (11 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 12/71] vhost-user-test: create a main loop per TestServer Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 14/71] vhost-user-test: create a temporary directory per TestServer Paolo Bonzini
                   ` (60 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

After the conversion to qgraph, the equivalent of "main" will be in
a constructor and will run even if the tests are not being requested.
Therefore, it should not assert that init_hugepagefs succeeds and will
be called when creating the TestServer.  This patch changes the prototype
of init_hugepagefs, this way the next patch looks nicer.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 93d5157..a282fc5 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -461,13 +461,19 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     g_mutex_unlock(&s->data_mutex);
 }
 
-static const char *init_hugepagefs(const char *path)
+static const char *init_hugepagefs(void)
 {
+    const char *path = getenv("QTEST_HUGETLBFS_PATH");
     struct statfs fs;
     int ret;
 
+    if (!path) {
+        return NULL;
+    }
+
     if (access(path, R_OK | W_OK | X_OK)) {
         g_test_message("access on path (%s): %s\n", path, strerror(errno));
+        abort();
         return NULL;
     }
 
@@ -477,11 +483,13 @@ static const char *init_hugepagefs(const char *path)
 
     if (ret != 0) {
         g_test_message("statfs on path (%s): %s\n", path, strerror(errno));
+        abort();
         return NULL;
     }
 
     if (fs.f_type != HUGETLBFS_MAGIC) {
         g_test_message("Warning: path not on HugeTLBFS: %s\n", path);
+        abort();
         return NULL;
     }
 
@@ -974,7 +982,6 @@ static void test_multiqueue(void)
 
 int main(int argc, char **argv)
 {
-    const char *hugefs;
     int ret;
     char template[] = "/tmp/vhost-test-XXXXXX";
 
@@ -989,13 +996,7 @@ int main(int argc, char **argv)
     }
     g_assert(tmpfs);
 
-    hugefs = getenv("QTEST_HUGETLBFS_PATH");
-    if (hugefs) {
-        root = init_hugepagefs(hugefs);
-        g_assert(root);
-    } else {
-        root = tmpfs;
-    }
+    root = init_hugepagefs() ? : tmpfs;
 
     if (qemu_memfd_check(0)) {
         qtest_add_data_func("/vhost-user/read-guest-mem/memfd",
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 14/71] vhost-user-test: create a temporary directory per TestServer
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (12 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 13/71] vhost-user-test: small changes to init_hugepagefs Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 15/71] tests/libqos: introduce virtio_start_device Paolo Bonzini
                   ` (59 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

This makes the tests more independent, and also the source and destination
TestServers in the migration test.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 75 ++++++++++++++++++++++---------------------------
 1 file changed, 34 insertions(+), 41 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index a282fc5..23f129f 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -139,6 +139,8 @@ typedef struct TestServer {
     gchar *socket_path;
     gchar *mig_path;
     gchar *chr_name;
+    const gchar *mem_path;
+    gchar *tmpfs;
     CharBackend chr;
     int fds_num;
     int fds[VHOST_MEMORY_MAX_NREGIONS];
@@ -159,9 +161,6 @@ static TestServer *test_server_new(const gchar *name);
 static void test_server_free(TestServer *server);
 static void test_server_listen(TestServer *server);
 
-static const char *tmpfs;
-static const char *root;
-
 enum test_memfd {
     TEST_MEMFD_AUTO,
     TEST_MEMFD_YES,
@@ -169,7 +168,7 @@ enum test_memfd {
 };
 
 static char *get_qemu_cmd(TestServer *s,
-                          int mem, enum test_memfd memfd, const char *mem_path,
+                          int mem, enum test_memfd memfd,
                           const char *chr_opts, const char *extra)
 {
     if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) {
@@ -184,7 +183,7 @@ static char *get_qemu_cmd(TestServer *s,
     } else {
         return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR
                                QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem,
-                               mem_path, s->chr_name, s->socket_path,
+                               s->mem_path, s->chr_name, s->socket_path,
                                chr_opts, s->chr_name, extra);
     }
 }
@@ -499,11 +498,21 @@ static const char *init_hugepagefs(void)
 static TestServer *test_server_new(const gchar *name)
 {
     TestServer *server = g_new0(TestServer, 1);
+    char template[] = "/tmp/vhost-test-XXXXXX";
+    const char *tmpfs;
 
     server->loop = g_main_loop_new(NULL, FALSE);
     /* run the main loop thread so the chardev may operate */
     server->thread = g_thread_new(NULL, thread_function, server->loop);
 
+    tmpfs = mkdtemp(template);
+    if (!tmpfs) {
+        g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
+    }
+    g_assert(tmpfs);
+
+    server->tmpfs = g_strdup(tmpfs);
+    server->mem_path = init_hugepagefs() ? : server->tmpfs;
     server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
     server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
     server->chr_name = g_strdup_printf("chr-%s", name);
@@ -560,6 +569,18 @@ static void test_server_free(TestServer *server)
     }
     g_main_loop_unref(server->loop);
 
+    unlink(server->socket_path);
+    g_free(server->socket_path);
+
+    unlink(server->mig_path);
+    g_free(server->mig_path);
+
+    ret = rmdir(server->tmpfs);
+    if (ret != 0) {
+        g_test_message("unable to rmdir: path (%s): %s\n",
+                       server->tmpfs, strerror(errno));
+    }
+
     qemu_chr_fe_deinit(&server->chr, true);
 
     for (i = 0; i < server->fds_num; i++) {
@@ -570,12 +591,6 @@ static void test_server_free(TestServer *server)
         close(server->log_fd);
     }
 
-    unlink(server->socket_path);
-    g_free(server->socket_path);
-
-    unlink(server->mig_path);
-    g_free(server->mig_path);
-
     g_free(server->chr_name);
     g_assert(server->bus);
     qpci_free_pc(server->bus);
@@ -681,7 +696,7 @@ static void test_read_guest_mem(const void *arg)
                              "read-guest-memfd" : "read-guest-mem");
     test_server_listen(server);
 
-    qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", "");
+    qemu_cmd = get_qemu_cmd(server, 512, memfd, "", "");
 
     s = qtest_start(qemu_cmd);
     g_free(qemu_cmd);
@@ -716,7 +731,7 @@ static void test_migrate(void)
     test_server_listen(s);
     test_server_listen(dest);
 
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", "");
+    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, "", "");
     from = qtest_start(cmd);
     g_free(cmd);
 
@@ -729,7 +744,7 @@ static void test_migrate(void)
     g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
 
     tmp = g_strdup_printf(" -incoming %s", uri);
-    cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp);
+    cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, "", tmp);
     g_free(tmp);
     to = qtest_init(cmd);
     g_free(cmd);
@@ -839,7 +854,7 @@ static void test_reconnect_subprocess(void)
     char *cmd;
 
     g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
+    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
     qtest_start(cmd);
     g_free(cmd);
 
@@ -881,7 +896,7 @@ static void test_connect_fail_subprocess(void)
 
     s->test_fail = true;
     g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
+    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
     qtest_start(cmd);
     g_free(cmd);
 
@@ -914,7 +929,7 @@ static void test_flags_mismatch_subprocess(void)
 
     s->test_flags = TEST_FLAGS_DISCONNECT;
     g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
+    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
     qtest_start(cmd);
     g_free(cmd);
 
@@ -962,7 +977,7 @@ static void test_multiqueue(void)
         cmd = g_strdup_printf(
             QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
             "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
-            512, 512, root, s->chr_name,
+            512, 512, s->mem_path, s->chr_name,
             s->socket_path, "", s->chr_name,
             s->queues, s->queues * 2 + 2);
     }
@@ -982,22 +997,11 @@ static void test_multiqueue(void)
 
 int main(int argc, char **argv)
 {
-    int ret;
-    char template[] = "/tmp/vhost-test-XXXXXX";
-
     g_test_init(&argc, &argv, NULL);
 
     module_call_init(MODULE_INIT_QOM);
     qemu_add_opts(&qemu_chardev_opts);
 
-    tmpfs = mkdtemp(template);
-    if (!tmpfs) {
-        g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
-    }
-    g_assert(tmpfs);
-
-    root = init_hugepagefs() ? : tmpfs;
-
     if (qemu_memfd_check(0)) {
         qtest_add_data_func("/vhost-user/read-guest-mem/memfd",
                             GINT_TO_POINTER(TEST_MEMFD_YES),
@@ -1021,16 +1025,5 @@ int main(int argc, char **argv)
         qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
     }
 
-    ret = g_test_run();
-
-    /* cleanup */
-
-    ret = rmdir(tmpfs);
-    if (ret != 0) {
-        g_test_message("unable to rmdir: path (%s): %s\n",
-                       tmpfs, strerror(errno));
-    }
-    g_assert_cmpint(ret, ==, 0);
-
-    return ret;
+    return g_test_run();
 }
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 15/71] tests/libqos: introduce virtio_start_device
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (13 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 14/71] vhost-user-test: create a temporary directory per TestServer Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-07  9:16   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 16/71] tests/libqos: rename qpci_init_pc and qpci_init_spapr functions Paolo Bonzini
                   ` (58 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

This function is intended to group all the qvirtio_* functions that
start the qvirtio devices.
Applied in all tests using this combination of functions.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/libqos/virtio.c    |  7 +++++++
 tests/libqos/virtio.h    |  1 +
 tests/vhost-user-test.c  |  4 +---
 tests/virtio-9p-test.c   |  4 +---
 tests/virtio-blk-test.c  | 10 +++-------
 tests/virtio-net-test.c  |  4 +---
 tests/virtio-scsi-test.c |  4 +---
 7 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 0dad5c1..c1ff020 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -365,3 +365,10 @@ const char *qvirtio_get_dev_type(void)
         return "pci";
     }
 }
+
+void qvirtio_start_device(QVirtioDevice *vdev)
+{
+    qvirtio_reset(vdev);
+    qvirtio_set_acknowledge(vdev);
+    qvirtio_set_driver(vdev);
+}
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 69b5b13..2c68668 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -146,5 +146,6 @@ bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len);
 void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx);
 
 const char *qvirtio_get_dev_type(void);
+void qvirtio_start_device(QVirtioDevice *vdev);
 
 #endif
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 23f129f..df8edb3 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -200,9 +200,7 @@ static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_ma
     g_assert_nonnull(s->dev);
 
     qvirtio_pci_device_enable(s->dev);
-    qvirtio_reset(&s->dev->vdev);
-    qvirtio_set_acknowledge(&s->dev->vdev);
-    qvirtio_set_driver(&s->dev->vdev);
+    qvirtio_start_device(&s->dev->vdev);
 
     s->alloc = pc_alloc_init(qts);
 
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index a2b3108..d275c74 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -65,9 +65,7 @@ static QVirtIO9P *qvirtio_9p_pci_start(void)
     v9p->dev = (QVirtioDevice *) dev;
 
     qvirtio_pci_device_enable(dev);
-    qvirtio_reset(v9p->dev);
-    qvirtio_set_acknowledge(v9p->dev);
-    qvirtio_set_driver(v9p->dev);
+    qvirtio_start_device(v9p->dev);
 
     v9p->vq = qvirtqueue_setup(v9p->dev, v9p->qs->alloc, 0);
 
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 04c6087..f97c158 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -116,10 +116,7 @@ static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
     g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
 
     qvirtio_pci_device_enable(dev);
-    qvirtio_reset(&dev->vdev);
-    qvirtio_set_acknowledge(&dev->vdev);
-    qvirtio_set_driver(&dev->vdev);
-
+    qvirtio_start_device(&dev->vdev);
     return dev;
 }
 
@@ -333,6 +330,7 @@ static void pci_indirect(void)
     qvirtio_set_features(&dev->vdev, features);
 
     vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
+
     qvirtio_set_driver_ok(&dev->vdev);
 
     /* Write request */
@@ -720,9 +718,7 @@ static void mmio_basic(void)
     g_assert(dev != NULL);
     g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
 
-    qvirtio_reset(&dev->vdev);
-    qvirtio_set_acknowledge(&dev->vdev);
-    qvirtio_set_driver(&dev->vdev);
+    qvirtio_start_device(&dev->vdev);
 
     alloc = generic_alloc_init(MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
     vq = qvirtqueue_setup(&dev->vdev, alloc, 0);
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index dcb87a8..f89e08f 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -45,9 +45,7 @@ static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot)
     g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_NET);
 
     qvirtio_pci_device_enable(dev);
-    qvirtio_reset(&dev->vdev);
-    qvirtio_set_acknowledge(&dev->vdev);
-    qvirtio_set_driver(&dev->vdev);
+    qvirtio_start_device(&dev->vdev);
 
     return dev;
 }
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 0d4f25d..961925c 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -159,9 +159,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
     g_assert_cmphex(vs->dev->device_type, ==, VIRTIO_ID_SCSI);
 
     qvirtio_pci_device_enable(dev);
-    qvirtio_reset(vs->dev);
-    qvirtio_set_acknowledge(vs->dev);
-    qvirtio_set_driver(vs->dev);
+    qvirtio_start_device(vs->dev);
 
     vs->num_queues = qvirtio_config_readl(vs->dev, 0);
 
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 16/71] tests/libqos: rename qpci_init_pc and qpci_init_spapr functions
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (14 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 15/71] tests/libqos: introduce virtio_start_device Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-07  9:23   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test Paolo Bonzini
                   ` (57 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Rename qpci_init_pc in qpci_pc_new and qpci_init_spapr in qpci_spapr_new,
since theese function actually allocate a new pci struct and initialize it.
Changed QOSOps field name from qpci_init to qpci_new.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/e1000e-test.c         | 2 +-
 tests/i440fx-test.c         | 2 +-
 tests/ide-test.c            | 2 +-
 tests/libqos/ahci.c         | 2 +-
 tests/libqos/libqos-pc.c    | 2 +-
 tests/libqos/libqos-spapr.c | 2 +-
 tests/libqos/libqos.c       | 2 +-
 tests/libqos/libqos.h       | 2 +-
 tests/libqos/pci-pc.c       | 2 +-
 tests/libqos/pci-pc.h       | 9 ++++++++-
 tests/libqos/pci-spapr.c    | 2 +-
 tests/libqos/pci-spapr.h    | 2 +-
 tests/q35-test.c            | 4 ++--
 tests/rtl8139-test.c        | 2 +-
 tests/sdhci-test.c          | 2 +-
 tests/tco-test.c            | 2 +-
 tests/usb-hcd-ehci-test.c   | 2 +-
 tests/vhost-user-test.c     | 2 +-
 18 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index c9408a5..5525589 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -395,7 +395,7 @@ static void data_test_init(e1000e_device *d)
     test_alloc = pc_alloc_init(global_qtest);
     g_assert_nonnull(test_alloc);
 
-    test_bus = qpci_init_pc(global_qtest, test_alloc);
+    test_bus = qpci_new_pc(global_qtest, test_alloc);
     g_assert_nonnull(test_bus);
 
     e1000e_device_init(test_bus, d);
diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
index 4390e55..69205b5 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(global_qtest, NULL);
+    return qpci_new_pc(global_qtest, NULL);
 }
 
 static void test_i440fx_defaults(gconstpointer opaque)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index f0280e6..8f5adae 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -157,7 +157,7 @@ static QPCIDevice *get_pci_device(QPCIBar *bmdma_bar, QPCIBar *ide_bar)
     uint16_t vendor_id, device_id;
 
     if (!pcibus) {
-        pcibus = qpci_init_pc(global_qtest, NULL);
+        pcibus = qpci_new_pc(global_qtest, NULL);
     }
 
     /* Find PCI device and verify it's the right one */
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 63fbc9e..cc1b08e 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -130,7 +130,7 @@ QPCIDevice *get_ahci_device(QTestState *qts, uint32_t *fingerprint)
     uint32_t ahci_fingerprint;
     QPCIBus *pcibus;
 
-    pcibus = qpci_init_pc(qts, NULL);
+    pcibus = qpci_new_pc(qts, 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 a9c1ace..293f9b6 100644
--- a/tests/libqos/libqos-pc.c
+++ b/tests/libqos/libqos-pc.c
@@ -6,7 +6,7 @@
 static QOSOps qos_ops = {
     .init_allocator = pc_alloc_init_flags,
     .uninit_allocator = pc_alloc_uninit,
-    .qpci_init = qpci_init_pc,
+    .qpci_new = qpci_new_pc,
     .qpci_free = qpci_free_pc,
     .shutdown = qtest_pc_shutdown,
 };
diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c
index a37791e..64addfe 100644
--- a/tests/libqos/libqos-spapr.c
+++ b/tests/libqos/libqos-spapr.c
@@ -6,7 +6,7 @@
 static QOSOps qos_ops = {
     .init_allocator = spapr_alloc_init_flags,
     .uninit_allocator = spapr_alloc_uninit,
-    .qpci_init = qpci_init_spapr,
+    .qpci_new = qpci_new_spapr,
     .qpci_free = qpci_free_spapr,
     .shutdown = qtest_spapr_shutdown,
 };
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index c514187..6c91371 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -25,7 +25,7 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
     qs->ops = ops;
     if (ops) {
         qs->alloc = ops->init_allocator(qs->qts, ALLOC_NO_FLAGS);
-        qs->pcibus = ops->qpci_init(qs->qts, qs->alloc);
+        qs->pcibus = ops->qpci_new(qs->qts, qs->alloc);
     }
 
     g_free(cmdline);
diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h
index 07d4b93..1af6035 100644
--- a/tests/libqos/libqos.h
+++ b/tests/libqos/libqos.h
@@ -10,7 +10,7 @@ typedef struct QOSState QOSState;
 typedef struct QOSOps {
     QGuestAllocator *(*init_allocator)(QTestState *qts, QAllocOpts);
     void (*uninit_allocator)(QGuestAllocator *);
-    QPCIBus *(*qpci_init)(QTestState *qts, QGuestAllocator *alloc);
+    QPCIBus *(*qpci_new)(QTestState *qts, QGuestAllocator *alloc);
     void (*qpci_free)(QPCIBus *bus);
     void (*shutdown)(QOSState *);
 } QOSOps;
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 585f528..d21f3e8 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -115,7 +115,7 @@ static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint3
     outl(0xcfc, value);
 }
 
-QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc)
+QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc)
 {
     QPCIBusPC *ret = g_new0(QPCIBusPC, 1);
 
diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
index 491eeac..84cc300 100644
--- a/tests/libqos/pci-pc.h
+++ b/tests/libqos/pci-pc.h
@@ -16,7 +16,14 @@
 #include "libqos/pci.h"
 #include "libqos/malloc.h"
 
-QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc);
+/* qpci_new_pc():
+* this function creates a new QPCIBusPC object,
+ * and properly initialize its fields.
+ *
+ * returns the QPCIBus *bus field of a newly
+ * allocated QPCIBusPC.
+ */
+QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc);
 void     qpci_free_pc(QPCIBus *bus);
 
 #endif
diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c
index c0f7e6d..f306cb7 100644
--- a/tests/libqos/pci-spapr.c
+++ b/tests/libqos/pci-spapr.c
@@ -160,7 +160,7 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
 #define SPAPR_PCI_MMIO32_WIN_SIZE    0x80000000 /* 2 GiB */
 #define SPAPR_PCI_IO_WIN_SIZE        0x10000
 
-QPCIBus *qpci_init_spapr(QTestState *qts, QGuestAllocator *alloc)
+QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc)
 {
     QPCIBusSPAPR *ret = g_new0(QPCIBusSPAPR, 1);
 
diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h
index 387686d..177e8c0 100644
--- a/tests/libqos/pci-spapr.h
+++ b/tests/libqos/pci-spapr.h
@@ -11,7 +11,7 @@
 #include "libqos/malloc.h"
 #include "libqos/pci.h"
 
-QPCIBus *qpci_init_spapr(QTestState *qts, QGuestAllocator *alloc);
+QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc);
 void     qpci_free_spapr(QPCIBus *bus);
 
 #endif
diff --git a/tests/q35-test.c b/tests/q35-test.c
index 7ea7acc..34b34bc 100644
--- a/tests/q35-test.c
+++ b/tests/q35-test.c
@@ -87,7 +87,7 @@ static void test_smram_lock(void)
 
     qtest_start("-M q35");
 
-    pcibus = qpci_init_pc(global_qtest, NULL);
+    pcibus = qpci_new_pc(global_qtest, NULL);
     g_assert(pcibus != NULL);
 
     pcidev = qpci_device_find(pcibus, 0);
@@ -146,7 +146,7 @@ static void test_tseg_size(const void *data)
     g_free(cmdline);
 
     /* locate the DRAM controller */
-    pcibus = qpci_init_pc(global_qtest, NULL);
+    pcibus = qpci_new_pc(global_qtest, NULL);
     g_assert(pcibus != NULL);
     pcidev = qpci_device_find(pcibus, 0);
     g_assert(pcidev != NULL);
diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
index 68bfc42..a85c91f 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(global_qtest, NULL);
+    pcibus = qpci_new_pc(global_qtest, NULL);
     qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
     g_assert(dev != NULL);
 
diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c
index 982f5eb..28d481b 100644
--- a/tests/sdhci-test.c
+++ b/tests/sdhci-test.c
@@ -187,7 +187,7 @@ static QSDHCI *machine_start(const struct sdhci_t *test)
         global_qtest = qtest_initf("-machine %s -device sdhci-pci",
                                    test->machine);
 
-        s->pci.bus = qpci_init_pc(global_qtest, NULL);
+        s->pci.bus = qpci_new_pc(global_qtest, NULL);
 
         /* Find PCI device and verify it's the right one */
         s->pci.dev = qpci_device_find(s->pci.bus, QPCI_DEVFN(4, 0));
diff --git a/tests/tco-test.c b/tests/tco-test.c
index 6bee9a3..f89a42c 100644
--- a/tests/tco-test.c
+++ b/tests/tco-test.c
@@ -64,7 +64,7 @@ static void test_init(TestData *d)
     global_qtest = qs;
     qtest_irq_intercept_in(qs, "ioapic");
 
-    d->bus = qpci_init_pc(qs, NULL);
+    d->bus = qpci_new_pc(qs, NULL);
     d->dev = qpci_device_find(d->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 f28ea27..8bc3e44 100644
--- a/tests/usb-hcd-ehci-test.c
+++ b/tests/usb-hcd-ehci-test.c
@@ -52,7 +52,7 @@ static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
 
 static void test_init(void)
 {
-    pcibus = qpci_init_pc(global_qtest, NULL);
+    pcibus = qpci_new_pc(global_qtest, NULL);
     g_assert(pcibus != NULL);
 
     qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index df8edb3..3414075 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -193,7 +193,7 @@ static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_ma
     uint32_t features;
     int i;
 
-    s->bus = qpci_init_pc(qts, NULL);
+    s->bus = qpci_new_pc(qts, NULL);
     g_assert_nonnull(s->bus);
 
     s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (15 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 16/71] tests/libqos: rename qpci_init_pc and qpci_init_spapr functions Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-07  9:24   ` Thomas Huth
  2018-12-12 14:12   ` Philippe Mathieu-Daudé
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 18/71] tests/libqos: embed allocators instead of malloc-ing them Paolo Bonzini
                   ` (56 subsequent siblings)
  73 siblings, 2 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

This test was merged into drive_del-test in 2014.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3e3b16b..2718548 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -726,7 +726,6 @@ tests/qom-test$(EXESUF): tests/qom-test.o
 tests/test-hmp$(EXESUF): tests/test-hmp.o
 tests/machine-none-test$(EXESUF): tests/machine-none-test.o
 tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y)
-tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
 tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
 tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
 tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 18/71] tests/libqos: embed allocators instead of malloc-ing them
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (16 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-07 12:32   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework Paolo Bonzini
                   ` (55 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

qgraph will embed these objects instead of allocating them in a separate
object.  Expose a new API "generic_alloc_init" and "generic_alloc_destroy"
for that, and rename the existing API with s/init/new/ and s/uninit/free/.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/ahci-test.c             |  6 ++--
 tests/e1000e-test.c           | 22 +++++++-------
 tests/ide-test.c              | 17 +++++------
 tests/libqos/libqos-pc.c      |  3 +-
 tests/libqos/libqos-spapr.c   |  3 +-
 tests/libqos/libqos.c         | 13 ++++----
 tests/libqos/libqos.h         | 11 ++++---
 tests/libqos/malloc-generic.c | 21 ++-----------
 tests/libqos/malloc-generic.h |  7 ++---
 tests/libqos/malloc-pc.c      | 18 ++---------
 tests/libqos/malloc-pc.h      |  4 +--
 tests/libqos/malloc-spapr.c   | 19 ++----------
 tests/libqos/malloc-spapr.h   |  4 +--
 tests/libqos/malloc.c         | 41 ++++---------------------
 tests/libqos/malloc.h         | 21 +++++++++----
 tests/rtas-test.c             |  2 +-
 tests/vhost-user-test.c       | 10 +++----
 tests/virtio-9p-test.c        | 12 ++++----
 tests/virtio-blk-test.c       | 69 ++++++++++++++++++++++---------------------
 tests/virtio-net-test.c       | 10 +++----
 tests/virtio-scsi-test.c      | 14 ++++-----
 21 files changed, 123 insertions(+), 204 deletions(-)

diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 5dd380e..9f07e6f 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -162,7 +162,7 @@ static AHCIQState *ahci_vboot(const char *cli, va_list ap)
     s = g_new0(AHCIQState, 1);
     s->parent = qtest_pc_vboot(cli, ap);
     global_qtest = s->parent->qts;
-    alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT);
+    alloc_set_flags(&s->parent->alloc, ALLOC_LEAK_ASSERT);
 
     /* Verify that we have an AHCI device present. */
     s->dev = get_ahci_device(s->parent->qts, &s->fingerprint);
@@ -1039,7 +1039,7 @@ static void test_dma_fragmented(void)
     generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
 
     /* Create a DMA buffer in guest memory, and write our pattern to it. */
-    ptr = guest_alloc(ahci->parent->alloc, bufsize);
+    ptr = guest_alloc(&ahci->parent->alloc, bufsize);
     g_assert(ptr);
     bufwrite(ptr, tx, bufsize);
 
@@ -1059,7 +1059,7 @@ static void test_dma_fragmented(void)
 
     /* Read back the guest's receive buffer into local memory */
     bufread(ptr, rx, bufsize);
-    guest_free(ahci->parent->alloc, ptr);
+    guest_free(&ahci->parent->alloc, ptr);
 
     g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
 
diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index 5525589..17a12b8 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -94,7 +94,7 @@ typedef struct e1000e_device {
 } e1000e_device;
 
 static int test_sockets[2];
-static QGuestAllocator *test_alloc;
+static QGuestAllocator test_alloc;
 static QPCIBus *test_bus;
 
 static void e1000e_pci_foreach_callback(QPCIDevice *dev, int devfn, void *data)
@@ -165,7 +165,7 @@ static void e1000e_device_init(QPCIBus *bus, e1000e_device *d)
         val | E1000E_CTRL_EXT_DRV_LOAD | E1000E_CTRL_EXT_TXLSFLOW);
 
     /* Allocate and setup TX ring */
-    d->tx_ring = guest_alloc(test_alloc, E1000E_RING_LEN);
+    d->tx_ring = guest_alloc(&test_alloc, E1000E_RING_LEN);
     g_assert(d->tx_ring != 0);
 
     e1000e_macreg_write(d, E1000E_TDBAL, (uint32_t) d->tx_ring);
@@ -178,7 +178,7 @@ static void e1000e_device_init(QPCIBus *bus, e1000e_device *d)
     e1000e_macreg_write(d, E1000E_TCTL, E1000E_TCTL_EN);
 
     /* Allocate and setup RX ring */
-    d->rx_ring = guest_alloc(test_alloc, E1000E_RING_LEN);
+    d->rx_ring = guest_alloc(&test_alloc, E1000E_RING_LEN);
     g_assert(d->rx_ring != 0);
 
     e1000e_macreg_write(d, E1000E_RDBAL, (uint32_t)d->rx_ring);
@@ -268,7 +268,7 @@ static void e1000e_send_verify(e1000e_device *d)
     uint32_t recv_len;
 
     /* Prepare test data buffer */
-    uint64_t data = guest_alloc(test_alloc, data_len);
+    uint64_t data = guest_alloc(&test_alloc, data_len);
     memwrite(data, "TEST", 5);
 
     /* Prepare TX descriptor */
@@ -296,7 +296,7 @@ static void e1000e_send_verify(e1000e_device *d)
     g_assert_cmpstr(buffer, == , "TEST");
 
     /* Free test data buffer */
-    guest_free(test_alloc, data);
+    guest_free(&test_alloc, data);
 }
 
 static void e1000e_receive_verify(e1000e_device *d)
@@ -348,7 +348,7 @@ static void e1000e_receive_verify(e1000e_device *d)
     g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
 
     /* Prepare test data buffer */
-    uint64_t data = guest_alloc(test_alloc, data_len);
+    uint64_t data = guest_alloc(&test_alloc, data_len);
 
     /* Prepare RX descriptor */
     memset(&descr, 0, sizeof(descr));
@@ -369,7 +369,7 @@ static void e1000e_receive_verify(e1000e_device *d)
     g_assert_cmpstr(buffer, == , "TEST");
 
     /* Free test data buffer */
-    guest_free(test_alloc, data);
+    guest_free(&test_alloc, data);
 }
 
 static void e1000e_device_clear(QPCIBus *bus, e1000e_device *d)
@@ -392,10 +392,8 @@ static void data_test_init(e1000e_device *d)
     qtest_start(cmdline);
     g_free(cmdline);
 
-    test_alloc = pc_alloc_init(global_qtest);
-    g_assert_nonnull(test_alloc);
-
-    test_bus = qpci_new_pc(global_qtest, test_alloc);
+    pc_alloc_init(&test_alloc, global_qtest, 0);
+    test_bus = qpci_new_pc(global_qtest, &test_alloc);
     g_assert_nonnull(test_bus);
 
     e1000e_device_init(test_bus, d);
@@ -405,7 +403,7 @@ static void data_test_clear(e1000e_device *d)
 {
     e1000e_device_clear(test_bus, d);
     close(test_sockets[0]);
-    pc_alloc_uninit(test_alloc);
+    alloc_destroy(&test_alloc);
     g_free(d->pci_dev);
     qpci_free_pc(test_bus);
     qtest_end();
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 8f5adae..ef776fc 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -120,7 +120,7 @@ enum {
 #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
 
 static QPCIBus *pcibus = NULL;
-static QGuestAllocator *guest_malloc;
+static QGuestAllocator guest_malloc;
 
 static char tmp_path[] = "/tmp/qtest.XXXXXX";
 static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
@@ -135,7 +135,7 @@ static void ide_test_start(const char *cmdline_fmt, ...)
     va_end(ap);
 
     qtest_start(cmdline);
-    guest_malloc = pc_alloc_init(global_qtest);
+    pc_alloc_init(&guest_malloc, global_qtest, 0);
 
     g_free(cmdline);
 }
@@ -146,8 +146,7 @@ static void ide_test_quit(void)
         qpci_free_pc(pcibus);
         pcibus = NULL;
     }
-    pc_alloc_uninit(guest_malloc);
-    guest_malloc = NULL;
+    alloc_destroy(&guest_malloc);
     qtest_end();
 }
 
@@ -246,7 +245,7 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
 
     /* Setup PRDT */
     len = sizeof(*prdt) * prdt_entries;
-    guest_prdt = guest_alloc(guest_malloc, len);
+    guest_prdt = guest_alloc(&guest_malloc, len);
     memwrite(guest_prdt, prdt, len);
     qpci_io_writel(dev, bmdma_bar, bmreg_prdt, guest_prdt);
 
@@ -311,7 +310,7 @@ static void test_bmdma_simple_rw(void)
     uint8_t *buf;
     uint8_t *cmpbuf;
     size_t len = 512;
-    uintptr_t guest_buf = guest_alloc(guest_malloc, len);
+    uintptr_t guest_buf = guest_alloc(&guest_malloc, len);
 
     PrdtEntry prdt[] = {
         {
@@ -381,7 +380,7 @@ static void test_bmdma_trim(void)
     const uint64_t bad_range = trim_range_le(TEST_IMAGE_SIZE / 512 - 1, 2);
     size_t len = 512;
     uint8_t *buf;
-    uintptr_t guest_buf = guest_alloc(guest_malloc, len);
+    uintptr_t guest_buf = guest_alloc(&guest_malloc, len);
 
     PrdtEntry prdt[] = {
         {
@@ -625,7 +624,7 @@ static void make_dirty(uint8_t device)
 
     dev = get_pci_device(&bmdma_bar, &ide_bar);
 
-    guest_buf = guest_alloc(guest_malloc, len);
+    guest_buf = guest_alloc(&guest_malloc, len);
     buf = g_malloc(len);
     memset(buf, rand() % 255 + 1, len);
     g_assert(guest_buf);
@@ -986,7 +985,7 @@ static void test_cdrom_dma(void)
                    "-device ide-cd,drive=sr0,bus=ide.0", tmp_path);
     qtest_irq_intercept_in(global_qtest, "ioapic");
 
-    guest_buf = guest_alloc(guest_malloc, len);
+    guest_buf = guest_alloc(&guest_malloc, len);
     prdt[0].addr = cpu_to_le32(guest_buf);
     prdt[0].size = cpu_to_le32(len | PRDT_EOT);
 
diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
index 293f9b6..d04abc5 100644
--- a/tests/libqos/libqos-pc.c
+++ b/tests/libqos/libqos-pc.c
@@ -4,8 +4,7 @@
 #include "libqos/pci-pc.h"
 
 static QOSOps qos_ops = {
-    .init_allocator = pc_alloc_init_flags,
-    .uninit_allocator = pc_alloc_uninit,
+    .alloc_init = pc_alloc_init,
     .qpci_new = qpci_new_pc,
     .qpci_free = qpci_free_pc,
     .shutdown = qtest_pc_shutdown,
diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c
index 64addfe..8766d54 100644
--- a/tests/libqos/libqos-spapr.c
+++ b/tests/libqos/libqos-spapr.c
@@ -4,8 +4,7 @@
 #include "libqos/pci-spapr.h"
 
 static QOSOps qos_ops = {
-    .init_allocator = spapr_alloc_init_flags,
-    .uninit_allocator = spapr_alloc_uninit,
+    .alloc_init = spapr_alloc_init,
     .qpci_new = qpci_new_spapr,
     .qpci_free = qpci_free_spapr,
     .shutdown = qtest_spapr_shutdown,
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index 6c91371..636a111 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -24,8 +24,8 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
     qs->qts = qtest_init(cmdline);
     qs->ops = ops;
     if (ops) {
-        qs->alloc = ops->init_allocator(qs->qts, ALLOC_NO_FLAGS);
-        qs->pcibus = ops->qpci_new(qs->qts, qs->alloc);
+        ops->alloc_init(&qs->alloc, qs->qts, ALLOC_NO_FLAGS);
+        qs->pcibus = ops->qpci_new(qs->qts, &qs->alloc);
     }
 
     g_free(cmdline);
@@ -58,11 +58,8 @@ void qtest_common_shutdown(QOSState *qs)
             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;
-        }
     }
+    alloc_destroy(&qs->alloc);
     qtest_quit(qs->qts);
     g_free(qs);
 }
@@ -116,7 +113,7 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
 
     /* If we were running, we can wait for an event. */
     if (running) {
-        migrate_allocator(from->alloc, to->alloc);
+        migrate_allocator(&from->alloc, &to->alloc);
         set_context(to);
         qtest_qmp_eventwait(to->qts, "RESUME");
         return;
@@ -146,7 +143,7 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
         g_assert_not_reached();
     }
 
-    migrate_allocator(from->alloc, to->alloc);
+    migrate_allocator(&from->alloc, &to->alloc);
     set_context(to);
 }
 
diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h
index 1af6035..149b0be 100644
--- a/tests/libqos/libqos.h
+++ b/tests/libqos/libqos.h
@@ -3,13 +3,12 @@
 
 #include "libqtest.h"
 #include "libqos/pci.h"
-#include "libqos/malloc-pc.h"
+#include "libqos/malloc.h"
 
 typedef struct QOSState QOSState;
 
 typedef struct QOSOps {
-    QGuestAllocator *(*init_allocator)(QTestState *qts, QAllocOpts);
-    void (*uninit_allocator)(QGuestAllocator *);
+    void (*alloc_init)(QGuestAllocator *, QTestState *, QAllocOpts);
     QPCIBus *(*qpci_new)(QTestState *qts, QGuestAllocator *alloc);
     void (*qpci_free)(QPCIBus *bus);
     void (*shutdown)(QOSState *);
@@ -17,7 +16,7 @@ typedef struct QOSOps {
 
 struct QOSState {
     QTestState *qts;
-    QGuestAllocator *alloc;
+    QGuestAllocator alloc;
     QPCIBus *pcibus;
     QOSOps *ops;
 };
@@ -36,12 +35,12 @@ void generate_pattern(void *buffer, size_t len, size_t cycle_len);
 
 static inline uint64_t qmalloc(QOSState *q, size_t bytes)
 {
-    return guest_alloc(q->alloc, bytes);
+    return guest_alloc(&q->alloc, bytes);
 }
 
 static inline void qfree(QOSState *q, uint64_t addr)
 {
-    guest_free(q->alloc, addr);
+    guest_free(&q->alloc, addr);
 }
 
 #endif
diff --git a/tests/libqos/malloc-generic.c b/tests/libqos/malloc-generic.c
index 33ce90b..2873c67 100644
--- a/tests/libqos/malloc-generic.c
+++ b/tests/libqos/malloc-generic.c
@@ -15,25 +15,10 @@
  * Mostly for valgrind happiness, but it does offer
  * a chokepoint for debugging guest memory leaks, too.
  */
-void generic_alloc_uninit(QGuestAllocator *allocator)
+void generic_alloc_init(QGuestAllocator *s, uint64_t base_addr,
+			uint64_t size, uint32_t page_size)
 {
-    alloc_uninit(allocator);
-}
-
-QGuestAllocator *generic_alloc_init_flags(uint64_t base_addr, uint64_t size,
-                                        uint32_t page_size, QAllocOpts flags)
-{
-    QGuestAllocator *s;
     uint64_t start = base_addr + (1 << 20); /* Start at 1MB */
 
-    s = alloc_init_flags(flags, start, start + size);
-    alloc_set_page_size(s, page_size);
-
-    return s;
-}
-
-inline QGuestAllocator *generic_alloc_init(uint64_t base_addr, uint64_t size,
-                                                            uint32_t page_size)
-{
-    return generic_alloc_init_flags(base_addr, size, page_size, ALLOC_NO_FLAGS);
+    alloc_init(s, 0, start, start + size, page_size);
 }
diff --git a/tests/libqos/malloc-generic.h b/tests/libqos/malloc-generic.h
index 90104ec..40ea058 100644
--- a/tests/libqos/malloc-generic.h
+++ b/tests/libqos/malloc-generic.h
@@ -12,10 +12,7 @@
 
 #include "libqos/malloc.h"
 
-QGuestAllocator *generic_alloc_init(uint64_t base_addr, uint64_t size,
-                                                            uint32_t page_size);
-QGuestAllocator *generic_alloc_init_flags(uint64_t base_addr, uint64_t size,
-                                        uint32_t page_size, QAllocOpts flags);
-void generic_alloc_uninit(QGuestAllocator *allocator);
+void generic_alloc_init(QGuestAllocator *s, uint64_t base_addr, uint64_t size,
+                        uint32_t page_size);
 
 #endif
diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index b83cb8f..9aff807 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -24,28 +24,14 @@
  * Mostly for valgrind happiness, but it does offer
  * a chokepoint for debugging guest memory leaks, too.
  */
-void pc_alloc_uninit(QGuestAllocator *allocator)
+void pc_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags)
 {
-    alloc_uninit(allocator);
-}
-
-QGuestAllocator *pc_alloc_init_flags(QTestState *qts, QAllocOpts flags)
-{
-    QGuestAllocator *s;
     uint64_t ram_size;
     QFWCFG *fw_cfg = pc_fw_cfg_init(qts);
 
     ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE);
-    s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000));
-    alloc_set_page_size(s, PAGE_SIZE);
+    alloc_init(s, flags, 1 << 20, MIN(ram_size, 0xE0000000), PAGE_SIZE);
 
     /* clean-up */
     g_free(fw_cfg);
-
-    return s;
-}
-
-inline QGuestAllocator *pc_alloc_init(QTestState *qts)
-{
-    return pc_alloc_init_flags(qts, ALLOC_NO_FLAGS);
 }
diff --git a/tests/libqos/malloc-pc.h b/tests/libqos/malloc-pc.h
index 10f3da6..21e75ae 100644
--- a/tests/libqos/malloc-pc.h
+++ b/tests/libqos/malloc-pc.h
@@ -15,8 +15,6 @@
 
 #include "libqos/malloc.h"
 
-QGuestAllocator *pc_alloc_init(QTestState *qts);
-QGuestAllocator *pc_alloc_init_flags(QTestState *qts, QAllocOpts flags);
-void pc_alloc_uninit(QGuestAllocator *allocator);
+void pc_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags);
 
 #endif
diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c
index 1c359ce..2a6b7e3 100644
--- a/tests/libqos/malloc-spapr.c
+++ b/tests/libqos/malloc-spapr.c
@@ -17,22 +17,7 @@
  */
 #define SPAPR_MIN_SIZE 0x10000000
 
-void spapr_alloc_uninit(QGuestAllocator *allocator)
+void spapr_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags)
 {
-    alloc_uninit(allocator);
-}
-
-QGuestAllocator *spapr_alloc_init_flags(QTestState *qts, QAllocOpts flags)
-{
-    QGuestAllocator *s;
-
-    s = alloc_init_flags(flags, 1 << 20, SPAPR_MIN_SIZE);
-    alloc_set_page_size(s, PAGE_SIZE);
-
-    return s;
-}
-
-QGuestAllocator *spapr_alloc_init(void)
-{
-    return spapr_alloc_init_flags(NULL, ALLOC_NO_FLAGS);
+    alloc_init(s, flags, 1 << 20, SPAPR_MIN_SIZE, PAGE_SIZE);
 }
diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h
index 52a9346..e5fe9bf 100644
--- a/tests/libqos/malloc-spapr.h
+++ b/tests/libqos/malloc-spapr.h
@@ -10,8 +10,6 @@
 
 #include "libqos/malloc.h"
 
-QGuestAllocator *spapr_alloc_init(void);
-QGuestAllocator *spapr_alloc_init_flags(QTestState *qts, QAllocOpts flags);
-void spapr_alloc_uninit(QGuestAllocator *allocator);
+void spapr_alloc_init(QGuestAllocator *s, QTestState *qts, QAllocOpts flags);
 
 #endif
diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c
index ac05874..f1412cf 100644
--- a/tests/libqos/malloc.c
+++ b/tests/libqos/malloc.c
@@ -15,24 +15,12 @@
 #include "qemu-common.h"
 #include "qemu/host-utils.h"
 
-typedef QTAILQ_HEAD(MemList, MemBlock) MemList;
-
 typedef struct MemBlock {
     QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME;
     uint64_t size;
     uint64_t addr;
 } MemBlock;
 
-struct QGuestAllocator {
-    QAllocOpts opts;
-    uint64_t start;
-    uint64_t end;
-    uint32_t page_size;
-
-    MemList *used;
-    MemList *free;
-};
-
 #define DEFAULT_PAGE_SIZE 4096
 
 static void mlist_delete(MemList *list, MemBlock *node)
@@ -225,7 +213,7 @@ static void mlist_free(QGuestAllocator *s, uint64_t addr)
  * Mostly for valgrind happiness, but it does offer
  * a chokepoint for debugging guest memory leaks, too.
  */
-void alloc_uninit(QGuestAllocator *allocator)
+void alloc_destroy(QGuestAllocator *allocator)
 {
     MemBlock *node;
     MemBlock *tmp;
@@ -261,7 +249,6 @@ void alloc_uninit(QGuestAllocator *allocator)
 
     g_free(allocator->used);
     g_free(allocator->free);
-    g_free(allocator);
 }
 
 uint64_t guest_alloc(QGuestAllocator *allocator, size_t size)
@@ -297,9 +284,10 @@ void guest_free(QGuestAllocator *allocator, uint64_t addr)
     }
 }
 
-QGuestAllocator *alloc_init(uint64_t start, uint64_t end)
+void alloc_init(QGuestAllocator *s, QAllocOpts opts,
+                uint64_t start, uint64_t end,
+                size_t page_size)
 {
-    QGuestAllocator *s = g_malloc0(sizeof(*s));
     MemBlock *node;
 
     s->start = start;
@@ -313,26 +301,7 @@ QGuestAllocator *alloc_init(uint64_t start, uint64_t end)
     node = mlist_new(s->start, s->end - s->start);
     QTAILQ_INSERT_HEAD(s->free, node, MLIST_ENTNAME);
 
-    s->page_size = DEFAULT_PAGE_SIZE;
-
-    return s;
-}
-
-QGuestAllocator *alloc_init_flags(QAllocOpts opts,
-                                  uint64_t start, uint64_t end)
-{
-    QGuestAllocator *s = alloc_init(start, end);
-    s->opts = opts;
-    return s;
-}
-
-void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size)
-{
-    /* Can't alter the page_size for an allocator in-use */
-    g_assert(QTAILQ_EMPTY(allocator->used));
-
-    g_assert(is_power_of_2(page_size));
-    allocator->page_size = page_size;
+    s->page_size = page_size;
 }
 
 void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts)
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
index 828fdda..4d1a2e2 100644
--- a/tests/libqos/malloc.h
+++ b/tests/libqos/malloc.h
@@ -23,19 +23,28 @@ typedef enum {
     ALLOC_PARANOID    = 0x04
 } QAllocOpts;
 
-typedef struct QGuestAllocator QGuestAllocator;
+typedef QTAILQ_HEAD(MemList, MemBlock) MemList;
 
-void alloc_uninit(QGuestAllocator *allocator);
+typedef struct QGuestAllocator {
+    QAllocOpts opts;
+    uint64_t start;
+    uint64_t end;
+    uint32_t page_size;
+
+    MemList *used;
+    MemList *free;
+} QGuestAllocator;
 
 /* Always returns page aligned values */
 uint64_t guest_alloc(QGuestAllocator *allocator, size_t size);
 void guest_free(QGuestAllocator *allocator, uint64_t addr);
 void migrate_allocator(QGuestAllocator *src, QGuestAllocator *dst);
 
-QGuestAllocator *alloc_init(uint64_t start, uint64_t end);
-QGuestAllocator *alloc_init_flags(QAllocOpts flags,
-                                  uint64_t start, uint64_t end);
-void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size);
 void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts);
 
+void alloc_init(QGuestAllocator *alloc, QAllocOpts flags,
+                uint64_t start, uint64_t end,
+                size_t page_size);
+void alloc_destroy(QGuestAllocator *allocator);
+
 #endif
diff --git a/tests/rtas-test.c b/tests/rtas-test.c
index 009bda6..ee88867 100644
--- a/tests/rtas-test.c
+++ b/tests/rtas-test.c
@@ -17,7 +17,7 @@ static void test_rtas_get_time_of_day(void)
     global_qtest = qs->qts;
 
     t1 = time(NULL);
-    ret = qrtas_get_time_of_day(qs->qts, qs->alloc, &tm, &ns);
+    ret = qrtas_get_time_of_day(qs->qts, &qs->alloc, &tm, &ns);
     g_assert_cmpint(ret, ==, 0);
     t2 = mktimegm(&tm);
     g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 3414075..0c9a79a 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -154,7 +154,7 @@ typedef struct TestServer {
     bool test_fail;
     int test_flags;
     int queues;
-    QGuestAllocator *alloc;
+    QGuestAllocator alloc;
 } TestServer;
 
 static TestServer *test_server_new(const gchar *name);
@@ -202,10 +202,10 @@ static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_ma
     qvirtio_pci_device_enable(s->dev);
     qvirtio_start_device(&s->dev->vdev);
 
-    s->alloc = pc_alloc_init(qts);
+    pc_alloc_init(&s->alloc, qts, 0);
 
     for (i = 0; i < s->queues * 2; i++) {
-        s->vq[i] = qvirtqueue_setup(&s->dev->vdev, s->alloc, i);
+        s->vq[i] = qvirtqueue_setup(&s->dev->vdev, &s->alloc, i);
     }
 
     features = qvirtio_get_features(&s->dev->vdev);
@@ -220,9 +220,9 @@ static void uninit_virtio_dev(TestServer *s)
     int i;
 
     for (i = 0; i < s->queues * 2; i++) {
-        qvirtqueue_cleanup(s->dev->vdev.bus, s->vq[i], s->alloc);
+        qvirtqueue_cleanup(s->dev->vdev.bus, s->vq[i], &s->alloc);
     }
-    pc_alloc_uninit(s->alloc);
+    alloc_destroy(&s->alloc);
 
     qvirtio_pci_device_free(s->dev);
 }
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index d275c74..8fd74f6 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -67,7 +67,7 @@ static QVirtIO9P *qvirtio_9p_pci_start(void)
     qvirtio_pci_device_enable(dev);
     qvirtio_start_device(v9p->dev);
 
-    v9p->vq = qvirtqueue_setup(v9p->dev, v9p->qs->alloc, 0);
+    v9p->vq = qvirtqueue_setup(v9p->dev, &v9p->qs->alloc, 0);
 
     qvirtio_set_driver_ok(v9p->dev);
 
@@ -76,7 +76,7 @@ static QVirtIO9P *qvirtio_9p_pci_start(void)
 
 static void qvirtio_9p_pci_stop(QVirtIO9P *v9p)
 {
-    qvirtqueue_cleanup(v9p->dev->bus, v9p->vq, v9p->qs->alloc);
+    qvirtqueue_cleanup(v9p->dev->bus, v9p->vq, &v9p->qs->alloc);
     qvirtio_pci_device_disable(container_of(v9p->dev, QVirtioPCIDevice, vdev));
     qvirtio_pci_device_free((QVirtioPCIDevice *)v9p->dev);
     qvirtio_9p_stop(v9p);
@@ -222,7 +222,7 @@ static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id,
 
     req->v9p = v9p;
     req->t_size = total_size;
-    req->t_msg = guest_alloc(v9p->qs->alloc, req->t_size);
+    req->t_msg = guest_alloc(&v9p->qs->alloc, req->t_size);
     v9fs_memwrite(req, &hdr, 7);
     req->tag = tag;
     return req;
@@ -232,7 +232,7 @@ static void v9fs_req_send(P9Req *req)
 {
     QVirtIO9P *v9p = req->v9p;
 
-    req->r_msg = guest_alloc(v9p->qs->alloc, P9_MAX_SIZE);
+    req->r_msg = guest_alloc(&v9p->qs->alloc, P9_MAX_SIZE);
     req->free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false,
                                     true);
     qvirtqueue_add(v9p->vq, req->r_msg, P9_MAX_SIZE, true, false);
@@ -290,8 +290,8 @@ static void v9fs_req_free(P9Req *req)
 {
     QVirtIO9P *v9p = req->v9p;
 
-    guest_free(v9p->qs->alloc, req->t_msg);
-    guest_free(v9p->qs->alloc, req->r_msg);
+    guest_free(&v9p->qs->alloc, req->t_msg);
+    guest_free(&v9p->qs->alloc, req->r_msg);
     g_free(req);
 }
 
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index f97c158..77457f7 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -15,6 +15,7 @@
 #include "libqos/virtio.h"
 #include "libqos/virtio-pci.h"
 #include "libqos/virtio-mmio.h"
+#include "libqos/malloc.h"
 #include "libqos/malloc-generic.h"
 #include "qapi/qmp/qdict.h"
 #include "qemu/bswap.h"
@@ -290,12 +291,12 @@ static void pci_basic(void)
     qs = pci_test_start();
     dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
 
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
+    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
 
-    test_basic(&dev->vdev, qs->alloc, &vqpci->vq);
+    test_basic(&dev->vdev, &qs->alloc, &vqpci->vq);
 
     /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
+    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
     qtest_shutdown(qs);
@@ -329,7 +330,7 @@ static void pci_indirect(void)
                             (1u << VIRTIO_BLK_F_SCSI));
     qvirtio_set_features(&dev->vdev, features);
 
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
+    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
 
     qvirtio_set_driver_ok(&dev->vdev);
 
@@ -340,11 +341,11 @@ static void pci_indirect(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
 
     g_free(req.data);
 
-    indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
+    indirect = qvring_indirect_desc_setup(&dev->vdev, &qs->alloc, 2);
     qvring_indirect_desc_add(indirect, req_addr, 528, false);
     qvring_indirect_desc_add(indirect, req_addr + 528, 1, true);
     free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
@@ -356,7 +357,7 @@ static void pci_indirect(void)
     g_assert_cmpint(status, ==, 0);
 
     g_free(indirect);
-    guest_free(qs->alloc, req_addr);
+    guest_free(&qs->alloc, req_addr);
 
     /* Read request */
     req.type = VIRTIO_BLK_T_IN;
@@ -365,11 +366,11 @@ static void pci_indirect(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
 
     g_free(req.data);
 
-    indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
+    indirect = qvring_indirect_desc_setup(&dev->vdev, &qs->alloc, 2);
     qvring_indirect_desc_add(indirect, req_addr, 16, false);
     qvring_indirect_desc_add(indirect, req_addr + 16, 513, true);
     free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
@@ -386,10 +387,10 @@ static void pci_indirect(void)
     g_free(data);
 
     g_free(indirect);
-    guest_free(qs->alloc, req_addr);
+    guest_free(&qs->alloc, req_addr);
 
     /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
+    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
     qtest_shutdown(qs);
@@ -444,7 +445,7 @@ static void pci_msix(void)
     dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
     qpci_msix_enable(dev->pdev);
 
-    qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
+    qvirtio_pci_set_msix_configuration_vector(dev, &qs->alloc, 0);
 
     capacity = qvirtio_config_readq(&dev->vdev, 0);
     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
@@ -456,8 +457,8 @@ static void pci_msix(void)
                             (1u << VIRTIO_BLK_F_SCSI));
     qvirtio_set_features(&dev->vdev, features);
 
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
-    qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
+    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
+    qvirtqueue_pci_msix_setup(dev, vqpci, &qs->alloc, 1);
 
     qvirtio_set_driver_ok(&dev->vdev);
 
@@ -477,7 +478,7 @@ static void pci_msix(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
 
     g_free(req.data);
 
@@ -492,7 +493,7 @@ static void pci_msix(void)
     status = readb(req_addr + 528);
     g_assert_cmpint(status, ==, 0);
 
-    guest_free(qs->alloc, req_addr);
+    guest_free(&qs->alloc, req_addr);
 
     /* Read request */
     req.type = VIRTIO_BLK_T_IN;
@@ -500,7 +501,7 @@ static void pci_msix(void)
     req.sector = 0;
     req.data = g_malloc0(512);
 
-    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
 
     g_free(req.data);
 
@@ -522,10 +523,10 @@ static void pci_msix(void)
     g_assert_cmpstr(data, ==, "TEST");
     g_free(data);
 
-    guest_free(qs->alloc, req_addr);
+    guest_free(&qs->alloc, req_addr);
 
     /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
+    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
     qpci_msix_disable(dev->pdev);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
@@ -552,7 +553,7 @@ static void pci_idx(void)
     dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
     qpci_msix_enable(dev->pdev);
 
-    qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
+    qvirtio_pci_set_msix_configuration_vector(dev, &qs->alloc, 0);
 
     capacity = qvirtio_config_readq(&dev->vdev, 0);
     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
@@ -564,8 +565,8 @@ static void pci_idx(void)
                             (1u << VIRTIO_BLK_F_SCSI));
     qvirtio_set_features(&dev->vdev, features);
 
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
-    qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
+    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
+    qvirtqueue_pci_msix_setup(dev, vqpci, &qs->alloc, 1);
 
     qvirtio_set_driver_ok(&dev->vdev);
 
@@ -576,7 +577,7 @@ static void pci_idx(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
 
     g_free(req.data);
 
@@ -595,7 +596,7 @@ static void pci_idx(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
 
     g_free(req.data);
 
@@ -613,7 +614,7 @@ static void pci_idx(void)
                                              QVIRTIO_BLK_TIMEOUT_US);
     g_assert_cmpint(status, ==, 0);
 
-    guest_free(qs->alloc, req_addr);
+    guest_free(&qs->alloc, req_addr);
 
     /* Read request */
     req.type = VIRTIO_BLK_T_IN;
@@ -621,7 +622,7 @@ static void pci_idx(void)
     req.sector = 1;
     req.data = g_malloc0(512);
 
-    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
 
     g_free(req.data);
 
@@ -645,10 +646,10 @@ static void pci_idx(void)
     g_assert_cmpstr(data, ==, "TEST");
     g_free(data);
 
-    guest_free(qs->alloc, req_addr);
+    guest_free(&qs->alloc, req_addr);
 
     /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
+    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
     qpci_msix_disable(dev->pdev);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
@@ -708,7 +709,7 @@ static void mmio_basic(void)
 {
     QVirtioMMIODevice *dev;
     QVirtQueue *vq;
-    QGuestAllocator *alloc;
+    QGuestAllocator alloc;
     int n_size = TEST_IMAGE_SIZE / 2;
     uint64_t capacity;
 
@@ -720,10 +721,10 @@ static void mmio_basic(void)
 
     qvirtio_start_device(&dev->vdev);
 
-    alloc = generic_alloc_init(MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
-    vq = qvirtqueue_setup(&dev->vdev, alloc, 0);
+    generic_alloc_init(&alloc, MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
+    vq = qvirtqueue_setup(&dev->vdev, &alloc, 0);
 
-    test_basic(&dev->vdev, alloc, vq);
+    test_basic(&dev->vdev, &alloc, vq);
 
     qmp_discard_response("{ 'execute': 'block_resize', "
                          " 'arguments': { 'device': 'drive0', "
@@ -735,9 +736,9 @@ static void mmio_basic(void)
     g_assert_cmpint(capacity, ==, n_size / 512);
 
     /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, vq, alloc);
+    qvirtqueue_cleanup(dev->vdev.bus, vq, &alloc);
     g_free(dev);
-    generic_alloc_uninit(alloc);
+    alloc_destroy(&alloc);
     test_end();
 }
 
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index f89e08f..fa06d9b 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -224,16 +224,16 @@ static void pci_basic(gconstpointer data)
     qs = pci_test_start(sv[1]);
     dev = virtio_net_pci_init(qs->pcibus, PCI_SLOT);
 
-    rx = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
-    tx = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 1);
+    rx = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
+    tx = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 1);
 
     driver_init(&dev->vdev);
-    func(&dev->vdev, qs->alloc, &rx->vq, &tx->vq, sv[0]);
+    func(&dev->vdev, &qs->alloc, &rx->vq, &tx->vq, sv[0]);
 
     /* End test */
     close(sv[0]);
-    qvirtqueue_cleanup(dev->vdev.bus, &tx->vq, qs->alloc);
-    qvirtqueue_cleanup(dev->vdev.bus, &rx->vq, qs->alloc);
+    qvirtqueue_cleanup(dev->vdev.bus, &tx->vq, &qs->alloc);
+    qvirtqueue_cleanup(dev->vdev.bus, &rx->vq, &qs->alloc);
     qvirtio_pci_device_disable(dev);
     g_free(dev->pdev);
     g_free(dev);
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 961925c..9298aa8 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -62,7 +62,7 @@ static void qvirtio_scsi_pci_free(QVirtIOSCSI *vs)
     int i;
 
     for (i = 0; i < vs->num_queues + 2; i++) {
-        qvirtqueue_cleanup(vs->dev->bus, vs->vq[i], vs->qs->alloc);
+        qvirtqueue_cleanup(vs->dev->bus, vs->vq[i], &vs->qs->alloc);
     }
     qvirtio_pci_device_disable(container_of(vs->dev, QVirtioPCIDevice, vdev));
     qvirtio_pci_device_free((QVirtioPCIDevice *)vs->dev);
@@ -75,7 +75,7 @@ static uint64_t qvirtio_scsi_alloc(QVirtIOSCSI *vs, size_t alloc_size,
 {
     uint64_t addr;
 
-    addr = guest_alloc(vs->qs->alloc, alloc_size);
+    addr = guest_alloc(&vs->qs->alloc, alloc_size);
     if (data) {
         memwrite(addr, data, alloc_size);
     }
@@ -133,10 +133,10 @@ static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb,
         memread(resp_addr, resp_out, sizeof(*resp_out));
     }
 
-    guest_free(vs->qs->alloc, req_addr);
-    guest_free(vs->qs->alloc, resp_addr);
-    guest_free(vs->qs->alloc, data_in_addr);
-    guest_free(vs->qs->alloc, data_out_addr);
+    guest_free(&vs->qs->alloc, req_addr);
+    guest_free(&vs->qs->alloc, resp_addr);
+    guest_free(&vs->qs->alloc, data_in_addr);
+    guest_free(&vs->qs->alloc, data_out_addr);
     return response;
 }
 
@@ -166,7 +166,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
     g_assert_cmpint(vs->num_queues, <, MAX_NUM_QUEUES);
 
     for (i = 0; i < vs->num_queues + 2; i++) {
-        vs->vq[i] = qvirtqueue_setup(vs->dev, vs->qs->alloc, i);
+        vs->vq[i] = qvirtqueue_setup(vs->dev, &vs->qs->alloc, i);
     }
 
     /* Clear the POWER ON OCCURRED unit attention */
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (17 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 18/71] tests/libqos: embed allocators instead of malloc-ing them Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-07 12:42   ` Thomas Huth
  2018-12-07 15:38   ` Thomas Huth
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 20/71] tests/libqos: pci-pc driver and interface nodes Paolo Bonzini
                   ` (54 subsequent siblings)
  73 siblings, 2 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph API that allows to add/remove nodes and edges from the graph,
implementation of Depth First Search to discover the paths and basic unit
test to check correctness of the API.
Included also a main executable that takes care of starting the framework,
create the nodes, set the available drivers/machines, discover the path and
run tests.

graph.h provides the public API to manage the graph nodes/edges
graph_extra.h provides a more private API used successively by the gtest integration part
qos-test.c provides the main executable

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
[Paolo's changes compared to the Google Summer of Code submission:
 * added subprocess to test options
 * refactored object creation to support live migration tests
 * removed driver .before callback (unused)
 * removed test .after callbacks (replaced by GTest destruction queue)]

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 configure                      |   2 +-
 include/qemu/module.h          |   2 +
 tests/Makefile.include         |  13 +-
 tests/libqos/qgraph.c          | 760 +++++++++++++++++++++++++++++++++++++++++
 tests/libqos/qgraph.h          | 575 +++++++++++++++++++++++++++++++
 tests/libqos/qgraph_internal.h | 264 ++++++++++++++
 tests/libqtest.h               |   3 +
 tests/qos-test.c               | 470 +++++++++++++++++++++++++
 tests/test-qgraph.c            | 434 +++++++++++++++++++++++
 9 files changed, 2520 insertions(+), 3 deletions(-)
 create mode 100644 tests/libqos/qgraph.c
 create mode 100644 tests/libqos/qgraph.h
 create mode 100644 tests/libqos/qgraph_internal.h
 create mode 100644 tests/qos-test.c
 create mode 100644 tests/test-qgraph.c

diff --git a/configure b/configure
index d2c0fd3..defcf6a 100755
--- a/configure
+++ b/configure
@@ -7520,7 +7520,7 @@ fi
 # tests might fail. Prefer to keep the relevant files in their own
 # directory and symlink the directory instead.
 DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
-DIRS="$DIRS tests/fp"
+DIRS="$DIRS tests/fp tests/qgraph"
 DIRS="$DIRS docs docs/interop fsdev scsi"
 DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
 DIRS="$DIRS roms/seabios roms/vgabios"
diff --git a/include/qemu/module.h b/include/qemu/module.h
index 54300ab..1fcdca0 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -44,6 +44,7 @@ typedef enum {
     MODULE_INIT_OPTS,
     MODULE_INIT_QOM,
     MODULE_INIT_TRACE,
+    MODULE_INIT_LIBQOS,
     MODULE_INIT_MAX
 } module_init_type;
 
@@ -51,6 +52,7 @@ typedef enum {
 #define opts_init(function) module_init(function, MODULE_INIT_OPTS)
 #define type_init(function) module_init(function, MODULE_INIT_QOM)
 #define trace_init(function) module_init(function, MODULE_INIT_TRACE)
+#define libqos_init(function) module_init(function, MODULE_INIT_LIBQOS)
 
 #define block_module_load_one(lib) module_load_one("block-", lib)
 #define ui_module_load_one(lib) module_load_one("ui-", lib)
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 2718548..905841e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -658,7 +658,10 @@ tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y)
 tests/test-crypto-afsplit$(EXESUF): tests/test-crypto-afsplit.o $(test-crypto-obj-y)
 tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y)
 
-libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
+libqgraph-obj-y = tests/libqos/qgraph.o
+
+libqos-obj-y = $(libqgraph-obj-y) tests/libqos/pci.o tests/libqos/fw_cfg.o
+libqos-obj-y += tests/libqos/malloc.o tests/libqos/malloc-generic.o
 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
@@ -670,7 +673,13 @@ 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-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
-libqos-virtio-obj-y = $(libqos-spapr-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
+libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o
+
+check-unit-y += tests/test-qgraph$(EXESUF)
+tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
+
+check-qtest-generic-y += tests/qos-test$(EXESUF)
+tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-obj-y)
 
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/qmp-cmd-test$(EXESUF): tests/qmp-cmd-test.o
diff --git a/tests/libqos/qgraph.c b/tests/libqos/qgraph.c
new file mode 100644
index 0000000..03783f5
--- /dev/null
+++ b/tests/libqos/qgraph.c
@@ -0,0 +1,760 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/queue.h"
+#include "libqos/qgraph_internal.h"
+#include "libqos/qgraph.h"
+
+#define QGRAPH_PRINT_DEBUG 0
+#define QOS_ROOT ""
+typedef struct QOSStackElement QOSStackElement;
+
+/* Graph Edge.*/
+struct QOSGraphEdge {
+    QOSEdgeType type;
+    char *dest;
+    void *arg;                /* just for QEDGE_CONTAINS
+                               * and QEDGE_CONSUMED_BY */
+    char *extra_device_opts;  /* added to -device option, "," is
+                               * automatically added
+                               */
+    char *before_cmd_line;    /* added before node cmd_line */
+    char *after_cmd_line;     /* added after -device options */
+    char *edge_name;          /* used by QEDGE_CONTAINS */
+    QSLIST_ENTRY(QOSGraphEdge) edge_list;
+};
+
+/* Linked list grouping all edges with the same source node */
+QSLIST_HEAD(QOSGraphEdgeList, QOSGraphEdge);
+
+
+/**
+ * Stack used to keep track of the discovered path when using
+ * the DFS algorithm
+ */
+struct QOSStackElement {
+    QOSGraphNode *node;
+    QOSStackElement *parent;
+    QOSGraphEdge *parent_edge;
+    int length;
+};
+
+/* Each enty in these hash table will consist of <string, node/edge> pair. */
+static GHashTable *edge_table;
+static GHashTable *node_table;
+
+/* stack used by the DFS algorithm to store the path from machine to test */
+static QOSStackElement qos_node_stack[QOS_PATH_MAX_ELEMENT_SIZE];
+static int qos_node_tos;
+
+/**
+ * add_edge(): creates an edge of type @type
+ * from @source to @dest node, and inserts it in the
+ * edges hash table
+ *
+ * Nodes @source and @dest do not necessarily need to exist.
+ * Possibility to add also options (see #QOSGraphEdgeOptions)
+ * edge->edge_name is used as identifier for get_device relationships,
+ * so by default is equal to @dest.
+ */
+static void add_edge(const char *source, const char *dest,
+                     QOSEdgeType type, QOSGraphEdgeOptions *opts)
+{
+    char *key;
+    QOSGraphEdgeList *list = g_hash_table_lookup(edge_table, source);
+
+    if (!list) {
+        list = g_new0(QOSGraphEdgeList, 1);
+        key = g_strdup(source);
+        g_hash_table_insert(edge_table, key, list);
+    }
+
+    if (!opts) {
+        opts = &(QOSGraphEdgeOptions) { };
+    }
+
+    QOSGraphEdge *edge = g_new0(QOSGraphEdge, 1);
+    edge->type = type;
+    edge->dest = g_strdup(dest);
+    edge->edge_name = g_strdup(opts->edge_name ? : dest);
+    edge->arg = g_memdup(opts->arg, opts->size_arg);
+
+    edge->before_cmd_line =
+        opts->before_cmd_line ? g_strconcat(" ", opts->before_cmd_line, NULL) : NULL;
+    edge->extra_device_opts =
+        opts->extra_device_opts ? g_strconcat(",", opts->extra_device_opts, NULL) : NULL;
+    edge->after_cmd_line =
+        opts->after_cmd_line ? g_strconcat(" ", opts->after_cmd_line, NULL) : NULL;
+
+    QSLIST_INSERT_HEAD(list, edge, edge_list);
+}
+
+/* destroy_edges(): frees all edges inside a given @list */
+static void destroy_edges(void *list)
+{
+    QOSGraphEdge *temp;
+    QOSGraphEdgeList *elist = list;
+
+    while (!QSLIST_EMPTY(elist)) {
+        temp = QSLIST_FIRST(elist);
+        QSLIST_REMOVE_HEAD(elist, edge_list);
+        g_free(temp->dest);
+        g_free(temp->before_cmd_line);
+        g_free(temp->after_cmd_line);
+        g_free(temp->extra_device_opts);
+        g_free(temp->edge_name);
+        g_free(temp->arg);
+        g_free(temp);
+    }
+    g_free(elist);
+}
+
+/**
+ * create_node(): creates a node @name of type @type
+ * and inserts it to the nodes hash table.
+ * By default, node is not available.
+ */
+static QOSGraphNode *create_node(const char *name, QOSNodeType type)
+{
+    if (g_hash_table_lookup(node_table, name)) {
+        g_printerr("Node %s already created\n", name);
+        abort();
+    }
+
+    QOSGraphNode *node = g_new0(QOSGraphNode, 1);
+    node->type = type;
+    node->available = FALSE;
+    node->name = g_strdup(name);
+    g_hash_table_insert(node_table, node->name, node);
+    return node;
+}
+
+/**
+ * destroy_node(): frees a node @val from the nodes hash table.
+ * Note that node->name is not free'd since it will represent the
+ * hash table key
+ */
+static void destroy_node(void *val)
+{
+    QOSGraphNode *node = val;
+    g_free(node->command_line);
+    g_free(node);
+}
+
+/**
+ * destroy_string(): frees @key from the nodes hash table.
+ * Actually frees the node->name
+ */
+static void destroy_string(void *key)
+{
+    g_free(key);
+}
+
+/**
+ * search_node(): search for a node @key in the nodes hash table
+ * Returns the QOSGraphNode if found, #NULL otherwise
+ */
+static QOSGraphNode *search_node(const char *key)
+{
+    return g_hash_table_lookup(node_table, key);
+}
+
+/**
+ * get_edgelist(): returns the edge list (value) assigned to
+ * the @key in the edge hash table.
+ * This list will contain all edges with source equal to @key
+ *
+ * Returns: on success: the %QOSGraphEdgeList
+ *          otherwise: abort()
+ */
+static QOSGraphEdgeList *get_edgelist(const char *key)
+{
+    return g_hash_table_lookup(edge_table, key);
+}
+
+/**
+ * search_list_edges(): search for an edge with destination @dest
+ * in the given @edgelist.
+ *
+ * Returns: on success: the %QOSGraphEdge
+ *          otherwise: #NULL
+ */
+static QOSGraphEdge *search_list_edges(QOSGraphEdgeList *edgelist,
+                                       const char *dest)
+{
+    QOSGraphEdge *tmp, *next;
+    if (!edgelist) {
+        return NULL;
+    }
+    QSLIST_FOREACH_SAFE(tmp, edgelist, edge_list, next) {
+        if (g_strcmp0(tmp->dest, dest) == 0) {
+            break;
+        }
+    }
+    return tmp;
+}
+
+/**
+ * search_machine(): search for a machine @name in the node hash
+ * table. A machine is the child of the root node.
+ * This function forces the research in the childs of the root,
+ * to check the node is a proper machine
+ *
+ * Returns: on success: the %QOSGraphNode
+ *          otherwise: #NULL
+ */
+static QOSGraphNode *search_machine(const char *name)
+{
+    QOSGraphNode *n;
+    QOSGraphEdgeList *root_list = get_edgelist(QOS_ROOT);
+    QOSGraphEdge *e = search_list_edges(root_list, name);
+    if (!e) {
+        return NULL;
+    }
+    n = search_node(e->dest);
+    if (n->type == QNODE_MACHINE) {
+        return n;
+    }
+    return NULL;
+}
+
+/**
+ * create_interface(): checks if there is already
+ * a node @node in the node hash table, if not
+ * creates a node @node of type #QNODE_INTERFACE
+ * and inserts it. If there is one, check it's
+ * a #QNODE_INTERFACE and abort() if it's not.
+ */
+static void create_interface(const char *node)
+{
+    QOSGraphNode *interface;
+    interface = search_node(node);
+    if (!interface) {
+        create_node(node, QNODE_INTERFACE);
+    } else if (interface->type != QNODE_INTERFACE) {
+        printf("Error: Node %s is not an interface\n", node);
+        abort();
+    }
+}
+
+/**
+ * build_machine_cmd_line(): builds the command line for the machine
+ * @node. The node name must be a valid qemu identifier, since it
+ * will be used to build the command line.
+ *
+ * It is also possible to pass an optional @args that will be
+ * concatenated to the command line.
+ *
+ * For machines, prepend -M to the machine name. ", @rgs" is added
+ * after the -M <machine> command.
+ */
+static void build_machine_cmd_line(QOSGraphNode *node, const char *args)
+{
+    char *arch, *machine;
+    qos_separate_arch_machine(node->name, &arch, &machine);
+    if (args) {
+        node->command_line = g_strconcat("-M ", machine, ",", args, NULL);
+    } else {
+        node->command_line = g_strconcat("-M ", machine, " ", NULL);
+    }
+}
+
+/**
+ * build_driver_cmd_line(): builds the command line for the driver
+ * @node. The node name must be a valid qemu identifier, since it
+ * will be used to build the command line.
+ *
+ * Driver do not need additional command line, since it will be
+ * provided by the edge options.
+ *
+ * For drivers, prepend -device to the node name.
+ */
+static void build_driver_cmd_line(QOSGraphNode *node)
+{
+    node->command_line = g_strconcat(" -device ", node->name, NULL);
+}
+
+/* qos_print_cb(): callback prints all path found by the DFS algorithm. */
+static void qos_print_cb(QOSGraphNode *path, int length)
+{
+    #if QGRAPH_PRINT_DEBUG
+        printf("%d elements\n", length);
+
+        if (!path) {
+            return;
+        }
+
+        while (path->path_edge) {
+            printf("%s ", path->name);
+            switch (path->path_edge->type) {
+            case QEDGE_PRODUCES:
+                printf("--PRODUCES--> ");
+                break;
+            case QEDGE_CONSUMED_BY:
+                printf("--CONSUMED_BY--> ");
+                break;
+            case QEDGE_CONTAINS:
+                printf("--CONTAINS--> ");
+                break;
+            }
+            path = search_node(path->path_edge->dest);
+        }
+
+        printf("%s\n\n", path->name);
+    #endif
+}
+
+/* qos_push(): push a node @el and edge @e in the qos_node_stack */
+static void qos_push(QOSGraphNode *el, QOSStackElement *parent,
+                     QOSGraphEdge *e)
+{
+    int len = 0; /* root is not counted */
+    if (qos_node_tos == QOS_PATH_MAX_ELEMENT_SIZE) {
+        g_printerr("QOSStack: full stack, cannot push");
+        abort();
+    }
+
+    if (parent) {
+        len = parent->length + 1;
+    }
+    qos_node_stack[qos_node_tos++] = (QOSStackElement) {
+        .node = el,
+        .parent = parent,
+        .parent_edge = e,
+        .length = len,
+    };
+}
+
+/* qos_tos(): returns the top of stack, without popping */
+static QOSStackElement *qos_tos(void)
+{
+    return &qos_node_stack[(qos_node_tos - 1)];
+}
+
+/* qos_pop(): pops an element from the tos, setting it unvisited*/
+static QOSStackElement *qos_pop(void)
+{
+    if (qos_node_tos == 0) {
+        g_printerr("QOSStack: empty stack, cannot pop");
+        abort();
+    }
+    QOSStackElement *e = qos_tos();
+    e->node->visited = FALSE;
+    qos_node_tos--;
+    return e;
+}
+
+/**
+ * qos_reverse_path(): reverses the found path, going from
+ * test-to-machine to machine-to-test
+ */
+static QOSGraphNode *qos_reverse_path(QOSStackElement *el)
+{
+    if (!el) {
+        return NULL;
+    }
+
+    el->node->path_edge = NULL;
+
+    while (el->parent) {
+        el->parent->node->path_edge = el->parent_edge;
+        el = el->parent;
+    }
+
+    return el->node;
+}
+
+/**
+ * qos_traverse_graph(): graph-walking algorithm, using Depth First Search it
+ * starts from the root @machine and walks all possible path until it
+ * reaches a test node.
+ * At that point, it reverses the path found and invokes the @callback.
+ *
+ * Being Depth First Search, time complexity is O(|V| + |E|), while
+ * space is O(|V|). In this case, the maximum stack size is set by
+ * QOS_PATH_MAX_ELEMENT_SIZE.
+ */
+static void qos_traverse_graph(QOSGraphNode *root, QOSTestCallback callback)
+{
+    QOSGraphNode *v, *dest_node, *path;
+    QOSStackElement *s_el;
+    QOSGraphEdge *e, *next;
+    QOSGraphEdgeList *list;
+
+    qos_push(root, NULL, NULL);
+
+    while (qos_node_tos > 0) {
+        s_el = qos_tos();
+        v = s_el->node;
+        if (v->visited) {
+            qos_pop();
+            continue;
+        }
+        v->visited = TRUE;
+        list = get_edgelist(v->name);
+        if (!list) {
+            qos_pop();
+            if (v->type == QNODE_TEST) {
+                v->visited = FALSE;
+                path = qos_reverse_path(s_el);
+                callback(path, s_el->length);
+            }
+        } else {
+            QSLIST_FOREACH_SAFE(e, list, edge_list, next) {
+                dest_node = search_node(e->dest);
+
+                if (!dest_node) {
+                    printf("node %s in %s -> %s does not exist\n",
+                            e->dest, v->name, e->dest);
+                    abort();
+                }
+
+                if (!dest_node->visited && dest_node->available) {
+                    qos_push(dest_node, s_el, e);
+                }
+            }
+        }
+    }
+}
+
+/* QGRAPH API*/
+
+QOSGraphNode *qos_graph_get_node(const char *key)
+{
+    return search_node(key);
+}
+
+bool qos_graph_has_node(const char *node)
+{
+    QOSGraphNode *n = search_node(node);
+    return n != NULL;
+}
+
+QOSNodeType qos_graph_get_node_type(const char *node)
+{
+    QOSGraphNode *n = search_node(node);
+    if (n) {
+        return n->type;
+    }
+    return -1;
+}
+
+bool qos_graph_get_node_availability(const char *node)
+{
+    QOSGraphNode *n = search_node(node);
+    if (n) {
+        return n->available;
+    }
+    return FALSE;
+}
+
+QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest)
+{
+    QOSGraphEdgeList *list = get_edgelist(node);
+    return search_list_edges(list, dest);
+}
+
+QOSEdgeType qos_graph_edge_get_type(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return -1;
+    }
+    return edge->type;;
+}
+
+char *qos_graph_edge_get_dest(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->dest;
+}
+
+void *qos_graph_edge_get_arg(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->arg;
+}
+
+char *qos_graph_edge_get_after_cmd_line(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->after_cmd_line;
+}
+
+char *qos_graph_edge_get_before_cmd_line(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->before_cmd_line;
+}
+
+char *qos_graph_edge_get_extra_device_opts(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->extra_device_opts;
+}
+
+char *qos_graph_edge_get_name(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->edge_name;
+}
+
+bool qos_graph_has_edge(const char *start, const char *dest)
+{
+    QOSGraphEdgeList *list = get_edgelist(start);
+    QOSGraphEdge *e = search_list_edges(list, dest);
+    if (e) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+QOSGraphNode *qos_graph_get_machine(const char *node)
+{
+    return search_machine(node);
+}
+
+bool qos_graph_has_machine(const char *node)
+{
+    QOSGraphNode *m = search_machine(node);
+    return m != NULL;
+}
+
+void qos_print_graph(void)
+{
+    qos_graph_foreach_test_path(qos_print_cb);
+}
+
+void qos_graph_init(void)
+{
+    if (!node_table) {
+        node_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                           destroy_string, destroy_node);
+        create_node(QOS_ROOT, QNODE_DRIVER);
+    }
+
+    if (!edge_table) {
+        edge_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                           destroy_string, destroy_edges);
+    }
+}
+
+void qos_graph_destroy(void)
+{
+    if (node_table) {
+        g_hash_table_destroy(node_table);
+    }
+
+    if (edge_table) {
+        g_hash_table_destroy(edge_table);
+    }
+
+    node_table = NULL;
+    edge_table = NULL;
+}
+
+void qos_node_destroy(void *key)
+{
+    g_hash_table_remove(node_table, key);
+}
+
+void qos_edge_destroy(void *key)
+{
+    g_hash_table_remove(edge_table, key);
+}
+
+void qos_add_test(const char *name, const char *interface,
+                  QOSTestFunc test_func, QOSGraphTestOptions *opts)
+{
+    QOSGraphNode *node;
+    char *test_name = g_strdup_printf("%s-tests/%s", interface, name);;
+
+    if (!opts) {
+        opts = &(QOSGraphTestOptions) { };
+    }
+    node = create_node(test_name, QNODE_TEST);
+    node->u.test.function = test_func;
+    node->u.test.arg = opts->arg;
+    assert(!opts->edge.arg);
+    assert(!opts->edge.size_arg);
+
+    node->u.test.before = opts->before;
+    node->u.test.subprocess = opts->subprocess;
+    node->available = TRUE;
+    add_edge(interface, test_name, QEDGE_CONSUMED_BY, &opts->edge);
+    g_free(test_name);
+}
+
+void qos_node_create_machine(const char *name, QOSCreateMachineFunc function)
+{
+    qos_node_create_machine_args(name, function, NULL);
+}
+
+void qos_node_create_machine_args(const char *name,
+                                  QOSCreateMachineFunc function,
+                                  const char *opts)
+{
+    QOSGraphNode *node = create_node(name, QNODE_MACHINE);
+    build_machine_cmd_line(node, opts);
+    node->u.machine.constructor = function;
+    add_edge(QOS_ROOT, name, QEDGE_CONTAINS, NULL);
+}
+
+void qos_node_create_driver(const char *name, QOSCreateDriverFunc function)
+{
+    QOSGraphNode *node = create_node(name, QNODE_DRIVER);
+    build_driver_cmd_line(node);
+    node->u.driver.constructor = function;
+}
+
+void qos_node_contains(const char *container, const char *contained,
+                       ...)
+{
+    va_list va;
+    va_start(va, contained);
+    QOSGraphEdgeOptions *opts;
+
+    do {
+        opts = va_arg(va, QOSGraphEdgeOptions *);
+        add_edge(container, contained, QEDGE_CONTAINS, opts);
+    } while (opts != NULL);
+
+    va_end(va);
+}
+
+void qos_node_produces(const char *producer, const char *interface)
+{
+    create_interface(interface);
+    add_edge(producer, interface, QEDGE_PRODUCES, NULL);
+}
+
+void qos_node_consumes(const char *consumer, const char *interface,
+                       QOSGraphEdgeOptions *opts)
+{
+    create_interface(interface);
+    add_edge(interface, consumer, QEDGE_CONSUMED_BY, opts);
+}
+
+void qos_graph_node_set_availability(const char *node, bool av)
+{
+    QOSGraphEdgeList *elist;
+    QOSGraphNode *n = search_node(node);
+    QOSGraphEdge *e, *next;
+    if (!n) {
+        return;
+    }
+    n->available = av;
+    elist = get_edgelist(node);
+    if (!elist) {
+        return;
+    }
+    QSLIST_FOREACH_SAFE(e, elist, edge_list, next) {
+        if (e->type == QEDGE_CONTAINS || e->type == QEDGE_PRODUCES) {
+            qos_graph_node_set_availability(e->dest, av);
+        }
+    }
+}
+
+void qos_graph_foreach_test_path(QOSTestCallback fn)
+{
+    QOSGraphNode *root = qos_graph_get_node(QOS_ROOT);
+    qos_traverse_graph(root, fn);
+}
+
+QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts)
+{
+    QOSGraphObject *obj;
+
+    g_assert(node->type == QNODE_MACHINE);
+    obj = node->u.machine.constructor(qts);
+    obj->free = g_free;
+    return obj;
+}
+
+QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
+                               QGuestAllocator *alloc, void *arg)
+{
+    QOSGraphObject *obj;
+
+    g_assert(node->type == QNODE_DRIVER);
+    obj = node->u.driver.constructor(parent, alloc, arg);
+    obj->free = g_free;
+    return obj;
+}
+
+void qos_object_destroy(QOSGraphObject *obj)
+{
+    if (!obj) {
+        return;
+    }
+    if (obj->destructor) {
+        obj->destructor(obj);
+    }
+    if (obj->free) {
+        obj->free(obj);
+    }
+}
+
+void qos_object_queue_destroy(QOSGraphObject *obj)
+{
+    g_test_queue_destroy((GDestroyNotify) qos_object_destroy, obj);
+}
+
+void qos_object_start_hw(QOSGraphObject *obj)
+{
+    if (obj->start_hw) {
+        obj->start_hw(obj);
+    }
+}
+
+void qos_separate_arch_machine(char *name, char **arch, char **machine)
+{
+    *arch = name;
+    while (*name != '\0' && *name != '/') {
+        name++;
+    }
+
+    if (*name == '/' && (*name + 1) != '\0') {
+        *machine = name + 1;
+    } else {
+        printf("Machine name has to be of the form <arch>/<machine>\n");
+        abort();
+    }
+}
+
+void qos_delete_abstract_cmd_line(const char *name, bool abstract)
+{
+    QOSGraphNode *node = search_node(name);
+    if (node && abstract) {
+        g_free(node->command_line);
+        node->command_line = NULL;
+    }
+}
diff --git a/tests/libqos/qgraph.h b/tests/libqos/qgraph.h
new file mode 100644
index 0000000..6ebb2e6
--- /dev/null
+++ b/tests/libqos/qgraph.h
@@ -0,0 +1,575 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef QGRAPH_H
+#define QGRAPH_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <gmodule.h>
+#include <glib.h>
+#include "qemu/module.h"
+#include "malloc.h"
+
+/* maximum path length */
+#define QOS_PATH_MAX_ELEMENT_SIZE 50
+
+typedef struct QOSGraphObject QOSGraphObject;
+typedef struct QOSGraphNode QOSGraphNode;
+typedef struct QOSGraphEdge QOSGraphEdge;
+typedef struct QOSGraphNodeOptions QOSGraphNodeOptions;
+typedef struct QOSGraphEdgeOptions QOSGraphEdgeOptions;
+typedef struct QOSGraphTestOptions QOSGraphTestOptions;
+
+/* Constructor for drivers, machines and test */
+typedef void *(*QOSCreateDriverFunc) (void *parent, QGuestAllocator *alloc,
+                                      void *addr);
+typedef void *(*QOSCreateMachineFunc) (QTestState *qts);
+typedef void (*QOSTestFunc) (void *parent, void *arg, QGuestAllocator *alloc);
+
+/* QOSGraphObject functions */
+typedef void *(*QOSGetDriver) (void *object, const char *interface);
+typedef QOSGraphObject *(*QOSGetDevice) (void *object, const char *name);
+typedef void (*QOSDestructorFunc) (QOSGraphObject *object);
+typedef void (*QOSStartFunct) (QOSGraphObject *object);
+
+/* Test options functions */
+typedef void *(*QOSBeforeTest) (GString *cmd_line, void *arg);
+
+/**
+ * SECTION: qgraph.h
+ * @title: Qtest Driver Framework
+ * @short_description: interfaces to organize drivers and tests
+ *                     as nodes in a graph
+ *
+ * This Qgraph API provides all basic functions to create a graph
+ * and instantiate nodes representing machines, drivers and tests
+ * representing their relations with CONSUMES, PRODUCES, and CONTAINS
+ * edges.
+ *
+ * The idea is to have a framework where each test asks for a specific
+ * driver, and the framework takes care of allocating the proper devices
+ * required and passing the correct command line arguments to QEMU.
+ *
+ * A node can be of four types:
+ * - QNODE_MACHINE:   for example "arm/raspi2"
+ * - QNODE_DRIVER:    for example "generic-sdhci"
+ * - QNODE_INTERFACE: for example "sdhci" (interface for all "-sdhci" drivers)
+ *                     an interface is not explicitly created, it will be auto-
+ *                     matically instantiated when a node consumes or produces
+ *                     it.
+ * - QNODE_TEST:      for example "sdhci-test", consumes an interface and tests
+ *                    the functions provided
+ *
+ * Notes for the nodes:
+ * - QNODE_MACHINE: each machine struct must have a QGuestAllocator and
+ *                  implement get_driver to return the allocator passing
+ *                  "memory". The function can also return NULL if the
+ *                  allocator is not set.
+ * - QNODE_DRIVER:  driver names must be unique, and machines and nodes
+ *                  planned to be "consumed" by other nodes must match QEMU
+ *                  drivers name, otherwise they won't be discovered
+ *
+ * An edge relation between two nodes (drivers or machines) X and Y can be:
+ * - X CONSUMES Y: Y can be plugged into X
+ * - X PRODUCES Y: X provides the interface Y
+ * - X CONTAINS Y: Y is part of X component
+ *
+ * Basic framework steps are the following:
+ * - All nodes and edges are created in their respective
+ *   machine/driver/test files
+ * - The framework starts QEMU and asks for a list of available devices
+ *   and machines (note that only machines and "consumed" nodes are mapped
+ *   1:1 with QEMU devices)
+ * - The framework walks the graph starting from the available machines and
+ *   performs a Depth First Search for tests
+ * - Once a test is found, the path is walked again and all drivers are
+ *   allocated accordingly and the final interface is passed to the test
+ * - The test is executed
+ * - Unused objects are cleaned and the path discovery is continued
+ *
+ * Depending on the QEMU binary used, only some drivers/machines will be
+ * available and only test that are reached by them will be executed.
+ *
+ * <example>
+ *   <title>Creating new driver an its interface</title>
+ *   <programlisting>
+ #include "libqos/qgraph.h"
+
+ struct My_driver {
+     QOSGraphObject obj;
+     Node_produced prod;
+     Node_contained cont;
+ }
+
+ static void my_destructor(QOSGraphObject *obj)
+ {
+    g_free(obj);
+ }
+
+ static void my_get_driver(void *object, const char *interface) {
+    My_driver *dev = object;
+    if (!g_strcmp0(interface, "my_interface")) {
+        return &dev->prod;
+    }
+    abort();
+ }
+
+ static void my_get_device(void *object, const char *device) {
+    My_driver *dev = object;
+    if (!g_strcmp0(device, "my_driver_contained")) {
+        return &dev->cont;
+    }
+    abort();
+ }
+
+ static void *my_driver_constructor(void *node_consumed,
+                                    QOSGraphObject *alloc)
+ {
+    My_driver dev = g_new(My_driver, 1);
+    // get the node pointed by the produce edge
+    dev->obj.get_driver = my_get_driver;
+    // get the node pointed by the contains
+    dev->obj.get_device = my_get_device;
+    // free the object
+    dev->obj.destructor = my_destructor;
+    do_something_with_node_consumed(node_consumed);
+    // set all fields of contained device
+    init_contained_device(&dev->cont);
+    return &dev->obj;
+ }
+
+ static void register_my_driver(void)
+ {
+     qos_node_create_driver("my_driver", my_driver_constructor);
+     // contained drivers don't need a constructor,
+     // they will be init by the parent.
+     qos_node_create_driver("my_driver_contained", NULL);
+
+    // For the sake of this example, assume machine x86_64/pc contains
+    // "other_node".
+    // This relation, along with the machine and "other_node" creation,
+    // should be defined in the x86_64_pc-machine.c file.
+    // "my_driver" will then consume "other_node"
+    qos_node_contains("my_driver", "my_driver_contained");
+    qos_node_produces("my_driver", "my_interface");
+    qos_node_consumes("my_driver", "other_node");
+ }
+ *   </programlisting>
+ * </example>
+ *
+ * In the above example, all possible types of relations are created:
+ * node "my_driver" consumes, contains and produces other nodes.
+ * more specifically:
+ * x86_64/pc -->contains--> other_node <--consumes-- my_driver
+ *                                                       |
+ *                      my_driver_contained <--contains--+
+ *                                                       |
+ *                             my_interface <--produces--+
+ *
+ * or inverting the consumes edge in consumed_by:
+ *
+ * x86_64/pc -->contains--> other_node --consumed_by--> my_driver
+ *                                                           |
+ *                          my_driver_contained <--contains--+
+ *                                                           |
+ *                                 my_interface <--produces--+
+ *
+ * <example>
+ *   <title>Creating new test</title>
+ *   <programlisting>
+ * #include "libqos/qgraph.h"
+ *
+ * static void my_test_function(void *obj, void *data)
+ * {
+ *    Node_produced *interface_to_test = obj;
+ *    // test interface_to_test
+ * }
+ *
+ * static void register_my_test(void)
+ * {
+ *    qos_add_test("my_interface", "my_test", my_test_function);
+ * }
+ *
+ * libqos_init(register_my_test);
+ *
+ *   </programlisting>
+ * </example>
+ *
+ * Here a new test is created, consuming "my_interface" node
+ * and creating a valid path from a machine to a test.
+ * Final graph will be like this:
+ * x86_64/pc -->contains--> other_node <--consumes-- my_driver
+ *                                                        |
+ *                       my_driver_contained <--contains--+
+ *                                                        |
+ *        my_test --consumes--> my_interface <--produces--+
+ *
+ * or inverting the consumes edge in consumed_by:
+ *
+ * x86_64/pc -->contains--> other_node --consumed_by--> my_driver
+ *                                                           |
+ *                          my_driver_contained <--contains--+
+ *                                                           |
+ *        my_test <--consumed_by-- my_interface <--produces--+
+ *
+ * Assuming there the binary is
+ * QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64
+ * a valid test path will be:
+ * "/x86_64/pc/other_node/my_driver/my_interface/my_test".
+ *
+ * Additional examples are also in libqos/test-qgraph.c
+ *
+ * Command line:
+ * Command line is built by using node names and optional arguments
+ * passed by the user when building the edges.
+ *
+ * There are three types of command line arguments:
+ * - in node      : created from the node name. For example, machines will
+ *                  have "-M <machine>" to its command line, while devices
+ *                  "- device <device>". It is automatically done by the
+ *                   framework.
+ * - after node   : added as additional argument to the node name.
+ *                  This argument is added optionally when creating edges,
+ *                  by setting the parameter @after_cmd_line and
+ *                  @extra_edge_opts in #QOSGraphEdgeOptions.
+ *                  The framework automatically adds
+ *                  a comma before @extra_edge_opts,
+ *                  because it is going to add attibutes
+ *                  after the destination node pointed by
+ *                  the edge containing these options, and automatically
+ *                  adds a space before @after_cmd_line, because it
+ *                  adds an additional device, not an attribute.
+ * - before node  : added as additional argument to the node name.
+ *                  This argument is added optionally when creating edges,
+ *                  by setting the parameter @before_cmd_line in
+ *                  #QOSGraphEdgeOptions. This attribute
+ *                  is going to add attibutes before the destination node
+ *                  pointed by the edge containing these options. It is
+ *                  helpful to commands that are not node-representable,
+ *                  such as "-fdsev" or "-netdev".
+ *
+ * While adding command line in edges is always used, not all nodes names are
+ * used in every path walk: this is because the contained or produced ones
+ * are already added by QEMU, so only nodes that "consumes" will be used to
+ * build the command line. Also, nodes that will have { "abstract" : true }
+ * as QMP attribute will loose their command line, since they are not proper
+ * devices to be added in QEMU.
+ *
+ * Example:
+ *
+ QOSGraphEdgeOptions opts = {
+     .arg = NULL,
+     .size_arg = 0,
+     .after_cmd_line = "-device other",
+     .before_cmd_line = "-netdev something",
+     .extra_edge_opts = "addr=04.0",
+ };
+ QOSGraphNode * node = qos_node_create_driver("my_node", constructor);
+ qos_node_consumes_args("my_node", "interface", &opts);
+ *
+ * Will produce the following command line:
+ * "-netdev something -device my_node,addr=04.0 -device other"
+ */
+
+/**
+ * Edge options to be passed to the contains/consumes *_args function.
+ */
+struct QOSGraphEdgeOptions {
+    void *arg;                    /*
+                                   * optional arg that will be used by
+                                   * dest edge
+                                   */
+    uint32_t size_arg;            /*
+                                   * optional arg size that will be used by
+                                   * dest edge
+                                   */
+    const char *extra_device_opts;/*
+                                   *optional additional command line for dest
+                                   * edge, used to add additional attributes
+                                   * *after* the node command line, the
+                                   * framework automatically prepends ","
+                                   * to this argument.
+                                   */
+    const char *before_cmd_line;  /*
+                                   * optional additional command line for dest
+                                   * edge, used to add additional attributes
+                                   * *before* the node command line, usually
+                                   * other non-node represented commands,
+                                   * like "-fdsev synt"
+                                   */
+    const char *after_cmd_line;   /*
+                                   * optional extra command line to be added
+                                   * after the device command. This option
+                                   * is used to add other devices
+                                   * command line that depend on current node.
+                                   * Automatically prepends " " to this
+                                   * argument
+                                   */
+    const char *edge_name;        /*
+                                   * optional edge to differentiate multiple
+                                   * devices with same node name
+                                   */
+};
+
+/**
+ * Test options to be passed to the test functions.
+ */
+struct QOSGraphTestOptions {
+    QOSGraphEdgeOptions edge;   /* edge arguments that will be used by test.
+                                 * Note that test *does not* use edge_name,
+                                 * and uses instead arg and size_arg as
+                                 * data arg for its test function.
+                                 */
+    void *arg;                  /* passed to the .before function, or to the
+                                 * test function if there is no .before
+                                 * function
+                                 */
+    QOSBeforeTest before;       /* executed before the test. Can add
+                                 * additional parameters to the command line
+				 * and modify the argument to the test function.
+                                 */
+    bool subprocess;            /* run the test in a subprocess */
+};
+
+/**
+ * Each driver, test or machine of this framework will have a
+ * QOSGraphObject as first field.
+ *
+ * This set of functions offered by QOSGraphObject are executed
+ * in different stages of the framework:
+ * - get_driver / get_device : Once a machine-to-test path has been
+ * found, the framework traverses it again and allocates all the
+ * nodes, using the provided constructor. To satisfy their relations,
+ * i.e. for produces or contains, where a struct constructor needs
+ * an external parameter represented by the previous node,
+ * the framework will call get_device (for contains) or
+ * get_driver (for produces), depending on the edge type, passing
+ * them the name of the next node to be taken and getting from them
+ * the corresponding pointer to the actual structure of the next node to
+ * be used in the path.
+ *
+ * - start_hw: This function is executed after all the path objects
+ * have been allocated, but before the test is run. It starts the hw, setting
+ * the initial configurations (*_device_enable) and making it ready for the
+ * test.
+ *
+ * - destructor: Opposite to the node constructor, destroys the object.
+ * This function is called after the test has been executed, and performs
+ * a complete cleanup of each node allocated field. In case no constuctor
+ * is provided, no destructor will be called.
+ *
+ */
+struct QOSGraphObject {
+    /* for produces edges, returns void * */
+    QOSGetDriver get_driver;
+    /* for contains edges, returns a QOSGraphObject * */
+    QOSGetDevice get_device;
+    /* start the hw, get ready for the test */
+    QOSStartFunct start_hw;
+    /* destroy this QOSGraphObject */
+    QOSDestructorFunc destructor;
+    /* free the memory associated to the QOSGraphObject and its contained
+     * children */
+    GDestroyNotify free;
+};
+
+/**
+ * qos_graph_init(): initialize the framework, creates two hash
+ * tables: one for the nodes and another for the edges.
+ */
+void qos_graph_init(void);
+
+/**
+ * qos_graph_destroy(): deallocates all the hash tables,
+ * freeing all nodes and edges.
+ */
+void qos_graph_destroy(void);
+
+/**
+ * qos_node_destroy(): removes and frees a node from the,
+ * nodes hash table.
+ */
+void qos_node_destroy(void *key);
+
+/**
+ * qos_edge_destroy(): removes and frees an edge from the,
+ * edges hash table.
+ */
+void qos_edge_destroy(void *key);
+
+/**
+ * qos_add_test(): adds a test node @name to the nodes hash table.
+ *
+ * The test will consume a @interface node, and once the
+ * graph walking algorithm has found it, the @test_func will be
+ * executed. It also has the possibility to
+ * add an optional @opts (see %QOSGraphNodeOptions).
+ *
+ * For tests, opts->edge.arg and size_arg represent the arg to pass
+ * to @test_func
+ */
+void qos_add_test(const char *name, const char *interface,
+                  QOSTestFunc test_func,
+                  QOSGraphTestOptions *opts);
+
+/**
+ * qos_node_create_machine(): creates the machine @name and
+ * adds it to the node hash table.
+ *
+ * This node will be of type QNODE_MACHINE and have @function
+ * as constructor
+ */
+void qos_node_create_machine(const char *name, QOSCreateMachineFunc function);
+
+/**
+ * qos_node_create_machine_args(): same as qos_node_create_machine,
+ * but with the possibility to add an optional ", @opts" after -M machine
+ * command line.
+ */
+void qos_node_create_machine_args(const char *name,
+                                  QOSCreateMachineFunc function,
+                                  const char *opts);
+
+/**
+ * qos_node_create_driver(): creates the driver @name and
+ * adds it to the node hash table.
+ *
+ * This node will be of type QNODE_DRIVER and have @function
+ * as constructor
+ */
+void qos_node_create_driver(const char *name, QOSCreateDriverFunc function);
+
+/**
+ * qos_node_contains(): creates an edge of type QEDGE_CONTAINS and
+ * adds it to the edge list mapped to @container in the
+ * edge hash table.
+ *
+ * This edge will have @container as source and @contained as destination.
+ *
+ * It also has the possibility to add optional NULL-terminated
+ * @opts parameters (see %QOSGraphEdgeOptions)
+ *
+ * This function can be useful whrn there are multiple devices
+ * with the same node name contained in a machine/other node
+ *
+ * For example, if "arm/raspi2" contains 2 "generic-sdhci"
+ * devices, the right commands will be:
+ * qos_node_create_machine("arm/raspi2");
+ * qos_node_create_driver("generic-sdhci", constructor);
+ * //assume rest of the fields are set NULL
+ * QOSGraphEdgeOptions op1 = { .edge_name = "emmc" };
+ * QOSGraphEdgeOptions op2 = { .edge_name = "sdcard" };
+ * qos_node_contains("arm/raspi2", "generic-sdhci", &op1, &op2, NULL);
+ *
+ * Of course this also requires that the @container's get_device function
+ * should implement a case for "emmc" and "sdcard".
+ *
+ * For contains, op1.arg and op1.size_arg represent the arg to pass
+ * to @contained constructor to properly initialize it.
+ */
+void qos_node_contains(const char *container, const char *contained, ...);
+
+/**
+ * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and
+ * adds it to the edge list mapped to @producer in the
+ * edge hash table.
+ *
+ * This edge will have @producer as source and @interface as destination.
+ */
+void qos_node_produces(const char *producer, const char *interface);
+
+/**
+ * qos_node_consumes():  creates an edge of type QEDGE_CONSUMED_BY and
+ * adds it to the edge list mapped to @interface in the
+ * edge hash table.
+ *
+ * This edge will have @interface as source and @consumer as destination.
+ * It also has the possibility to add an optional @opts
+ * (see %QOSGraphEdgeOptions)
+ */
+void qos_node_consumes(const char *consumer, const char *interface,
+                       QOSGraphEdgeOptions *opts);
+
+/**
+ * qos_invalidate_command_line(): invalidates current command line, so that
+ * qgraph framework cannot try to cache the current command line and
+ * forces QEMU to restart.
+ */
+void qos_invalidate_command_line(void);
+
+/**
+ * qos_get_current_command_line(): return the command line required by the
+ * machine and driver objects.  This is the same string that was passed to
+ * the test's "before" callback, if any.
+ */
+const char *qos_get_current_command_line(void);
+
+/**
+ * qos_allocate_objects():
+ * @qts: The #QTestState that will be referred to by the machine object.
+ * @alloc: Where to store the allocator for the machine object, or %NULL.
+ *
+ * Allocate driver objects for the current test
+ * path, but relative to the QTestState @qts.
+ *
+ * Returns a test object just like the one that was passed to
+ * the test function, but relative to @qts.
+ */
+void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc);
+
+/**
+ * qos_object_destroy(): calls the destructor for @obj
+ */
+void qos_object_destroy(QOSGraphObject *obj);
+
+/**
+ * qos_object_queue_destroy(): queue the destructor for @obj so that it is
+ * called at the end of the test
+ */
+void qos_object_queue_destroy(QOSGraphObject *obj);
+
+/**
+ * qos_object_start_hw(): calls the start_hw function for @obj
+ */
+void qos_object_start_hw(QOSGraphObject *obj);
+
+/**
+ * qos_machine_new(): instantiate a new machine node
+ * @node: A machine node to be instantiated
+ * @qts: The #QTestState that will be referred to by the machine object.
+ *
+ * Returns a machine object.
+ */
+QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts);
+
+/**
+ * qos_machine_new(): instantiate a new driver node
+ * @node: A driver node to be instantiated
+ * @parent: A #QOSGraphObject to be consumed by the new driver node
+ * @alloc: An allocator to be used by the new driver node.
+ * @arg: The argument for the consumed-by edge to @node.
+ *
+ * Calls the constructor for the driver object.
+ */
+QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
+                               QGuestAllocator *alloc, void *arg);
+
+
+#endif
diff --git a/tests/libqos/qgraph_internal.h b/tests/libqos/qgraph_internal.h
new file mode 100644
index 0000000..bb4d82c
--- /dev/null
+++ b/tests/libqos/qgraph_internal.h
@@ -0,0 +1,264 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef QGRAPH_EXTRA_H
+#define QGRAPH_EXTRA_H
+
+/* This header is declaring additional helper functions defined in
+ * libqos/qgraph.c
+ * It should not be included in tests
+ */
+
+#include "libqos/qgraph.h"
+
+typedef struct QOSGraphMachine QOSGraphMachine;
+typedef struct QOSGraphEdgeList QOSGraphEdgeList;
+typedef enum QOSEdgeType QOSEdgeType;
+typedef enum QOSNodeType QOSNodeType;
+
+/* callback called when the walk path algorithm found a
+ * valid path
+ */
+typedef void (*QOSTestCallback) (QOSGraphNode *path, int len);
+
+/* edge types*/
+enum QOSEdgeType {
+    QEDGE_CONTAINS,
+    QEDGE_PRODUCES,
+    QEDGE_CONSUMED_BY
+};
+
+/* node types*/
+enum QOSNodeType {
+    QNODE_MACHINE,
+    QNODE_DRIVER,
+    QNODE_INTERFACE,
+    QNODE_TEST
+};
+
+/* Graph Node */
+struct QOSGraphNode {
+    QOSNodeType type;
+    bool available;     /* set by QEMU via QMP, used during graph walk */
+    bool visited;       /* used during graph walk */
+    char *name;         /* used to identify the node */
+    char *command_line; /* used to start QEMU at test execution */
+    union {
+        struct {
+            QOSCreateDriverFunc constructor;
+        } driver;
+        struct {
+            QOSCreateMachineFunc constructor;
+        } machine;
+        struct {
+            QOSTestFunc function;
+            void *arg;
+            QOSBeforeTest before;
+            bool subprocess;
+        } test;
+    } u;
+
+    /**
+     * only used when traversing the path, never rely on that except in the
+     * qos_traverse_graph callback function
+     */
+    QOSGraphEdge *path_edge;
+};
+
+/**
+ * qos_graph_get_node(): returns the node mapped to that @key.
+ * It performs an hash map search O(1)
+ *
+ * Returns: on success: the %QOSGraphNode
+ *          otherwise: #NULL
+ */
+QOSGraphNode *qos_graph_get_node(const char *key);
+
+/**
+ * qos_graph_has_node(): returns #TRUE if the node
+ * has map has a node mapped to that @key.
+ */
+bool qos_graph_has_node(const char *node);
+
+/**
+ * qos_graph_get_node_type(): returns the %QOSNodeType
+ * of the node @node.
+ * It performs an hash map search O(1)
+ * Returns: on success: the %QOSNodeType
+ *          otherwise: #-1
+ */
+QOSNodeType qos_graph_get_node_type(const char *node);
+
+/**
+ * qos_graph_get_node_availability(): returns the availability (boolean)
+ * of the node @node.
+ */
+bool qos_graph_get_node_availability(const char *node);
+
+/**
+ * qos_graph_get_edge(): returns the edge
+ * linking of the node @node with @dest.
+ *
+ * Returns: on success: the %QOSGraphEdge
+ *          otherwise: #NULL
+ */
+QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest);
+
+/**
+ * qos_graph_edge_get_type(): returns the edge type
+ * of the edge @edge.
+ *
+ * Returns: on success: the %QOSEdgeType
+ *          otherwise: #-1
+ */
+QOSEdgeType qos_graph_edge_get_type(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_edge_get_dest(): returns the name of the node
+ * pointed as destination of edge @edge.
+ *
+ * Returns: on success: the destination
+ *          otherwise: #NULL
+ */
+char *qos_graph_edge_get_dest(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_has_edge(): returns #TRUE if there
+ * exists an edge from @start to @dest.
+ */
+bool qos_graph_has_edge(const char *start, const char *dest);
+
+/**
+ * qos_graph_edge_get_arg(): returns the args assigned
+ * to that @edge.
+ *
+ * Returns: on success: the arg
+ *          otherwise: #NULL
+ */
+void *qos_graph_edge_get_arg(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_edge_get_after_cmd_line(): returns the edge
+ * command line that will be added after all the node arguments
+ * and all the before_cmd_line arguments.
+ *
+ * Returns: on success: the char* arg
+ *          otherwise: #NULL
+ */
+char *qos_graph_edge_get_after_cmd_line(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_edge_get_before_cmd_line(): returns the edge
+ * command line that will be added before the node command
+ * line argument.
+ *
+ * Returns: on success: the char* arg
+ *          otherwise: #NULL
+ */
+char *qos_graph_edge_get_before_cmd_line(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_edge_get_extra_device_opts(): returns the arg
+ * command line that will be added to the node command
+ * line argument.
+ *
+ * Returns: on success: the char* arg
+ *          otherwise: #NULL
+ */
+char *qos_graph_edge_get_extra_device_opts(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_edge_get_name(): returns the name
+ * assigned to the destination node (different only)
+ * if there are multiple devices with the same node name
+ * e.g. a node has two "generic-sdhci", "emmc" and "sdcard"
+ * there will be two edges with edge_name ="emmc" and "sdcard"
+ *
+ * Returns always the char* edge_name
+ */
+char *qos_graph_edge_get_name(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_get_machine(): returns the machine assigned
+ * to that @node name.
+ *
+ * It performs a search only trough the list of machines
+ * (i.e. the QOS_ROOT child).
+ *
+ * Returns: on success: the %QOSGraphNode
+ *          otherwise: #NULL
+ */
+QOSGraphNode *qos_graph_get_machine(const char *node);
+
+/**
+ * qos_graph_has_machine(): returns #TRUE if the node
+ * has map has a node mapped to that @node.
+ */
+bool qos_graph_has_machine(const char *node);
+
+
+/**
+ * qos_print_graph(): walks the graph and prints
+ * all machine-to-test paths.
+ */
+void qos_print_graph(void);
+
+/**
+ * qos_graph_foreach_test_path(): executes the Depth First search
+ * algorithm and applies @fn to all discovered paths.
+ *
+ * See qos_traverse_graph() in qgraph.c for more info on
+ * how it works.
+ */
+void qos_graph_foreach_test_path(QOSTestCallback fn);
+
+/**
+ * qos_separate_arch_machine(): separate arch from machine.
+ * This function requires every machine @name to be in the form
+ * <arch>/<machine_name>, like "arm/raspi2" or "x86_64/pc".
+ *
+ * The function will split then the string in two parts,
+ * assigning @arch to point to <arch>/<machine_name>, and
+ * @machine to <machine_name>.
+ *
+ * For example, "x86_64/pc" will be split in this way:
+ * *arch = "x86_64/pc"
+ * *machine = "pc"
+ *
+ * Note that this function *does not* allocate any new string,
+ * but just sets the pointer *arch and *machine to the respective
+ * part of the string.
+ */
+void qos_separate_arch_machine(char *name, char **arch, char **machine);
+
+/**
+ * qos_delete_abstract_cmd_line(): if @abstract is #TRUE, delete the
+ * command line present in node mapped with key @name.
+ *
+ * This function is called when the QMP query returns a node with
+ * { "abstract" : <boolean> } attribute.
+ */
+void qos_delete_abstract_cmd_line(const char *name, bool abstract);
+
+/**
+ * qos_graph_node_set_availability(): sets the node identified
+ * by @node with availability @av.
+ */
+void qos_graph_node_set_availability(const char *node, bool av);
+
+#endif
diff --git a/tests/libqtest.h b/tests/libqtest.h
index ed88ff9..2fd1e51 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -576,6 +576,9 @@ static inline QTestState *qtest_start(const char *args)
  */
 static inline void qtest_end(void)
 {
+    if (!global_qtest) {
+        return;
+    }
     qtest_quit(global_qtest);
     global_qtest = NULL;
 }
diff --git a/tests/qos-test.c b/tests/qos-test.c
new file mode 100644
index 0000000..d85ed71
--- /dev/null
+++ b/tests/qos-test.c
@@ -0,0 +1,470 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <getopt.h>
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qlist.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "libqos/qgraph_internal.h"
+
+static char *old_path;
+
+/**
+ * create_machine_name(): appends the architecture to @name if
+ * @is_machine is valid.
+ */
+static void create_machine_name(const char **name, bool is_machine)
+{
+    const char *arch;
+    if (!is_machine) {
+        return;
+    }
+    arch = qtest_get_arch();
+    *name = g_strconcat(arch, "/", *name, NULL);
+}
+
+/**
+ * destroy_machine_name(): frees the given @name if
+ * @is_machine is valid.
+ */
+static void destroy_machine_name(const char *name, bool is_machine)
+{
+    if (!is_machine) {
+        return;
+    }
+    g_free((char *)name);
+}
+
+/**
+ * apply_to_qlist(): using QMP queries QEMU for a list of
+ * machines and devices available, and sets the respective node
+ * as TRUE. If a node is found, also all its produced and contained
+ * child are marked available.
+ *
+ * See qos_graph_node_set_availability() for more info
+ */
+static void apply_to_qlist(QList *list, bool is_machine)
+{
+    const QListEntry *p;
+    const char *name;
+    bool abstract;
+    QDict *minfo;
+    QObject *qobj;
+    QString *qstr;
+    QBool *qbol;
+
+    for (p = qlist_first(list); p; p = qlist_next(p)) {
+        minfo = qobject_to(QDict, qlist_entry_obj(p));
+        qobj = qdict_get(minfo, "name");
+        qstr = qobject_to(QString, qobj);
+        name = qstring_get_str(qstr);
+
+        create_machine_name(&name, is_machine);
+        qos_graph_node_set_availability(name, TRUE);
+
+        qobj = qdict_get(minfo, "alias");
+        if (qobj) {
+            qstr = qobject_to(QString, qobj);
+
+            destroy_machine_name(name, is_machine);
+            name = qstring_get_str(qstr);
+
+            create_machine_name(&name, is_machine);
+            qos_graph_node_set_availability(name, TRUE);
+        }
+
+        qobj = qdict_get(minfo, "abstract");
+        if (qobj) {
+            qbol = qobject_to(QBool, qobj);
+            abstract = qbool_get_bool(qbol);
+            qos_delete_abstract_cmd_line(name, abstract);
+        }
+
+        destroy_machine_name(name, is_machine);
+    }
+}
+
+/**
+ * qos_set_machines_devices_available(): sets availability of qgraph
+ * machines and devices.
+ *
+ * This function firstly starts QEMU with "-machine none" option,
+ * and then executes the QMP protocol asking for the list of devices
+ * and machines available.
+ *
+ * for each of these items, it looks up the corresponding qgraph node,
+ * setting it as available. The list currently returns all devices that
+ * are either machines or QEDGE_CONSUMED_BY other nodes.
+ * Therefore, in order to mark all other nodes, it recursively sets
+ * all its QEDGE_CONTAINS and QEDGE_PRODUCES child as available too.
+ */
+static void qos_set_machines_devices_available(void)
+{
+    QDict *response;
+    QDict *args = qdict_new();
+    QList *list;
+
+    qtest_start("-machine none");
+    response = qmp("{ 'execute': 'query-machines' }");
+    list = qdict_get_qlist(response, "return");
+
+    apply_to_qlist(list, TRUE);
+
+    qobject_unref(response);
+
+    qdict_put_bool(args, "abstract", TRUE);
+    qdict_put_str(args, "implements", "device");
+
+    response = qmp("{'execute': 'qom-list-types',"
+                   " 'arguments': %p }", args);
+    g_assert(qdict_haskey(response, "return"));
+    list = qdict_get_qlist(response, "return");
+
+    apply_to_qlist(list, FALSE);
+
+    qtest_end();
+    qobject_unref(response);
+
+}
+
+static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
+{
+    if (obj->get_driver) {
+        return obj->get_driver(obj, "memory");
+    } else {
+        return NULL;
+    }
+}
+
+static void restart_qemu_or_continue(char *path)
+{
+    /* compares the current command line with the
+     * one previously executed: if they are the same,
+     * don't restart QEMU, if they differ, stop previous
+     * QEMU subprocess (if active) and start over with
+     * the new command line
+     */
+    if (g_strcmp0(old_path, path)) {
+        qtest_end();
+        qos_invalidate_command_line();
+        old_path = g_strdup(path);
+        qtest_start(path);
+    } else { /* if cmd line is the same, reset the guest */
+        qobject_unref(qmp("{ 'execute': 'system_reset' }"));
+        qmp_eventwait("RESET");
+    }
+}
+
+void qos_invalidate_command_line(void)
+{
+    g_free(old_path);
+    old_path = NULL;
+}
+
+/**
+ * allocate_objects(): given an array of nodes @arg,
+ * walks the path invoking all constructors and
+ * passing the corresponding parameter in order to
+ * continue the objects allocation.
+ * Once the test is reached, return the object it consumes.
+ *
+ * Since the machine and QEDGE_CONSUMED_BY nodes allocate
+ * memory in the constructor, g_test_queue_destroy is used so
+ * that after execution they can be safely free'd.  (The test's
+ * ->before callback is also welcome to use g_test_queue_destroy).
+ *
+ * Note: as specified in walk_path() too, @arg is an array of
+ * char *, where arg[0] is a pointer to the command line
+ * string that will be used to properly start QEMU when executing
+ * the test, and the remaining elements represent the actual objects
+ * that will be allocated.
+ */
+static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
+{
+    int current = 0;
+    QGuestAllocator *alloc;
+    QOSGraphObject *parent = NULL;
+    QOSGraphEdge *edge;
+    QOSGraphNode *node;
+    void *edge_arg;
+    void *obj;
+
+    node = qos_graph_get_node(path[current]);
+    g_assert(node->type == QNODE_MACHINE);
+
+    obj = qos_machine_new(node, qts);
+    qos_object_queue_destroy(obj);
+
+    alloc = get_machine_allocator(obj);
+    if (p_alloc) {
+        *p_alloc = alloc;
+    }
+
+    for (;;) {
+        if (node->type != QNODE_INTERFACE) {
+            qos_object_start_hw(obj);
+            parent = obj;
+        }
+
+        /* follow edge and get object for next node constructor */
+        current++;
+        edge = qos_graph_get_edge(path[current - 1], path[current]);
+        node = qos_graph_get_node(path[current]);
+
+        if (node->type == QNODE_TEST) {
+            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
+            return obj;
+        }
+
+        switch (qos_graph_edge_get_type(edge)) {
+        case QEDGE_PRODUCES:
+            obj = parent->get_driver(parent, path[current]);
+            break;
+
+        case QEDGE_CONSUMED_BY:
+            edge_arg = qos_graph_edge_get_arg(edge);
+            obj = qos_driver_new(node, obj, alloc, edge_arg);
+            qos_object_queue_destroy(obj);
+            break;
+
+        case QEDGE_CONTAINS:
+            obj = parent->get_device(parent, path[current]);
+            break;
+        }
+    }
+}
+
+/* The argument to run_one_test, which is the test function that is registered
+ * with GTest, is a vector of strings.  The first item is the initial command
+ * line (before it is modified by the test's "before" function), the remaining
+ * items are node names forming the path to the test node.
+ */
+static char **current_path;
+
+const char *qos_get_current_command_line(void)
+{
+    return current_path[0];
+}
+
+void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
+{
+    return allocate_objects(qts, current_path + 1, p_alloc);
+}
+
+/**
+ * run_one_test(): given an array of nodes @arg,
+ * walks the path invoking all constructors and
+ * passing the corresponding parameter in order to
+ * continue the objects allocation.
+ * Once the test is reached, its function is executed.
+ *
+ * Since the machine and QEDGE_CONSUMED_BY nodes allocate
+ * memory in the constructor, g_test_queue_destroy is used so
+ * that after execution they can be safely free'd.  The test's
+ * ->before callback is also welcome to use g_test_queue_destroy.
+ *
+ * Note: as specified in walk_path() too, @arg is an array of
+ * char *, where arg[0] is a pointer to the command line
+ * string that will be used to properly start QEMU when executing
+ * the test, and the remaining elements represent the actual objects
+ * that will be allocated.
+ *
+ * The order of execution is the following:
+ * 1) @before test function as defined in the given QOSGraphTestOptions
+ * 2) start QEMU
+ * 3) call all nodes constructor and get_driver/get_device depending on edge,
+ *    start the hardware (*_device_enable functions)
+ * 4) start test
+ */
+static void run_one_test(const void *arg)
+{
+    QOSGraphNode *test_node;
+    QGuestAllocator *alloc = NULL;
+    void *obj;
+    char **path = (char **) arg;
+    GString *cmd_line = g_string_new(path[0]);
+    void *test_arg;
+
+    /* Before test */
+    current_path = path;
+    test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]);
+    test_arg = test_node->u.test.arg;
+    if (test_node->u.test.before) {
+        test_arg = test_node->u.test.before(cmd_line, test_arg);
+    }
+
+    restart_qemu_or_continue(cmd_line->str);
+    g_string_free(cmd_line, TRUE);
+
+    obj = qos_allocate_objects(global_qtest, &alloc);
+    test_node->u.test.function(obj, test_arg, alloc);
+}
+
+static void subprocess_run_one_test(const void *arg)
+{
+    const gchar *path = arg;
+    g_test_trap_subprocess(path, 0, 0);
+    g_test_trap_assert_passed();
+}
+
+/*
+ * in this function, 2 path will be built:
+ * path_str, a one-string path (ex "pc/i440FX-pcihost/...")
+ * path_vec, a string-array path (ex [0] = "pc", [1] = "i440FX-pcihost").
+ *
+ * path_str will be only used to build the test name, and won't need the
+ * architecture name at beginning, since it will be added by qtest_add_func().
+ *
+ * path_vec is used to allocate all constructors of the path nodes.
+ * Each name in this array except position 0 must correspond to a valid
+ * QOSGraphNode name.
+ * Position 0 is special, initially contains just the <machine> name of
+ * the node, (ex for "x86_64/pc" it will be "pc"), used to build the test
+ * path (see below). After it will contain the command line used to start
+ * qemu with all required devices.
+ *
+ * Note that the machine node name must be with format <arch>/<machine>
+ * (ex "x86_64/pc"), because it will identify the node "x86_64/pc"
+ * and start QEMU with "-M pc". For this reason,
+ * when building path_str, path_vec
+ * initially contains the <machine> at position 0 ("pc"),
+ * and the node name at position 1 (<arch>/<machine>)
+ * ("x86_64/pc"), followed by the rest of the nodes.
+ */
+static void walk_path(QOSGraphNode *orig_path, int len)
+{
+    QOSGraphNode *path;
+    QOSGraphEdge *edge;
+
+    /* etype set to QEDGE_CONSUMED_BY so that machine can add to the command line */
+    QOSEdgeType etype = QEDGE_CONSUMED_BY;
+
+    /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */
+    char **path_vec = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2));
+    int path_vec_size = 0;
+
+    char *machine = NULL, *arch = NULL;
+    char *after_cmd = NULL, *before_cmd = NULL, *after_device = NULL;
+    char *node_name = orig_path->name, *path_str;
+
+    GString *cmd_line = g_string_new("");
+    GString *cmd_line2 = g_string_new("");
+
+    path = qos_graph_get_node(node_name); /* root */
+    node_name = qos_graph_edge_get_dest(path->path_edge); /* machine name */
+
+    qos_separate_arch_machine(node_name, &arch, &machine);
+    path_vec[path_vec_size++] = arch;
+    path_vec[path_vec_size++] = machine;
+
+    for (;;) {
+        path = qos_graph_get_node(node_name);
+        if (!path->path_edge) {
+            break;
+        }
+
+        node_name = qos_graph_edge_get_dest(path->path_edge);
+
+        /* append node command line + previous edge command line */
+        if (path->command_line && etype == QEDGE_CONSUMED_BY) {
+            g_string_append(cmd_line, path->command_line);
+            if (after_device) {
+                g_string_append(cmd_line, after_device);
+            }
+        }
+
+        path_vec[path_vec_size++] = qos_graph_edge_get_name(path->path_edge);
+        /* detect if edge has command line args */
+        after_cmd = qos_graph_edge_get_after_cmd_line(path->path_edge);
+        after_device = qos_graph_edge_get_extra_device_opts(path->path_edge);
+        before_cmd = qos_graph_edge_get_before_cmd_line(path->path_edge);
+        edge = qos_graph_get_edge(path->name, node_name);
+        etype = qos_graph_edge_get_type(edge);
+
+        if (before_cmd) {
+            g_string_append(cmd_line, before_cmd);
+        }
+        if (after_cmd) {
+            g_string_append(cmd_line2, after_cmd);
+        }
+    }
+
+    path_vec[path_vec_size++] = NULL;
+    if (after_device) {
+        g_string_append(cmd_line, after_device);
+    }
+    g_string_append(cmd_line, cmd_line2->str);
+    g_string_free(cmd_line2, TRUE);
+
+    /* here position 0 has <arch>/<machine>, position 1 has <machine>.
+     * The path must not have the <arch>
+     */
+    path_str = g_strjoinv("/", path_vec + 1);
+
+    /* put arch/machine in position 1 so run_one_test can do its work
+     * and add the command line at position 0.
+     */
+    path_vec[0] = g_string_free(cmd_line, FALSE);
+    path_vec[1] = arch;
+
+    if (path->u.test.subprocess) {
+        gchar *subprocess_path = g_strdup_printf("/%s/%s/subprocess",
+                                                 qtest_get_arch(), path_str);
+        qtest_add_data_func(path_str, subprocess_path, subprocess_run_one_test);
+        g_test_add_data_func(subprocess_path, path_vec, run_one_test);
+    } else {
+        qtest_add_data_func(path_str, path_vec, run_one_test);
+    }
+
+    g_free(path_str);
+}
+
+
+
+/**
+ * main(): heart of the qgraph framework.
+ *
+ * - Initializes the glib test framework
+ * - Creates the graph by invoking the various _init constructors
+ * - Starts QEMU to mark the available devices
+ * - Walks the graph, and each path is added to
+ *   the glib test framework (walk_path)
+ * - Runs the tests, calling allocate_object() and allocating the
+ *   machine/drivers/test objects
+ * - Cleans up everything
+ */
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    qos_graph_init();
+    module_call_init(MODULE_INIT_QOM);
+    module_call_init(MODULE_INIT_LIBQOS);
+    qos_set_machines_devices_available();
+
+    qos_graph_foreach_test_path(walk_path);
+    g_test_run();
+    qtest_end();
+    qos_graph_destroy();
+    g_free(old_path);
+    return 0;
+}
diff --git a/tests/test-qgraph.c b/tests/test-qgraph.c
new file mode 100644
index 0000000..f6a6565
--- /dev/null
+++ b/tests/test-qgraph.c
@@ -0,0 +1,434 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/qgraph_internal.h"
+
+#define MACHINE_PC "x86_64/pc"
+#define MACHINE_RASPI2 "arm/raspi2"
+#define I440FX "i440FX-pcihost"
+#define PCIBUS_PC "pcibus-pc"
+#define SDHCI "sdhci"
+#define PCIBUS "pci-bus"
+#define SDHCI_PCI "sdhci-pci"
+#define SDHCI_MM "generic-sdhci"
+#define REGISTER_TEST "register-test"
+
+int npath;
+
+static void *machinefunct(QTestState *qts)
+{
+    return NULL;
+}
+
+static void *driverfunct(void *obj, QGuestAllocator *machine, void *arg)
+{
+    return NULL;
+}
+
+static void testfunct(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    return;
+}
+
+static void check_interface(const char *interface)
+{
+    g_assert_cmpint(qos_graph_has_machine(interface), ==, FALSE);
+    g_assert_nonnull(qos_graph_get_node(interface));
+    g_assert_cmpint(qos_graph_has_node(interface), ==, TRUE);
+    g_assert_cmpint(qos_graph_get_node_type(interface), ==, QNODE_INTERFACE);
+    qos_graph_node_set_availability(interface, TRUE);
+    g_assert_cmpint(qos_graph_get_node_availability(interface), ==, TRUE);
+}
+
+static void check_machine(const char *machine)
+{
+    qos_node_create_machine(machine, machinefunct);
+    g_assert_nonnull(qos_graph_get_machine(machine));
+    g_assert_cmpint(qos_graph_has_machine(machine), ==, TRUE);
+    g_assert_nonnull(qos_graph_get_node(machine));
+    g_assert_cmpint(qos_graph_get_node_availability(machine), ==, FALSE);
+    qos_graph_node_set_availability(machine, TRUE);
+    g_assert_cmpint(qos_graph_get_node_availability(machine), ==, TRUE);
+    g_assert_cmpint(qos_graph_has_node(machine), ==, TRUE);
+    g_assert_cmpint(qos_graph_get_node_type(machine), ==, QNODE_MACHINE);
+}
+
+static void check_contains(const char *machine, const char *driver)
+{
+    QOSGraphEdge *edge;
+    qos_node_contains(machine, driver, NULL);
+
+    edge = qos_graph_get_edge(machine, driver);
+    g_assert_nonnull(edge);
+    g_assert_cmpint(qos_graph_edge_get_type(edge), ==, QEDGE_CONTAINS);
+    g_assert_cmpint(qos_graph_has_edge(machine, driver), ==, TRUE);
+}
+
+static void check_produces(const char *machine, const char *interface)
+{
+    QOSGraphEdge *edge;
+
+    qos_node_produces(machine, interface);
+    check_interface(interface);
+    edge = qos_graph_get_edge(machine, interface);
+    g_assert_nonnull(edge);
+    g_assert_cmpint(qos_graph_edge_get_type(edge), ==,
+                    QEDGE_PRODUCES);
+    g_assert_cmpint(qos_graph_has_edge(machine, interface), ==, TRUE);
+}
+
+static void check_consumes(const char *driver, const char *interface)
+{
+    QOSGraphEdge *edge;
+
+    qos_node_consumes(driver, interface, NULL);
+    check_interface(interface);
+    edge = qos_graph_get_edge(interface, driver);
+    g_assert_nonnull(edge);
+    g_assert_cmpint(qos_graph_edge_get_type(edge), ==, QEDGE_CONSUMED_BY);
+    g_assert_cmpint(qos_graph_has_edge(interface, driver), ==, TRUE);
+}
+
+static void check_driver(const char *driver)
+{
+    qos_node_create_driver(driver, driverfunct);
+    g_assert_cmpint(qos_graph_has_machine(driver), ==, FALSE);
+    g_assert_nonnull(qos_graph_get_node(driver));
+    g_assert_cmpint(qos_graph_has_node(driver), ==, TRUE);
+    g_assert_cmpint(qos_graph_get_node_type(driver), ==, QNODE_DRIVER);
+    g_assert_cmpint(qos_graph_get_node_availability(driver), ==, FALSE);
+    qos_graph_node_set_availability(driver, TRUE);
+    g_assert_cmpint(qos_graph_get_node_availability(driver), ==, TRUE);
+}
+
+static void check_test(const char *test, const char *interface)
+{
+    QOSGraphEdge *edge;
+    const char *full_name = g_strdup_printf("%s-tests/%s", interface, test);
+
+    qos_add_test(test, interface, testfunct, NULL);
+    g_assert_cmpint(qos_graph_has_machine(test), ==, FALSE);
+    g_assert_cmpint(qos_graph_has_machine(full_name), ==, FALSE);
+    g_assert_nonnull(qos_graph_get_node(full_name));
+    g_assert_cmpint(qos_graph_has_node(full_name), ==, TRUE);
+    g_assert_cmpint(qos_graph_get_node_type(full_name), ==, QNODE_TEST);
+    edge = qos_graph_get_edge(interface, full_name);
+    g_assert_nonnull(edge);
+    g_assert_cmpint(qos_graph_edge_get_type(edge), ==,
+                    QEDGE_CONSUMED_BY);
+    g_assert_cmpint(qos_graph_has_edge(interface, full_name), ==, TRUE);
+    g_assert_cmpint(qos_graph_get_node_availability(full_name), ==, TRUE);
+    qos_graph_node_set_availability(full_name, FALSE);
+    g_assert_cmpint(qos_graph_get_node_availability(full_name), ==, FALSE);
+}
+
+static void count_each_test(QOSGraphNode *path, int len)
+{
+    npath++;
+}
+
+static void check_leaf_discovered(int n)
+{
+    npath = 0;
+    qos_graph_foreach_test_path(count_each_test);
+    g_assert_cmpint(n, ==, npath);
+}
+
+/* G_Test functions */
+
+static void init_nop(void)
+{
+    qos_graph_init();
+    qos_graph_destroy();
+}
+
+static void test_machine(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_PC);
+    qos_graph_destroy();
+}
+
+static void test_contains(void)
+{
+    qos_graph_init();
+    check_contains(MACHINE_PC, I440FX);
+    g_assert_null(qos_graph_get_machine(MACHINE_PC));
+    g_assert_null(qos_graph_get_machine(I440FX));
+    g_assert_null(qos_graph_get_node(MACHINE_PC));
+    g_assert_null(qos_graph_get_node(I440FX));
+    qos_graph_destroy();
+}
+
+static void test_multiple_contains(void)
+{
+    qos_graph_init();
+    check_contains(MACHINE_PC, I440FX);
+    check_contains(MACHINE_PC, PCIBUS_PC);
+    qos_graph_destroy();
+}
+
+static void test_produces(void)
+{
+    qos_graph_init();
+    check_produces(MACHINE_PC, I440FX);
+    g_assert_null(qos_graph_get_machine(MACHINE_PC));
+    g_assert_null(qos_graph_get_machine(I440FX));
+    g_assert_null(qos_graph_get_node(MACHINE_PC));
+    g_assert_nonnull(qos_graph_get_node(I440FX));
+    qos_graph_destroy();
+}
+
+static void test_multiple_produces(void)
+{
+    qos_graph_init();
+    check_produces(MACHINE_PC, I440FX);
+    check_produces(MACHINE_PC, PCIBUS_PC);
+    qos_graph_destroy();
+}
+
+static void test_consumes(void)
+{
+    qos_graph_init();
+    check_consumes(I440FX, SDHCI);
+    g_assert_null(qos_graph_get_machine(I440FX));
+    g_assert_null(qos_graph_get_machine(SDHCI));
+    g_assert_null(qos_graph_get_node(I440FX));
+    g_assert_nonnull(qos_graph_get_node(SDHCI));
+    qos_graph_destroy();
+}
+
+static void test_multiple_consumes(void)
+{
+    qos_graph_init();
+    check_consumes(I440FX, SDHCI);
+    check_consumes(PCIBUS_PC, SDHCI);
+    qos_graph_destroy();
+}
+
+static void test_driver(void)
+{
+    qos_graph_init();
+    check_driver(I440FX);
+    qos_graph_destroy();
+}
+
+static void test_test(void)
+{
+    qos_graph_init();
+    check_test(REGISTER_TEST, SDHCI);
+    qos_graph_destroy();
+}
+
+static void test_machine_contains_driver(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_PC);
+    check_driver(I440FX);
+    check_contains(MACHINE_PC, I440FX);
+    qos_graph_destroy();
+}
+
+static void test_driver_contains_driver(void)
+{
+    qos_graph_init();
+    check_driver(PCIBUS_PC);
+    check_driver(I440FX);
+    check_contains(PCIBUS_PC, I440FX);
+    qos_graph_destroy();
+}
+
+static void test_machine_produces_interface(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_PC);
+    check_produces(MACHINE_PC, SDHCI);
+    qos_graph_destroy();
+}
+
+static void test_driver_produces_interface(void)
+{
+    qos_graph_init();
+    check_driver(I440FX);
+    check_produces(I440FX, SDHCI);
+    qos_graph_destroy();
+}
+
+static void test_machine_consumes_interface(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_PC);
+    check_consumes(MACHINE_PC, SDHCI);
+    qos_graph_destroy();
+}
+
+static void test_driver_consumes_interface(void)
+{
+    qos_graph_init();
+    check_driver(I440FX);
+    check_consumes(I440FX, SDHCI);
+    qos_graph_destroy();
+}
+
+static void test_test_consumes_interface(void)
+{
+    qos_graph_init();
+    check_test(REGISTER_TEST, SDHCI);
+    qos_graph_destroy();
+}
+
+static void test_full_sample(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_PC);
+    check_contains(MACHINE_PC, I440FX);
+    check_driver(I440FX);
+    check_driver(PCIBUS_PC);
+    check_contains(I440FX, PCIBUS_PC);
+    check_produces(PCIBUS_PC, PCIBUS);
+    check_driver(SDHCI_PCI);
+    qos_node_consumes(SDHCI_PCI, PCIBUS, NULL);
+    check_produces(SDHCI_PCI, SDHCI);
+    check_driver(SDHCI_MM);
+    check_produces(SDHCI_MM, SDHCI);
+    qos_add_test(REGISTER_TEST, SDHCI, testfunct, NULL);
+    check_leaf_discovered(1);
+    qos_print_graph();
+    qos_graph_destroy();
+}
+
+static void test_full_sample_raspi(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_PC);
+    check_contains(MACHINE_PC, I440FX);
+    check_driver(I440FX);
+    check_driver(PCIBUS_PC);
+    check_contains(I440FX, PCIBUS_PC);
+    check_produces(PCIBUS_PC, PCIBUS);
+    check_driver(SDHCI_PCI);
+    qos_node_consumes(SDHCI_PCI, PCIBUS, NULL);
+    check_produces(SDHCI_PCI, SDHCI);
+    check_machine(MACHINE_RASPI2);
+    check_contains(MACHINE_RASPI2, SDHCI_MM);
+    check_driver(SDHCI_MM);
+    check_produces(SDHCI_MM, SDHCI);
+    qos_add_test(REGISTER_TEST, SDHCI, testfunct, NULL);
+    qos_print_graph();
+    check_leaf_discovered(2);
+    qos_graph_destroy();
+}
+
+static void test_cycle(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_RASPI2);
+    check_driver("B");
+    check_driver("C");
+    check_driver("D");
+    check_contains(MACHINE_RASPI2, "B");
+    check_contains("B", "C");
+    check_contains("C", "D");
+    check_contains("D", MACHINE_RASPI2);
+    check_leaf_discovered(0);
+    qos_print_graph();
+    qos_graph_destroy();
+}
+
+static void test_two_test_same_interface(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_RASPI2);
+    check_produces(MACHINE_RASPI2, "B");
+    qos_add_test("C", "B", testfunct, NULL);
+    qos_add_test("D", "B", testfunct, NULL);
+    check_contains(MACHINE_RASPI2, "B");
+    check_leaf_discovered(4);
+    qos_print_graph();
+    qos_graph_destroy();
+}
+
+static void test_test_in_path(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_RASPI2);
+    check_produces(MACHINE_RASPI2, "B");
+    qos_add_test("C", "B", testfunct, NULL);
+    check_driver("D");
+    check_consumes("D", "B");
+    check_produces("D", "E");
+    qos_add_test("F", "E", testfunct, NULL);
+    check_leaf_discovered(2);
+    qos_print_graph();
+    qos_graph_destroy();
+}
+
+static void test_double_edge(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_RASPI2);
+    check_produces("B", "C");
+    qos_node_consumes("C", "B", NULL);
+    qos_add_test("D", "C", testfunct, NULL);
+    check_contains(MACHINE_RASPI2, "B");
+    qos_print_graph();
+    qos_graph_destroy();
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    g_test_add_func("/qgraph/init_nop", init_nop);
+    g_test_add_func("/qgraph/test_machine", test_machine);
+    g_test_add_func("/qgraph/test_contains", test_contains);
+    g_test_add_func("/qgraph/test_multiple_contains", test_multiple_contains);
+    g_test_add_func("/qgraph/test_produces", test_produces);
+    g_test_add_func("/qgraph/test_multiple_produces", test_multiple_produces);
+    g_test_add_func("/qgraph/test_consumes", test_consumes);
+    g_test_add_func("/qgraph/test_multiple_consumes",
+                    test_multiple_consumes);
+    g_test_add_func("/qgraph/test_driver", test_driver);
+    g_test_add_func("/qgraph/test_test", test_test);
+    g_test_add_func("/qgraph/test_machine_contains_driver",
+                    test_machine_contains_driver);
+    g_test_add_func("/qgraph/test_driver_contains_driver",
+                    test_driver_contains_driver);
+    g_test_add_func("/qgraph/test_machine_produces_interface",
+                    test_machine_produces_interface);
+    g_test_add_func("/qgraph/test_driver_produces_interface",
+                    test_driver_produces_interface);
+    g_test_add_func("/qgraph/test_machine_consumes_interface",
+                    test_machine_consumes_interface);
+    g_test_add_func("/qgraph/test_driver_consumes_interface",
+                    test_driver_consumes_interface);
+    g_test_add_func("/qgraph/test_test_consumes_interface",
+                    test_test_consumes_interface);
+    g_test_add_func("/qgraph/test_full_sample", test_full_sample);
+    g_test_add_func("/qgraph/test_full_sample_raspi", test_full_sample_raspi);
+    g_test_add_func("/qgraph/test_cycle", test_cycle);
+    g_test_add_func("/qgraph/test_two_test_same_interface",
+                    test_two_test_same_interface);
+    g_test_add_func("/qgraph/test_test_in_path", test_test_in_path);
+    g_test_add_func("/qgraph/test_double_edge", test_double_edge);
+
+    g_test_run();
+    return 0;
+}
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 20/71] tests/libqos: pci-pc driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (18 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 21/71] tests/libqos: x86_64/pc machine node Paolo Bonzini
                   ` (53 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add pci-bus-pc node, move QPCIBusPC struct declaration in its header
(since it will be needed by other drivers) and introduce a setter method
for drivers that do not need to allocate but have to initialize QPCIBusPC.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  6 +++-
 tests/libqos/pci-pc.c  | 83 ++++++++++++++++++++++++++++++++------------------
 tests/libqos/pci-pc.h  | 17 +++++++++--
 tests/libqos/pci.c     | 32 +++++++++++++++++--
 tests/libqos/pci.h     | 12 ++++++++
 5 files changed, 115 insertions(+), 35 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 905841e..93f31e8 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -675,11 +675,15 @@ libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
 libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o
 
+# Devices
+qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
+qos-test-obj-y += $(libqos-pc-obj-y)
+
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
 
 check-qtest-generic-y += tests/qos-test$(EXESUF)
-tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-obj-y)
+tests/qos-test$(EXESUF): $(qos-test-obj-y)
 
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/qmp-cmd-test$(EXESUF): tests/qmp-cmd-test.o
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index d21f3e8..041bfed 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -18,15 +18,9 @@
 
 #include "qemu-common.h"
 
-
 #define ACPI_PCIHP_ADDR         0xae00
 #define PCI_EJ_BASE             0x0008
 
-typedef struct QPCIBusPC
-{
-    QPCIBus bus;
-} QPCIBusPC;
-
 static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr)
 {
     return inb(addr);
@@ -115,44 +109,65 @@ static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint3
     outl(0xcfc, value);
 }
 
-QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc)
+static void *qpci_pc_get_driver(void *obj, const char *interface)
 {
-    QPCIBusPC *ret = g_new0(QPCIBusPC, 1);
+    QPCIBusPC *qpci = obj;
+    if (!g_strcmp0(interface, "pci-bus")) {
+        return &qpci->bus;
+    }
+    fprintf(stderr, "%s not present in pci-bus-pc\n", interface);
+    g_assert_not_reached();
+}
 
+void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc)
+{
     assert(qts);
 
-    ret->bus.pio_readb = qpci_pc_pio_readb;
-    ret->bus.pio_readw = qpci_pc_pio_readw;
-    ret->bus.pio_readl = qpci_pc_pio_readl;
-    ret->bus.pio_readq = qpci_pc_pio_readq;
+    qpci->bus.pio_readb = qpci_pc_pio_readb;
+    qpci->bus.pio_readw = qpci_pc_pio_readw;
+    qpci->bus.pio_readl = qpci_pc_pio_readl;
+    qpci->bus.pio_readq = qpci_pc_pio_readq;
+
+    qpci->bus.pio_writeb = qpci_pc_pio_writeb;
+    qpci->bus.pio_writew = qpci_pc_pio_writew;
+    qpci->bus.pio_writel = qpci_pc_pio_writel;
+    qpci->bus.pio_writeq = qpci_pc_pio_writeq;
+
+    qpci->bus.memread = qpci_pc_memread;
+    qpci->bus.memwrite = qpci_pc_memwrite;
 
-    ret->bus.pio_writeb = qpci_pc_pio_writeb;
-    ret->bus.pio_writew = qpci_pc_pio_writew;
-    ret->bus.pio_writel = qpci_pc_pio_writel;
-    ret->bus.pio_writeq = qpci_pc_pio_writeq;
+    qpci->bus.config_readb = qpci_pc_config_readb;
+    qpci->bus.config_readw = qpci_pc_config_readw;
+    qpci->bus.config_readl = qpci_pc_config_readl;
 
-    ret->bus.memread = qpci_pc_memread;
-    ret->bus.memwrite = qpci_pc_memwrite;
+    qpci->bus.config_writeb = qpci_pc_config_writeb;
+    qpci->bus.config_writew = qpci_pc_config_writew;
+    qpci->bus.config_writel = qpci_pc_config_writel;
 
-    ret->bus.config_readb = qpci_pc_config_readb;
-    ret->bus.config_readw = qpci_pc_config_readw;
-    ret->bus.config_readl = qpci_pc_config_readl;
+    qpci->bus.qts = qts;
+    qpci->bus.pio_alloc_ptr = 0xc000;
+    qpci->bus.mmio_alloc_ptr = 0xE0000000;
+    qpci->bus.mmio_limit = 0x100000000ULL;
 
-    ret->bus.config_writeb = qpci_pc_config_writeb;
-    ret->bus.config_writew = qpci_pc_config_writew;
-    ret->bus.config_writel = qpci_pc_config_writel;
+    qpci->obj.get_driver = qpci_pc_get_driver;
+}
 
-    ret->bus.qts = qts;
-    ret->bus.pio_alloc_ptr = 0xc000;
-    ret->bus.mmio_alloc_ptr = 0xE0000000;
-    ret->bus.mmio_limit = 0x100000000ULL;
+QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc)
+{
+    QPCIBusPC *qpci = g_new0(QPCIBusPC, 1);
+    qpci_init_pc(qpci, qts, alloc);
 
-    return &ret->bus;
+    return &qpci->bus;
 }
 
 void qpci_free_pc(QPCIBus *bus)
 {
-    QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
+    QPCIBusPC *s;
+
+    if (!bus) {
+        return;
+    }
+    s = container_of(bus, QPCIBusPC, bus);
 
     g_free(s);
 }
@@ -171,3 +186,11 @@ void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
 
     qmp_eventwait("DEVICE_DELETED");
 }
+
+static void qpci_pc_register_nodes(void)
+{
+    qos_node_create_driver("pci-bus-pc", NULL);
+    qos_node_produces("pci-bus-pc", "pci-bus");
+}
+
+libqos_init(qpci_pc_register_nodes);
diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
index 84cc300..7b0751d 100644
--- a/tests/libqos/pci-pc.h
+++ b/tests/libqos/pci-pc.h
@@ -15,9 +15,22 @@
 
 #include "libqos/pci.h"
 #include "libqos/malloc.h"
+#include "libqos/qgraph.h"
 
-/* qpci_new_pc():
-* this function creates a new QPCIBusPC object,
+typedef struct QPCIBusPC {
+    QOSGraphObject obj;
+    QPCIBus bus;
+} QPCIBusPC;
+
+/* qpci_init_pc():
+ * this function initialize an already allocated
+ * QPCIBusPC object.
+ *
+ * @ret must be a valid QPCIBusPC * pointer.
+ */
+void qpci_init_pc(QPCIBusPC *ret, QTestState *qts, QGuestAllocator *alloc);
+/* qpci_pc_new():
+ * this function creates a new QPCIBusPC object,
  * and properly initialize its fields.
  *
  * returns the QPCIBus *bus field of a newly
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index e8c342c..8257904 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -15,6 +15,7 @@
 
 #include "hw/pci/pci_regs.h"
 #include "qemu/host-utils.h"
+#include "libqos/qgraph.h"
 
 void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
                          void (*func)(QPCIDevice *dev, int devfn, void *data),
@@ -50,13 +51,20 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
     }
 }
 
+static void qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
+{
+    g_assert(dev);
+
+    dev->bus = bus;
+    dev->devfn = devfn;
+}
+
 QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
 {
     QPCIDevice *dev;
 
     dev = g_malloc0(sizeof(*dev));
-    dev->bus = bus;
-    dev->devfn = devfn;
+    qpci_device_set(dev, bus, devfn);
 
     if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
         g_free(dev);
@@ -66,6 +74,17 @@ QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
     return dev;
 }
 
+void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr)
+{
+    uint16_t vendor_id, device_id;
+
+    qpci_device_set(dev, bus, addr->devfn);
+    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
+    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
+    g_assert(!addr->vendor_id || vendor_id == addr->vendor_id);
+    g_assert(!addr->device_id || device_id == addr->device_id);
+}
+
 void qpci_device_enable(QPCIDevice *dev)
 {
     uint16_t cmd;
@@ -395,3 +414,12 @@ QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
     QPCIBar bar = { .addr = addr };
     return bar;
 }
+
+void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr)
+{
+    g_assert(addr);
+    g_assert(opts);
+
+    opts->arg = addr;
+    opts->size_arg = sizeof(QPCIAddress);
+}
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
index 0b7e936..9fd521a 100644
--- a/tests/libqos/pci.h
+++ b/tests/libqos/pci.h
@@ -14,6 +14,7 @@
 #define LIBQOS_PCI_H
 
 #include "libqtest.h"
+#include "libqos/qgraph.h"
 
 #define QPCI_PIO_LIMIT    0x10000
 
@@ -22,6 +23,7 @@
 typedef struct QPCIDevice QPCIDevice;
 typedef struct QPCIBus QPCIBus;
 typedef struct QPCIBar QPCIBar;
+typedef struct QPCIAddress QPCIAddress;
 
 struct QPCIBus {
     uint8_t (*pio_readb)(QPCIBus *bus, uint32_t addr);
@@ -51,6 +53,7 @@ struct QPCIBus {
     QTestState *qts;
     uint16_t pio_alloc_ptr;
     uint64_t mmio_alloc_ptr, mmio_limit;
+
 };
 
 struct QPCIBar {
@@ -66,10 +69,17 @@ struct QPCIDevice
     uint64_t msix_table_off, msix_pba_off;
 };
 
+struct QPCIAddress {
+    uint32_t devfn;
+    uint16_t vendor_id;
+    uint16_t device_id;
+};
+
 void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
                          void (*func)(QPCIDevice *dev, int devfn, void *data),
                          void *data);
 QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn);
+void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr);
 
 void qpci_device_enable(QPCIDevice *dev);
 uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id);
@@ -110,4 +120,6 @@ void qpci_iounmap(QPCIDevice *dev, QPCIBar addr);
 QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr);
 
 void qpci_unplug_acpi_device_test(const char *id, uint8_t slot);
+
+void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr);
 #endif
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 21/71] tests/libqos: x86_64/pc machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (19 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 20/71] tests/libqos: pci-pc driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 22/71] tests/libqos: sdhci driver and interface nodes Paolo Bonzini
                   ` (52 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add pc machine for the x86_64 QEMU binary. This machine contains an i440FX-pcihost
driver, that contains itself a pci-bus-pc that produces the pci-bus interface.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include           |   3 ++
 tests/libqos/x86_64_pc-machine.c | 110 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100644 tests/libqos/x86_64_pc-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 93f31e8..1266109 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -679,6 +679,9 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
 qos-test-obj-y += $(libqos-pc-obj-y)
 
+# Machines
+qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
+
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
 
diff --git a/tests/libqos/x86_64_pc-machine.c b/tests/libqos/x86_64_pc-machine.c
new file mode 100644
index 0000000..5834c01
--- /dev/null
+++ b/tests/libqos/x86_64_pc-machine.c
@@ -0,0 +1,110 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "pci-pc.h"
+#include "malloc-pc.h"
+
+typedef struct QX86_64_PCMachine QX86_64_PCMachine;
+typedef struct i440FX_pcihost i440FX_pcihost;
+typedef struct QSDHCI_PCI  QSDHCI_PCI;
+
+struct i440FX_pcihost {
+    QOSGraphObject obj;
+    QPCIBusPC pci;
+};
+
+struct QX86_64_PCMachine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    i440FX_pcihost bridge;
+};
+
+/* i440FX_pcihost */
+
+static QOSGraphObject *i440FX_host_get_device(void *obj, const char *device)
+{
+    i440FX_pcihost *host = obj;
+    if (!g_strcmp0(device, "pci-bus-pc")) {
+        return &host->pci.obj;
+    }
+    fprintf(stderr, "%s not present in i440FX-pcihost\n", device);
+    g_assert_not_reached();
+}
+
+static void qos_create_i440FX_host(i440FX_pcihost *host,
+				   QTestState *qts,
+                                   QGuestAllocator *alloc)
+{
+    host->obj.get_device = i440FX_host_get_device;
+    qpci_init_pc(&host->pci, qts, alloc);
+}
+
+/* x86_64/pc machine */
+
+static void pc_destructor(QOSGraphObject *obj)
+{
+    QX86_64_PCMachine *machine = (QX86_64_PCMachine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *pc_get_driver(void *object, const char *interface)
+{
+    QX86_64_PCMachine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in x86_64/pc\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *pc_get_device(void *obj, const char *device)
+{
+    QX86_64_PCMachine *machine = obj;
+    if (!g_strcmp0(device, "i440FX-pcihost")) {
+        return &machine->bridge.obj;
+    }
+
+    fprintf(stderr, "%s not present in x86_64/pc\n", device);
+    g_assert_not_reached();
+}
+
+static void *qos_create_machine_pc(QTestState *qts)
+{
+    QX86_64_PCMachine *machine = g_new0(QX86_64_PCMachine, 1);
+    machine->obj.get_device = pc_get_device;
+    machine->obj.get_driver = pc_get_driver;
+    machine->obj.destructor = pc_destructor;
+    pc_alloc_init(&machine->alloc, qts, ALLOC_NO_FLAGS);
+    qos_create_i440FX_host(&machine->bridge, qts, &machine->alloc);
+
+    return &machine->obj;
+}
+
+static void pc_machine_register_nodes(void)
+{
+    qos_node_create_machine("x86_64/pc", qos_create_machine_pc);
+    qos_node_create_driver("i440FX-pcihost", NULL);
+    qos_node_contains("x86_64/pc", "i440FX-pcihost", NULL);
+    qos_node_contains("i440FX-pcihost", "pci-bus-pc", NULL);
+}
+
+libqos_init(pc_machine_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 22/71] tests/libqos: sdhci driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (20 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 21/71] tests/libqos: x86_64/pc machine node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-12 14:35   ` Philippe Mathieu-Daudé
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 23/71] tests/libqos: arm/raspi2 machine node Paolo Bonzini
                   ` (51 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for sdhci-pci and generic-sdhci (memory mapped) drivers.
Both drivers implement (produce) the same interface sdhci, that provides the
readw - readq - writeq functions.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |   1 +
 tests/libqos/sdhci.c   | 163 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/sdhci.h   |  70 +++++++++++++++++++++
 3 files changed, 234 insertions(+)
 create mode 100644 tests/libqos/sdhci.c
 create mode 100644 tests/libqos/sdhci.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 1266109..66c7848 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -678,6 +678,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 # Devices
 qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
 qos-test-obj-y += $(libqos-pc-obj-y)
+qos-test-obj-y += tests/libqos/sdhci.o
 
 # Machines
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
diff --git a/tests/libqos/sdhci.c b/tests/libqos/sdhci.c
new file mode 100644
index 0000000..0685bee
--- /dev/null
+++ b/tests/libqos/sdhci.c
@@ -0,0 +1,163 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "pci.h"
+#include "sdhci.h"
+#include "hw/pci/pci.h"
+
+static void set_qsdhci_fields(QSDHCI *s, uint8_t version, uint8_t baseclock,
+                              bool sdma, uint64_t reg)
+{
+    s->props.version = version;
+    s->props.baseclock = baseclock;
+    s->props.capab.sdma = sdma;
+    s->props.capab.reg = reg;
+}
+
+/* Memory mapped implementation of QSDHCI */
+
+static uint16_t sdhci_mm_readw(QSDHCI *s, uint32_t reg)
+{
+    QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
+    return qtest_readw(smm->qts, smm->addr + reg);
+}
+
+static uint64_t sdhci_mm_readq(QSDHCI *s, uint32_t reg)
+{
+    QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
+    return qtest_readq(smm->qts, smm->addr + reg);
+}
+
+static void sdhci_mm_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
+{
+    QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
+    qtest_writeq(smm->qts, smm->addr + reg, val);
+}
+
+static void *sdhci_mm_get_driver(void *obj, const char *interface)
+{
+    QSDHCI_MemoryMapped *smm = obj;
+    if (!g_strcmp0(interface, "sdhci")) {
+        return &smm->sdhci;
+    }
+    fprintf(stderr, "%s not present in generic-sdhci\n", interface);
+    g_assert_not_reached();
+}
+
+void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts,
+		       uint32_t addr, QSDHCIProperties *common)
+{
+    sdhci->obj.get_driver = sdhci_mm_get_driver;
+    sdhci->sdhci.readw = sdhci_mm_readw;
+    sdhci->sdhci.readq = sdhci_mm_readq;
+    sdhci->sdhci.writeq = sdhci_mm_writeq;
+    memcpy(&sdhci->sdhci.props, common, sizeof(QSDHCIProperties));
+    sdhci->addr = addr;
+    sdhci->qts = qts;
+}
+
+/* PCI implementation of QSDHCI */
+
+static uint16_t sdhci_pci_readw(QSDHCI *s, uint32_t reg)
+{
+    QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
+    return qpci_io_readw(&spci->dev, spci->mem_bar, reg);
+}
+
+static uint64_t sdhci_pci_readq(QSDHCI *s, uint32_t reg)
+{
+    QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
+    return qpci_io_readq(&spci->dev, spci->mem_bar, reg);
+}
+
+static void sdhci_pci_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
+{
+    QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
+    return qpci_io_writeq(&spci->dev, spci->mem_bar, reg, val);
+}
+
+static void *sdhci_pci_get_driver(void *object, const char *interface)
+{
+    QSDHCI_PCI *spci = object;
+    if (!g_strcmp0(interface, "sdhci")) {
+        return &spci->sdhci;
+    }
+
+    fprintf(stderr, "%s not present in sdhci-pci\n", interface);
+    g_assert_not_reached();
+}
+
+static void sdhci_pci_start_hw(QOSGraphObject *obj)
+{
+    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
+    qpci_device_enable(&spci->dev);
+}
+
+static void sdhci_destructor(QOSGraphObject *obj)
+{
+    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
+    qpci_iounmap(&spci->dev, spci->mem_bar);
+}
+
+static void *sdhci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QSDHCI_PCI *spci = g_new0(QSDHCI_PCI, 1);
+    QPCIBus *bus = pci_bus;
+    uint64_t barsize;
+
+    qpci_device_init(&spci->dev, bus, addr);
+    spci->mem_bar = qpci_iomap(&spci->dev, 0, &barsize);
+    spci->sdhci.readw = sdhci_pci_readw;
+    spci->sdhci.readq = sdhci_pci_readq;
+    spci->sdhci.writeq = sdhci_pci_writeq;
+    set_qsdhci_fields(&spci->sdhci, 2, 0, 1, 0x057834b4);
+
+    spci->obj.get_driver = sdhci_pci_get_driver;
+    spci->obj.start_hw = sdhci_pci_start_hw;
+    spci->obj.destructor = sdhci_destructor;
+    return &spci->obj;
+}
+
+static void qsdhci_register_nodes(void)
+{
+    QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(4, 0),
+        .vendor_id = PCI_VENDOR_ID_REDHAT,
+        .device_id = PCI_DEVICE_ID_REDHAT_SDHCI,
+    };
+
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+
+    /* generic-sdhci */
+    qos_node_create_driver("generic-sdhci", NULL);
+    qos_node_produces("generic-sdhci", "sdhci");
+
+    /* sdhci-pci */
+    add_qpci_address(&opts, &addr);
+    qos_node_create_driver("sdhci-pci", sdhci_pci_create);
+    qos_node_produces("sdhci-pci", "sdhci");
+    qos_node_consumes("sdhci-pci", "pci-bus", &opts);
+
+}
+
+libqos_init(qsdhci_register_nodes);
diff --git a/tests/libqos/sdhci.h b/tests/libqos/sdhci.h
new file mode 100644
index 0000000..e9880fc
--- /dev/null
+++ b/tests/libqos/sdhci.h
@@ -0,0 +1,70 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef QGRAPH_QSDHCI
+#define QGRAPH_QSDHCI
+
+#include "libqos/qgraph.h"
+#include "pci.h"
+
+typedef struct QSDHCI QSDHCI;
+typedef struct QSDHCI_MemoryMapped QSDHCI_MemoryMapped;
+typedef struct QSDHCI_PCI  QSDHCI_PCI;
+typedef struct QSDHCIProperties QSDHCIProperties;
+
+/* Properties common to all QSDHCI devices */
+struct QSDHCIProperties {
+    uint8_t version;
+    uint8_t baseclock;
+    struct {
+        bool sdma;
+        uint64_t reg;
+    } capab;
+};
+
+struct QSDHCI {
+    uint16_t (*readw)(QSDHCI *s, uint32_t reg);
+    uint64_t (*readq)(QSDHCI *s, uint32_t reg);
+    void (*writeq)(QSDHCI *s, uint32_t reg, uint64_t val);
+    QSDHCIProperties props;
+};
+
+/* Memory Mapped implementation of QSDHCI */
+struct QSDHCI_MemoryMapped {
+    QOSGraphObject obj;
+    QTestState *qts;
+    QSDHCI sdhci;
+    uint64_t addr;
+};
+
+/* PCI implementation of QSDHCI */
+struct QSDHCI_PCI {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+    QSDHCI sdhci;
+    QPCIBar mem_bar;
+};
+
+/**
+ * qos_init_sdhci_mm(): external constructor used by all drivers/machines
+ * that "contain" a #QSDHCI_MemoryMapped driver
+ */
+void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts,
+		       uint32_t addr, QSDHCIProperties *common);
+
+#endif
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 23/71] tests/libqos: arm/raspi2 machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (21 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 22/71] tests/libqos: sdhci driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-12 15:26   ` Philippe Mathieu-Daudé
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 24/71] tests/libqos: arm/smdkc210 " Paolo Bonzini
                   ` (50 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add arm/raspi2 machine to the graph. This machine contains a generic-sdhci, so
its constructor must take care of setting it properly when called.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include            |  1 +
 tests/libqos/arm-raspi2-machine.c | 91 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+)
 create mode 100644 tests/libqos/arm-raspi2-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 66c7848..75951f8 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -681,6 +681,7 @@ qos-test-obj-y += $(libqos-pc-obj-y)
 qos-test-obj-y += tests/libqos/sdhci.o
 
 # Machines
+qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
diff --git a/tests/libqos/arm-raspi2-machine.c b/tests/libqos/arm-raspi2-machine.c
new file mode 100644
index 0000000..3aff670
--- /dev/null
+++ b/tests/libqos/arm-raspi2-machine.c
@@ -0,0 +1,91 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "sdhci.h"
+
+#define ARM_PAGE_SIZE             4096
+#define RASPI2_RAM_ADDR           0
+#define RASPI2_RAM_SIZE           0x20000000
+
+typedef struct QRaspi2Machine QRaspi2Machine;
+
+struct QRaspi2Machine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    QSDHCI_MemoryMapped sdhci;
+};
+
+static void *raspi2_get_driver(void *object, const char *interface)
+{
+    QRaspi2Machine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in arm/raspi2\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *raspi2_get_device(void *obj, const char *device)
+{
+    QRaspi2Machine *machine = obj;
+    if (!g_strcmp0(device, "generic-sdhci")) {
+        return &machine->sdhci.obj;
+    }
+
+    fprintf(stderr, "%s not present in arm/raspi2\n", device);
+    g_assert_not_reached();
+}
+
+static void raspi2_destructor(QOSGraphObject *obj)
+{
+    QRaspi2Machine *machine = (QRaspi2Machine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *qos_create_machine_arm_raspi2(QTestState *qts)
+{
+    QRaspi2Machine *machine = g_new0(QRaspi2Machine, 1);
+
+    alloc_init(&machine->alloc, 0,
+               RASPI2_RAM_ADDR + (1 << 20),
+               RASPI2_RAM_ADDR + RASPI2_RAM_SIZE,
+               ARM_PAGE_SIZE);
+    machine->obj.get_device = raspi2_get_device;
+    machine->obj.get_driver = raspi2_get_driver;
+    machine->obj.destructor = raspi2_destructor;
+    qos_init_sdhci_mm(&machine->sdhci, qts, 0x3f300000, &(QSDHCIProperties) {
+        .version = 3,
+        .baseclock = 52,
+        .capab.sdma = false,
+        .capab.reg = 0x052134b4
+    });
+    return &machine->obj;
+}
+
+static void raspi2_register_nodes(void)
+{
+    qos_node_create_machine("arm/raspi2", qos_create_machine_arm_raspi2);
+    qos_node_contains("arm/raspi2", "generic-sdhci", NULL);
+}
+
+libqos_init(raspi2_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 24/71] tests/libqos: arm/smdkc210 machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (22 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 23/71] tests/libqos: arm/raspi2 machine node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 25/71] tests/libqos: arm/sabrelite " Paolo Bonzini
                   ` (49 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add arm/smdkc210 machine machine to the graph. This machine contains generic-sdhci, so
its constructor must take care of setting it properly when called.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include              |  1 +
 tests/libqos/arm-smdkc210-machine.c | 91 +++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+)
 create mode 100644 tests/libqos/arm-smdkc210-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 75951f8..bda5ce7 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -682,6 +682,7 @@ qos-test-obj-y += tests/libqos/sdhci.o
 
 # Machines
 qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
+qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
diff --git a/tests/libqos/arm-smdkc210-machine.c b/tests/libqos/arm-smdkc210-machine.c
new file mode 100644
index 0000000..1fb9dfc
--- /dev/null
+++ b/tests/libqos/arm-smdkc210-machine.c
@@ -0,0 +1,91 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "sdhci.h"
+
+#define ARM_PAGE_SIZE             4096
+#define SMDKC210_RAM_ADDR         0x40000000ull
+#define SMDKC210_RAM_SIZE         0x40000000ull
+
+typedef struct QSmdkc210Machine QSmdkc210Machine;
+
+struct QSmdkc210Machine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    QSDHCI_MemoryMapped sdhci;
+};
+
+static void *smdkc210_get_driver(void *object, const char *interface)
+{
+    QSmdkc210Machine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in arm/smdkc210\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *smdkc210_get_device(void *obj, const char *device)
+{
+    QSmdkc210Machine *machine = obj;
+    if (!g_strcmp0(device, "generic-sdhci")) {
+        return &machine->sdhci.obj;
+    }
+
+    fprintf(stderr, "%s not present in arm/smdkc210\n", device);
+    g_assert_not_reached();
+}
+
+static void smdkc210_destructor(QOSGraphObject *obj)
+{
+    QSmdkc210Machine *machine = (QSmdkc210Machine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *qos_create_machine_arm_smdkc210(QTestState *qts)
+{
+    QSmdkc210Machine *machine = g_new0(QSmdkc210Machine, 1);
+
+    alloc_init(&machine->alloc, 0,
+               SMDKC210_RAM_ADDR,
+               SMDKC210_RAM_ADDR + SMDKC210_RAM_SIZE,
+               ARM_PAGE_SIZE);
+    machine->obj.get_device = smdkc210_get_device;
+    machine->obj.get_driver = smdkc210_get_driver;
+    machine->obj.destructor = smdkc210_destructor;
+    qos_init_sdhci_mm(&machine->sdhci, qts, 0x12510000, &(QSDHCIProperties) {
+        .version = 2,
+        .baseclock = 0,
+        .capab.sdma = true,
+        .capab.reg = 0x5e80080,
+    });
+    return &machine->obj;
+}
+
+static void smdkc210_register_nodes(void)
+{
+    qos_node_create_machine("arm/smdkc210", qos_create_machine_arm_smdkc210);
+    qos_node_contains("arm/smdkc210", "generic-sdhci", NULL);
+}
+
+libqos_init(smdkc210_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 25/71] tests/libqos: arm/sabrelite machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (23 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 24/71] tests/libqos: arm/smdkc210 " Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 26/71] tests/libqos: arm/xilinx-zynq-a9 " Paolo Bonzini
                   ` (48 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add arm/sabrelite machine to the graph. This machine contains generic-sdhci, so
its constructor must take care of setting it properly when called.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include               |  1 +
 tests/libqos/arm-sabrelite-machine.c | 91 ++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+)
 create mode 100644 tests/libqos/arm-sabrelite-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index bda5ce7..6c42ada 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -682,6 +682,7 @@ qos-test-obj-y += tests/libqos/sdhci.o
 
 # Machines
 qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
+qos-test-obj-y += tests/libqos/arm-sabrelite-machine.o
 qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
diff --git a/tests/libqos/arm-sabrelite-machine.c b/tests/libqos/arm-sabrelite-machine.c
new file mode 100644
index 0000000..c4128d8
--- /dev/null
+++ b/tests/libqos/arm-sabrelite-machine.c
@@ -0,0 +1,91 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "sdhci.h"
+
+#define ARM_PAGE_SIZE            4096
+#define SABRELITE_RAM_START      0x10000000
+#define SABRELITE_RAM_END        0x30000000
+
+typedef struct QSabreliteMachine QSabreliteMachine;
+
+struct QSabreliteMachine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    QSDHCI_MemoryMapped sdhci;
+};
+
+static void *sabrelite_get_driver(void *object, const char *interface)
+{
+    QSabreliteMachine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in arm/sabrelite\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *sabrelite_get_device(void *obj, const char *device)
+{
+    QSabreliteMachine *machine = obj;
+    if (!g_strcmp0(device, "generic-sdhci")) {
+        return &machine->sdhci.obj;
+    }
+
+    fprintf(stderr, "%s not present in arm/sabrelite\n", device);
+    g_assert_not_reached();
+}
+
+static void sabrelite_destructor(QOSGraphObject *obj)
+{
+    QSabreliteMachine *machine = (QSabreliteMachine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *qos_create_machine_arm_sabrelite(QTestState *qts)
+{
+    QSabreliteMachine *machine = g_new0(QSabreliteMachine, 1);
+
+    alloc_init(&machine->alloc, 0,
+               SABRELITE_RAM_START,
+               SABRELITE_RAM_END,
+               ARM_PAGE_SIZE);
+    machine->obj.get_device = sabrelite_get_device;
+    machine->obj.get_driver = sabrelite_get_driver;
+    machine->obj.destructor = sabrelite_destructor;
+    qos_init_sdhci_mm(&machine->sdhci, qts, 0x02190000, &(QSDHCIProperties) {
+        .version = 3,
+        .baseclock = 0,
+        .capab.sdma = true,
+        .capab.reg = 0x057834b4,
+    });
+    return &machine->obj;
+}
+
+static void sabrelite_register_nodes(void)
+{
+    qos_node_create_machine("arm/sabrelite", qos_create_machine_arm_sabrelite);
+    qos_node_contains("arm/sabrelite", "generic-sdhci", NULL);
+}
+
+libqos_init(sabrelite_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 26/71] tests/libqos: arm/xilinx-zynq-a9 machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (24 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 25/71] tests/libqos: arm/sabrelite " Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 27/71] tests/libqos: aarch64/xlnx-zcu102 " Paolo Bonzini
                   ` (47 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add xilinx-zynq-a9 machine to the graph. This machine contains generic-sdhci, so
its constructor must take care of setting it properly when called.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include                    |  1 +
 tests/libqos/arm-xilinx-zynq-a9-machine.c | 94 +++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)
 create mode 100644 tests/libqos/arm-xilinx-zynq-a9-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 6c42ada..462c99b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -684,6 +684,7 @@ qos-test-obj-y += tests/libqos/sdhci.o
 qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
 qos-test-obj-y += tests/libqos/arm-sabrelite-machine.o
 qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
+qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
diff --git a/tests/libqos/arm-xilinx-zynq-a9-machine.c b/tests/libqos/arm-xilinx-zynq-a9-machine.c
new file mode 100644
index 0000000..4e199fc
--- /dev/null
+++ b/tests/libqos/arm-xilinx-zynq-a9-machine.c
@@ -0,0 +1,94 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "sdhci.h"
+
+typedef struct QXilinxZynqA9Machine QXilinxZynqA9Machine;
+
+struct QXilinxZynqA9Machine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    QSDHCI_MemoryMapped sdhci;
+};
+
+#define ARM_PAGE_SIZE             4096
+#define XILINX_ZYNQ_A9_RAM_ADDR   0
+#define XILINX_ZYNQ_A9_RAM_SIZE   0x20000000
+
+static void *xilinx_zynq_a9_get_driver(void *object, const char *interface)
+{
+    QXilinxZynqA9Machine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in arm/xilinx-zynq-a9\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *xilinx_zynq_a9_get_device(void *obj, const char *device)
+{
+    QXilinxZynqA9Machine *machine = obj;
+    if (!g_strcmp0(device, "generic-sdhci")) {
+        return &machine->sdhci.obj;
+    }
+
+    fprintf(stderr, "%s not present in arm/xilinx-zynq-a9\n", device);
+    g_assert_not_reached();
+}
+
+static void xilinx_zynq_a9_destructor(QOSGraphObject *obj)
+{
+    QXilinxZynqA9Machine *machine = (QXilinxZynqA9Machine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *qos_create_machine_arm_xilinx_zynq_a9(QTestState *qts)
+{
+    QXilinxZynqA9Machine *machine = g_new0(QXilinxZynqA9Machine, 1);
+
+    alloc_init(&machine->alloc, 0,
+               XILINX_ZYNQ_A9_RAM_ADDR + (1 << 20),
+               XILINX_ZYNQ_A9_RAM_ADDR + XILINX_ZYNQ_A9_RAM_SIZE,
+               ARM_PAGE_SIZE);
+
+    machine->obj.get_device = xilinx_zynq_a9_get_device;
+    machine->obj.get_driver = xilinx_zynq_a9_get_driver;
+    machine->obj.destructor = xilinx_zynq_a9_destructor;
+    /* Datasheet: UG585 (v1.12.1) */
+    qos_init_sdhci_mm(&machine->sdhci, qts, 0xe0100000, &(QSDHCIProperties) {
+        .version = 2,
+        .baseclock = 0,
+        .capab.sdma = true,
+        .capab.reg = 0x69ec0080,
+    });
+    return &machine->obj;
+}
+
+static void xilinx_zynq_a9_register_nodes(void)
+{
+    qos_node_create_machine("arm/xilinx-zynq-a9",
+                            qos_create_machine_arm_xilinx_zynq_a9);
+    qos_node_contains("arm/xilinx-zynq-a9", "generic-sdhci", NULL);
+}
+
+libqos_init(xilinx_zynq_a9_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 27/71] tests/libqos: aarch64/xlnx-zcu102 machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (25 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 26/71] tests/libqos: arm/xilinx-zynq-a9 " Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 28/71] qos-test: sdhci test node Paolo Bonzini
                   ` (46 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add xlnx-zcu102 machine to the graph. This machine contains generic-sdhci, so
its constructor must take care of setting it properly when called.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include                     |  1 +
 tests/libqos/aarch64-xlnx-zcu102-machine.c | 93 ++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+)
 create mode 100644 tests/libqos/aarch64-xlnx-zcu102-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 462c99b..752f2c2 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -681,6 +681,7 @@ qos-test-obj-y += $(libqos-pc-obj-y)
 qos-test-obj-y += tests/libqos/sdhci.o
 
 # Machines
+qos-test-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
 qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
 qos-test-obj-y += tests/libqos/arm-sabrelite-machine.o
 qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
diff --git a/tests/libqos/aarch64-xlnx-zcu102-machine.c b/tests/libqos/aarch64-xlnx-zcu102-machine.c
new file mode 100644
index 0000000..2019a44
--- /dev/null
+++ b/tests/libqos/aarch64-xlnx-zcu102-machine.c
@@ -0,0 +1,93 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "sdhci.h"
+
+typedef struct QXlnxZCU102Machine QXlnxZCU102Machine;
+
+struct QXlnxZCU102Machine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    QSDHCI_MemoryMapped sdhci;
+};
+
+#define ARM_PAGE_SIZE          4096
+#define XLNX_ZCU102_RAM_ADDR   0
+#define XLNX_ZCU102_RAM_SIZE   0x20000000
+
+static void *xlnx_zcu102_get_driver(void *object, const char *interface)
+{
+    QXlnxZCU102Machine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in aarch64/xlnx-zcu102\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *xlnx_zcu102_get_device(void *obj, const char *device)
+{
+    QXlnxZCU102Machine *machine = obj;
+    if (!g_strcmp0(device, "generic-sdhci")) {
+        return &machine->sdhci.obj;
+    }
+
+    fprintf(stderr, "%s not present in aarch64/xlnx-zcu102\n", device);
+    g_assert_not_reached();
+}
+
+static void xlnx_zcu102_destructor(QOSGraphObject *obj)
+{
+    QXlnxZCU102Machine *machine = (QXlnxZCU102Machine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *qos_create_machine_aarch64_xlnx_zcu102(QTestState *qts)
+{
+    QXlnxZCU102Machine *machine = g_new0(QXlnxZCU102Machine, 1);
+
+    alloc_init(&machine->alloc, 0,
+               XLNX_ZCU102_RAM_ADDR + (1 << 20),
+               XLNX_ZCU102_RAM_ADDR + XLNX_ZCU102_RAM_SIZE,
+               ARM_PAGE_SIZE);
+
+    machine->obj.get_device = xlnx_zcu102_get_device;
+    machine->obj.get_driver = xlnx_zcu102_get_driver;
+    machine->obj.destructor = xlnx_zcu102_destructor;
+    /* Datasheet: UG1085 (v1.7) */
+    qos_init_sdhci_mm(&machine->sdhci, qts, 0xff160000, &(QSDHCIProperties) {
+        .version = 3,
+        .baseclock = 0,
+        .capab.sdma = true,
+        .capab.reg = 0x280737ec6481
+    });
+    return &machine->obj;
+}
+
+static void xlnx_zcu102_register_nodes(void)
+{
+    qos_node_create_machine("aarch64/xlnx-zcu102", qos_create_machine_aarch64_xlnx_zcu102);
+    qos_node_contains("aarch64/xlnx-zcu102", "generic-sdhci", NULL);
+}
+
+libqos_init(xlnx_zcu102_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 28/71] qos-test: sdhci test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (26 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 27/71] tests/libqos: aarch64/xlnx-zcu102 " Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-12 14:28   ` Philippe Mathieu-Daudé
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 29/71] tests/qgraph: add generic PCI testcases Paolo Bonzini
                   ` (45 subsequent siblings)
  73 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/sdhci-test in first qgraph test node, sdhci-test. This test
consumes an sdhci interface and checks that its function return the
expected values.

Note that this test does not allocate any sdhci structure, it's all done by the
qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |   7 +-
 tests/sdhci-test.c     | 185 ++++++-------------------------------------------
 2 files changed, 24 insertions(+), 168 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 752f2c2..e6be21c 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -216,7 +216,6 @@ check-qtest-i386-y += tests/migration-test$(EXESUF)
 check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF)
 check-qtest-i386-y += tests/numa-test$(EXESUF)
 check-qtest-x86_64-y += $(check-qtest-i386-y)
-check-qtest-x86_64-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
 
 check-qtest-alpha-y += tests/boot-serial-test$(EXESUF)
 
@@ -278,11 +277,9 @@ check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
 check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
 check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
-check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
 check-qtest-arm-y += tests/hexloader-test$(EXESUF)
 
 check-qtest-aarch64-y = tests/numa-test$(EXESUF)
-check-qtest-aarch64-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
 check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
 check-qtest-aarch64-y += tests/migration-test$(EXESUF)
 
@@ -688,6 +685,9 @@ qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
 qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
+# Tests
+qos-test-obj-y += tests/sdhci-test.o
+
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
 
@@ -780,7 +780,6 @@ tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
 tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y)
 tests/numa-test$(EXESUF): tests/numa-test.o
 tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
-tests/sdhci-test$(EXESUF): tests/sdhci-test.o $(libqos-pc-obj-y)
 tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
 
 tests/migration/stress$(EXESUF): tests/migration/stress.o
diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c
index 28d481b..2f177e5 100644
--- a/tests/sdhci-test.c
+++ b/tests/sdhci-test.c
@@ -12,6 +12,8 @@
 #include "libqtest.h"
 #include "libqos/pci-pc.h"
 #include "hw/pci/pci.h"
+#include "libqos/qgraph.h"
+#include "libqos/sdhci.h"
 
 #define SDHC_CAPAB                      0x40
 FIELD(SDHC_CAPAB, BASECLKFREQ,               8, 8); /* since v2 */
@@ -20,99 +22,11 @@ FIELD(SDHC_CAPAB, SDR,                      32, 3); /* since v3 */
 FIELD(SDHC_CAPAB, DRIVER,                   36, 3); /* since v3 */
 #define SDHC_HCVER                      0xFE
 
-static const struct sdhci_t {
-    const char *arch, *machine;
-    struct {
-        uintptr_t addr;
-        uint8_t version;
-        uint8_t baseclock;
-        struct {
-            bool sdma;
-            uint64_t reg;
-        } capab;
-    } sdhci;
-    struct {
-        uint16_t vendor_id, device_id;
-    } pci;
-} models[] = {
-    /* PC via PCI */
-    { "x86_64", "pc",
-        {-1,         2, 0,  {1, 0x057834b4} },
-        .pci = { PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_SDHCI } },
-
-    /* Exynos4210 */
-    { "arm",    "smdkc210",
-        {0x12510000, 2, 0,  {1, 0x5e80080} } },
-
-    /* i.MX 6 */
-    { "arm",    "sabrelite",
-        {0x02190000, 3, 0,  {1, 0x057834b4} } },
-
-    /* BCM2835 */
-    { "arm",    "raspi2",
-        {0x3f300000, 3, 52, {0, 0x052134b4} } },
-
-    /* Zynq-7000 */
-    { "arm",    "xilinx-zynq-a9",   /* Datasheet: UG585 (v1.12.1) */
-        {0xe0100000, 2, 0,  {1, 0x69ec0080} } },
-
-    /* ZynqMP */
-    { "aarch64", "xlnx-zcu102",     /* Datasheet: UG1085 (v1.7) */
-        {0xff160000, 3, 0,  {1, 0x280737ec6481} } },
-
-};
-
-typedef struct QSDHCI {
-    struct {
-        QPCIBus *bus;
-        QPCIDevice *dev;
-    } pci;
-    union {
-        QPCIBar mem_bar;
-        uint64_t addr;
-    };
-} QSDHCI;
-
-static uint16_t sdhci_readw(QSDHCI *s, uint32_t reg)
-{
-    uint16_t val;
-
-    if (s->pci.dev) {
-        val = qpci_io_readw(s->pci.dev, s->mem_bar, reg);
-    } else {
-        val = qtest_readw(global_qtest, s->addr + reg);
-    }
-
-    return val;
-}
-
-static uint64_t sdhci_readq(QSDHCI *s, uint32_t reg)
-{
-    uint64_t val;
-
-    if (s->pci.dev) {
-        val = qpci_io_readq(s->pci.dev, s->mem_bar, reg);
-    } else {
-        val = qtest_readq(global_qtest, s->addr + reg);
-    }
-
-    return val;
-}
-
-static void sdhci_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
-{
-    if (s->pci.dev) {
-        qpci_io_writeq(s->pci.dev, s->mem_bar, reg, val);
-    } else {
-        qtest_writeq(global_qtest, s->addr + reg, val);
-    }
-}
-
 static void check_specs_version(QSDHCI *s, uint8_t version)
 {
     uint32_t v;
 
-    v = sdhci_readw(s, SDHC_HCVER);
+    v = s->readw(s, SDHC_HCVER);
     v &= 0xff;
     v += 1;
     g_assert_cmpuint(v, ==, version);
@@ -122,7 +36,7 @@ static void check_capab_capareg(QSDHCI *s, uint64_t expec_capab)
 {
     uint64_t capab;
 
-    capab = sdhci_readq(s, SDHC_CAPAB);
+    capab = s->readq(s, SDHC_CAPAB);
     g_assert_cmphex(capab, ==, expec_capab);
 }
 
@@ -131,11 +45,11 @@ static void check_capab_readonly(QSDHCI *s)
     const uint64_t vrand = 0x123456789abcdef;
     uint64_t capab0, capab1;
 
-    capab0 = sdhci_readq(s, SDHC_CAPAB);
+    capab0 = s->readq(s, SDHC_CAPAB);
     g_assert_cmpuint(capab0, !=, vrand);
 
-    sdhci_writeq(s, SDHC_CAPAB, vrand);
-    capab1 = sdhci_readq(s, SDHC_CAPAB);
+    s->writeq(s, SDHC_CAPAB, vrand);
+    capab1 = s->readq(s, SDHC_CAPAB);
     g_assert_cmpuint(capab1, !=, vrand);
     g_assert_cmpuint(capab1, ==, capab0);
 }
@@ -147,7 +61,7 @@ static void check_capab_baseclock(QSDHCI *s, uint8_t expec_freq)
     if (!expec_freq) {
         return;
     }
-    capab = sdhci_readq(s, SDHC_CAPAB);
+    capab = s->readq(s, SDHC_CAPAB);
     capab_freq = FIELD_EX64(capab, SDHC_CAPAB, BASECLKFREQ);
     g_assert_cmpuint(capab_freq, ==, expec_freq);
 }
@@ -156,7 +70,7 @@ static void check_capab_sdma(QSDHCI *s, bool supported)
 {
     uint64_t capab, capab_sdma;
 
-    capab = sdhci_readq(s, SDHC_CAPAB);
+    capab = s->readq(s, SDHC_CAPAB);
     capab_sdma = FIELD_EX64(capab, SDHC_CAPAB, SDMA);
     g_assert_cmpuint(capab_sdma, ==, supported);
 }
@@ -167,7 +81,7 @@ static void check_capab_v3(QSDHCI *s, uint8_t version)
 
     if (version < 3) {
         /* before v3 those fields are RESERVED */
-        capab = sdhci_readq(s, SDHC_CAPAB);
+        capab = s->readq(s, SDHC_CAPAB);
         capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, SDR);
         g_assert_cmpuint(capab_v3, ==, 0);
         capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, DRIVER);
@@ -175,78 +89,21 @@ static void check_capab_v3(QSDHCI *s, uint8_t version)
     }
 }
 
-static QSDHCI *machine_start(const struct sdhci_t *test)
-{
-    QSDHCI *s = g_new0(QSDHCI, 1);
-
-    if (test->pci.vendor_id) {
-        /* PCI */
-        uint16_t vendor_id, device_id;
-        uint64_t barsize;
-
-        global_qtest = qtest_initf("-machine %s -device sdhci-pci",
-                                   test->machine);
-
-        s->pci.bus = qpci_new_pc(global_qtest, NULL);
-
-        /* Find PCI device and verify it's the right one */
-        s->pci.dev = qpci_device_find(s->pci.bus, QPCI_DEVFN(4, 0));
-        g_assert_nonnull(s->pci.dev);
-        vendor_id = qpci_config_readw(s->pci.dev, PCI_VENDOR_ID);
-        device_id = qpci_config_readw(s->pci.dev, PCI_DEVICE_ID);
-        g_assert(vendor_id == test->pci.vendor_id);
-        g_assert(device_id == test->pci.device_id);
-        s->mem_bar = qpci_iomap(s->pci.dev, 0, &barsize);
-        qpci_device_enable(s->pci.dev);
-    } else {
-        /* SysBus */
-        global_qtest = qtest_initf("-machine %s", test->machine);
-        s->addr = test->sdhci.addr;
-    }
-
-    return s;
-}
-
-static void machine_stop(QSDHCI *s)
-{
-    qpci_free_pc(s->pci.bus);
-    g_free(s->pci.dev);
-    qtest_quit(global_qtest);
-    g_free(s);
-}
-
-static void test_machine(const void *data)
+static void test_registers(void *obj, void *data, QGuestAllocator *alloc)
 {
-    const struct sdhci_t *test = data;
-    QSDHCI *s;
+    QSDHCI *s = obj;
 
-    s = machine_start(test);
-
-    check_specs_version(s, test->sdhci.version);
-    check_capab_capareg(s, test->sdhci.capab.reg);
+    check_specs_version(s, s->props.version);
+    check_capab_capareg(s, s->props.capab.reg);
     check_capab_readonly(s);
-    check_capab_v3(s, test->sdhci.version);
-    check_capab_sdma(s, test->sdhci.capab.sdma);
-    check_capab_baseclock(s, test->sdhci.baseclock);
-
-    machine_stop(s);
+    check_capab_v3(s, s->props.version);
+    check_capab_sdma(s, s->props.capab.sdma);
+    check_capab_baseclock(s, s->props.baseclock);
 }
 
-int main(int argc, char *argv[])
+static void register_sdhci_test(void)
 {
-    const char *arch = qtest_get_arch();
-    char *name;
-    int i;
-
-    g_test_init(&argc, &argv, NULL);
-    for (i = 0; i < ARRAY_SIZE(models); i++) {
-        if (strcmp(arch, models[i].arch)) {
-            continue;
-        }
-        name = g_strdup_printf("sdhci/%s", models[i].machine);
-        qtest_add_data_func(name, &models[i], test_machine);
-        g_free(name);
-    }
-
-    return g_test_run();
+    qos_add_test("registers", "sdhci", test_registers, NULL);
 }
+
+libqos_init(register_sdhci_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 29/71] tests/qgraph: add generic PCI testcases
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (27 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 28/71] qos-test: sdhci test node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 30/71] tests/libqos: pci-spapr driver and interface nodes Paolo Bonzini
                   ` (44 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  1 +
 tests/pci-test.c       | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
 create mode 100644 tests/pci-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index e6be21c..f749fae 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -686,6 +686,7 @@ qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 # Tests
+qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
diff --git a/tests/pci-test.c b/tests/pci-test.c
new file mode 100644
index 0000000..ff80985
--- /dev/null
+++ b/tests/pci-test.c
@@ -0,0 +1,25 @@
+/*
+ * QTest testcase for PCI
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * 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/qgraph.h"
+#include "libqos/pci.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void *obj, void *data, QGuestAllocator *alloc)
+{
+}
+
+static void register_pci_test(void)
+{
+    qos_add_test("nop", "pci-device", nop, NULL);
+}
+
+libqos_init(register_pci_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 30/71] tests/libqos: pci-spapr driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (28 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 29/71] tests/qgraph: add generic PCI testcases Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 31/71] tests/qgraph: ppc64/pseries machine node Paolo Bonzini
                   ` (43 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add pci-bus-spapr node, that produces pci-bus. Move QPCIBusSPAPR struct
declaration in its header (since it will be needed by other drivers)
and introduce a setter method for drivers that do not need to allocate
but have to initialize QPCIBusSPAPR.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include   |   2 +-
 tests/libqos/pci-spapr.c | 116 +++++++++++++++++++++++++----------------------
 tests/libqos/pci-spapr.h |  24 ++++++++++
 3 files changed, 88 insertions(+), 54 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index f749fae..9bf1f25 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -674,7 +674,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 
 # Devices
 qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
-qos-test-obj-y += $(libqos-pc-obj-y)
+qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 qos-test-obj-y += tests/libqos/sdhci.o
 
 # Machines
diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c
index f306cb7..24f2c2c 100644
--- a/tests/libqos/pci-spapr.c
+++ b/tests/libqos/pci-spapr.c
@@ -9,33 +9,13 @@
 #include "libqtest.h"
 #include "libqos/pci-spapr.h"
 #include "libqos/rtas.h"
+#include "libqos/qgraph.h"
 
 #include "hw/pci/pci_regs.h"
 
 #include "qemu-common.h"
 #include "qemu/host-utils.h"
 
-
-/* From include/hw/pci-host/spapr.h */
-
-typedef struct QPCIWindow {
-    uint64_t pci_base;    /* window address in PCI space */
-    uint64_t size;        /* window size */
-} QPCIWindow;
-
-typedef struct QPCIBusSPAPR {
-    QPCIBus bus;
-    QGuestAllocator *alloc;
-
-    uint64_t buid;
-
-    uint64_t pio_cpu_base;
-    QPCIWindow pio;
-
-    uint64_t mmio32_cpu_base;
-    QPCIWindow mmio32;
-} QPCIBusSPAPR;
-
 /*
  * PCI devices are always little-endian
  * SPAPR by default is big-endian
@@ -160,60 +140,90 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
 #define SPAPR_PCI_MMIO32_WIN_SIZE    0x80000000 /* 2 GiB */
 #define SPAPR_PCI_IO_WIN_SIZE        0x10000
 
-QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc)
+static void *qpci_spapr_get_driver(void *obj, const char *interface)
 {
-    QPCIBusSPAPR *ret = g_new0(QPCIBusSPAPR, 1);
+    QPCIBusSPAPR *qpci = obj;
+    if (!g_strcmp0(interface, "pci-bus")) {
+        return &qpci->bus;
+    }
+    fprintf(stderr, "%s not present in pci-bus-spapr", interface);
+    g_assert_not_reached();
+}
 
+void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts,
+                     QGuestAllocator *alloc)
+{
     assert(qts);
 
-    ret->alloc = alloc;
+    qpci->alloc = alloc;
 
-    ret->bus.pio_readb = qpci_spapr_pio_readb;
-    ret->bus.pio_readw = qpci_spapr_pio_readw;
-    ret->bus.pio_readl = qpci_spapr_pio_readl;
-    ret->bus.pio_readq = qpci_spapr_pio_readq;
+    qpci->bus.pio_readb = qpci_spapr_pio_readb;
+    qpci->bus.pio_readw = qpci_spapr_pio_readw;
+    qpci->bus.pio_readl = qpci_spapr_pio_readl;
+    qpci->bus.pio_readq = qpci_spapr_pio_readq;
 
-    ret->bus.pio_writeb = qpci_spapr_pio_writeb;
-    ret->bus.pio_writew = qpci_spapr_pio_writew;
-    ret->bus.pio_writel = qpci_spapr_pio_writel;
-    ret->bus.pio_writeq = qpci_spapr_pio_writeq;
+    qpci->bus.pio_writeb = qpci_spapr_pio_writeb;
+    qpci->bus.pio_writew = qpci_spapr_pio_writew;
+    qpci->bus.pio_writel = qpci_spapr_pio_writel;
+    qpci->bus.pio_writeq = qpci_spapr_pio_writeq;
 
-    ret->bus.memread = qpci_spapr_memread;
-    ret->bus.memwrite = qpci_spapr_memwrite;
+    qpci->bus.memread = qpci_spapr_memread;
+    qpci->bus.memwrite = qpci_spapr_memwrite;
 
-    ret->bus.config_readb = qpci_spapr_config_readb;
-    ret->bus.config_readw = qpci_spapr_config_readw;
-    ret->bus.config_readl = qpci_spapr_config_readl;
+    qpci->bus.config_readb = qpci_spapr_config_readb;
+    qpci->bus.config_readw = qpci_spapr_config_readw;
+    qpci->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;
+    qpci->bus.config_writeb = qpci_spapr_config_writeb;
+    qpci->bus.config_writew = qpci_spapr_config_writew;
+    qpci->bus.config_writel = qpci_spapr_config_writel;
 
     /* FIXME: We assume the default location of the PHB for now.
      * Ideally we'd parse the device tree deposited in the guest to
      * get the window locations */
-    ret->buid = 0x800000020000000ULL;
+    qpci->buid = 0x800000020000000ULL;
 
-    ret->pio_cpu_base = SPAPR_PCI_BASE;
-    ret->pio.pci_base = 0;
-    ret->pio.size = SPAPR_PCI_IO_WIN_SIZE;
+    qpci->pio_cpu_base = SPAPR_PCI_BASE;
+    qpci->pio.pci_base = 0;
+    qpci->pio.size = SPAPR_PCI_IO_WIN_SIZE;
 
     /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */
-    ret->mmio32_cpu_base = SPAPR_PCI_BASE;
-    ret->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE;
-    ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE;
+    qpci->mmio32_cpu_base = SPAPR_PCI_BASE;
+    qpci->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE;
+    qpci->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE;
 
-    ret->bus.qts = qts;
-    ret->bus.pio_alloc_ptr = 0xc000;
-    ret->bus.mmio_alloc_ptr = ret->mmio32.pci_base;
-    ret->bus.mmio_limit = ret->mmio32.pci_base + ret->mmio32.size;
+    qpci->bus.qts = qts;
+    qpci->bus.pio_alloc_ptr = 0xc000;
+    qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base;
+    qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size;
 
-    return &ret->bus;
+    qpci->obj.get_driver = qpci_spapr_get_driver;
+}
+
+QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc)
+{
+    QPCIBusSPAPR *qpci = g_new0(QPCIBusSPAPR, 1);
+    qpci_init_spapr(qpci, qts, alloc);
+
+    return &qpci->bus;
 }
 
 void qpci_free_spapr(QPCIBus *bus)
 {
-    QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
+    QPCIBusSPAPR *s;
+
+    if (!bus) {
+        return;
+    }
+    s = container_of(bus, QPCIBusSPAPR, bus);
 
     g_free(s);
 }
+
+static void qpci_spapr_register_nodes(void)
+{
+    qos_node_create_driver("pci-bus-spapr", NULL);
+    qos_node_produces("pci-bus-spapr", "pci-bus");
+}
+
+libqos_init(qpci_spapr_register_nodes);
diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h
index 177e8c0..d9e2563 100644
--- a/tests/libqos/pci-spapr.h
+++ b/tests/libqos/pci-spapr.h
@@ -10,7 +10,31 @@
 
 #include "libqos/malloc.h"
 #include "libqos/pci.h"
+#include "libqos/qgraph.h"
 
+/* From include/hw/pci-host/spapr.h */
+
+typedef struct QPCIWindow {
+    uint64_t pci_base;    /* window address in PCI space */
+    uint64_t size;        /* window size */
+} QPCIWindow;
+
+typedef struct QPCIBusSPAPR {
+    QOSGraphObject obj;
+    QPCIBus bus;
+    QGuestAllocator *alloc;
+
+    uint64_t buid;
+
+    uint64_t pio_cpu_base;
+    QPCIWindow pio;
+
+    uint64_t mmio32_cpu_base;
+    QPCIWindow mmio32;
+} QPCIBusSPAPR;
+
+void qpci_init_spapr(QPCIBusSPAPR *ret, QTestState *qts,
+                     QGuestAllocator *alloc);
 QPCIBus *qpci_new_spapr(QTestState *qts, QGuestAllocator *alloc);
 void     qpci_free_spapr(QPCIBus *bus);
 
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 31/71] tests/qgraph: ppc64/pseries machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (29 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 30/71] tests/libqos: pci-spapr driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 32/71] tests/libqos: has_buggy_msi flag Paolo Bonzini
                   ` (42 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add pseries  machine for the ppc64 QEMU binary. This machine contains a
spapr-pci-host-bridge driver, that contains itself a pci-bus-spapr
that produces the pci-bus interface.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include               |   1 +
 tests/libqos/ppc64_pseries-machine.c | 111 +++++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+)
 create mode 100644 tests/libqos/ppc64_pseries-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 9bf1f25..ae8adb0 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -683,6 +683,7 @@ qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
 qos-test-obj-y += tests/libqos/arm-sabrelite-machine.o
 qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
 qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
+qos-test-obj-y += tests/libqos/ppc64_pseries-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 # Tests
diff --git a/tests/libqos/ppc64_pseries-machine.c b/tests/libqos/ppc64_pseries-machine.c
new file mode 100644
index 0000000..534320f
--- /dev/null
+++ b/tests/libqos/ppc64_pseries-machine.c
@@ -0,0 +1,111 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+ #include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "pci-spapr.h"
+#include "libqos/malloc-spapr.h"
+
+typedef struct QSPAPR_pci_host QSPAPR_pci_host;
+typedef struct Qppc64_pseriesMachine Qppc64_pseriesMachine;
+
+struct QSPAPR_pci_host {
+    QOSGraphObject obj;
+    QPCIBusSPAPR pci;
+};
+
+struct Qppc64_pseriesMachine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    QSPAPR_pci_host bridge;
+};
+
+/* QSPAPR_pci_host */
+
+static QOSGraphObject *QSPAPR_host_get_device(void *obj, const char *device)
+{
+    QSPAPR_pci_host *host = obj;
+    if (!g_strcmp0(device, "pci-bus-spapr")) {
+        return &host->pci.obj;
+    }
+    fprintf(stderr, "%s not present in QSPAPR_pci_host\n", device);
+    g_assert_not_reached();
+}
+
+static void qos_create_QSPAPR_host(QSPAPR_pci_host *host,
+                                   QTestState *qts,
+				   QGuestAllocator *alloc)
+{
+    host->obj.get_device = QSPAPR_host_get_device;
+    qpci_init_spapr(&host->pci, qts, alloc);
+}
+
+/* ppc64/pseries machine */
+
+static void spapr_destructor(QOSGraphObject *obj)
+{
+    Qppc64_pseriesMachine *machine = (Qppc64_pseriesMachine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *spapr_get_driver(void *object, const char *interface)
+{
+    Qppc64_pseriesMachine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in ppc64/pseries\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *spapr_get_device(void *obj, const char *device)
+{
+    Qppc64_pseriesMachine *machine = obj;
+    if (!g_strcmp0(device, "spapr-pci-host-bridge")) {
+        return &machine->bridge.obj;
+    }
+
+    fprintf(stderr, "%s not present in ppc64/pseries\n", device);
+    g_assert_not_reached();
+}
+
+static void *qos_create_machine_spapr(QTestState *qts)
+{
+    Qppc64_pseriesMachine *machine = g_new0(Qppc64_pseriesMachine, 1);
+    machine->obj.get_device = spapr_get_device;
+    machine->obj.get_driver = spapr_get_driver;
+    machine->obj.destructor = spapr_destructor;
+    spapr_alloc_init(&machine->alloc, qts, ALLOC_NO_FLAGS);
+
+    qos_create_QSPAPR_host(&machine->bridge, qts, &machine->alloc);
+
+    return &machine->obj;
+}
+
+static void spapr_machine_register_nodes(void)
+{
+    qos_node_create_machine("ppc64/pseries", qos_create_machine_spapr);
+    qos_node_create_driver("spapr-pci-host-bridge", NULL);
+    qos_node_contains("ppc64/pseries", "spapr-pci-host-bridge", NULL);
+    qos_node_contains("spapr-pci-host-bridge", "pci-bus-spapr", NULL);
+}
+
+libqos_init(spapr_machine_register_nodes);
+
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 32/71] tests/libqos: has_buggy_msi flag
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (30 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 31/71] tests/qgraph: ppc64/pseries machine node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 33/71] tests/libqos: e1000e driver and interface nodes Paolo Bonzini
                   ` (41 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

The Qgraph framework makes any test using
pci bus run the same function using pci-pci and
pci-spapr bus. However, some tests are not ready to use
the spapr bus, due to a MSI bug. Until it does not get
fixed, this flag allows them to skip the test

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/libqos/pci-pc.c    |  3 +++
 tests/libqos/pci-spapr.c |  3 +++
 tests/libqos/pci.c       | 14 ++++++++++++++
 tests/libqos/pci.h       |  4 ++++
 4 files changed, 24 insertions(+)

diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 041bfed..4247cda 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -123,6 +123,9 @@ void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc)
 {
     assert(qts);
 
+    /* tests can use pci-bus */
+    qpci->bus.has_buggy_msi = FALSE;
+
     qpci->bus.pio_readb = qpci_pc_pio_readb;
     qpci->bus.pio_readw = qpci_pc_pio_readw;
     qpci->bus.pio_readl = qpci_pc_pio_readl;
diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c
index 24f2c2c..502a0e5 100644
--- a/tests/libqos/pci-spapr.c
+++ b/tests/libqos/pci-spapr.c
@@ -155,6 +155,9 @@ void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts,
 {
     assert(qts);
 
+    /* tests cannot use spapr, needs to be fixed first */
+    qpci->bus.has_buggy_msi = TRUE;
+
     qpci->alloc = alloc;
 
     qpci->bus.pio_readb = qpci_spapr_pio_readb;
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index 8257904..662ee7a 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -51,6 +51,20 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
     }
 }
 
+bool qpci_has_buggy_msi(QPCIDevice *dev)
+{
+    return dev->bus->has_buggy_msi;
+}
+
+bool qpci_check_buggy_msi(QPCIDevice *dev)
+{
+    if (qpci_has_buggy_msi(dev)) {
+        g_test_skip("Skipping due to incomplete support for MSI");
+        return true;
+    }
+    return false;
+}
+
 static void qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
 {
     g_assert(dev);
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
index 9fd521a..8e1d292 100644
--- a/tests/libqos/pci.h
+++ b/tests/libqos/pci.h
@@ -53,6 +53,7 @@ struct QPCIBus {
     QTestState *qts;
     uint16_t pio_alloc_ptr;
     uint64_t mmio_alloc_ptr, mmio_limit;
+    bool has_buggy_msi; /* TRUE for spapr, FALSE for pci */
 
 };
 
@@ -81,6 +82,9 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
 QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn);
 void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr);
 
+bool qpci_has_buggy_msi(QPCIDevice *dev);
+bool qpci_check_buggy_msi(QPCIDevice *dev);
+
 void qpci_device_enable(QPCIDevice *dev);
 uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id);
 void qpci_msix_enable(QPCIDevice *dev);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 33/71] tests/libqos: e1000e driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (31 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 32/71] tests/libqos: has_buggy_msi flag Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 34/71] qos-test: e1000e test node Paolo Bonzini
                   ` (40 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-e1000e.
It consumes a pci-bus, and it's directly used by tests
(e1000e is pci based).

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |   1 +
 tests/libqos/e1000e.c  | 260 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/e1000e.h  |  53 ++++++++++
 3 files changed, 314 insertions(+)
 create mode 100644 tests/libqos/e1000e.c
 create mode 100644 tests/libqos/e1000e.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ae8adb0..7d53a54 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -675,6 +675,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 # Devices
 qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
 qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
+qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/sdhci.o
 
 # Machines
diff --git a/tests/libqos/e1000e.c b/tests/libqos/e1000e.c
new file mode 100644
index 0000000..54d3898
--- /dev/null
+++ b/tests/libqos/e1000e.c
@@ -0,0 +1,260 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu-common.h"
+#include "libqos/pci-pc.h"
+#include "qemu/sockets.h"
+#include "qemu/iov.h"
+#include "qemu/bitops.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "e1000e.h"
+
+#define E1000E_IMS      (0x00d0)
+
+#define E1000E_STATUS   (0x0008)
+#define E1000E_STATUS_LU BIT(1)
+#define E1000E_STATUS_ASDV1000 BIT(9)
+
+#define E1000E_CTRL     (0x0000)
+#define E1000E_CTRL_RESET BIT(26)
+
+#define E1000E_RCTL     (0x0100)
+#define E1000E_RCTL_EN  BIT(1)
+#define E1000E_RCTL_UPE BIT(3)
+#define E1000E_RCTL_MPE BIT(4)
+
+#define E1000E_RFCTL     (0x5008)
+#define E1000E_RFCTL_EXTEN  BIT(15)
+
+#define E1000E_TCTL     (0x0400)
+#define E1000E_TCTL_EN  BIT(1)
+
+#define E1000E_CTRL_EXT             (0x0018)
+#define E1000E_CTRL_EXT_DRV_LOAD    BIT(28)
+#define E1000E_CTRL_EXT_TXLSFLOW    BIT(22)
+
+#define E1000E_IVAR                 (0x00E4)
+#define E1000E_IVAR_TEST_CFG        ((E1000E_RX0_MSG_ID << 0)    | BIT(3)  | \
+                                     (E1000E_TX0_MSG_ID << 8)    | BIT(11) | \
+                                     (E1000E_OTHER_MSG_ID << 16) | BIT(19) | \
+                                     BIT(31))
+
+#define E1000E_RING_LEN             (0x1000)
+
+#define E1000E_TDBAL    (0x3800)
+
+#define E1000E_TDBAH    (0x3804)
+#define E1000E_TDH      (0x3810)
+
+#define E1000E_RDBAL    (0x2800)
+#define E1000E_RDBAH    (0x2804)
+#define E1000E_RDH      (0x2810)
+
+#define E1000E_TXD_LEN              (16)
+#define E1000E_RXD_LEN              (16)
+
+static void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val);
+}
+
+static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, reg);
+}
+
+void e1000e_tx_ring_push(QE1000E *d, void *descr)
+{
+    uint32_t tail = e1000e_macreg_read(d, E1000E_TDT);
+    uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000E_TXD_LEN;
+
+    memwrite(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN);
+    e1000e_macreg_write(d, E1000E_TDT, (tail + 1) % len);
+
+    /* Read WB data for the packet transmitted */
+    memread(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN);
+}
+
+void e1000e_rx_ring_push(QE1000E *d, void *descr)
+{
+    uint32_t tail = e1000e_macreg_read(d, E1000E_RDT);
+    uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000E_RXD_LEN;
+
+    memwrite(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN);
+    e1000e_macreg_write(d, E1000E_RDT, (tail + 1) % len);
+
+    /* Read WB data for the packet received */
+    memread(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN);
+}
+
+static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
+{
+    QPCIDevice *res = data;
+    memcpy(res, dev, sizeof(QPCIDevice));
+    g_free(dev);
+}
+
+void e1000e_wait_isr(QE1000E *d, uint16_t msg_id)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+
+    do {
+        if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) {
+            return;
+        }
+        clock_step(10000);
+    } while (g_get_monotonic_time() < end_time);
+
+    g_error("Timeout expired");
+}
+
+static void e1000e_pci_destructor(QOSGraphObject *obj)
+{
+    QE1000E_PCI *epci = (QE1000E_PCI *) obj;
+    qpci_iounmap(&epci->pci_dev, epci->mac_regs);
+    qpci_msix_disable(&epci->pci_dev);
+}
+
+static void e1000e_pci_start_hw(QOSGraphObject *obj)
+{
+    QE1000E_PCI *d = (QE1000E_PCI *) obj;
+    uint32_t val;
+
+    /* Enable the device */
+    qpci_device_enable(&d->pci_dev);
+
+    /* Reset the device */
+    val = e1000e_macreg_read(&d->e1000e, E1000E_CTRL);
+    e1000e_macreg_write(&d->e1000e, E1000E_CTRL, val | E1000E_CTRL_RESET);
+
+    /* Enable and configure MSI-X */
+    qpci_msix_enable(&d->pci_dev);
+    e1000e_macreg_write(&d->e1000e, E1000E_IVAR, E1000E_IVAR_TEST_CFG);
+
+    /* Check the device status - link and speed */
+    val = e1000e_macreg_read(&d->e1000e, E1000E_STATUS);
+    g_assert_cmphex(val & (E1000E_STATUS_LU | E1000E_STATUS_ASDV1000),
+        ==, E1000E_STATUS_LU | E1000E_STATUS_ASDV1000);
+
+    /* Initialize TX/RX logic */
+    e1000e_macreg_write(&d->e1000e, E1000E_RCTL, 0);
+    e1000e_macreg_write(&d->e1000e, E1000E_TCTL, 0);
+
+    /* Notify the device that the driver is ready */
+    val = e1000e_macreg_read(&d->e1000e, E1000E_CTRL_EXT);
+    e1000e_macreg_write(&d->e1000e, E1000E_CTRL_EXT,
+        val | E1000E_CTRL_EXT_DRV_LOAD | E1000E_CTRL_EXT_TXLSFLOW);
+
+    e1000e_macreg_write(&d->e1000e, E1000E_TDBAL,
+                           (uint32_t) d->e1000e.tx_ring);
+    e1000e_macreg_write(&d->e1000e, E1000E_TDBAH,
+                           (uint32_t) (d->e1000e.tx_ring >> 32));
+    e1000e_macreg_write(&d->e1000e, E1000E_TDLEN, E1000E_RING_LEN);
+    e1000e_macreg_write(&d->e1000e, E1000E_TDT, 0);
+    e1000e_macreg_write(&d->e1000e, E1000E_TDH, 0);
+
+    /* Enable transmit */
+    e1000e_macreg_write(&d->e1000e, E1000E_TCTL, E1000E_TCTL_EN);
+    e1000e_macreg_write(&d->e1000e, E1000E_RDBAL,
+                           (uint32_t)d->e1000e.rx_ring);
+    e1000e_macreg_write(&d->e1000e, E1000E_RDBAH,
+                           (uint32_t)(d->e1000e.rx_ring >> 32));
+    e1000e_macreg_write(&d->e1000e, E1000E_RDLEN, E1000E_RING_LEN);
+    e1000e_macreg_write(&d->e1000e, E1000E_RDT, 0);
+    e1000e_macreg_write(&d->e1000e, E1000E_RDH, 0);
+
+    /* Enable receive */
+    e1000e_macreg_write(&d->e1000e, E1000E_RFCTL, E1000E_RFCTL_EXTEN);
+    e1000e_macreg_write(&d->e1000e, E1000E_RCTL, E1000E_RCTL_EN  |
+                                        E1000E_RCTL_UPE |
+                                        E1000E_RCTL_MPE);
+
+    /* Enable all interrupts */
+    e1000e_macreg_write(&d->e1000e, E1000E_IMS, 0xFFFFFFFF);
+
+}
+
+static void *e1000e_pci_get_driver(void *obj, const char *interface)
+{
+    QE1000E_PCI *epci = obj;
+    if (!g_strcmp0(interface, "e1000e-if")) {
+        return &epci->e1000e;
+    }
+
+    /* implicit contains */
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &epci->pci_dev;
+    }
+
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
+}
+
+static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
+                               void *addr)
+{
+    QE1000E_PCI *d = g_new0(QE1000E_PCI, 1);
+    QPCIBus *bus = pci_bus;
+    QPCIAddress *address = addr;
+
+    qpci_device_foreach(bus, address->vendor_id, address->device_id,
+                        e1000e_foreach_callback, &d->pci_dev);
+
+    /* Map BAR0 (mac registers) */
+    d->mac_regs = qpci_iomap(&d->pci_dev, 0, NULL);
+
+    /* Allocate and setup TX ring */
+    d->e1000e.tx_ring = guest_alloc(alloc, E1000E_RING_LEN);
+    g_assert(d->e1000e.tx_ring != 0);
+
+    /* Allocate and setup RX ring */
+    d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN);
+    g_assert(d->e1000e.rx_ring != 0);
+
+    d->obj.get_driver = e1000e_pci_get_driver;
+    d->obj.start_hw = e1000e_pci_start_hw;
+    d->obj.destructor = e1000e_pci_destructor;
+
+    return &d->obj;
+}
+
+static void e1000e_register_nodes(void)
+{
+    QPCIAddress addr = {
+        .vendor_id = 0x8086,
+        .device_id = 0x10D3,
+    };
+
+    /* FIXME: every test using this node needs to setup a -netdev socket,id=hs0
+     * otherwise QEMU is not going to start */
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "netdev=hs0",
+    };
+    add_qpci_address(&opts, &addr);
+
+    qos_node_create_driver("e1000e", e1000e_pci_create);
+    qos_node_consumes("e1000e", "pci-bus", &opts);
+}
+
+libqos_init(e1000e_register_nodes);
diff --git a/tests/libqos/e1000e.h b/tests/libqos/e1000e.h
new file mode 100644
index 0000000..9d37094
--- /dev/null
+++ b/tests/libqos/e1000e.h
@@ -0,0 +1,53 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef QGRAPH_E1000E
+#define QGRAPH_E1000E
+
+#include "libqos/qgraph.h"
+#include "pci.h"
+
+#define E1000E_RX0_MSG_ID           (0)
+#define E1000E_TX0_MSG_ID           (1)
+#define E1000E_OTHER_MSG_ID         (2)
+
+#define E1000E_TDLEN    (0x3808)
+#define E1000E_TDT      (0x3818)
+#define E1000E_RDLEN    (0x2808)
+#define E1000E_RDT      (0x2818)
+
+typedef struct QE1000E QE1000E;
+typedef struct QE1000E_PCI QE1000E_PCI;
+
+struct QE1000E {
+    uint64_t tx_ring;
+    uint64_t rx_ring;
+};
+
+struct QE1000E_PCI {
+    QOSGraphObject obj;
+    QPCIDevice pci_dev;
+    QPCIBar mac_regs;
+    QE1000E e1000e;
+};
+
+void e1000e_wait_isr(QE1000E *d, uint16_t msg_id);
+void e1000e_tx_ring_push(QE1000E *d, void *descr);
+void e1000e_rx_ring_push(QE1000E *d, void *descr);
+
+#endif
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 34/71] qos-test: e1000e test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (32 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 33/71] tests/libqos: e1000e driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 35/71] tests/libqos: virtio-pci driver and interface nodes Paolo Bonzini
                   ` (39 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/e1000e-test in qgraph test node, e1000e-test. This test
consumes an e1000e interface and checks that its function return the
expected values.

Note that this test does not allocate any e1000e structure, it's all done by the
qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |   3 +-
 tests/e1000e-test.c    | 356 +++++++++++--------------------------------------
 2 files changed, 78 insertions(+), 281 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 7d53a54..dc40b10 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -157,7 +157,6 @@ check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
 check-qtest-virtio-y += $(check-qtest-virtioserial-y)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
-check-qtest-pci-y += tests/e1000e-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
 check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
@@ -688,6 +687,7 @@ qos-test-obj-y += tests/libqos/ppc64_pseries-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 # Tests
+qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 
@@ -726,7 +726,6 @@ tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
 tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
 tests/e1000-test$(EXESUF): tests/e1000-test.o
-tests/e1000e-test$(EXESUF): tests/e1000e-test.o $(libqos-pc-obj-y)
 tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y)
 tests/pcnet-test$(EXESUF): tests/pcnet-test.o
 tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index 17a12b8..652a606 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -32,210 +32,9 @@
 #include "qemu/iov.h"
 #include "qemu/bitops.h"
 #include "libqos/malloc.h"
-#include "libqos/malloc-pc.h"
-#include "libqos/malloc-generic.h"
+#include "libqos/e1000e.h"
 
-#define E1000E_IMS      (0x00d0)
-
-#define E1000E_STATUS   (0x0008)
-#define E1000E_STATUS_LU BIT(1)
-#define E1000E_STATUS_ASDV1000 BIT(9)
-
-#define E1000E_CTRL     (0x0000)
-#define E1000E_CTRL_RESET BIT(26)
-
-#define E1000E_RCTL     (0x0100)
-#define E1000E_RCTL_EN  BIT(1)
-#define E1000E_RCTL_UPE BIT(3)
-#define E1000E_RCTL_MPE BIT(4)
-
-#define E1000E_RFCTL     (0x5008)
-#define E1000E_RFCTL_EXTEN  BIT(15)
-
-#define E1000E_TCTL     (0x0400)
-#define E1000E_TCTL_EN  BIT(1)
-
-#define E1000E_CTRL_EXT             (0x0018)
-#define E1000E_CTRL_EXT_DRV_LOAD    BIT(28)
-#define E1000E_CTRL_EXT_TXLSFLOW    BIT(22)
-
-#define E1000E_RX0_MSG_ID           (0)
-#define E1000E_TX0_MSG_ID           (1)
-#define E1000E_OTHER_MSG_ID         (2)
-
-#define E1000E_IVAR                 (0x00E4)
-#define E1000E_IVAR_TEST_CFG        ((E1000E_RX0_MSG_ID << 0)    | BIT(3)  | \
-                                     (E1000E_TX0_MSG_ID << 8)    | BIT(11) | \
-                                     (E1000E_OTHER_MSG_ID << 16) | BIT(19) | \
-                                     BIT(31))
-
-#define E1000E_RING_LEN             (0x1000)
-#define E1000E_TXD_LEN              (16)
-#define E1000E_RXD_LEN              (16)
-
-#define E1000E_TDBAL    (0x3800)
-#define E1000E_TDBAH    (0x3804)
-#define E1000E_TDLEN    (0x3808)
-#define E1000E_TDH      (0x3810)
-#define E1000E_TDT      (0x3818)
-
-#define E1000E_RDBAL    (0x2800)
-#define E1000E_RDBAH    (0x2804)
-#define E1000E_RDLEN    (0x2808)
-#define E1000E_RDH      (0x2810)
-#define E1000E_RDT      (0x2818)
-
-typedef struct e1000e_device {
-    QPCIDevice *pci_dev;
-    QPCIBar mac_regs;
-
-    uint64_t tx_ring;
-    uint64_t rx_ring;
-} e1000e_device;
-
-static int test_sockets[2];
-static QGuestAllocator test_alloc;
-static QPCIBus *test_bus;
-
-static void e1000e_pci_foreach_callback(QPCIDevice *dev, int devfn, void *data)
-{
-    QPCIDevice **res = data;
-
-    g_assert_null(*res);
-    *res = dev;
-}
-
-static QPCIDevice *e1000e_device_find(QPCIBus *bus)
-{
-    static const int e1000e_vendor_id = 0x8086;
-    static const int e1000e_dev_id = 0x10D3;
-
-    QPCIDevice *e1000e_dev = NULL;
-
-    qpci_device_foreach(bus, e1000e_vendor_id, e1000e_dev_id,
-        e1000e_pci_foreach_callback, &e1000e_dev);
-
-    g_assert_nonnull(e1000e_dev);
-
-    return e1000e_dev;
-}
-
-static void e1000e_macreg_write(e1000e_device *d, uint32_t reg, uint32_t val)
-{
-    qpci_io_writel(d->pci_dev, d->mac_regs, reg, val);
-}
-
-static uint32_t e1000e_macreg_read(e1000e_device *d, uint32_t reg)
-{
-    return qpci_io_readl(d->pci_dev, d->mac_regs, reg);
-}
-
-static void e1000e_device_init(QPCIBus *bus, e1000e_device *d)
-{
-    uint32_t val;
-
-    d->pci_dev = e1000e_device_find(bus);
-
-    /* Enable the device */
-    qpci_device_enable(d->pci_dev);
-
-    /* Map BAR0 (mac registers) */
-    d->mac_regs = qpci_iomap(d->pci_dev, 0, NULL);
-
-    /* Reset the device */
-    val = e1000e_macreg_read(d, E1000E_CTRL);
-    e1000e_macreg_write(d, E1000E_CTRL, val | E1000E_CTRL_RESET);
-
-    /* Enable and configure MSI-X */
-    qpci_msix_enable(d->pci_dev);
-    e1000e_macreg_write(d, E1000E_IVAR, E1000E_IVAR_TEST_CFG);
-
-    /* Check the device status - link and speed */
-    val = e1000e_macreg_read(d, E1000E_STATUS);
-    g_assert_cmphex(val & (E1000E_STATUS_LU | E1000E_STATUS_ASDV1000),
-        ==, E1000E_STATUS_LU | E1000E_STATUS_ASDV1000);
-
-    /* Initialize TX/RX logic */
-    e1000e_macreg_write(d, E1000E_RCTL, 0);
-    e1000e_macreg_write(d, E1000E_TCTL, 0);
-
-    /* Notify the device that the driver is ready */
-    val = e1000e_macreg_read(d, E1000E_CTRL_EXT);
-    e1000e_macreg_write(d, E1000E_CTRL_EXT,
-        val | E1000E_CTRL_EXT_DRV_LOAD | E1000E_CTRL_EXT_TXLSFLOW);
-
-    /* Allocate and setup TX ring */
-    d->tx_ring = guest_alloc(&test_alloc, E1000E_RING_LEN);
-    g_assert(d->tx_ring != 0);
-
-    e1000e_macreg_write(d, E1000E_TDBAL, (uint32_t) d->tx_ring);
-    e1000e_macreg_write(d, E1000E_TDBAH, (uint32_t) (d->tx_ring >> 32));
-    e1000e_macreg_write(d, E1000E_TDLEN, E1000E_RING_LEN);
-    e1000e_macreg_write(d, E1000E_TDT, 0);
-    e1000e_macreg_write(d, E1000E_TDH, 0);
-
-    /* Enable transmit */
-    e1000e_macreg_write(d, E1000E_TCTL, E1000E_TCTL_EN);
-
-    /* Allocate and setup RX ring */
-    d->rx_ring = guest_alloc(&test_alloc, E1000E_RING_LEN);
-    g_assert(d->rx_ring != 0);
-
-    e1000e_macreg_write(d, E1000E_RDBAL, (uint32_t)d->rx_ring);
-    e1000e_macreg_write(d, E1000E_RDBAH, (uint32_t)(d->rx_ring >> 32));
-    e1000e_macreg_write(d, E1000E_RDLEN, E1000E_RING_LEN);
-    e1000e_macreg_write(d, E1000E_RDT, 0);
-    e1000e_macreg_write(d, E1000E_RDH, 0);
-
-    /* Enable receive */
-    e1000e_macreg_write(d, E1000E_RFCTL, E1000E_RFCTL_EXTEN);
-    e1000e_macreg_write(d, E1000E_RCTL, E1000E_RCTL_EN  |
-                                        E1000E_RCTL_UPE |
-                                        E1000E_RCTL_MPE);
-
-    /* Enable all interrupts */
-    e1000e_macreg_write(d, E1000E_IMS, 0xFFFFFFFF);
-}
-
-static void e1000e_tx_ring_push(e1000e_device *d, void *descr)
-{
-    uint32_t tail = e1000e_macreg_read(d, E1000E_TDT);
-    uint32_t len = e1000e_macreg_read(d, E1000E_TDLEN) / E1000E_TXD_LEN;
-
-    memwrite(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN);
-    e1000e_macreg_write(d, E1000E_TDT, (tail + 1) % len);
-
-    /* Read WB data for the packet transmitted */
-    memread(d->tx_ring + tail * E1000E_TXD_LEN, descr, E1000E_TXD_LEN);
-}
-
-static void e1000e_rx_ring_push(e1000e_device *d, void *descr)
-{
-    uint32_t tail = e1000e_macreg_read(d, E1000E_RDT);
-    uint32_t len = e1000e_macreg_read(d, E1000E_RDLEN) / E1000E_RXD_LEN;
-
-    memwrite(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN);
-    e1000e_macreg_write(d, E1000E_RDT, (tail + 1) % len);
-
-    /* Read WB data for the packet received */
-    memread(d->rx_ring + tail * E1000E_RXD_LEN, descr, E1000E_RXD_LEN);
-}
-
-static void e1000e_wait_isr(e1000e_device *d, uint16_t msg_id)
-{
-    guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-
-    do {
-        if (qpci_msix_pending(d->pci_dev, msg_id)) {
-            return;
-        }
-        clock_step(10000);
-    } while (g_get_monotonic_time() < end_time);
-
-    g_error("Timeout expired");
-}
-
-static void e1000e_send_verify(e1000e_device *d)
+static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
 {
     struct {
         uint64_t buffer_addr;
@@ -268,7 +67,7 @@ static void e1000e_send_verify(e1000e_device *d)
     uint32_t recv_len;
 
     /* Prepare test data buffer */
-    uint64_t data = guest_alloc(&test_alloc, data_len);
+    uint64_t data = guest_alloc(alloc, data_len);
     memwrite(data, "TEST", 5);
 
     /* Prepare TX descriptor */
@@ -296,10 +95,10 @@ static void e1000e_send_verify(e1000e_device *d)
     g_assert_cmpstr(buffer, == , "TEST");
 
     /* Free test data buffer */
-    guest_free(&test_alloc, data);
+    guest_free(alloc, data);
 }
 
-static void e1000e_receive_verify(e1000e_device *d)
+static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
 {
     union {
         struct {
@@ -348,7 +147,7 @@ static void e1000e_receive_verify(e1000e_device *d)
     g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
 
     /* Prepare test data buffer */
-    uint64_t data = guest_alloc(&test_alloc, data_len);
+    uint64_t data = guest_alloc(alloc, data_len);
 
     /* Prepare RX descriptor */
     memset(&descr, 0, sizeof(descr));
@@ -369,109 +168,108 @@ static void e1000e_receive_verify(e1000e_device *d)
     g_assert_cmpstr(buffer, == , "TEST");
 
     /* Free test data buffer */
-    guest_free(&test_alloc, data);
-}
-
-static void e1000e_device_clear(QPCIBus *bus, e1000e_device *d)
-{
-    qpci_iounmap(d->pci_dev, d->mac_regs);
-    qpci_msix_disable(d->pci_dev);
+    guest_free(alloc, data);
 }
 
-static void data_test_init(e1000e_device *d)
+static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
 {
-    char *cmdline;
-
-    int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
-    g_assert_cmpint(ret, != , -1);
-
-    cmdline = g_strdup_printf("-netdev socket,fd=%d,id=hs0 "
-                              "-device e1000e,netdev=hs0", test_sockets[1]);
-    g_assert_nonnull(cmdline);
-
-    qtest_start(cmdline);
-    g_free(cmdline);
-
-    pc_alloc_init(&test_alloc, global_qtest, 0);
-    test_bus = qpci_new_pc(global_qtest, &test_alloc);
-    g_assert_nonnull(test_bus);
-
-    e1000e_device_init(test_bus, d);
+    /* init does nothing */
 }
 
-static void data_test_clear(e1000e_device *d)
+static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
 {
-    e1000e_device_clear(test_bus, d);
-    close(test_sockets[0]);
-    alloc_destroy(&test_alloc);
-    g_free(d->pci_dev);
-    qpci_free_pc(test_bus);
-    qtest_end();
-}
-
-static void test_e1000e_init(gconstpointer data)
-{
-    e1000e_device d;
-
-    data_test_init(&d);
-    data_test_clear(&d);
-}
-
-static void test_e1000e_tx(gconstpointer data)
-{
-    e1000e_device d;
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
 
-    data_test_init(&d);
-    e1000e_send_verify(&d);
-    data_test_clear(&d);
+    e1000e_send_verify(d, data, alloc);
 }
 
-static void test_e1000e_rx(gconstpointer data)
+static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
 {
-    e1000e_device d;
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
 
-    data_test_init(&d);
-    e1000e_receive_verify(&d);
-    data_test_clear(&d);
+    e1000e_receive_verify(d, data, alloc);
 }
 
-static void test_e1000e_multiple_transfers(gconstpointer data)
+static void test_e1000e_multiple_transfers(void *obj, void *data,
+                                           QGuestAllocator *alloc)
 {
     static const long iterations = 4 * 1024;
     long i;
 
-    e1000e_device d;
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
 
-    data_test_init(&d);
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
 
     for (i = 0; i < iterations; i++) {
-        e1000e_send_verify(&d);
-        e1000e_receive_verify(&d);
+        e1000e_send_verify(d, data, alloc);
+        e1000e_receive_verify(d, data, alloc);
     }
 
-    data_test_clear(&d);
 }
 
-static void test_e1000e_hotplug(gconstpointer data)
+static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
 {
-    qtest_start("-device e1000e");
-
     qtest_qmp_device_add("e1000e", "e1000e_net", "{'addr': '0x06'}");
     qpci_unplug_acpi_device_test("e1000e_net", 0x06);
+}
+
+static void data_test_clear(void *sockets)
+{
+    int *test_sockets = sockets;
 
-    qtest_end();
+    close(test_sockets[0]);
+    qos_invalidate_command_line();
+    close(test_sockets[1]);
+    g_free(test_sockets);
 }
 
-int main(int argc, char **argv)
+static void *data_test_init(GString *cmd_line, void *arg)
 {
-    g_test_init(&argc, &argv, NULL);
+    int *test_sockets = g_new(int, 2);
+    int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
+    g_assert_cmpint(ret, != , -1);
 
-    qtest_add_data_func("e1000e/init", NULL, test_e1000e_init);
-    qtest_add_data_func("e1000e/tx", NULL, test_e1000e_tx);
-    qtest_add_data_func("e1000e/rx", NULL, test_e1000e_rx);
-    qtest_add_data_func("e1000e/multiple_transfers", NULL,
-        test_e1000e_multiple_transfers);
-    qtest_add_data_func("e1000e/hotplug", NULL, test_e1000e_hotplug);
+    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
+			   test_sockets[1]);
 
-    return g_test_run();
+    g_test_queue_destroy(data_test_clear, test_sockets);
+    return test_sockets;
 }
+
+static void register_e1000e_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = data_test_init,
+    };
+
+    qos_add_test("init", "e1000e", test_e1000e_init, &opts);
+    qos_add_test("tx", "e1000e", test_e1000e_tx, &opts);
+    qos_add_test("rx", "e1000e", test_e1000e_rx, &opts);
+    qos_add_test("multiple_transfers", "e1000e",
+                      test_e1000e_multiple_transfers, &opts);
+    qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts);
+}
+
+libqos_init(register_e1000e_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 35/71] tests/libqos: virtio-pci driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (33 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 34/71] qos-test: e1000e test node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 36/71] tests/libqos: remove global_qtest from virtio endianness checks Paolo Bonzini
                   ` (38 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add QOSGraphObject to QVirtioPCIDevice structure, with a basic
constructor. virtio-pci is not present in qgraph, since it
will be used as starting point by its subclasses (virtio-*-pci)

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include    |   1 +
 tests/libqos/virtio-pci.c | 106 ++++++++++++++++++++++++++++++++++------------
 tests/libqos/virtio-pci.h |  14 ++++++
 tests/virtio-blk-test.c   |   6 +++
 4 files changed, 99 insertions(+), 28 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index dc40b10..1d4e147 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -676,6 +676,7 @@ qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
 qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/sdhci.o
+qos-test-obj-y += $(libqos-virtio-obj-y)
 
 # Machines
 qos-test-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 550dede..6bcdbbb 100644
--- a/tests/libqos/virtio-pci.c
+++ b/tests/libqos/virtio-pci.c
@@ -15,12 +15,26 @@
 #include "libqos/pci-pc.h"
 #include "libqos/malloc.h"
 #include "libqos/malloc-pc.h"
+#include "libqos/qgraph.h"
 #include "standard-headers/linux/virtio_ring.h"
 #include "standard-headers/linux/virtio_pci.h"
 
 #include "hw/pci/pci.h"
 #include "hw/pci/pci_regs.h"
 
+/* virtio-pci is a superclass of all virtio-xxx-pci devices;
+ * the relation between virtio-pci and virtio-xxx-pci is implicit,
+ * and therefore virtio-pci does not produce virtio and is not
+ * reached by any edge, not even as a "contains" edge.
+ * In facts, every device is a QVirtioPCIDevice with
+ * additional fields, since every one has its own
+ * number of queues and various attributes.
+ * Virtio-pci provides default functions to start the
+ * hw and destroy the object, and nodes that want to
+ * override them should always remember to call the
+ * original qvirtio_pci_destructor and qvirtio_pci_start_hw.
+ */
+
 typedef struct QVirtioPCIForeachData {
     void (*func)(QVirtioDevice *d, void *data);
     uint16_t device_type;
@@ -32,36 +46,36 @@ typedef struct QVirtioPCIForeachData {
 void qvirtio_pci_device_free(QVirtioPCIDevice *dev)
 {
     g_free(dev->pdev);
-    g_free(dev);
 }
 
-static QVirtioPCIDevice *qpcidevice_to_qvirtiodevice(QPCIDevice *pdev)
+static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_dev)
 {
-    QVirtioPCIDevice *vpcidev;
-    vpcidev = g_malloc0(sizeof(*vpcidev));
+    dev->pdev = pci_dev;
+    dev->vdev.device_type = qpci_config_readw(pci_dev, PCI_SUBSYSTEM_ID);
 
-    if (pdev) {
-        vpcidev->pdev = pdev;
-        vpcidev->vdev.device_type =
-                            qpci_config_readw(vpcidev->pdev, PCI_SUBSYSTEM_ID);
-    }
+    dev->config_msix_entry = -1;
 
-    vpcidev->config_msix_entry = -1;
+    dev->vdev.bus = &qvirtio_pci;
 
-    return vpcidev;
+    /* each virtio-xxx-pci device should override at least this function */
+    dev->obj.get_driver = NULL;
+    dev->obj.start_hw = qvirtio_pci_start_hw;
+    dev->obj.destructor = qvirtio_pci_destructor;
 }
 
 static void qvirtio_pci_foreach_callback(
                         QPCIDevice *dev, int devfn, void *data)
 {
     QVirtioPCIForeachData *d = data;
-    QVirtioPCIDevice *vpcidev = qpcidevice_to_qvirtiodevice(dev);
+    QVirtioPCIDevice *vpcidev = g_new0(QVirtioPCIDevice, 1);
 
+    qvirtio_pci_init_from_pcidev(vpcidev, dev);
     if (vpcidev->vdev.device_type == d->device_type &&
         (!d->has_slot || vpcidev->pdev->devfn == d->slot << 3)) {
         d->func(&vpcidev->vdev, d->user_data);
     } else {
         qvirtio_pci_device_free(vpcidev);
+        g_free(vpcidev);
     }
 }
 
@@ -69,14 +83,14 @@ static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data)
 {
     QVirtioPCIDevice **vpcidev = data;
     assert(!*vpcidev);
-    *vpcidev = (QVirtioPCIDevice *)d;
+    *vpcidev = container_of(d, QVirtioPCIDevice, vdev);
 }
 
 #define CONFIG_BASE(dev) (VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled))
 
 static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     return qpci_io_readb(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
 }
 
@@ -90,7 +104,7 @@ static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off)
 
 static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     uint16_t value;
 
     value = qpci_io_readw(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
@@ -102,7 +116,7 @@ static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t off)
 
 static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     uint32_t value;
 
     value = qpci_io_readl(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
@@ -114,7 +128,7 @@ static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t off)
 
 static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     uint64_t val;
 
     val = qpci_io_readq(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
@@ -127,37 +141,37 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off)
 
 static uint32_t qvirtio_pci_get_features(QVirtioDevice *d)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void qvirtio_pci_set_features(QVirtioDevice *d, uint32_t features)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
 static uint32_t qvirtio_pci_get_guest_features(QVirtioDevice *d)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES);
 }
 
 static uint8_t qvirtio_pci_get_status(QVirtioDevice *d)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS);
 }
 
 static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS, status);
 }
 
 static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     QVirtQueuePCI *vqpci = (QVirtQueuePCI *)vq;
     uint32_t data;
 
@@ -182,7 +196,7 @@ static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
 
 static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     uint32_t data;
 
     if (dev->pdev->msix_enabled) {
@@ -206,19 +220,19 @@ static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d)
 
 static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_SEL, index);
 }
 
 static uint16_t qvirtio_pci_get_queue_size(QVirtioDevice *d)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     return qpci_io_readw(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NUM);
 }
 
 static void qvirtio_pci_set_queue_address(QVirtioDevice *d, uint32_t pfn)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_PFN, pfn);
 }
 
@@ -270,7 +284,7 @@ static void qvirtio_pci_virtqueue_cleanup(QVirtQueue *vq,
 
 static void qvirtio_pci_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
 {
-    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
+    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     qpci_io_writew(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NOTIFY, vq->index);
 }
 
@@ -294,6 +308,7 @@ const QVirtioBus qvirtio_pci = {
     .virtqueue_kick = qvirtio_pci_virtqueue_kick,
 };
 
+/* TODO: delete this once qgraph is completed */
 static void qvirtio_pci_foreach(QPCIBus *bus, uint16_t device_type,
                 bool has_slot, int slot,
                 void (*func)(QVirtioDevice *d, void *data), void *data)
@@ -416,3 +431,38 @@ void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d,
     vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR);
     g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR);
 }
+
+void qvirtio_pci_destructor(QOSGraphObject *obj)
+{
+    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)obj;
+    qvirtio_pci_device_disable(dev);
+    qvirtio_pci_device_free(dev);
+}
+
+void qvirtio_pci_start_hw(QOSGraphObject *obj)
+{
+    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)obj;
+    qvirtio_pci_device_enable(dev);
+    qvirtio_start_device(&dev->vdev);
+}
+
+void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr)
+{
+    QPCIDevice *pci_dev = qpci_device_find(bus, addr->devfn);
+    g_assert_nonnull(pci_dev);
+    qvirtio_pci_init_from_pcidev(dev, pci_dev);
+}
+
+QVirtioPCIDevice *virtio_pci_new(QPCIBus *bus, QPCIAddress * addr)
+{
+    QVirtioPCIDevice *dev;
+    QPCIDevice *pci_dev = qpci_device_find(bus, addr->devfn);
+    if (!pci_dev) {
+        return NULL;
+    }
+
+    dev = g_new0(QVirtioPCIDevice, 1);
+    qvirtio_pci_init_from_pcidev(dev, pci_dev);
+    dev->obj.free = g_free;
+    return dev;
+}
diff --git a/tests/libqos/virtio-pci.h b/tests/libqos/virtio-pci.h
index 6ef1909..5631352 100644
--- a/tests/libqos/virtio-pci.h
+++ b/tests/libqos/virtio-pci.h
@@ -12,8 +12,10 @@
 
 #include "libqos/virtio.h"
 #include "libqos/pci.h"
+#include "libqos/qgraph.h"
 
 typedef struct QVirtioPCIDevice {
+    QOSGraphObject obj;
     QVirtioDevice vdev;
     QPCIDevice *pdev;
     QPCIBar bar;
@@ -31,11 +33,23 @@ typedef struct QVirtQueuePCI {
 
 extern const QVirtioBus qvirtio_pci;
 
+void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr);
+QVirtioPCIDevice *virtio_pci_new(QPCIBus *bus, QPCIAddress * addr);
 QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type);
 QVirtioPCIDevice *qvirtio_pci_device_find_slot(QPCIBus *bus,
                                                uint16_t device_type, int slot);
 void qvirtio_pci_device_free(QVirtioPCIDevice *dev);
 
+/* virtio-pci object functions available for subclasses that
+ * override the original start_hw and destroy
+ * function. All virtio-xxx-pci subclass that override must
+ * take care of calling these two functions in the respective
+ * places
+ */
+void qvirtio_pci_destructor(QOSGraphObject *obj);
+void qvirtio_pci_start_hw(QOSGraphObject *obj);
+
+
 void qvirtio_pci_device_enable(QVirtioPCIDevice *d);
 void qvirtio_pci_device_disable(QVirtioPCIDevice *d);
 
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 77457f7..a9dcbe2 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -299,6 +299,7 @@ static void pci_basic(void)
     qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
+    g_free(dev);
     qtest_shutdown(qs);
 }
 
@@ -393,6 +394,7 @@ static void pci_indirect(void)
     qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
+    g_free(dev);
     qtest_shutdown(qs);
 }
 
@@ -422,6 +424,7 @@ static void pci_config(void)
 
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
+    g_free(dev);
 
     qtest_shutdown(qs);
 }
@@ -530,6 +533,7 @@ static void pci_msix(void)
     qpci_msix_disable(dev->pdev);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
+    g_free(dev);
     qtest_shutdown(qs);
 }
 
@@ -653,6 +657,7 @@ static void pci_idx(void)
     qpci_msix_disable(dev->pdev);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
+    g_free(dev);
     qtest_shutdown(qs);
 }
 
@@ -673,6 +678,7 @@ static void pci_hotplug(void)
     g_assert(dev);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(dev);
+    g_free(dev);
 
     /* unplug secondary disk */
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 36/71] tests/libqos: remove global_qtest from virtio endianness checks
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (34 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 35/71] tests/libqos: virtio-pci driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 37/71] tests/libqos: virtio-mmio driver and interface nodes Paolo Bonzini
                   ` (37 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

This is needed to support migration tests with qgraph.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/libqos/virtio-pci.c | 11 ++++++++++-
 tests/libqos/virtio.c     |  5 +++++
 tests/libqos/virtio.h     |  8 ++------
 3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 6bcdbbb..0b58b74 100644
--- a/tests/libqos/virtio-pci.c
+++ b/tests/libqos/virtio-pci.c
@@ -43,6 +43,14 @@ typedef struct QVirtioPCIForeachData {
     void *user_data;
 } QVirtioPCIForeachData;
 
+static inline bool qvirtio_pci_is_big_endian(QVirtioPCIDevice *dev)
+{
+    QPCIBus *bus = dev->pdev->bus;
+
+    /* FIXME: virtio 1.0 is always little-endian */
+    return qtest_big_endian(bus->qts);
+}
+
 void qvirtio_pci_device_free(QVirtioPCIDevice *dev)
 {
     g_free(dev->pdev);
@@ -56,6 +64,7 @@ static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_
     dev->config_msix_entry = -1;
 
     dev->vdev.bus = &qvirtio_pci;
+    dev->vdev.big_endian = qvirtio_pci_is_big_endian(dev);
 
     /* each virtio-xxx-pci device should override at least this function */
     dev->obj.get_driver = NULL;
@@ -99,7 +108,7 @@ static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off)
  * so with a big-endian guest the order has been reversed,
  * reverse it again
  * virtio-1.0 is always little-endian, like PCI, but this
- * case will be managed inside qvirtio_is_big_endian()
+ * case will be managed inside qvirtio_pci_is_big_endian()
  */
 
 static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t off)
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index c1ff020..5a62950 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -372,3 +372,8 @@ void qvirtio_start_device(QVirtioDevice *vdev)
     qvirtio_set_acknowledge(vdev);
     qvirtio_set_driver(vdev);
 }
+
+bool qvirtio_is_big_endian(QVirtioDevice *d)
+{
+    return d->big_endian;
+}
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 2c68668..7f0f9dd 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -21,6 +21,7 @@ typedef struct QVirtioDevice {
     const QVirtioBus *bus;
     /* Device type */
     uint16_t device_type;
+    bool big_endian;
 } QVirtioDevice;
 
 typedef struct QVirtQueue {
@@ -90,12 +91,6 @@ struct QVirtioBus {
     void (*virtqueue_kick)(QVirtioDevice *d, QVirtQueue *vq);
 };
 
-static inline bool qvirtio_is_big_endian(QVirtioDevice *d)
-{
-    /* FIXME: virtio 1.0 is always little-endian */
-    return qtest_big_endian(global_qtest);
-}
-
 static inline uint32_t qvring_size(uint32_t num, uint32_t align)
 {
     return ((sizeof(struct vring_desc) * num + sizeof(uint16_t) * (3 + num)
@@ -109,6 +104,7 @@ uint32_t qvirtio_config_readl(QVirtioDevice *d, uint64_t addr);
 uint64_t qvirtio_config_readq(QVirtioDevice *d, uint64_t addr);
 uint32_t qvirtio_get_features(QVirtioDevice *d);
 void qvirtio_set_features(QVirtioDevice *d, uint32_t features);
+bool qvirtio_is_big_endian(QVirtioDevice *d);
 
 void qvirtio_reset(QVirtioDevice *d);
 void qvirtio_set_acknowledge(QVirtioDevice *d);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 37/71] tests/libqos: virtio-mmio driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (35 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 36/71] tests/libqos: remove global_qtest from virtio endianness checks Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 38/71] tests/libqos: arm/virt machine node Paolo Bonzini
                   ` (36 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add virtio-mmio node in qgraph framework.
virtio-mmio produces virtio-bus, the interface consumed by all virtio-*-device
nodes.

Being a memory-mapped device, it doesn't have to provide a constructor
to qgraph, since it's always "contained" inside some other nodes.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/libqos/virtio-mmio.c | 116 +++++++++++++++++++++++++++------------------
 tests/libqos/virtio-mmio.h |   6 ++-
 tests/virtio-blk-test.c    |   3 +-
 3 files changed, 77 insertions(+), 48 deletions(-)

diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c
index 7aa8383..b46621e 100644
--- a/tests/libqos/virtio-mmio.c
+++ b/tests/libqos/virtio-mmio.c
@@ -12,74 +12,74 @@
 #include "libqos/virtio.h"
 #include "libqos/virtio-mmio.h"
 #include "libqos/malloc.h"
-#include "libqos/malloc-generic.h"
+#include "libqos/qgraph.h"
 #include "standard-headers/linux/virtio_ring.h"
 
 static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    return readb(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    return qtest_readb(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    return readw(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    return qtest_readw(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    return readl(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    return qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    return readq(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    return qtest_readq(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint32_t qvirtio_mmio_get_features(QVirtioDevice *d)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    writel(dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0);
-    return readl(dev->addr + QVIRTIO_MMIO_HOST_FEATURES);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0);
+    return qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_HOST_FEATURES);
 }
 
 static void qvirtio_mmio_set_features(QVirtioDevice *d, uint32_t features)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     dev->features = features;
-    writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 0);
-    writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, features);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 0);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, features);
 }
 
 static uint32_t qvirtio_mmio_get_guest_features(QVirtioDevice *d)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     return dev->features;
 }
 
 static uint8_t qvirtio_mmio_get_status(QVirtioDevice *d)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    return (uint8_t)readl(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    return (uint8_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS);
 }
 
 static void qvirtio_mmio_set_status(QVirtioDevice *d, uint8_t status)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    writel(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status);
 }
 
 static bool qvirtio_mmio_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     uint32_t isr;
 
-    isr = readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 1;
+    isr = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 1;
     if (isr != 0) {
-        writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 1);
+        qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 1);
         return true;
     }
 
@@ -88,12 +88,12 @@ static bool qvirtio_mmio_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
 
 static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     uint32_t isr;
 
-    isr = readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 2;
+    isr = qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 2;
     if (isr != 0) {
-        writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 2);
+        qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 2);
         return true;
     }
 
@@ -102,34 +102,34 @@ static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d)
 
 static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    writel(dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index);
 
-    g_assert_cmphex(readl(dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0);
+    g_assert_cmphex(qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0);
 }
 
 static uint16_t qvirtio_mmio_get_queue_size(QVirtioDevice *d)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    return (uint16_t)readl(dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    return (uint16_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX);
 }
 
 static void qvirtio_mmio_set_queue_address(QVirtioDevice *d, uint32_t pfn)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    writel(dev->addr + QVIRTIO_MMIO_QUEUE_PFN, pfn);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_PFN, pfn);
 }
 
 static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d,
                                         QGuestAllocator *alloc, uint16_t index)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     QVirtQueue *vq;
     uint64_t addr;
 
     vq = g_malloc0(sizeof(*vq));
     qvirtio_mmio_queue_select(d, index);
-    writel(dev->addr + QVIRTIO_MMIO_QUEUE_ALIGN, dev->page_size);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_ALIGN, dev->page_size);
 
     vq->index = index;
     vq->size = qvirtio_mmio_get_queue_size(d);
@@ -139,7 +139,7 @@ static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d,
     vq->indirect = (dev->features & (1u << VIRTIO_RING_F_INDIRECT_DESC)) != 0;
     vq->event = (dev->features & (1u << VIRTIO_RING_F_EVENT_IDX)) != 0;
 
-    writel(dev->addr + QVIRTIO_MMIO_QUEUE_NUM, vq->size);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NUM, vq->size);
 
     /* Check different than 0 */
     g_assert_cmpint(vq->size, !=, 0);
@@ -163,8 +163,8 @@ static void qvirtio_mmio_virtqueue_cleanup(QVirtQueue *vq,
 
 static void qvirtio_mmio_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
-    writel(dev->addr + QVIRTIO_MMIO_QUEUE_NOTIFY, vq->index);
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NOTIFY, vq->index);
 }
 
 const QVirtioBus qvirtio_mmio = {
@@ -187,21 +187,45 @@ const QVirtioBus qvirtio_mmio = {
     .virtqueue_kick = qvirtio_mmio_virtqueue_kick,
 };
 
-QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size)
+static void *qvirtio_mmio_get_driver(void *obj, const char *interface)
 {
-    QVirtioMMIODevice *dev;
-    uint32_t magic;
-    dev = g_malloc0(sizeof(*dev));
+    QVirtioMMIODevice *virtio_mmio = obj;
+    if (!g_strcmp0(interface, "virtio-bus")) {
+        return &virtio_mmio->vdev;
+    }
+    fprintf(stderr, "%s not present in virtio-mmio\n", interface);
+    g_assert_not_reached();
+}
+
+static void qvirtio_mmio_start_hw(QOSGraphObject *obj)
+{
+    QVirtioMMIODevice *dev = (QVirtioMMIODevice *) obj;
+    qvirtio_start_device(&dev->vdev);
+}
 
-    magic = readl(addr + QVIRTIO_MMIO_MAGIC_VALUE);
+void qvirtio_mmio_init_device(QVirtioMMIODevice *dev, QTestState *qts,
+			      uint64_t addr, uint32_t page_size)
+{
+    uint32_t magic;
+    magic = qtest_readl(qts, addr + QVIRTIO_MMIO_MAGIC_VALUE);
     g_assert(magic == ('v' | 'i' << 8 | 'r' << 16 | 't' << 24));
 
+    dev->qts = qts;
     dev->addr = addr;
     dev->page_size = page_size;
-    dev->vdev.device_type = readl(addr + QVIRTIO_MMIO_DEVICE_ID);
+    dev->vdev.device_type = qtest_readl(qts, addr + QVIRTIO_MMIO_DEVICE_ID);
     dev->vdev.bus = &qvirtio_mmio;
 
-    writel(addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size);
+    qtest_writel(qts, addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size);
+
+    dev->obj.get_driver = qvirtio_mmio_get_driver;
+    dev->obj.start_hw = qvirtio_mmio_start_hw;
+}
 
-    return dev;
+static void virtio_mmio_register_nodes(void)
+{
+    qos_node_create_driver("virtio-mmio", NULL);
+    qos_node_produces("virtio-mmio", "virtio-bus");
 }
+
+libqos_init(virtio_mmio_register_nodes);
diff --git a/tests/libqos/virtio-mmio.h b/tests/libqos/virtio-mmio.h
index e3e52b9..2b4198f 100644
--- a/tests/libqos/virtio-mmio.h
+++ b/tests/libqos/virtio-mmio.h
@@ -11,6 +11,7 @@
 #define LIBQOS_VIRTIO_MMIO_H
 
 #include "libqos/virtio.h"
+#include "libqos/qgraph.h"
 
 #define QVIRTIO_MMIO_MAGIC_VALUE        0x000
 #define QVIRTIO_MMIO_VERSION            0x004
@@ -33,7 +34,9 @@
 #define QVIRTIO_MMIO_DEVICE_SPECIFIC    0x100
 
 typedef struct QVirtioMMIODevice {
+    QOSGraphObject obj;
     QVirtioDevice vdev;
+    QTestState *qts;
     uint64_t addr;
     uint32_t page_size;
     uint32_t features; /* As it cannot be read later, save it */
@@ -41,6 +44,7 @@ typedef struct QVirtioMMIODevice {
 
 extern const QVirtioBus qvirtio_mmio;
 
-QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size);
+void qvirtio_mmio_init_device(QVirtioMMIODevice *dev, QTestState *qts,
+			      uint64_t addr, uint32_t page_size);
 
 #endif
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index a9dcbe2..0a13a5a 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -721,7 +721,8 @@ static void mmio_basic(void)
 
     arm_test_start();
 
-    dev = qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
+    dev = g_malloc0(sizeof(QVirtioMMIODevice));
+    qvirtio_mmio_init_device(dev, global_qtest, MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
     g_assert(dev != NULL);
     g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
 
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 38/71] tests/libqos: arm/virt machine node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (36 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 37/71] tests/libqos: virtio-mmio driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 39/71] tests/qgraph: add generic virtio testcases Paolo Bonzini
                   ` (35 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add arm/virt machine to the graph. This machine contains virtio-mmio, so
its constructor must take care of setting it properly when called.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include          |  1 +
 tests/libqos/arm-virt-machine.c | 90 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)
 create mode 100644 tests/libqos/arm-virt-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 1d4e147..4545232 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -683,6 +683,7 @@ qos-test-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
 qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
 qos-test-obj-y += tests/libqos/arm-sabrelite-machine.o
 qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
+qos-test-obj-y += tests/libqos/arm-virt-machine.o
 qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
 qos-test-obj-y += tests/libqos/ppc64_pseries-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
diff --git a/tests/libqos/arm-virt-machine.c b/tests/libqos/arm-virt-machine.c
new file mode 100644
index 0000000..05aa0b2
--- /dev/null
+++ b/tests/libqos/arm-virt-machine.c
@@ -0,0 +1,90 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/malloc.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-mmio.h"
+
+#define ARM_PAGE_SIZE               4096
+#define VIRTIO_MMIO_BASE_ADDR       0x0A003E00
+#define ARM_VIRT_RAM_ADDR           0x40000000
+#define ARM_VIRT_RAM_SIZE           0x20000000
+#define VIRTIO_MMIO_SIZE            0x00000200
+
+typedef struct QVirtMachine QVirtMachine;
+
+struct QVirtMachine {
+    QOSGraphObject obj;
+    QGuestAllocator alloc;
+    QVirtioMMIODevice virtio_mmio;
+};
+
+static void virt_destructor(QOSGraphObject *obj)
+{
+    QVirtMachine *machine = (QVirtMachine *) obj;
+    alloc_destroy(&machine->alloc);
+}
+
+static void *virt_get_driver(void *object, const char *interface)
+{
+    QVirtMachine *machine = object;
+    if (!g_strcmp0(interface, "memory")) {
+        return &machine->alloc;
+    }
+
+    fprintf(stderr, "%s not present in arm/virtio\n", interface);
+    g_assert_not_reached();
+}
+
+static QOSGraphObject *virt_get_device(void *obj, const char *device)
+{
+    QVirtMachine *machine = obj;
+    if (!g_strcmp0(device, "virtio-mmio")) {
+        return &machine->virtio_mmio.obj;
+    }
+
+    fprintf(stderr, "%s not present in arm/virtio\n", device);
+    g_assert_not_reached();
+}
+
+static void *qos_create_machine_arm_virt(QTestState *qts)
+{
+    QVirtMachine *machine = g_new0(QVirtMachine, 1);
+
+    alloc_init(&machine->alloc, 0,
+	       ARM_VIRT_RAM_ADDR,
+	       ARM_VIRT_RAM_ADDR + ARM_VIRT_RAM_SIZE,
+	       ARM_PAGE_SIZE);
+    qvirtio_mmio_init_device(&machine->virtio_mmio, qts, VIRTIO_MMIO_BASE_ADDR,
+                             VIRTIO_MMIO_SIZE);
+
+    machine->obj.get_device = virt_get_device;
+    machine->obj.get_driver = virt_get_driver;
+    machine->obj.destructor = virt_destructor;
+    return machine;
+}
+
+static void virtio_mmio_register_nodes(void)
+{
+    qos_node_create_machine("arm/virt", qos_create_machine_arm_virt);
+    qos_node_contains("arm/virt", "virtio-mmio", NULL);
+}
+
+libqos_init(virtio_mmio_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 39/71] tests/qgraph: add generic virtio testcases
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (37 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 38/71] tests/libqos: arm/virt machine node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 40/71] tests/libqos: virtio-serial driver and interface nodes Paolo Bonzini
                   ` (34 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  1 +
 tests/virtio-test.c    | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
 create mode 100644 tests/virtio-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 4545232..9603022 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -692,6 +692,7 @@ qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
+qos-test-obj-y += tests/virtio-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
diff --git a/tests/virtio-test.c b/tests/virtio-test.c
new file mode 100644
index 0000000..804e537
--- /dev/null
+++ b/tests/virtio-test.c
@@ -0,0 +1,25 @@
+/*
+ * QTest testcase for virtio
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * 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/qgraph.h"
+#include "libqos/pci.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void *obj, void *data, QGuestAllocator *alloc)
+{
+}
+
+static void register_virtio_test(void)
+{
+    qos_add_test("nop", "virtio", nop, NULL);
+}
+
+libqos_init(register_virtio_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 40/71] tests/libqos: virtio-serial driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (38 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 39/71] tests/qgraph: add generic virtio testcases Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 41/71] qos-test: virtio-console and virtio-serial test node Paolo Bonzini
                   ` (33 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-serial-pci and virtio-serial-device.
Both nodes produce virtio-serial, but virtio-serial-pci receives
a pci-bus and uses virtio-pci QOSGraphObject and functions,
while virtio-serial-device receives a virtio-bus and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include       |   1 +
 tests/libqos/virtio-serial.c | 110 +++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-serial.h |  39 +++++++++++++++
 3 files changed, 150 insertions(+)
 create mode 100644 tests/libqos/virtio-serial.c
 create mode 100644 tests/libqos/virtio-serial.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 9603022..58f548d 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -677,6 +677,7 @@ qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/sdhci.o
 qos-test-obj-y += $(libqos-virtio-obj-y)
+qos-test-obj-y += tests/libqos/virtio-serial.o
 
 # Machines
 qos-test-obj-y += tests/libqos/aarch64-xlnx-zcu102-machine.o
diff --git a/tests/libqos/virtio-serial.c b/tests/libqos/virtio-serial.c
new file mode 100644
index 0000000..91cedef
--- /dev/null
+++ b/tests/libqos/virtio-serial.c
@@ -0,0 +1,110 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-serial.h"
+
+static void *qvirtio_serial_get_driver(QVirtioSerial *v_serial,
+                                       const char *interface)
+{
+    if (!g_strcmp0(interface, "virtio-serial")) {
+        return v_serial;
+    }
+    if (!g_strcmp0(interface, "virtio")) {
+        return v_serial->vdev;
+    }
+
+    fprintf(stderr, "%s not present in virtio-serial-device\n", interface);
+    g_assert_not_reached();
+}
+
+static void *qvirtio_serial_device_get_driver(void *object,
+                                              const char *interface)
+{
+    QVirtioSerialDevice *v_serial = object;
+    return qvirtio_serial_get_driver(&v_serial->serial, interface);
+}
+
+static void *virtio_serial_device_create(void *virtio_dev,
+                                         QGuestAllocator *t_alloc,
+                                         void *addr)
+{
+    QVirtioSerialDevice *virtio_device = g_new0(QVirtioSerialDevice, 1);
+    QVirtioSerial *interface = &virtio_device->serial;
+
+    interface->vdev = virtio_dev;
+
+    virtio_device->obj.get_driver = qvirtio_serial_device_get_driver;
+
+    return &virtio_device->obj;
+}
+
+/* virtio-serial-pci */
+static void *qvirtio_serial_pci_get_driver(void *object, const char *interface)
+{
+    QVirtioSerialPCI *v_serial = object;
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_serial->pci_vdev.pdev;
+    }
+    return qvirtio_serial_get_driver(&v_serial->serial, interface);
+}
+
+static void *virtio_serial_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
+                                      void *addr)
+{
+    QVirtioSerialPCI *virtio_spci = g_new0(QVirtioSerialPCI, 1);
+    QVirtioSerial *interface = &virtio_spci->serial;
+    QOSGraphObject *obj = &virtio_spci->pci_vdev.obj;
+
+    virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr);
+    interface->vdev = &virtio_spci->pci_vdev.vdev;
+
+    obj->get_driver = qvirtio_serial_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_serial_register_nodes(void)
+{
+   QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(4, 0),
+    };
+
+    QOSGraphEdgeOptions edge_opts = { };
+
+    /* virtio-serial-device */
+    edge_opts.extra_device_opts = "id=vser0";
+    qos_node_create_driver("virtio-serial-device",
+                            virtio_serial_device_create);
+    qos_node_consumes("virtio-serial-device", "virtio-bus", &edge_opts);
+    qos_node_produces("virtio-serial-device", "virtio");
+    qos_node_produces("virtio-serial-device", "virtio-serial");
+
+    /* virtio-serial-pci */
+    edge_opts.extra_device_opts = "id=vser0,addr=04.0";
+    add_qpci_address(&edge_opts, &addr);
+    qos_node_create_driver("virtio-serial-pci", virtio_serial_pci_create);
+    qos_node_consumes("virtio-serial-pci", "pci-bus", &edge_opts);
+    qos_node_produces("virtio-serial-pci", "pci-device");
+    qos_node_produces("virtio-serial-pci", "virtio");
+    qos_node_produces("virtio-serial-pci", "virtio-serial");
+}
+
+libqos_init(virtio_serial_register_nodes);
diff --git a/tests/libqos/virtio-serial.h b/tests/libqos/virtio-serial.h
new file mode 100644
index 0000000..b7e2a5d
--- /dev/null
+++ b/tests/libqos/virtio-serial.h
@@ -0,0 +1,39 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "libqos/qgraph.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+
+typedef struct QVirtioSerial QVirtioSerial;
+typedef struct QVirtioSerialPCI QVirtioSerialPCI;
+typedef struct QVirtioSerialDevice QVirtioSerialDevice;
+
+struct QVirtioSerial {
+    QVirtioDevice *vdev;
+};
+
+struct QVirtioSerialPCI {
+    QVirtioPCIDevice pci_vdev;
+    QVirtioSerial serial;
+};
+
+struct QVirtioSerialDevice {
+    QOSGraphObject obj;
+    QVirtioSerial serial;
+};
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 41/71] qos-test: virtio-console and virtio-serial test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (39 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 40/71] tests/libqos: virtio-serial driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 42/71] tests/libqos: virtio-9p driver and interface nodes Paolo Bonzini
                   ` (32 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/virtio-console-test and tests/virtio-serial-test
in qgraph test node. This test consumes a virtio-serial interface
and checks that its function return the expected values.

Note that this test does not allocate any virtio-console or
virtio-serial structure, it's all done by the qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include      |  8 ++------
 tests/libqos/virtio.c       |  1 +
 tests/virtio-console-test.c | 38 --------------------------------------
 tests/virtio-serial-test.c  | 27 ++++++++++++---------------
 4 files changed, 15 insertions(+), 59 deletions(-)
 delete mode 100644 tests/virtio-console-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 58f548d..88821a7 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -143,8 +143,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 
-check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF)
-
 check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
@@ -153,8 +151,6 @@ check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
 ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
 check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF)
 endif
-check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
-check-qtest-virtio-y += $(check-qtest-virtioserial-y)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
@@ -293,6 +289,7 @@ check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
 check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF)
 check-qtest-s390x-y += tests/drive_del-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-ccw-test$(EXESUF)
+check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF)
 check-qtest-s390x-y += tests/migration-test$(EXESUF)
 
@@ -694,6 +691,7 @@ qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-y += tests/virtio-test.o
+qos-test-obj-y += tests/virtio-serial-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -745,8 +743,6 @@ tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(lib
 tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y)
 tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
 tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o $(libqos-virtio-obj-y)
-tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o $(libqos-virtio-obj-y)
-tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o $(libqos-virtio-obj-y)
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 5a62950..9fc8c7e 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -352,6 +352,7 @@ void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx)
 /*
  * qvirtio_get_dev_type:
  * Returns: the preferred virtio bus/device type for the current architecture.
+ * TODO: delete this
  */
 const char *qvirtio_get_dev_type(void)
 {
diff --git a/tests/virtio-console-test.c b/tests/virtio-console-test.c
deleted file mode 100644
index a7c6f16..0000000
--- a/tests/virtio-console-test.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * QTest testcase for VirtIO Console
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * 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/virtio.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void console_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-serial-%s,id=vser0 "
-                               "-device virtconsole,bus=vser0.0",
-                               qvirtio_get_dev_type());
-    qtest_end();
-}
-
-static void serialport_nop(void)
-{
-    global_qtest = qtest_initf("-device virtio-serial-%s,id=vser0 "
-                               "-device virtserialport,bus=vser0.0",
-                               qvirtio_get_dev_type());
-    qtest_end();
-}
-
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/console/nop", console_nop);
-    qtest_add_func("/virtio/serialport/nop", serialport_nop);
-
-    return g_test_run();
-}
diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c
index 8da9980..85f35e0 100644
--- a/tests/virtio-serial-test.c
+++ b/tests/virtio-serial-test.c
@@ -9,33 +9,30 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
-#include "libqos/virtio.h"
+#include "libqos/virtio-serial.h"
 
 /* Tests only initialization so far. TODO: Replace with functional tests */
-static void virtio_serial_nop(void)
+static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc)
 {
+    /* no operation */
 }
 
-static void hotplug(void)
+static void serial_hotplug(void *obj, void *data, QGuestAllocator *alloc)
 {
     qtest_qmp_device_add("virtserialport", "hp-port", "{}");
-
     qtest_qmp_device_del("hp-port");
 }
 
-int main(int argc, char **argv)
+static void register_virtio_serial_test(void)
 {
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/serial/nop", virtio_serial_nop);
-    qtest_add_func("/virtio/serial/hotplug", hotplug);
+    QOSGraphTestOptions opts = { };
 
-    global_qtest = qtest_initf("-device virtio-serial-%s",
-                               qvirtio_get_dev_type());
-    ret = g_test_run();
+    opts.edge.before_cmd_line = "-device virtconsole,bus=vser0.0";
+    qos_add_test("console-nop", "virtio-serial", virtio_serial_nop, &opts);
 
-    qtest_end();
+    opts.edge.before_cmd_line = "-device virtserialport,bus=vser0.0";
+    qos_add_test("serialport-nop", "virtio-serial", virtio_serial_nop, &opts);
 
-    return ret;
+    qos_add_test("hotplug", "virtio-serial", serial_hotplug, NULL);
 }
+libqos_init(register_virtio_serial_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 42/71] tests/libqos: virtio-9p driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (40 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 41/71] qos-test: virtio-console and virtio-serial test node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 43/71] qos-test: virtio-9p test node Paolo Bonzini
                   ` (31 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-9p-pci and virtio-9p-device.
Both nodes produce virtio-9p, but virtio-9p-pci receives
a pci-bus and overrides virtio-pci QOSGraphObject and its functions,
while virtio-9p-device receives a virtio and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include   |   1 +
 tests/libqos/virtio-9p.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-9p.h |  42 ++++++++++++
 3 files changed, 216 insertions(+)
 create mode 100644 tests/libqos/virtio-9p.c
 create mode 100644 tests/libqos/virtio-9p.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 88821a7..6a6aa7d 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -674,6 +674,7 @@ qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/sdhci.o
 qos-test-obj-y += $(libqos-virtio-obj-y)
+qos-test-obj-y += tests/libqos/virtio-9p.o
 qos-test-obj-y += tests/libqos/virtio-serial.o
 
 # Machines
diff --git a/tests/libqos/virtio-9p.c b/tests/libqos/virtio-9p.c
new file mode 100644
index 0000000..a378b56
--- /dev/null
+++ b/tests/libqos/virtio-9p.c
@@ -0,0 +1,173 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "libqos/virtio-9p.h"
+#include "libqos/qgraph.h"
+
+static QGuestAllocator *alloc;
+
+static void virtio_9p_cleanup(QVirtio9P *interface)
+{
+    qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
+}
+
+static void virtio_9p_setup(QVirtio9P *interface)
+{
+    interface->vq = qvirtqueue_setup(interface->vdev, alloc, 0);
+    qvirtio_set_driver_ok(interface->vdev);
+}
+
+/* virtio-9p-device */
+static void virtio_9p_device_destructor(QOSGraphObject *obj)
+{
+    QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj;
+    QVirtio9P *v9p = &v_9p->v9p;
+
+    virtio_9p_cleanup(v9p);
+}
+
+static void virtio_9p_device_start_hw(QOSGraphObject *obj)
+{
+    QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj;
+    QVirtio9P *v9p = &v_9p->v9p;
+
+    virtio_9p_setup(v9p);
+}
+
+static void *virtio_9p_get_driver(QVirtio9P *v_9p,
+                                         const char *interface)
+{
+    if (!g_strcmp0(interface, "virtio-9p")) {
+        return v_9p;
+    }
+    if (!g_strcmp0(interface, "virtio")) {
+        return v_9p->vdev;
+    }
+
+    fprintf(stderr, "%s not present in virtio-9p-device\n", interface);
+    g_assert_not_reached();
+}
+
+static void *virtio_9p_device_get_driver(void *object, const char *interface)
+{
+    QVirtio9PDevice *v_9p = object;
+    return virtio_9p_get_driver(&v_9p->v9p, interface);
+}
+
+static void *virtio_9p_device_create(void *virtio_dev,
+                                     QGuestAllocator *t_alloc,
+                                     void *addr)
+{
+    QVirtio9PDevice *virtio_device = g_new0(QVirtio9PDevice, 1);
+    QVirtio9P *interface = &virtio_device->v9p;
+
+    interface->vdev = virtio_dev;
+    alloc = t_alloc;
+
+    virtio_device->obj.destructor = virtio_9p_device_destructor;
+    virtio_device->obj.get_driver = virtio_9p_device_get_driver;
+    virtio_device->obj.start_hw = virtio_9p_device_start_hw;
+
+    return &virtio_device->obj;
+}
+
+/* virtio-9p-pci */
+static void virtio_9p_pci_destructor(QOSGraphObject *obj)
+{
+    QVirtio9PPCI *v9_pci = (QVirtio9PPCI *) obj;
+    QVirtio9P *interface = &v9_pci->v9p;
+    QOSGraphObject *pci_vobj =  &v9_pci->pci_vdev.obj;
+
+    virtio_9p_cleanup(interface);
+    qvirtio_pci_destructor(pci_vobj);
+}
+
+static void virtio_9p_pci_start_hw(QOSGraphObject *obj)
+{
+    QVirtio9PPCI *v9_pci = (QVirtio9PPCI *) obj;
+    QVirtio9P *interface = &v9_pci->v9p;
+    QOSGraphObject *pci_vobj =  &v9_pci->pci_vdev.obj;
+
+    qvirtio_pci_start_hw(pci_vobj);
+    virtio_9p_setup(interface);
+}
+
+static void *virtio_9p_pci_get_driver(void *object, const char *interface)
+{
+    QVirtio9PPCI *v_9p = object;
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_9p->pci_vdev.pdev;
+    }
+    return virtio_9p_get_driver(&v_9p->v9p, interface);
+}
+
+static void *virtio_9p_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
+                                  void *addr)
+{
+    QVirtio9PPCI *v9_pci = g_new0(QVirtio9PPCI, 1);
+    QVirtio9P *interface = &v9_pci->v9p;
+    QOSGraphObject *obj = &v9_pci->pci_vdev.obj;
+
+    virtio_pci_init(&v9_pci->pci_vdev, pci_bus, addr);
+    interface->vdev = &v9_pci->pci_vdev.vdev;
+    alloc = t_alloc;
+
+    g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_9P);
+
+    obj->destructor = virtio_9p_pci_destructor;
+    obj->start_hw = virtio_9p_pci_start_hw;
+    obj->get_driver = virtio_9p_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_9p_register_nodes(void)
+{
+    const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
+    const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
+
+    QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(4, 0),
+    };
+
+    QOSGraphEdgeOptions opts = {
+        .before_cmd_line = "-fsdev synth,id=fsdev0",
+    };
+
+    /* virtio-9p-device */
+    opts.extra_device_opts = str_simple,
+    qos_node_create_driver("virtio-9p-device", virtio_9p_device_create);
+    qos_node_consumes("virtio-9p-device", "virtio-bus", &opts);
+    qos_node_produces("virtio-9p-device", "virtio");
+    qos_node_produces("virtio-9p-device", "virtio-9p");
+
+    /* virtio-9p-pci */
+    opts.extra_device_opts = str_addr;
+    add_qpci_address(&opts, &addr);
+    qos_node_create_driver("virtio-9p-pci", virtio_9p_pci_create);
+    qos_node_consumes("virtio-9p-pci", "pci-bus", &opts);
+    qos_node_produces("virtio-9p-pci", "pci-device");
+    qos_node_produces("virtio-9p-pci", "virtio");
+    qos_node_produces("virtio-9p-pci", "virtio-9p");
+
+}
+
+libqos_init(virtio_9p_register_nodes);
diff --git a/tests/libqos/virtio-9p.h b/tests/libqos/virtio-9p.h
new file mode 100644
index 0000000..dba2277
--- /dev/null
+++ b/tests/libqos/virtio-9p.h
@@ -0,0 +1,42 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "libqos/qgraph.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+
+typedef struct QVirtio9P QVirtio9P;
+typedef struct QVirtio9PPCI QVirtio9PPCI;
+typedef struct QVirtio9PDevice QVirtio9PDevice;
+
+#define MOUNT_TAG "qtest"
+
+struct QVirtio9P {
+    QVirtioDevice *vdev;
+    QVirtQueue *vq;
+};
+
+struct QVirtio9PPCI {
+    QVirtioPCIDevice pci_vdev;
+    QVirtio9P v9p;
+};
+
+struct QVirtio9PDevice {
+    QOSGraphObject obj;
+    QVirtio9P v9p;
+};
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 43/71] qos-test: virtio-9p test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (41 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 42/71] tests/libqos: virtio-9p driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 44/71] tests/libqos: virtio-balloon driver and interface nodes Paolo Bonzini
                   ` (30 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/virtio-9p-test into a qgraph test node.
This test consumes a virtio-9p interface and checks that its functions
return the expected values.

Note that this test does not allocate any virtio-9p structure,
it's all done by the qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |   5 +-
 tests/virtio-9p-test.c | 218 +++++++++++++++++--------------------------------
 2 files changed, 78 insertions(+), 145 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 6a6aa7d..2a531df 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -148,9 +148,6 @@ check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
-ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
-check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF)
-endif
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
@@ -692,6 +689,7 @@ qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-y += tests/virtio-test.o
+qos-test-obj-y += tests/virtio-9p-test.o
 qos-test-obj-y += tests/virtio-serial-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
@@ -743,7 +741,6 @@ tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
 tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y)
 tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y)
 tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
-tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o $(libqos-virtio-obj-y)
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index 8fd74f6..16107ad 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -9,99 +9,36 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
-#include "qemu-common.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/libqos-spapr.h"
-#include "libqos/virtio.h"
-#include "libqos/virtio-pci.h"
-#include "standard-headers/linux/virtio_ids.h"
-#include "standard-headers/linux/virtio_pci.h"
 #include "hw/9pfs/9p.h"
 #include "hw/9pfs/9p-synth.h"
+#include "libqos/virtio-9p.h"
+#include "libqos/qgraph.h"
 
 #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
+static QGuestAllocator *alloc;
 
-static const char mount_tag[] = "qtest";
-
-typedef struct {
-    QVirtioDevice *dev;
-    QOSState *qs;
-    QVirtQueue *vq;
-} QVirtIO9P;
-
-static QVirtIO9P *qvirtio_9p_start(const char *driver)
-{
-    const char *arch = qtest_get_arch();
-    const char *cmd = "-fsdev synth,id=fsdev0 "
-                      "-device %s,fsdev=fsdev0,mount_tag=%s";
-    QVirtIO9P *v9p = g_new0(QVirtIO9P, 1);
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        v9p->qs = qtest_pc_boot(cmd, driver, mount_tag);
-    } else if (strcmp(arch, "ppc64") == 0) {
-        v9p->qs = qtest_spapr_boot(cmd, driver, mount_tag);
-    } else {
-        g_printerr("virtio-9p tests are only available on x86 or ppc64\n");
-        exit(EXIT_FAILURE);
-    }
-    global_qtest = v9p->qs->qts;
-
-    return v9p;
-}
-
-static void qvirtio_9p_stop(QVirtIO9P *v9p)
-{
-    qtest_shutdown(v9p->qs);
-    g_free(v9p);
-}
-
-static QVirtIO9P *qvirtio_9p_pci_start(void)
-{
-    QVirtIO9P *v9p = qvirtio_9p_start("virtio-9p-pci");
-    QVirtioPCIDevice *dev = qvirtio_pci_device_find(v9p->qs->pcibus,
-                                                    VIRTIO_ID_9P);
-    g_assert_nonnull(dev);
-    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_9P);
-    v9p->dev = (QVirtioDevice *) dev;
-
-    qvirtio_pci_device_enable(dev);
-    qvirtio_start_device(v9p->dev);
-
-    v9p->vq = qvirtqueue_setup(v9p->dev, &v9p->qs->alloc, 0);
-
-    qvirtio_set_driver_ok(v9p->dev);
-
-    return v9p;
-}
-
-static void qvirtio_9p_pci_stop(QVirtIO9P *v9p)
-{
-    qvirtqueue_cleanup(v9p->dev->bus, v9p->vq, &v9p->qs->alloc);
-    qvirtio_pci_device_disable(container_of(v9p->dev, QVirtioPCIDevice, vdev));
-    qvirtio_pci_device_free((QVirtioPCIDevice *)v9p->dev);
-    qvirtio_9p_stop(v9p);
-}
-
-static void pci_config(QVirtIO9P *v9p)
+static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    size_t tag_len = qvirtio_config_readw(v9p->dev, 0);
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
+    size_t tag_len = qvirtio_config_readw(v9p->vdev, 0);
     char *tag;
     int i;
 
-    g_assert_cmpint(tag_len, ==, strlen(mount_tag));
+    g_assert_cmpint(tag_len, ==, strlen(MOUNT_TAG));
 
     tag = g_malloc(tag_len);
     for (i = 0; i < tag_len; i++) {
-        tag[i] = qvirtio_config_readb(v9p->dev, i + 2);
+        tag[i] = qvirtio_config_readb(v9p->vdev, i + 2);
     }
-    g_assert_cmpmem(tag, tag_len, mount_tag, tag_len);
+    g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len);
     g_free(tag);
 }
 
 #define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
 
 typedef struct {
-    QVirtIO9P *v9p;
+    QVirtio9P *v9p;
     uint16_t tag;
     uint64_t t_msg;
     uint32_t t_size;
@@ -204,7 +141,7 @@ static void v9fs_string_read(P9Req *req, uint16_t *len, char **string)
     uint16_t tag;
 } QEMU_PACKED P9Hdr;
 
-static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id,
+static P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id,
                             uint16_t tag)
 {
     P9Req *req = g_new0(P9Req, 1);
@@ -222,7 +159,7 @@ static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id,
 
     req->v9p = v9p;
     req->t_size = total_size;
-    req->t_msg = guest_alloc(&v9p->qs->alloc, req->t_size);
+    req->t_msg = guest_alloc(alloc, req->t_size);
     v9fs_memwrite(req, &hdr, 7);
     req->tag = tag;
     return req;
@@ -230,13 +167,13 @@ static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id,
 
 static void v9fs_req_send(P9Req *req)
 {
-    QVirtIO9P *v9p = req->v9p;
+    QVirtio9P *v9p = req->v9p;
 
-    req->r_msg = guest_alloc(&v9p->qs->alloc, P9_MAX_SIZE);
+    req->r_msg = guest_alloc(alloc, P9_MAX_SIZE);
     req->free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false,
                                     true);
     qvirtqueue_add(v9p->vq, req->r_msg, P9_MAX_SIZE, true, false);
-    qvirtqueue_kick(v9p->dev, v9p->vq, req->free_head);
+    qvirtqueue_kick(v9p->vdev, v9p->vq, req->free_head);
     req->t_off = 0;
 }
 
@@ -255,9 +192,9 @@ static const char *rmessage_name(uint8_t id)
 
 static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len)
 {
-    QVirtIO9P *v9p = req->v9p;
+    QVirtio9P *v9p = req->v9p;
 
-    qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, len,
+    qvirtio_wait_used_elem(v9p->vdev, v9p->vq, req->free_head, len,
                            QVIRTIO_9P_TIMEOUT_US);
 }
 
@@ -288,10 +225,8 @@ static void v9fs_req_recv(P9Req *req, uint8_t id)
 
 static void v9fs_req_free(P9Req *req)
 {
-    QVirtIO9P *v9p = req->v9p;
-
-    guest_free(&v9p->qs->alloc, req->t_msg);
-    guest_free(&v9p->qs->alloc, req->r_msg);
+    guest_free(alloc, req->t_msg);
+    guest_free(alloc, req->r_msg);
     g_free(req);
 }
 
@@ -304,7 +239,7 @@ static void v9fs_rlerror(P9Req *req, uint32_t *err)
 }
 
 /* size[4] Tversion tag[2] msize[4] version[s] */
-static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version,
+static P9Req *v9fs_tversion(QVirtio9P *v9p, uint32_t msize, const char *version,
                             uint16_t tag)
 {
     P9Req *req;
@@ -339,7 +274,7 @@ static void v9fs_rversion(P9Req *req, uint16_t *len, char **version)
 }
 
 /* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */
-static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname,
+static P9Req *v9fs_tattach(QVirtio9P *v9p, uint32_t fid, uint32_t n_uname,
                            uint16_t tag)
 {
     const char *uname = ""; /* ignored by QEMU */
@@ -368,7 +303,7 @@ static void v9fs_rattach(P9Req *req, v9fs_qid *qid)
 }
 
 /* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
-static P9Req *v9fs_twalk(QVirtIO9P *v9p, uint32_t fid, uint32_t newfid,
+static P9Req *v9fs_twalk(QVirtio9P *v9p, uint32_t fid, uint32_t newfid,
                          uint16_t nwname, char *const wnames[], uint16_t tag)
 {
     P9Req *req;
@@ -410,7 +345,7 @@ static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid)
 }
 
 /* size[4] Tlopen tag[2] fid[4] flags[4] */
-static P9Req *v9fs_tlopen(QVirtIO9P *v9p, uint32_t fid, uint32_t flags,
+static P9Req *v9fs_tlopen(QVirtio9P *v9p, uint32_t fid, uint32_t flags,
                           uint16_t tag)
 {
     P9Req *req;
@@ -438,7 +373,7 @@ static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
 }
 
 /* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */
-static P9Req *v9fs_twrite(QVirtIO9P *v9p, uint32_t fid, uint64_t offset,
+static P9Req *v9fs_twrite(QVirtio9P *v9p, uint32_t fid, uint64_t offset,
                           uint32_t count, const void *data, uint16_t tag)
 {
     P9Req *req;
@@ -466,7 +401,7 @@ static void v9fs_rwrite(P9Req *req, uint32_t *count)
 }
 
 /* size[4] Tflush tag[2] oldtag[2] */
-static P9Req *v9fs_tflush(QVirtIO9P *v9p, uint16_t oldtag, uint16_t tag)
+static P9Req *v9fs_tflush(QVirtio9P *v9p, uint16_t oldtag, uint16_t tag)
 {
     P9Req *req;
 
@@ -483,8 +418,10 @@ static void v9fs_rflush(P9Req *req)
     v9fs_req_free(req);
 }
 
-static void fs_version(QVirtIO9P *v9p)
+static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     const char *version = "9P2000.L";
     uint16_t server_len;
     char *server_version;
@@ -499,18 +436,22 @@ static void fs_version(QVirtIO9P *v9p)
     g_free(server_version);
 }
 
-static void fs_attach(QVirtIO9P *v9p)
+static void fs_attach(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     P9Req *req;
 
-    fs_version(v9p);
+    fs_version(v9p, NULL, t_alloc);
     req = v9fs_tattach(v9p, 0, getuid(), 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rattach(req, NULL);
 }
 
-static void fs_walk(QVirtIO9P *v9p)
+static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     char *wnames[P9_MAXWELEM];
     uint16_t nwqid;
     v9fs_qid *wqid;
@@ -521,7 +462,7 @@ static void fs_walk(QVirtIO9P *v9p)
         wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i);
     }
 
-    fs_attach(v9p);
+    fs_attach(v9p, NULL, t_alloc);
     req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rwalk(req, &nwqid, &wqid);
@@ -535,13 +476,15 @@ static void fs_walk(QVirtIO9P *v9p)
     g_free(wqid);
 }
 
-static void fs_walk_no_slash(QVirtIO9P *v9p)
+static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     char *const wnames[] = { g_strdup(" /") };
     P9Req *req;
     uint32_t err;
 
-    fs_attach(v9p);
+    fs_attach(v9p, NULL, t_alloc);
     req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rlerror(req, &err);
@@ -551,13 +494,15 @@ static void fs_walk_no_slash(QVirtIO9P *v9p)
     g_free(wnames[0]);
 }
 
-static void fs_walk_dotdot(QVirtIO9P *v9p)
+static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     char *const wnames[] = { g_strdup("..") };
     v9fs_qid root_qid, *wqid;
     P9Req *req;
 
-    fs_version(v9p);
+    fs_version(v9p, NULL, t_alloc);
     req = v9fs_tattach(v9p, 0, getuid(), 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rattach(req, &root_qid);
@@ -572,12 +517,14 @@ static void fs_walk_dotdot(QVirtIO9P *v9p)
     g_free(wnames[0]);
 }
 
-static void fs_lopen(QVirtIO9P *v9p)
+static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) };
     P9Req *req;
 
-    fs_attach(v9p);
+    fs_attach(v9p, NULL, t_alloc);
     req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rwalk(req, NULL, NULL);
@@ -589,15 +536,17 @@ static void fs_lopen(QVirtIO9P *v9p)
     g_free(wnames[0]);
 }
 
-static void fs_write(QVirtIO9P *v9p)
+static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     static const uint32_t write_count = P9_MAX_SIZE / 2;
     char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) };
     char *buf = g_malloc0(write_count);
     uint32_t count;
     P9Req *req;
 
-    fs_attach(v9p);
+    fs_attach(v9p, NULL, t_alloc);
     req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rwalk(req, NULL, NULL);
@@ -615,14 +564,16 @@ static void fs_write(QVirtIO9P *v9p)
     g_free(wnames[0]);
 }
 
-static void fs_flush_success(QVirtIO9P *v9p)
+static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
     P9Req *req, *flush_req;
     uint32_t reply_len;
     uint8_t should_block;
 
-    fs_attach(v9p);
+    fs_attach(v9p, NULL, t_alloc);
     req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rwalk(req, NULL, NULL);
@@ -650,14 +601,16 @@ static void fs_flush_success(QVirtIO9P *v9p)
     g_free(wnames[0]);
 }
 
-static void fs_flush_ignored(QVirtIO9P *v9p)
+static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtio9P *v9p = obj;
+    alloc = t_alloc;
     char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
     P9Req *req, *flush_req;
     uint32_t count;
     uint8_t should_block;
 
-    fs_attach(v9p);
+    fs_attach(v9p, NULL, t_alloc);
     req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
     v9fs_req_wait_for_reply(req, NULL);
     v9fs_rwalk(req, NULL, NULL);
@@ -685,39 +638,22 @@ static void fs_flush_ignored(QVirtIO9P *v9p)
     g_free(wnames[0]);
 }
 
-typedef void (*v9fs_test_fn)(QVirtIO9P *v9p);
-
-static void v9fs_run_pci_test(gconstpointer data)
+static void register_virtio_9p_test(void)
 {
-    v9fs_test_fn fn = data;
-    QVirtIO9P *v9p = qvirtio_9p_pci_start();
-
-    if (fn) {
-        fn(v9p);
-    }
-    qvirtio_9p_pci_stop(v9p);
-}
-
-static void v9fs_qtest_pci_add(const char *path, v9fs_test_fn fn)
-{
-    qtest_add_data_func(path, fn, v9fs_run_pci_test);
+    qos_add_test("config", "virtio-9p", pci_config, NULL);
+    qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
+    qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
+    qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
+    qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
+                 NULL);
+    qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
+                 fs_walk_dotdot, NULL);
+    qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
+    qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
+    qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
+                 NULL);
+    qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
+                 NULL);
 }
 
-int main(int argc, char **argv)
-{
-    g_test_init(&argc, &argv, NULL);
-    v9fs_qtest_pci_add("/virtio/9p/pci/nop", NULL);
-    v9fs_qtest_pci_add("/virtio/9p/pci/config", pci_config);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/version/basic", fs_version);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/attach/basic", fs_attach);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/basic", fs_walk);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/no_slash", fs_walk_no_slash);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/dotdot_from_root",
-                       fs_walk_dotdot);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/lopen/basic", fs_lopen);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/write/basic", fs_write);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/flush/success", fs_flush_success);
-    v9fs_qtest_pci_add("/virtio/9p/pci/fs/flush/ignored", fs_flush_ignored);
-
-    return g_test_run();
-}
+libqos_init(register_virtio_9p_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 44/71] tests/libqos: virtio-balloon driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (42 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 43/71] qos-test: virtio-9p test node Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 45/71] tests/qgraph: remove virtio-balloon-test Paolo Bonzini
                   ` (29 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-balloon-pci and virtio-balloon-device.
Both nodes produce virtio-balloon, but virtio-balloon-pci receives
a pci-bus and uses virtio-pci QOSGraphObject and functions,
while virtio-balloon-device receives a virtio and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include        |   1 +
 tests/libqos/virtio-balloon.c | 113 ++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-balloon.h |  39 +++++++++++++++
 3 files changed, 153 insertions(+)
 create mode 100644 tests/libqos/virtio-balloon.c
 create mode 100644 tests/libqos/virtio-balloon.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 2a531df..d31aade 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -672,6 +672,7 @@ qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/sdhci.o
 qos-test-obj-y += $(libqos-virtio-obj-y)
 qos-test-obj-y += tests/libqos/virtio-9p.o
+qos-test-obj-y += tests/libqos/virtio-balloon.o
 qos-test-obj-y += tests/libqos/virtio-serial.o
 
 # Machines
diff --git a/tests/libqos/virtio-balloon.c b/tests/libqos/virtio-balloon.c
new file mode 100644
index 0000000..7e6e9e9
--- /dev/null
+++ b/tests/libqos/virtio-balloon.c
@@ -0,0 +1,113 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-balloon.h"
+
+/* virtio-balloon-device */
+static void *qvirtio_balloon_get_driver(QVirtioBalloon *v_balloon,
+                                        const char *interface)
+{
+    if (!g_strcmp0(interface, "virtio-balloon")) {
+        return v_balloon;
+    }
+    if (!g_strcmp0(interface, "virtio")) {
+        return v_balloon->vdev;
+    }
+
+    fprintf(stderr, "%s not present in virtio-balloon-device\n", interface);
+    g_assert_not_reached();
+}
+
+static void *qvirtio_balloon_device_get_driver(void *object,
+                                               const char *interface)
+{
+    QVirtioBalloonDevice *v_balloon = object;
+    return qvirtio_balloon_get_driver(&v_balloon->balloon, interface);
+}
+
+static void *virtio_balloon_device_create(void *virtio_dev,
+                                          QGuestAllocator *t_alloc,
+                                          void *addr)
+{
+    QVirtioBalloonDevice *virtio_bdevice = g_new0(QVirtioBalloonDevice, 1);
+    QVirtioBalloon *interface = &virtio_bdevice->balloon;
+
+    interface->vdev = virtio_dev;
+
+    virtio_bdevice->obj.get_driver = qvirtio_balloon_device_get_driver;
+
+    return &virtio_bdevice->obj;
+}
+
+/* virtio-balloon-pci */
+static void *qvirtio_balloon_pci_get_driver(void *object,
+                                            const char *interface)
+{
+    QVirtioBalloonPCI *v_balloon = object;
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_balloon->pci_vdev.pdev;
+    }
+    return qvirtio_balloon_get_driver(&v_balloon->balloon, interface);
+}
+
+static void *virtio_balloon_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
+                                  void *addr)
+{
+    QVirtioBalloonPCI *virtio_bpci = g_new0(QVirtioBalloonPCI, 1);
+    QVirtioBalloon *interface = &virtio_bpci->balloon;
+    QOSGraphObject *obj = &virtio_bpci->pci_vdev.obj;
+
+
+    virtio_pci_init(&virtio_bpci->pci_vdev, pci_bus, addr);
+    interface->vdev = &virtio_bpci->pci_vdev.vdev;
+
+    obj->get_driver = qvirtio_balloon_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_balloon_register_nodes(void)
+{
+    QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(4, 0),
+    };
+
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+
+    /* virtio-balloon-device */
+    qos_node_create_driver("virtio-balloon-device",
+                            virtio_balloon_device_create);
+    qos_node_consumes("virtio-balloon-device", "virtio-bus", NULL);
+    qos_node_produces("virtio-balloon-device", "virtio");
+    qos_node_produces("virtio-balloon-device", "virtio-balloon");
+
+    /* virtio-balloon-pci */
+    add_qpci_address(&opts, &addr);
+    qos_node_create_driver("virtio-balloon-pci", virtio_balloon_pci_create);
+    qos_node_consumes("virtio-balloon-pci", "pci-bus", &opts);
+    qos_node_produces("virtio-balloon-pci", "pci-device");
+    qos_node_produces("virtio-balloon-pci", "virtio");
+    qos_node_produces("virtio-balloon-pci", "virtio-balloon");
+}
+
+libqos_init(virtio_balloon_register_nodes);
diff --git a/tests/libqos/virtio-balloon.h b/tests/libqos/virtio-balloon.h
new file mode 100644
index 0000000..e8066c4
--- /dev/null
+++ b/tests/libqos/virtio-balloon.h
@@ -0,0 +1,39 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "libqos/qgraph.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+
+typedef struct QVirtioBalloon QVirtioBalloon;
+typedef struct QVirtioBalloonPCI QVirtioBalloonPCI;
+typedef struct QVirtioBalloonDevice QVirtioBalloonDevice;
+
+struct QVirtioBalloon {
+    QVirtioDevice *vdev;
+};
+
+struct QVirtioBalloonPCI {
+    QVirtioPCIDevice pci_vdev;
+    QVirtioBalloon balloon;
+};
+
+struct QVirtioBalloonDevice {
+    QOSGraphObject obj;
+    QVirtioBalloon balloon;
+};
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 45/71] tests/qgraph: remove virtio-balloon-test
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (43 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 44/71] tests/libqos: virtio-balloon driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 46/71] tests/libqos: virtio-rng driver and interface nodes Paolo Bonzini
                   ` (28 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

The tests/virtio-balloon-test is covered by generic virtio tests,
so remove it.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include      |  3 ---
 tests/virtio-balloon-test.c | 33 ---------------------------------
 2 files changed, 36 deletions(-)
 delete mode 100644 tests/virtio-balloon-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index d31aade..68bacf1 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -144,7 +144,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 
 check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
@@ -286,7 +285,6 @@ check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
 check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF)
 check-qtest-s390x-y += tests/drive_del-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-ccw-test$(EXESUF)
-check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF)
 check-qtest-s390x-y += tests/migration-test$(EXESUF)
 
@@ -736,7 +734,6 @@ tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
 tests/ne2000-test$(EXESUF): tests/ne2000-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
-tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o $(libqos-virtio-obj-y)
 tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
 tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y)
diff --git a/tests/virtio-balloon-test.c b/tests/virtio-balloon-test.c
deleted file mode 100644
index 5a1d0cc..0000000
--- a/tests/virtio-balloon-test.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * QTest testcase for VirtIO Balloon
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * 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/virtio.h"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void balloon_nop(void)
-{
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/balloon/nop", balloon_nop);
-
-    global_qtest = qtest_initf("-device virtio-balloon-%s",
-                               qvirtio_get_dev_type());
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
-}
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 46/71] tests/libqos: virtio-rng driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (44 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 45/71] tests/qgraph: remove virtio-balloon-test Paolo Bonzini
@ 2018-12-03 15:32 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 47/71] qos-test: virtio-rng test node Paolo Bonzini
                   ` (27 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-rng-pci and virtio-rng-device.
Both nodes produce virtio-rng, but virtio-rng-pci receives
a pci-bus and uses virtio-pci QOSGraphObject and functions,
while virtio-rng-device receives a virtio and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include    |   1 +
 tests/libqos/virtio-rng.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-rng.h |  39 ++++++++++++++++
 3 files changed, 150 insertions(+)
 create mode 100644 tests/libqos/virtio-rng.c
 create mode 100644 tests/libqos/virtio-rng.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 68bacf1..00ca6e8 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -671,6 +671,7 @@ qos-test-obj-y += tests/libqos/sdhci.o
 qos-test-obj-y += $(libqos-virtio-obj-y)
 qos-test-obj-y += tests/libqos/virtio-9p.o
 qos-test-obj-y += tests/libqos/virtio-balloon.o
+qos-test-obj-y += tests/libqos/virtio-rng.o
 qos-test-obj-y += tests/libqos/virtio-serial.o
 
 # Machines
diff --git a/tests/libqos/virtio-rng.c b/tests/libqos/virtio-rng.c
new file mode 100644
index 0000000..a1d2c76
--- /dev/null
+++ b/tests/libqos/virtio-rng.c
@@ -0,0 +1,110 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-rng.h"
+
+/* virtio-rng-device */
+static void *qvirtio_rng_get_driver(QVirtioRng *v_rng,
+                                    const char *interface)
+{
+    if (!g_strcmp0(interface, "virtio-rng")) {
+        return v_rng;
+    }
+    if (!g_strcmp0(interface, "virtio")) {
+        return v_rng->vdev;
+    }
+
+    fprintf(stderr, "%s not present in virtio-rng-device\n", interface);
+    g_assert_not_reached();
+}
+
+static void *qvirtio_rng_device_get_driver(void *object,
+                                           const char *interface)
+{
+    QVirtioRngDevice *v_rng = object;
+    return qvirtio_rng_get_driver(&v_rng->rng, interface);
+}
+
+static void *virtio_rng_device_create(void *virtio_dev,
+                                      QGuestAllocator *t_alloc,
+                                      void *addr)
+{
+    QVirtioRngDevice *virtio_rdevice = g_new0(QVirtioRngDevice, 1);
+    QVirtioRng *interface = &virtio_rdevice->rng;
+
+    interface->vdev = virtio_dev;
+
+    virtio_rdevice->obj.get_driver = qvirtio_rng_device_get_driver;
+
+    return &virtio_rdevice->obj;
+}
+
+/* virtio-rng-pci */
+static void *qvirtio_rng_pci_get_driver(void *object, const char *interface)
+{
+    QVirtioRngPCI *v_rng = object;
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_rng->pci_vdev.pdev;
+    }
+    return qvirtio_rng_get_driver(&v_rng->rng, interface);
+}
+
+static void *virtio_rng_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
+                                   void *addr)
+{
+    QVirtioRngPCI *virtio_rpci = g_new0(QVirtioRngPCI, 1);
+    QVirtioRng *interface = &virtio_rpci->rng;
+    QOSGraphObject *obj = &virtio_rpci->pci_vdev.obj;
+
+    virtio_pci_init(&virtio_rpci->pci_vdev, pci_bus, addr);
+    interface->vdev = &virtio_rpci->pci_vdev.vdev;
+
+    obj->get_driver = qvirtio_rng_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_rng_register_nodes(void)
+{
+    QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(4, 0),
+    };
+
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+
+    /* virtio-rng-device */
+    qos_node_create_driver("virtio-rng-device", virtio_rng_device_create);
+    qos_node_consumes("virtio-rng-device", "virtio-bus", NULL);
+    qos_node_produces("virtio-rng-device", "virtio");
+    qos_node_produces("virtio-rng-device", "virtio-rng");
+
+    /* virtio-rng-pci */
+    add_qpci_address(&opts, &addr);
+    qos_node_create_driver("virtio-rng-pci", virtio_rng_pci_create);
+    qos_node_consumes("virtio-rng-pci", "pci-bus", &opts);
+    qos_node_produces("virtio-rng-pci", "pci-device");
+    qos_node_produces("virtio-rng-pci", "virtio");
+    qos_node_produces("virtio-rng-pci", "virtio-rng");
+}
+
+libqos_init(virtio_rng_register_nodes);
diff --git a/tests/libqos/virtio-rng.h b/tests/libqos/virtio-rng.h
new file mode 100644
index 0000000..fbba988
--- /dev/null
+++ b/tests/libqos/virtio-rng.h
@@ -0,0 +1,39 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "libqos/qgraph.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+
+typedef struct QVirtioRng QVirtioRng;
+typedef struct QVirtioRngPCI QVirtioRngPCI;
+typedef struct QVirtioRngDevice QVirtioRngDevice;
+
+struct QVirtioRng {
+    QVirtioDevice *vdev;
+};
+
+struct QVirtioRngPCI {
+    QVirtioPCIDevice pci_vdev;
+    QVirtioRng rng;
+};
+
+struct QVirtioRngDevice {
+    QOSGraphObject obj;
+    QVirtioRng rng;
+};
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 47/71] qos-test: virtio-rng test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (45 preceding siblings ...)
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 46/71] tests/libqos: virtio-rng driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 48/71] tests/libqos: virtio-blk driver and interface nodes Paolo Bonzini
                   ` (26 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/virtio-rng-test in qgraph test node,
virtio-rng-test. This test consumes a virtio-rng interface
and checks that its function return the expected values.

Some functions are implemented only for virtio-rng-pci, so they
don't consume virtio-rng, but virtio-rng-pci

Note that this test does not allocate any virtio-rng structure,
it's all done by the qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include  |  3 +--
 tests/virtio-rng-test.c | 27 +++++++--------------------
 2 files changed, 8 insertions(+), 22 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 00ca6e8..a7c01a3 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -145,7 +145,6 @@ check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 
 check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
@@ -690,6 +689,7 @@ qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-y += tests/virtio-test.o
 qos-test-obj-y += tests/virtio-9p-test.o
+qos-test-obj-y += tests/virtio-rng-test.o
 qos-test-obj-y += tests/virtio-serial-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
@@ -738,7 +738,6 @@ tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
 tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y)
-tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y)
 tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c
index 657d9a4..5309c7c 100644
--- a/tests/virtio-rng-test.c
+++ b/tests/virtio-rng-test.c
@@ -9,16 +9,12 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
-#include "libqos/pci.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-rng.h"
 
 #define PCI_SLOT_HP             0x06
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
-{
-}
-
-static void hotplug(void)
+static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc)
 {
     const char *arch = qtest_get_arch();
 
@@ -30,18 +26,9 @@ static void hotplug(void)
     }
 }
 
-int main(int argc, char **argv)
+static void register_virtio_rng_test(void)
 {
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/rng/pci/nop", pci_nop);
-    qtest_add_func("/virtio/rng/pci/hotplug", hotplug);
-
-    qtest_start("-device virtio-rng-pci");
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
+    qos_add_test("hotplug", "virtio-rng-pci", rng_hotplug, NULL);
 }
+
+libqos_init(register_virtio_rng_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 48/71] tests/libqos: virtio-blk driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (46 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 47/71] qos-test: virtio-rng test node Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 49/71] qos-test: virtio-blk test node Paolo Bonzini
                   ` (25 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-blk-pci and virtio-blk-device.
Both nodes produce virtio-blk, but virtio-blk-pci receives
a pci-bus and uses virtio-pci QOSGraphObject and functions,
while virtio-blk-device receives a virtio and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include    |   1 +
 tests/libqos/virtio-blk.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-blk.h |  40 +++++++++++++++
 3 files changed, 165 insertions(+)
 create mode 100644 tests/libqos/virtio-blk.c
 create mode 100644 tests/libqos/virtio-blk.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index a7c01a3..5e1d75c 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -670,6 +670,7 @@ qos-test-obj-y += tests/libqos/sdhci.o
 qos-test-obj-y += $(libqos-virtio-obj-y)
 qos-test-obj-y += tests/libqos/virtio-9p.o
 qos-test-obj-y += tests/libqos/virtio-balloon.o
+qos-test-obj-y += tests/libqos/virtio-blk.o
 qos-test-obj-y += tests/libqos/virtio-rng.o
 qos-test-obj-y += tests/libqos/virtio-serial.o
 
diff --git a/tests/libqos/virtio-blk.c b/tests/libqos/virtio-blk.c
new file mode 100644
index 0000000..c17bdf4
--- /dev/null
+++ b/tests/libqos/virtio-blk.c
@@ -0,0 +1,124 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "standard-headers/linux/virtio_blk.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-blk.h"
+
+#define PCI_SLOT                0x04
+#define PCI_FN                  0x00
+
+/* virtio-blk-device */
+static void *qvirtio_blk_get_driver(QVirtioBlk *v_blk,
+                                    const char *interface)
+{
+    if (!g_strcmp0(interface, "virtio-blk")) {
+        return v_blk;
+    }
+    if (!g_strcmp0(interface, "virtio")) {
+        return v_blk->vdev;
+    }
+
+    fprintf(stderr, "%s not present in virtio-blk-device\n", interface);
+    g_assert_not_reached();
+}
+
+static void *qvirtio_blk_device_get_driver(void *object,
+                                           const char *interface)
+{
+    QVirtioBlkDevice *v_blk = object;
+    return qvirtio_blk_get_driver(&v_blk->blk, interface);
+}
+
+static void *virtio_blk_device_create(void *virtio_dev,
+                                      QGuestAllocator *t_alloc,
+                                      void *addr)
+{
+    QVirtioBlkDevice *virtio_blk = g_new0(QVirtioBlkDevice, 1);
+    QVirtioBlk *interface = &virtio_blk->blk;
+
+    interface->vdev = virtio_dev;
+
+    virtio_blk->obj.get_driver = qvirtio_blk_device_get_driver;
+
+    return &virtio_blk->obj;
+}
+
+/* virtio-blk-pci */
+static void *qvirtio_blk_pci_get_driver(void *object, const char *interface)
+{
+    QVirtioBlkPCI *v_blk = object;
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_blk->pci_vdev.pdev;
+    }
+    return qvirtio_blk_get_driver(&v_blk->blk, interface);
+}
+
+static void *virtio_blk_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
+                                      void *addr)
+{
+    QVirtioBlkPCI *virtio_blk = g_new0(QVirtioBlkPCI, 1);
+    QVirtioBlk *interface = &virtio_blk->blk;
+    QOSGraphObject *obj = &virtio_blk->pci_vdev.obj;
+
+    virtio_pci_init(&virtio_blk->pci_vdev, pci_bus, addr);
+    interface->vdev = &virtio_blk->pci_vdev.vdev;
+
+    g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_BLOCK);
+
+    obj->get_driver = qvirtio_blk_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_blk_register_nodes(void)
+{
+    /* FIXME: every test using these two nodes needs to setup a
+     * -drive,id=drive0 otherwise QEMU is not going to start.
+     * Therefore, we do not include "produces" edge for virtio
+     * and pci-device yet.
+    */
+
+    char *arg = g_strdup_printf("id=drv0,drive=drive0,addr=%x.%x",
+                                PCI_SLOT, PCI_FN);
+
+    QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(PCI_SLOT, PCI_FN),
+    };
+
+    QOSGraphEdgeOptions opts = { };
+
+    /* virtio-blk-device */
+    opts.extra_device_opts = "drive=drive0";
+    qos_node_create_driver("virtio-blk-device", virtio_blk_device_create);
+    qos_node_consumes("virtio-blk-device", "virtio-bus", &opts);
+    qos_node_produces("virtio-blk-device", "virtio-blk");
+
+    /* virtio-blk-pci */
+    opts.extra_device_opts = arg;
+    add_qpci_address(&opts, &addr);
+    qos_node_create_driver("virtio-blk-pci", virtio_blk_pci_create);
+    qos_node_consumes("virtio-blk-pci", "pci-bus", &opts);
+    qos_node_produces("virtio-blk-pci", "virtio-blk");
+
+    g_free(arg);
+}
+
+libqos_init(virtio_blk_register_nodes);
diff --git a/tests/libqos/virtio-blk.h b/tests/libqos/virtio-blk.h
new file mode 100644
index 0000000..dc25849
--- /dev/null
+++ b/tests/libqos/virtio-blk.h
@@ -0,0 +1,40 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "libqos/qgraph.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+
+typedef struct QVirtioBlk QVirtioBlk;
+typedef struct QVirtioBlkPCI QVirtioBlkPCI;
+typedef struct QVirtioBlkDevice QVirtioBlkDevice;
+
+/* virtqueue is created in each test */
+struct QVirtioBlk {
+    QVirtioDevice *vdev;
+};
+
+struct QVirtioBlkPCI {
+    QVirtioPCIDevice pci_vdev;
+    QVirtioBlk blk;
+};
+
+struct QVirtioBlkDevice {
+    QOSGraphObject obj;
+    QVirtioBlk blk;
+};
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 49/71] qos-test: virtio-blk test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (47 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 48/71] tests/libqos: virtio-blk driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 50/71] tests/libqos: virtio-net driver and interface nodes Paolo Bonzini
                   ` (24 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Convert tests/virtio-blk-test in qgraph test node,
virtio-blk-test. This test consumes a virtio-blk interface
and checks that its function return the expected values.

Some functions are implemented only for virtio-blk-pci, so they
don't consume virtio-blk, but virtio-blk-pci

Note that this test does not allocate any virtio-blk structure,
it's all done by the qtest walking graph mechanism.  The allocator
is also provided by qgraph; remove malloc-generic.c and malloc-generic.h
which are not used anymore.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include        |   6 +-
 tests/libqos/malloc-generic.c |  24 ---
 tests/libqos/malloc-generic.h |  18 --
 tests/libqtest.h              |   3 +
 tests/virtio-blk-test.c       | 473 ++++++++++++++++--------------------------
 5 files changed, 188 insertions(+), 336 deletions(-)
 delete mode 100644 tests/libqos/malloc-generic.c
 delete mode 100644 tests/libqos/malloc-generic.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 5e1d75c..8ba1ca9 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -144,7 +144,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 
 check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
@@ -264,7 +263,6 @@ check-qtest-arm-y += tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/pca9552-test$(EXESUF)
 check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
-check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
 check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
 check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
 check-qtest-arm-y += tests/hexloader-test$(EXESUF)
@@ -648,7 +646,7 @@ tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y)
 libqgraph-obj-y = tests/libqos/qgraph.o
 
 libqos-obj-y = $(libqgraph-obj-y) tests/libqos/pci.o tests/libqos/fw_cfg.o
-libqos-obj-y += tests/libqos/malloc.o tests/libqos/malloc-generic.o
+libqos-obj-y += tests/libqos/malloc.o
 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
@@ -690,6 +688,7 @@ qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-y += tests/virtio-test.o
 qos-test-obj-y += tests/virtio-9p-test.o
+qos-test-obj-y += tests/virtio-blk-test.o
 qos-test-obj-y += tests/virtio-rng-test.o
 qos-test-obj-y += tests/virtio-serial-test.o
 
@@ -736,7 +735,6 @@ tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
 tests/ne2000-test$(EXESUF): tests/ne2000-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
-tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
 tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y)
 tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
diff --git a/tests/libqos/malloc-generic.c b/tests/libqos/malloc-generic.c
deleted file mode 100644
index 2873c67..0000000
--- a/tests/libqos/malloc-generic.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Basic libqos generic malloc support
- *
- * Copyright (c) 2014 Marc Marí
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "libqos/malloc-generic.h"
-#include "libqos/malloc.h"
-
-/*
- * Mostly for valgrind happiness, but it does offer
- * a chokepoint for debugging guest memory leaks, too.
- */
-void generic_alloc_init(QGuestAllocator *s, uint64_t base_addr,
-			uint64_t size, uint32_t page_size)
-{
-    uint64_t start = base_addr + (1 << 20); /* Start at 1MB */
-
-    alloc_init(s, 0, start, start + size, page_size);
-}
diff --git a/tests/libqos/malloc-generic.h b/tests/libqos/malloc-generic.h
deleted file mode 100644
index 40ea058..0000000
--- a/tests/libqos/malloc-generic.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Basic libqos generic malloc support
- *
- * Copyright (c) 2014 Marc Marí
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef LIBQOS_MALLOC_GENERIC_H
-#define LIBQOS_MALLOC_GENERIC_H
-
-#include "libqos/malloc.h"
-
-void generic_alloc_init(QGuestAllocator *s, uint64_t base_addr, uint64_t size,
-                        uint32_t page_size);
-
-#endif
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 2fd1e51..1760c55 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -17,6 +17,9 @@
 #ifndef LIBQTEST_H
 #define LIBQTEST_H
 
+#include "qapi/qmp/qobject.h"
+#include "qapi/qmp/qdict.h"
+
 typedef struct QTestState QTestState;
 
 extern QTestState *global_qtest;
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 0a13a5a..e16e8ad 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -10,20 +10,11 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/libqos-spapr.h"
-#include "libqos/virtio.h"
-#include "libqos/virtio-pci.h"
-#include "libqos/virtio-mmio.h"
-#include "libqos/malloc.h"
-#include "libqos/malloc-generic.h"
-#include "qapi/qmp/qdict.h"
 #include "qemu/bswap.h"
-#include "standard-headers/linux/virtio_ids.h"
-#include "standard-headers/linux/virtio_config.h"
-#include "standard-headers/linux/virtio_ring.h"
 #include "standard-headers/linux/virtio_blk.h"
 #include "standard-headers/linux/virtio_pci.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-blk.h"
 
 /* TODO actually test the results and get rid of this */
 #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
@@ -31,13 +22,6 @@
 #define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
 #define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
 #define PCI_SLOT_HP             0x06
-#define PCI_SLOT                0x04
-#define PCI_FN                  0x00
-
-#define MMIO_PAGE_SIZE          4096
-#define MMIO_DEV_BASE_ADDR      0x0A003E00
-#define MMIO_RAM_ADDR           0x40000000
-#define MMIO_RAM_SIZE           0x20000000
 
 typedef struct QVirtioBlkReq {
     uint32_t type;
@@ -47,78 +31,27 @@ typedef struct QVirtioBlkReq {
     uint8_t status;
 } QVirtioBlkReq;
 
+static void drive_destroy(void *path)
+{
+    unlink(path);
+    g_free(path);
+    qos_invalidate_command_line();
+}
+
 static char *drive_create(void)
 {
     int fd, ret;
-    char *tmp_path = g_strdup("/tmp/qtest.XXXXXX");
+    char *t_path = g_strdup("/tmp/qtest.XXXXXX");
 
     /* Create a temporary raw image */
-    fd = mkstemp(tmp_path);
+    fd = mkstemp(t_path);
     g_assert_cmpint(fd, >=, 0);
     ret = ftruncate(fd, TEST_IMAGE_SIZE);
     g_assert_cmpint(ret, ==, 0);
     close(fd);
 
-    return tmp_path;
-}
-
-static QOSState *pci_test_start(void)
-{
-    QOSState *qs;
-    const char *arch = qtest_get_arch();
-    char *tmp_path;
-    const char *cmd = "-drive if=none,id=drive0,file=%s,format=raw "
-                      "-drive if=none,id=drive1,file=null-co://,format=raw "
-                      "-device virtio-blk-pci,id=drv0,drive=drive0,"
-                      "addr=%x.%x";
-
-    tmp_path = drive_create();
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qs = qtest_pc_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
-    } else if (strcmp(arch, "ppc64") == 0) {
-        qs = qtest_spapr_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
-    } else {
-        g_printerr("virtio-blk tests are only available on x86 or ppc64\n");
-        exit(EXIT_FAILURE);
-    }
-    global_qtest = qs->qts;
-    unlink(tmp_path);
-    g_free(tmp_path);
-    return qs;
-}
-
-static void arm_test_start(void)
-{
-    char *tmp_path;
-
-    tmp_path = drive_create();
-
-    global_qtest = qtest_initf("-machine virt "
-                               "-drive if=none,id=drive0,file=%s,format=raw "
-                               "-device virtio-blk-device,drive=drive0",
-                               tmp_path);
-    unlink(tmp_path);
-    g_free(tmp_path);
-}
-
-static void test_end(void)
-{
-    qtest_end();
-}
-
-static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
-{
-    QVirtioPCIDevice *dev;
-
-    dev = qvirtio_pci_device_find_slot(bus, VIRTIO_ID_BLOCK, slot);
-    g_assert(dev != NULL);
-    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
-    g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
-
-    qvirtio_pci_device_enable(dev);
-    qvirtio_start_device(&dev->vdev);
-    return dev;
+    g_test_queue_destroy(drive_destroy, t_path);
+    return t_path;
 }
 
 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
@@ -282,32 +215,21 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
     }
 }
 
-static void pci_basic(void)
+static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    QVirtioPCIDevice *dev;
-    QOSState *qs;
-    QVirtQueuePCI *vqpci;
-
-    qs = pci_test_start();
-    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
-
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
-
-    test_basic(&dev->vdev, &qs->alloc, &vqpci->vq);
+    QVirtioBlk *blk_if = obj;
+    QVirtQueue *vq;
+    vq = qvirtqueue_setup(blk_if->vdev, t_alloc, 0);
+    test_basic(blk_if->vdev, t_alloc, vq);
+    qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
 
-    /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
-    qvirtio_pci_device_disable(dev);
-    qvirtio_pci_device_free(dev);
-    g_free(dev);
-    qtest_shutdown(qs);
 }
 
-static void pci_indirect(void)
+static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
 {
-    QVirtioPCIDevice *dev;
-    QVirtQueuePCI *vqpci;
-    QOSState *qs;
+    QVirtQueue *vq;
+    QVirtioBlk *blk_if = obj;
+    QVirtioDevice *dev = blk_if->vdev;
     QVirtioBlkReq req;
     QVRingIndirectDesc *indirect;
     uint64_t req_addr;
@@ -317,23 +239,19 @@ static void pci_indirect(void)
     uint8_t status;
     char *data;
 
-    qs = pci_test_start();
-
-    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
-
-    capacity = qvirtio_config_readq(&dev->vdev, 0);
+    capacity = qvirtio_config_readq(dev, 0);
     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 
-    features = qvirtio_get_features(&dev->vdev);
+    features = qvirtio_get_features(dev);
     g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
     features = features & ~(QVIRTIO_F_BAD_FEATURE |
                             (1u << VIRTIO_RING_F_EVENT_IDX) |
                             (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(&dev->vdev, features);
+    qvirtio_set_features(dev, features);
 
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
+    vq = qvirtqueue_setup(dev, t_alloc, 0);
 
-    qvirtio_set_driver_ok(&dev->vdev);
+    qvirtio_set_driver_ok(dev);
 
     /* Write request */
     req.type = VIRTIO_BLK_T_OUT;
@@ -342,23 +260,23 @@ static void pci_indirect(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
 
     g_free(req.data);
 
-    indirect = qvring_indirect_desc_setup(&dev->vdev, &qs->alloc, 2);
+    indirect = qvring_indirect_desc_setup(dev, t_alloc, 2);
     qvring_indirect_desc_add(indirect, req_addr, 528, false);
     qvring_indirect_desc_add(indirect, req_addr + 528, 1, true);
-    free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
-    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+    qvirtqueue_kick(dev, vq, free_head);
 
-    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
+    qvirtio_wait_used_elem(dev, vq, free_head, NULL,
                            QVIRTIO_BLK_TIMEOUT_US);
     status = readb(req_addr + 528);
     g_assert_cmpint(status, ==, 0);
 
     g_free(indirect);
-    guest_free(&qs->alloc, req_addr);
+    guest_free(t_alloc, req_addr);
 
     /* Read request */
     req.type = VIRTIO_BLK_T_IN;
@@ -367,17 +285,17 @@ static void pci_indirect(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
 
     g_free(req.data);
 
-    indirect = qvring_indirect_desc_setup(&dev->vdev, &qs->alloc, 2);
+    indirect = qvring_indirect_desc_setup(dev, t_alloc, 2);
     qvring_indirect_desc_add(indirect, req_addr, 16, false);
     qvring_indirect_desc_add(indirect, req_addr + 16, 513, true);
-    free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
-    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+    free_head = qvirtqueue_add_indirect(vq, indirect);
+    qvirtqueue_kick(dev, vq, free_head);
 
-    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
+    qvirtio_wait_used_elem(dev, vq, free_head, NULL,
                            QVIRTIO_BLK_TIMEOUT_US);
     status = readb(req_addr + 528);
     g_assert_cmpint(status, ==, 0);
@@ -388,52 +306,37 @@ static void pci_indirect(void)
     g_free(data);
 
     g_free(indirect);
-    guest_free(&qs->alloc, req_addr);
-
-    /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
-    qvirtio_pci_device_disable(dev);
-    qvirtio_pci_device_free(dev);
-    g_free(dev);
-    qtest_shutdown(qs);
+    guest_free(t_alloc, req_addr);
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
 }
 
-static void pci_config(void)
+static void config(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    QVirtioPCIDevice *dev;
-    QOSState *qs;
+    QVirtioBlk *blk_if = obj;
+    QVirtioDevice *dev = blk_if->vdev;
     int n_size = TEST_IMAGE_SIZE / 2;
     uint64_t capacity;
 
-    qs = pci_test_start();
-
-    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
-
-    capacity = qvirtio_config_readq(&dev->vdev, 0);
+    capacity = qvirtio_config_readq(dev, 0);
     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 
-    qvirtio_set_driver_ok(&dev->vdev);
+    qvirtio_set_driver_ok(dev);
 
     qmp_discard_response("{ 'execute': 'block_resize', "
                          " 'arguments': { 'device': 'drive0', "
                          " 'size': %d } }", n_size);
-    qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
+    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
 
-    capacity = qvirtio_config_readq(&dev->vdev, 0);
+    capacity = qvirtio_config_readq(dev, 0);
     g_assert_cmpint(capacity, ==, n_size / 512);
-
-    qvirtio_pci_device_disable(dev);
-    qvirtio_pci_device_free(dev);
-    g_free(dev);
-
-    qtest_shutdown(qs);
 }
 
-static void pci_msix(void)
+static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
 {
-    QVirtioPCIDevice *dev;
-    QOSState *qs;
-    QVirtQueuePCI *vqpci;
+    QVirtQueue *vq;
+    QVirtioBlkPCI *blk = obj;
+    QVirtioPCIDevice *pdev = &blk->pci_vdev;
+    QVirtioDevice *dev = &pdev->vdev;
     QVirtioBlkReq req;
     int n_size = TEST_IMAGE_SIZE / 2;
     uint64_t req_addr;
@@ -442,36 +345,38 @@ static void pci_msix(void)
     uint32_t free_head;
     uint8_t status;
     char *data;
+    QOSGraphObject *blk_object = obj;
+    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
 
-    qs = pci_test_start();
-
-    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
-    qpci_msix_enable(dev->pdev);
+    if (qpci_check_buggy_msi(pci_dev)) {
+        return;
+    }
 
-    qvirtio_pci_set_msix_configuration_vector(dev, &qs->alloc, 0);
+    qpci_msix_enable(pdev->pdev);
+    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
 
-    capacity = qvirtio_config_readq(&dev->vdev, 0);
+    capacity = qvirtio_config_readq(dev, 0);
     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 
-    features = qvirtio_get_features(&dev->vdev);
+    features = qvirtio_get_features(dev);
     features = features & ~(QVIRTIO_F_BAD_FEATURE |
                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
                             (1u << VIRTIO_RING_F_EVENT_IDX) |
                             (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(&dev->vdev, features);
+    qvirtio_set_features(dev, features);
 
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
-    qvirtqueue_pci_msix_setup(dev, vqpci, &qs->alloc, 1);
+    vq = qvirtqueue_setup(dev, t_alloc, 0);
+    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
 
-    qvirtio_set_driver_ok(&dev->vdev);
+    qvirtio_set_driver_ok(dev);
 
     qmp_discard_response("{ 'execute': 'block_resize', "
                          " 'arguments': { 'device': 'drive0', "
                          " 'size': %d } }", n_size);
 
-    qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
+    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
 
-    capacity = qvirtio_config_readq(&dev->vdev, 0);
+    capacity = qvirtio_config_readq(dev, 0);
     g_assert_cmpint(capacity, ==, n_size / 512);
 
     /* Write request */
@@ -481,22 +386,22 @@ static void pci_msix(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
 
     g_free(req.data);
 
-    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
-    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+    free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+    qvirtqueue_add(vq, req_addr + 16, 512, false, true);
+    qvirtqueue_add(vq, req_addr + 528, 1, true, false);
+    qvirtqueue_kick(dev, vq, free_head);
 
-    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
+    qvirtio_wait_used_elem(dev, vq, free_head, NULL,
                            QVIRTIO_BLK_TIMEOUT_US);
 
     status = readb(req_addr + 528);
     g_assert_cmpint(status, ==, 0);
 
-    guest_free(&qs->alloc, req_addr);
+    guest_free(t_alloc, req_addr);
 
     /* Read request */
     req.type = VIRTIO_BLK_T_IN;
@@ -504,18 +409,18 @@ static void pci_msix(void)
     req.sector = 0;
     req.data = g_malloc0(512);
 
-    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
 
     g_free(req.data);
 
-    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
+    free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+    qvirtqueue_add(vq, req_addr + 16, 512, true, true);
+    qvirtqueue_add(vq, req_addr + 528, 1, true, false);
 
-    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+    qvirtqueue_kick(dev, vq, free_head);
 
 
-    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
+    qvirtio_wait_used_elem(dev, vq, free_head, NULL,
                            QVIRTIO_BLK_TIMEOUT_US);
 
     status = readb(req_addr + 528);
@@ -526,22 +431,19 @@ static void pci_msix(void)
     g_assert_cmpstr(data, ==, "TEST");
     g_free(data);
 
-    guest_free(&qs->alloc, req_addr);
+    guest_free(t_alloc, req_addr);
 
     /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
-    qpci_msix_disable(dev->pdev);
-    qvirtio_pci_device_disable(dev);
-    qvirtio_pci_device_free(dev);
-    g_free(dev);
-    qtest_shutdown(qs);
+    qpci_msix_disable(pdev->pdev);
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
 }
 
-static void pci_idx(void)
+static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
 {
-    QVirtioPCIDevice *dev;
-    QOSState *qs;
-    QVirtQueuePCI *vqpci;
+    QVirtQueue *vq;
+    QVirtioBlkPCI *blk = obj;
+    QVirtioPCIDevice *pdev = &blk->pci_vdev;
+    QVirtioDevice *dev = &pdev->vdev;
     QVirtioBlkReq req;
     uint64_t req_addr;
     uint64_t capacity;
@@ -551,28 +453,30 @@ static void pci_idx(void)
     uint32_t desc_idx;
     uint8_t status;
     char *data;
+    QOSGraphObject *blk_object = obj;
+    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
 
-    qs = pci_test_start();
-
-    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
-    qpci_msix_enable(dev->pdev);
+    if (qpci_check_buggy_msi(pci_dev)) {
+        return;
+    }
 
-    qvirtio_pci_set_msix_configuration_vector(dev, &qs->alloc, 0);
+    qpci_msix_enable(pdev->pdev);
+    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
 
-    capacity = qvirtio_config_readq(&dev->vdev, 0);
+    capacity = qvirtio_config_readq(dev, 0);
     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 
-    features = qvirtio_get_features(&dev->vdev);
+    features = qvirtio_get_features(dev);
     features = features & ~(QVIRTIO_F_BAD_FEATURE |
                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
                             (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
                             (1u << VIRTIO_BLK_F_SCSI));
-    qvirtio_set_features(&dev->vdev, features);
+    qvirtio_set_features(dev, features);
 
-    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
-    qvirtqueue_pci_msix_setup(dev, vqpci, &qs->alloc, 1);
+    vq = qvirtqueue_setup(dev, t_alloc, 0);
+    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
 
-    qvirtio_set_driver_ok(&dev->vdev);
+    qvirtio_set_driver_ok(dev);
 
     /* Write request */
     req.type = VIRTIO_BLK_T_OUT;
@@ -581,16 +485,16 @@ static void pci_idx(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
 
     g_free(req.data);
 
-    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
-    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+    free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+    qvirtqueue_add(vq, req_addr + 16, 512, false, true);
+    qvirtqueue_add(vq, req_addr + 528, 1, true, false);
+    qvirtqueue_kick(dev, vq, free_head);
 
-    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
+    qvirtio_wait_used_elem(dev, vq, free_head, NULL,
                            QVIRTIO_BLK_TIMEOUT_US);
 
     /* Write request */
@@ -600,25 +504,25 @@ static void pci_idx(void)
     req.data = g_malloc0(512);
     strcpy(req.data, "TEST");
 
-    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
 
     g_free(req.data);
 
     /* Notify after processing the third request */
-    qvirtqueue_set_used_event(&vqpci->vq, 2);
-    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
-    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+    qvirtqueue_set_used_event(vq, 2);
+    free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+    qvirtqueue_add(vq, req_addr + 16, 512, false, true);
+    qvirtqueue_add(vq, req_addr + 528, 1, true, false);
+    qvirtqueue_kick(dev, vq, free_head);
     write_head = free_head;
 
     /* No notification expected */
-    status = qvirtio_wait_status_byte_no_isr(&dev->vdev,
-                                             &vqpci->vq, req_addr + 528,
+    status = qvirtio_wait_status_byte_no_isr(dev,
+                                             vq, req_addr + 528,
                                              QVIRTIO_BLK_TIMEOUT_US);
     g_assert_cmpint(status, ==, 0);
 
-    guest_free(&qs->alloc, req_addr);
+    guest_free(t_alloc, req_addr);
 
     /* Read request */
     req.type = VIRTIO_BLK_T_IN;
@@ -626,20 +530,20 @@ static void pci_idx(void)
     req.sector = 1;
     req.data = g_malloc0(512);
 
-    req_addr = virtio_blk_request(&qs->alloc, &dev->vdev, &req, 512);
+    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
 
     g_free(req.data);
 
-    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
-    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
+    free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+    qvirtqueue_add(vq, req_addr + 16, 512, true, true);
+    qvirtqueue_add(vq, req_addr + 528, 1, true, false);
 
-    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
+    qvirtqueue_kick(dev, vq, free_head);
 
     /* We get just one notification for both requests */
-    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, write_head, NULL,
+    qvirtio_wait_used_elem(dev, vq, write_head, NULL,
                            QVIRTIO_BLK_TIMEOUT_US);
-    g_assert(qvirtqueue_get_buf(&vqpci->vq, &desc_idx, NULL));
+    g_assert(qvirtqueue_get_buf(vq, &desc_idx, NULL));
     g_assert_cmpint(desc_idx, ==, free_head);
 
     status = readb(req_addr + 528);
@@ -650,125 +554,114 @@ static void pci_idx(void)
     g_assert_cmpstr(data, ==, "TEST");
     g_free(data);
 
-    guest_free(&qs->alloc, req_addr);
+    guest_free(t_alloc, req_addr);
 
     /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, &qs->alloc);
-    qpci_msix_disable(dev->pdev);
-    qvirtio_pci_device_disable(dev);
-    qvirtio_pci_device_free(dev);
-    g_free(dev);
-    qtest_shutdown(qs);
+    qpci_msix_disable(pdev->pdev);
+
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
 }
 
-static void pci_hotplug(void)
+static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
 {
+    QVirtioPCIDevice *dev1 = obj;
     QVirtioPCIDevice *dev;
-    QOSState *qs;
-    const char *arch = qtest_get_arch();
-
-    qs = pci_test_start();
 
     /* plug secondary disk */
     qtest_qmp_device_add("virtio-blk-pci", "drv1",
                          "{'addr': %s, 'drive': 'drive1'}",
-                         stringify(PCI_SLOT_HP));
+                         stringify(PCI_SLOT_HP) ".0");
 
-    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT_HP);
-    g_assert(dev);
+    dev = virtio_pci_new(dev1->pdev->bus,
+                         &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });
+    g_assert_nonnull(dev);
+    g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
     qvirtio_pci_device_disable(dev);
-    qvirtio_pci_device_free(dev);
-    g_free(dev);
+    qos_object_destroy((QOSGraphObject *)dev);
 
     /* unplug secondary disk */
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
-    }
-    qtest_shutdown(qs);
+    qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
 }
 
 /*
  * Check that setting the vring addr on a non-existent virtqueue does
  * not crash.
  */
-static void test_nonexistent_virtqueue(void)
+static void test_nonexistent_virtqueue(void *obj, void *data,
+                                       QGuestAllocator *t_alloc)
 {
+    QVirtioBlkPCI *blk = obj;
+    QVirtioPCIDevice *pdev = &blk->pci_vdev;
     QPCIBar bar0;
-    QOSState *qs;
     QPCIDevice *dev;
 
-    qs = pci_test_start();
-    dev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4, 0));
+    dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
     g_assert(dev != NULL);
-
     qpci_device_enable(dev);
+
     bar0 = qpci_iomap(dev, 0, NULL);
 
     qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
     qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
 
+
     g_free(dev);
-    qtest_shutdown(qs);
 }
 
-static void mmio_basic(void)
+static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    QVirtioMMIODevice *dev;
-    QVirtQueue *vq;
-    QGuestAllocator alloc;
+    QVirtioBlk *blk_if = obj;
+    QVirtioDevice *dev = blk_if->vdev;
     int n_size = TEST_IMAGE_SIZE / 2;
     uint64_t capacity;
+    QVirtQueue *vq;
 
-    arm_test_start();
-
-    dev = g_malloc0(sizeof(QVirtioMMIODevice));
-    qvirtio_mmio_init_device(dev, global_qtest, MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
-    g_assert(dev != NULL);
-    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
-
-    qvirtio_start_device(&dev->vdev);
-
-    generic_alloc_init(&alloc, MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
-    vq = qvirtqueue_setup(&dev->vdev, &alloc, 0);
+    vq = qvirtqueue_setup(dev, t_alloc, 0);
 
-    test_basic(&dev->vdev, &alloc, vq);
+    test_basic(dev, t_alloc, vq);
 
     qmp_discard_response("{ 'execute': 'block_resize', "
                          " 'arguments': { 'device': 'drive0', "
                          " 'size': %d } }", n_size);
 
-    qvirtio_wait_queue_isr(&dev->vdev, vq, QVIRTIO_BLK_TIMEOUT_US);
+    qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
 
-    capacity = qvirtio_config_readq(&dev->vdev, 0);
+    capacity = qvirtio_config_readq(dev, 0);
     g_assert_cmpint(capacity, ==, n_size / 512);
 
-    /* End test */
-    qvirtqueue_cleanup(dev->vdev.bus, vq, &alloc);
-    g_free(dev);
-    alloc_destroy(&alloc);
-    test_end();
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+
 }
 
-int main(int argc, char **argv)
+static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
 {
-    const char *arch = qtest_get_arch();
-
-    g_test_init(&argc, &argv, NULL);
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0 ||
-        strcmp(arch, "ppc64") == 0) {
-        qtest_add_func("/virtio/blk/pci/basic", pci_basic);
-        qtest_add_func("/virtio/blk/pci/indirect", pci_indirect);
-        qtest_add_func("/virtio/blk/pci/config", pci_config);
-        qtest_add_func("/virtio/blk/pci/nxvirtq", test_nonexistent_virtqueue);
-        if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-            qtest_add_func("/virtio/blk/pci/msix", pci_msix);
-            qtest_add_func("/virtio/blk/pci/idx", pci_idx);
-        }
-        qtest_add_func("/virtio/blk/pci/hotplug", pci_hotplug);
-    } else if (strcmp(arch, "arm") == 0) {
-        qtest_add_func("/virtio/blk/mmio/basic", mmio_basic);
-    }
+    char *tmp_path = drive_create();
 
-    return g_test_run();
+    g_string_append_printf(cmd_line,
+                           " -drive if=none,id=drive0,file=%s,format=raw "
+                           "-drive if=none,id=drive1,file=null-co://,format=raw ",
+			   tmp_path);
+
+    return arg;
 }
+
+static void register_virtio_blk_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = virtio_blk_test_setup,
+    };
+
+    qos_add_test("indirect", "virtio-blk", indirect, &opts);
+    qos_add_test("config", "virtio-blk", config, &opts);
+    qos_add_test("basic", "virtio-blk", basic, &opts);
+    qos_add_test("resize", "virtio-blk", resize, &opts);
+
+    /* tests just for virtio-blk-pci */
+    qos_add_test("msix", "virtio-blk-pci", msix, &opts);
+    qos_add_test("idx", "virtio-blk-pci", idx, &opts);
+    qos_add_test("nxvirtq", "virtio-blk-pci",
+                      test_nonexistent_virtqueue, &opts);
+    qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug, &opts);
+}
+
+libqos_init(register_virtio_blk_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 50/71] tests/libqos: virtio-net driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (48 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 49/71] qos-test: virtio-blk test node Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 51/71] qos-test: virtio-net test node Paolo Bonzini
                   ` (23 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-net-pci and virtio-net-device.
Both nodes produce virtio-net, but virtio-net-pci receives
a pci-bus and overrides virtio-pci QOSGraphObject and its functions,
while virtio-net-device receives a virtio and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include    |   1 +
 tests/libqos/virtio-net.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-net.h |  41 +++++++++++
 tests/libqos/virtio.c     |   1 +
 tests/libqos/virtio.h     |   1 +
 5 files changed, 226 insertions(+)
 create mode 100644 tests/libqos/virtio-net.c
 create mode 100644 tests/libqos/virtio-net.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8ba1ca9..211c675 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -669,6 +669,7 @@ qos-test-obj-y += $(libqos-virtio-obj-y)
 qos-test-obj-y += tests/libqos/virtio-9p.o
 qos-test-obj-y += tests/libqos/virtio-balloon.o
 qos-test-obj-y += tests/libqos/virtio-blk.o
+qos-test-obj-y += tests/libqos/virtio-net.o
 qos-test-obj-y += tests/libqos/virtio-rng.o
 qos-test-obj-y += tests/libqos/virtio-serial.o
 
diff --git a/tests/libqos/virtio-net.c b/tests/libqos/virtio-net.c
new file mode 100644
index 0000000..3ddfbdc
--- /dev/null
+++ b/tests/libqos/virtio-net.c
@@ -0,0 +1,182 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-net.h"
+#include "hw/virtio/virtio-net.h"
+
+
+static QGuestAllocator *alloc;
+
+static void virtio_net_cleanup(QVirtioNet *interface)
+{
+    qvirtqueue_cleanup(interface->vdev->bus, interface->rx, alloc);
+    qvirtqueue_cleanup(interface->vdev->bus, interface->tx, alloc);
+}
+
+static void virtio_net_setup(QVirtioNet *interface)
+{
+    QVirtioDevice *vdev = interface->vdev;
+    uint64_t features;
+
+    features = qvirtio_get_features(vdev);
+    features &= ~(QVIRTIO_F_BAD_FEATURE |
+                  (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+                  (1u << VIRTIO_RING_F_EVENT_IDX));
+    qvirtio_set_features(vdev, features);
+
+    interface->rx = qvirtqueue_setup(vdev, alloc, 0);
+    interface->tx = qvirtqueue_setup(vdev, alloc, 1);
+    qvirtio_set_driver_ok(vdev);
+}
+
+/* virtio-net-device */
+static void qvirtio_net_device_destructor(QOSGraphObject *obj)
+{
+    QVirtioNetDevice *v_net = (QVirtioNetDevice *) obj;
+    virtio_net_cleanup(&v_net->net);
+}
+
+static void qvirtio_net_device_start_hw(QOSGraphObject *obj)
+{
+    QVirtioNetDevice *v_net = (QVirtioNetDevice *) obj;
+    QVirtioNet *interface = &v_net->net;
+
+    virtio_net_setup(interface);
+}
+
+static void *qvirtio_net_get_driver(QVirtioNet *v_net,
+                                    const char *interface)
+{
+    if (!g_strcmp0(interface, "virtio-net")) {
+        return v_net;
+    }
+    if (!g_strcmp0(interface, "virtio")) {
+        return v_net->vdev;
+    }
+
+    fprintf(stderr, "%s not present in virtio-net-device\n", interface);
+    g_assert_not_reached();
+}
+
+static void *qvirtio_net_device_get_driver(void *object,
+                                           const char *interface)
+{
+    QVirtioNetDevice *v_net = object;
+    return qvirtio_net_get_driver(&v_net->net, interface);
+}
+
+static void *virtio_net_device_create(void *virtio_dev,
+                                          QGuestAllocator *t_alloc,
+                                          void *addr)
+{
+    QVirtioNetDevice *virtio_ndevice = g_new0(QVirtioNetDevice, 1);
+    QVirtioNet *interface = &virtio_ndevice->net;
+
+    interface->vdev = virtio_dev;
+    alloc = t_alloc;
+
+    virtio_ndevice->obj.destructor = qvirtio_net_device_destructor;
+    virtio_ndevice->obj.get_driver = qvirtio_net_device_get_driver;
+    virtio_ndevice->obj.start_hw = qvirtio_net_device_start_hw;
+
+    return &virtio_ndevice->obj;
+}
+
+/* virtio-net-pci */
+static void qvirtio_net_pci_destructor(QOSGraphObject *obj)
+{
+    QVirtioNetPCI *v_net = (QVirtioNetPCI *) obj;
+    QVirtioNet *interface = &v_net->net;
+    QOSGraphObject *pci_vobj =  &v_net->pci_vdev.obj;
+
+    virtio_net_cleanup(interface);
+    qvirtio_pci_destructor(pci_vobj);
+}
+
+static void qvirtio_net_pci_start_hw(QOSGraphObject *obj)
+{
+    QVirtioNetPCI *v_net = (QVirtioNetPCI *) obj;
+    QVirtioNet *interface = &v_net->net;
+    QOSGraphObject *pci_vobj =  &v_net->pci_vdev.obj;
+
+    qvirtio_pci_start_hw(pci_vobj);
+    virtio_net_setup(interface);
+}
+
+static void *qvirtio_net_pci_get_driver(void *object,
+                                            const char *interface)
+{
+    QVirtioNetPCI *v_net = object;
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_net->pci_vdev.pdev;
+    }
+    return qvirtio_net_get_driver(&v_net->net, interface);
+}
+
+static void *virtio_net_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
+                                  void *addr)
+{
+    QVirtioNetPCI *virtio_bpci = g_new0(QVirtioNetPCI, 1);
+    QVirtioNet *interface = &virtio_bpci->net;
+    QOSGraphObject *obj = &virtio_bpci->pci_vdev.obj;
+
+    virtio_pci_init(&virtio_bpci->pci_vdev, pci_bus, addr);
+    interface->vdev = &virtio_bpci->pci_vdev.vdev;
+    alloc = t_alloc;
+
+    g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_NET);
+
+    obj->destructor = qvirtio_net_pci_destructor;
+    obj->start_hw = qvirtio_net_pci_start_hw;
+    obj->get_driver = qvirtio_net_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_net_register_nodes(void)
+{
+    /* FIXME: every test using these nodes needs to setup a
+     * -netdev socket,id=hs0 otherwise QEMU is not going to start.
+     * Therefore, we do not include "produces" edge for virtio
+     * and pci-device yet.
+     */
+    QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(4, 0),
+    };
+
+    QOSGraphEdgeOptions opts = { };
+
+    /* virtio-net-device */
+    opts.extra_device_opts = "netdev=hs0";
+    qos_node_create_driver("virtio-net-device",
+                            virtio_net_device_create);
+    qos_node_consumes("virtio-net-device", "virtio-bus", &opts);
+    qos_node_produces("virtio-net-device", "virtio-net");
+
+    /* virtio-net-pci */
+    opts.extra_device_opts = "netdev=hs0,addr=04.0";
+    add_qpci_address(&opts, &addr);
+    qos_node_create_driver("virtio-net-pci", virtio_net_pci_create);
+    qos_node_consumes("virtio-net-pci", "pci-bus", &opts);
+    qos_node_produces("virtio-net-pci", "virtio-net");
+}
+
+libqos_init(virtio_net_register_nodes);
diff --git a/tests/libqos/virtio-net.h b/tests/libqos/virtio-net.h
new file mode 100644
index 0000000..e6905cd
--- /dev/null
+++ b/tests/libqos/virtio-net.h
@@ -0,0 +1,41 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "libqos/qgraph.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+
+typedef struct QVirtioNet QVirtioNet;
+typedef struct QVirtioNetPCI QVirtioNetPCI;
+typedef struct QVirtioNetDevice QVirtioNetDevice;
+
+struct QVirtioNet {
+    QVirtioDevice *vdev;
+    QVirtQueue *rx;
+    QVirtQueue *tx;
+};
+
+struct QVirtioNetPCI {
+    QVirtioPCIDevice pci_vdev;
+    QVirtioNet net;
+};
+
+struct QVirtioNetDevice {
+    QOSGraphObject obj;
+    QVirtioNet net;
+};
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 9fc8c7e..e4925d1 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -40,6 +40,7 @@ uint32_t qvirtio_get_features(QVirtioDevice *d)
 
 void qvirtio_set_features(QVirtioDevice *d, uint32_t features)
 {
+    d->features = features;
     d->bus->set_features(d, features);
 }
 
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 7f0f9dd..3f97d79 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -21,6 +21,7 @@ typedef struct QVirtioDevice {
     const QVirtioBus *bus;
     /* Device type */
     uint16_t device_type;
+    uint64_t features;
     bool big_endian;
 } QVirtioDevice;
 
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 51/71] qos-test: virtio-net test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (49 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 50/71] tests/libqos: virtio-net driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 52/71] tests/libqos: support multiqueue for virtio-net Paolo Bonzini
                   ` (22 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/virtio-net-test in qgraph test node,
virtio-net-test. This test consumes a virtio-net interface
and checks that its function return the expected values.

Some functions are implemented only for virtio-net-pci, so they
don't consume virtio-net, but virtio-net-pci

Note that this test does not allocate any virtio-net structure,
it's all done by the qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include  |   3 +-
 tests/virtio-net-test.c | 165 +++++++++++++++---------------------------------
 2 files changed, 53 insertions(+), 115 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 211c675..d300f60 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -143,7 +143,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 
-check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
@@ -690,6 +689,7 @@ qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-y += tests/virtio-test.o
 qos-test-obj-y += tests/virtio-9p-test.o
 qos-test-obj-y += tests/virtio-blk-test.o
+qos-test-obj-y += tests/virtio-net-test.o
 qos-test-obj-y += tests/virtio-rng-test.o
 qos-test-obj-y += tests/virtio-serial-test.o
 
@@ -737,7 +737,6 @@ tests/ne2000-test$(EXESUF): tests/ne2000-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
-tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y)
 tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index fa06d9b..c6550e1 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -9,18 +9,11 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
-#include "qemu-common.h"
-#include "qemu/sockets.h"
 #include "qemu/iov.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/libqos-spapr.h"
-#include "libqos/virtio.h"
-#include "libqos/virtio-pci.h"
 #include "qapi/qmp/qdict.h"
-#include "qemu/bswap.h"
 #include "hw/virtio/virtio-net.h"
-#include "standard-headers/linux/virtio_ids.h"
-#include "standard-headers/linux/virtio_ring.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-net.h"
 
 #define PCI_SLOT_HP             0x06
 #define PCI_SLOT                0x04
@@ -29,59 +22,8 @@
 #define QVIRTIO_NET_TIMEOUT_US (30 * 1000 * 1000)
 #define VNET_HDR_SIZE sizeof(struct virtio_net_hdr_mrg_rxbuf)
 
-static void test_end(void)
-{
-    qtest_end();
-}
-
 #ifndef _WIN32
 
-static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot)
-{
-    QVirtioPCIDevice *dev;
-
-    dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
-    g_assert(dev != NULL);
-    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_NET);
-
-    qvirtio_pci_device_enable(dev);
-    qvirtio_start_device(&dev->vdev);
-
-    return dev;
-}
-
-static QOSState *pci_test_start(int socket)
-{
-    QOSState *qs;
-    const char *arch = qtest_get_arch();
-    const char *cmd = "-netdev socket,fd=%d,id=hs0 -device "
-                      "virtio-net-pci,netdev=hs0";
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qs = qtest_pc_boot(cmd, socket);
-    } else if (strcmp(arch, "ppc64") == 0) {
-        qs = qtest_spapr_boot(cmd, socket);
-    } else {
-        g_printerr("virtio-net tests are only available on x86 or ppc64\n");
-        exit(EXIT_FAILURE);
-    }
-    global_qtest = qs->qts;
-    return qs;
-}
-
-static void driver_init(QVirtioDevice *dev)
-{
-    uint32_t features;
-
-    features = qvirtio_get_features(dev);
-    features = features & ~(QVIRTIO_F_BAD_FEATURE |
-                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
-                            (1u << VIRTIO_RING_F_EVENT_IDX));
-    qvirtio_set_features(dev, features);
-
-    qvirtio_set_driver_ok(dev);
-}
-
 static void rx_test(QVirtioDevice *dev,
                     QGuestAllocator *alloc, QVirtQueue *vq,
                     int socket)
@@ -191,81 +133,78 @@ static void rx_stop_cont_test(QVirtioDevice *dev,
     guest_free(alloc, req_addr);
 }
 
-static void send_recv_test(QVirtioDevice *dev,
-                           QGuestAllocator *alloc, QVirtQueue *rvq,
-                           QVirtQueue *tvq, int socket)
+static void send_recv_test(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    rx_test(dev, alloc, rvq, socket);
-    tx_test(dev, alloc, tvq, socket);
+    QVirtioNet *net_if = obj;
+    QVirtioDevice *dev = net_if->vdev;
+    QVirtQueue *rx = net_if->rx;
+    QVirtQueue *tx = net_if->tx;
+    int *sv = data;
+
+    rx_test(dev, t_alloc, rx, sv[0]);
+    tx_test(dev, t_alloc, tx, sv[0]);
 }
 
-static void stop_cont_test(QVirtioDevice *dev,
-                           QGuestAllocator *alloc, QVirtQueue *rvq,
-                           QVirtQueue *tvq, int socket)
+static void stop_cont_test(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    rx_stop_cont_test(dev, alloc, rvq, socket);
+    QVirtioNet *net_if = obj;
+    QVirtioDevice *dev = net_if->vdev;
+    QVirtQueue *rx = net_if->rx;
+    int *sv = data;
+
+    rx_stop_cont_test(dev, t_alloc, rx, sv[0]);
 }
 
-static void pci_basic(gconstpointer data)
+#endif
+
+static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    QVirtioPCIDevice *dev;
-    QOSState *qs;
-    QVirtQueuePCI *tx, *rx;
-    void (*func) (QVirtioDevice *dev,
-                  QGuestAllocator *alloc,
-                  QVirtQueue *rvq,
-                  QVirtQueue *tvq,
-                  int socket) = data;
-    int sv[2], ret;
+    const char *arch = qtest_get_arch();
 
-    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
-    g_assert_cmpint(ret, !=, -1);
+    qtest_qmp_device_add("virtio-net-pci", "net1",
+                         "{'addr': %s}", stringify(PCI_SLOT_HP));
 
-    qs = pci_test_start(sv[1]);
-    dev = virtio_net_pci_init(qs->pcibus, PCI_SLOT);
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP);
+    }
 
-    rx = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 0);
-    tx = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, &qs->alloc, 1);
+}
 
-    driver_init(&dev->vdev);
-    func(&dev->vdev, &qs->alloc, &rx->vq, &tx->vq, sv[0]);
+static void virtio_net_test_cleanup(void *sockets)
+{
+    int *sv = sockets;
 
-    /* End test */
     close(sv[0]);
-    qvirtqueue_cleanup(dev->vdev.bus, &tx->vq, &qs->alloc);
-    qvirtqueue_cleanup(dev->vdev.bus, &rx->vq, &qs->alloc);
-    qvirtio_pci_device_disable(dev);
-    g_free(dev->pdev);
-    g_free(dev);
-    qtest_shutdown(qs);
+    qos_invalidate_command_line();
+    close(sv[1]);
+    g_free(sv);
 }
-#endif
 
-static void hotplug(void)
+static void *virtio_net_test_setup(GString *cmd_line, void *arg)
 {
-    const char *arch = qtest_get_arch();
-
-    qtest_start("-device virtio-net-pci");
+    int ret;
+    int *sv = g_new(int, 2);
 
-    qtest_qmp_device_add("virtio-net-pci", "net1",
-                         "{'addr': %s}", stringify(PCI_SLOT_HP));
+    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
+    g_assert_cmpint(ret, !=, -1);
 
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP);
-    }
+    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", sv[1]);
 
-    test_end();
+    g_test_queue_destroy(virtio_net_test_cleanup, sv);
+    return sv;
 }
 
-int main(int argc, char **argv)
+static void register_virtio_net_test(void)
 {
-    g_test_init(&argc, &argv, NULL);
+    QOSGraphTestOptions opts = {
+        .before = virtio_net_test_setup,
+    };
+
 #ifndef _WIN32
-    qtest_add_data_func("/virtio/net/pci/basic", send_recv_test, pci_basic);
-    qtest_add_data_func("/virtio/net/pci/rx_stop_cont",
-                        stop_cont_test, pci_basic);
+    qos_add_test("basic", "virtio-net", send_recv_test, &opts);
+    qos_add_test("rx_stop_cont", "virtio-net", stop_cont_test, &opts);
 #endif
-    qtest_add_func("/virtio/net/pci/hotplug", hotplug);
-
-    return g_test_run();
+    qos_add_test("hotplug", "virtio-pci", hotplug, &opts);
 }
+
+libqos_init(register_virtio_net_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 52/71] tests/libqos: support multiqueue for virtio-net
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (50 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 51/71] qos-test: virtio-net test node Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 53/71] vhost-user-test: always use 256 MiB of guest memory Paolo Bonzini
                   ` (21 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Initialize the additional virtqueues if they are supported.
This is needed to switch vhost-user-test's multiqueue test
to the virtio-net qgraph.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/libqos/virtio-net.c | 21 +++++++++++++++++----
 tests/libqos/virtio-net.h |  4 ++--
 tests/virtio-net-test.c   |  6 +++---
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/tests/libqos/virtio-net.c b/tests/libqos/virtio-net.c
index 3ddfbdc..61c5617 100644
--- a/tests/libqos/virtio-net.c
+++ b/tests/libqos/virtio-net.c
@@ -27,14 +27,19 @@ static QGuestAllocator *alloc;
 
 static void virtio_net_cleanup(QVirtioNet *interface)
 {
-    qvirtqueue_cleanup(interface->vdev->bus, interface->rx, alloc);
-    qvirtqueue_cleanup(interface->vdev->bus, interface->tx, alloc);
+    int i;
+
+    for (i = 0; i < interface->n_queues; i++) {
+        qvirtqueue_cleanup(interface->vdev->bus, interface->queues[i], alloc);
+    }
+    g_free(interface->queues);
 }
 
 static void virtio_net_setup(QVirtioNet *interface)
 {
     QVirtioDevice *vdev = interface->vdev;
     uint64_t features;
+    int i;
 
     features = qvirtio_get_features(vdev);
     features &= ~(QVIRTIO_F_BAD_FEATURE |
@@ -42,8 +47,16 @@ static void virtio_net_setup(QVirtioNet *interface)
                   (1u << VIRTIO_RING_F_EVENT_IDX));
     qvirtio_set_features(vdev, features);
 
-    interface->rx = qvirtqueue_setup(vdev, alloc, 0);
-    interface->tx = qvirtqueue_setup(vdev, alloc, 1);
+    if (features & (1u << VIRTIO_NET_F_MQ)) {
+        interface->n_queues = qvirtio_config_readw(vdev, 8) * 2;
+    } else {
+        interface->n_queues = 2;
+    }
+
+    interface->queues = g_new(QVirtQueue *, interface->n_queues);
+    for (i = 0; i < interface->n_queues; i++) {
+        interface->queues[i] = qvirtqueue_setup(vdev, alloc, i);
+    }
     qvirtio_set_driver_ok(vdev);
 }
 
diff --git a/tests/libqos/virtio-net.h b/tests/libqos/virtio-net.h
index e6905cd..28238a1 100644
--- a/tests/libqos/virtio-net.h
+++ b/tests/libqos/virtio-net.h
@@ -26,8 +26,8 @@ typedef struct QVirtioNetDevice QVirtioNetDevice;
 
 struct QVirtioNet {
     QVirtioDevice *vdev;
-    QVirtQueue *rx;
-    QVirtQueue *tx;
+    int n_queues;
+    QVirtQueue **queues;
 };
 
 struct QVirtioNetPCI {
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index c6550e1..b232074 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -137,8 +137,8 @@ static void send_recv_test(void *obj, void *data, QGuestAllocator *t_alloc)
 {
     QVirtioNet *net_if = obj;
     QVirtioDevice *dev = net_if->vdev;
-    QVirtQueue *rx = net_if->rx;
-    QVirtQueue *tx = net_if->tx;
+    QVirtQueue *rx = net_if->queues[0];
+    QVirtQueue *tx = net_if->queues[1];
     int *sv = data;
 
     rx_test(dev, t_alloc, rx, sv[0]);
@@ -149,7 +149,7 @@ static void stop_cont_test(void *obj, void *data, QGuestAllocator *t_alloc)
 {
     QVirtioNet *net_if = obj;
     QVirtioDevice *dev = net_if->vdev;
-    QVirtQueue *rx = net_if->rx;
+    QVirtQueue *rx = net_if->queues[0];
     int *sv = data;
 
     rx_stop_cont_test(dev, t_alloc, rx, sv[0]);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 53/71] vhost-user-test: always use 256 MiB of guest memory
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (51 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 52/71] tests/libqos: support multiqueue for virtio-net Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 54/71] qos-test: vhost-user test node Paolo Bonzini
                   ` (20 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Some tests are using a small amount of RAM for the guest (2 MiB) in order to
save host memory, others are using 512 MiB.

However, pSeries machines only support multiples of 256 MiB.  Using 256
MiB of memory does not use more host memory than now, even for the
migration test that starts two guests, and it allows running the test on
pSeries too.

This of course is not optimal, it would be nice to let the qgraph machine object
judge how much memory to provide.  This is left for future work, together
with a more generic framework that wraps the QEMU command line.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/vhost-user-test.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 0c9a79a..f135052 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -694,7 +694,7 @@ static void test_read_guest_mem(const void *arg)
                              "read-guest-memfd" : "read-guest-mem");
     test_server_listen(server);
 
-    qemu_cmd = get_qemu_cmd(server, 512, memfd, "", "");
+    qemu_cmd = get_qemu_cmd(server, 256, memfd, "", "");
 
     s = qtest_start(qemu_cmd);
     g_free(qemu_cmd);
@@ -729,7 +729,7 @@ static void test_migrate(void)
     test_server_listen(s);
     test_server_listen(dest);
 
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, "", "");
+    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, "", "");
     from = qtest_start(cmd);
     g_free(cmd);
 
@@ -739,10 +739,10 @@ static void test_migrate(void)
     }
 
     size = get_log_size(s);
-    g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
+    g_assert_cmpint(size, ==, (256 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
 
     tmp = g_strdup_printf(" -incoming %s", uri);
-    cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, "", tmp);
+    cmd = get_qemu_cmd(dest, 256, TEST_MEMFD_AUTO, "", tmp);
     g_free(tmp);
     to = qtest_init(cmd);
     g_free(cmd);
@@ -852,7 +852,7 @@ static void test_reconnect_subprocess(void)
     char *cmd;
 
     g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
+    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, ",server", "");
     qtest_start(cmd);
     g_free(cmd);
 
@@ -894,7 +894,7 @@ static void test_connect_fail_subprocess(void)
 
     s->test_fail = true;
     g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
+    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, ",server", "");
     qtest_start(cmd);
     g_free(cmd);
 
@@ -927,7 +927,7 @@ static void test_flags_mismatch_subprocess(void)
 
     s->test_flags = TEST_FLAGS_DISCONNECT;
     g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
+    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, ",server", "");
     qtest_start(cmd);
     g_free(cmd);
 
@@ -968,14 +968,14 @@ static void test_multiqueue(void)
         cmd = g_strdup_printf(
             QEMU_CMD_MEMFD QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
             "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
-            512, 512, s->chr_name,
+            256, 256, s->chr_name,
             s->socket_path, "", s->chr_name,
             s->queues, s->queues * 2 + 2);
     } else {
         cmd = g_strdup_printf(
             QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
             "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
-            512, 512, s->mem_path, s->chr_name,
+            256, 256, s->mem_path, s->chr_name,
             s->socket_path, "", s->chr_name,
             s->queues, s->queues * 2 + 2);
     }
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 54/71] qos-test: vhost-user test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (52 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 53/71] vhost-user-test: always use 256 MiB of guest memory Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 55/71] tests/libqos: virtio-scsi driver and interface nodes Paolo Bonzini
                   ` (19 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Convert tests/virtio-net-test in qgraph test node,
virtio-net-test. This test consumes a virtio-net interface
and checks that its function return the expected values.

Note that this test does not allocate any virtio-net structure,
it's all done by the qtest walking graph mechanism.  Nevertheless,
vhost-user-test is a bit more complex than the other tests, because
it requires more complicated setup of back-ends and thus almost each
test has a slightly different opts.before function.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include  |   5 +-
 tests/vhost-user-test.c | 378 +++++++++++++++++++-----------------------------
 2 files changed, 150 insertions(+), 233 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index d300f60..070d93e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -192,7 +192,6 @@ check-qtest-i386-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF)
 check-qtest-i386-y += tests/cpu-plug-test$(EXESUF)
 check-qtest-i386-y += tests/q35-test$(EXESUF)
 check-qtest-i386-y += tests/vmgenid-test$(EXESUF)
-check-qtest-i386-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF)
@@ -686,6 +685,7 @@ qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
+qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
 qos-test-obj-y += tests/virtio-test.o
 qos-test-obj-y += tests/virtio-9p-test.o
 qos-test-obj-y += tests/virtio-blk-test.o
@@ -758,9 +758,6 @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
 tests/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o
 tests/migration-test$(EXESUF): tests/migration-test.o
-tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \
-	$(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y) \
-	$(chardev-obj-y)
 tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
 tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
 tests/test-keyval$(EXESUF): tests/test-keyval.o $(test-util-obj-y) $(test-qapi-obj-y)
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index f135052..1d22d8a 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -38,8 +38,7 @@
 #define QEMU_CMD_MEMFD  " -m %d -object memory-backend-memfd,id=mem,size=%dM," \
                         " -numa node,memdev=mem"
 #define QEMU_CMD_CHR    " -chardev socket,id=%s,path=%s%s"
-#define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce"
-#define QEMU_CMD_NET    " -device virtio-net-pci,netdev=net0"
+#define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce"
 
 #define HUGETLBFS_MAGIC       0x958458f6
 
@@ -133,13 +132,9 @@ enum {
 };
 
 typedef struct TestServer {
-    QPCIBus *bus;
-    QVirtioPCIDevice *dev;
-    QVirtQueue *vq[VHOST_MAX_VIRTQUEUES];
     gchar *socket_path;
     gchar *mig_path;
     gchar *chr_name;
-    const gchar *mem_path;
     gchar *tmpfs;
     CharBackend chr;
     int fds_num;
@@ -154,9 +149,9 @@ typedef struct TestServer {
     bool test_fail;
     int test_flags;
     int queues;
-    QGuestAllocator alloc;
 } TestServer;
 
+static const char *init_hugepagefs(void);
 static TestServer *test_server_new(const gchar *name);
 static void test_server_free(TestServer *server);
 static void test_server_listen(TestServer *server);
@@ -167,64 +162,27 @@ enum test_memfd {
     TEST_MEMFD_NO,
 };
 
-static char *get_qemu_cmd(TestServer *s,
-                          int mem, enum test_memfd memfd,
-                          const char *chr_opts, const char *extra)
+static void append_vhost_opts(TestServer *s, GString *cmd_line,
+                             const char *chr_opts)
 {
-    if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) {
-        memfd = TEST_MEMFD_YES;
-    }
-
-    if (memfd == TEST_MEMFD_YES) {
-        return g_strdup_printf(QEMU_CMD_MEMFD QEMU_CMD_CHR
-                               QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem,
-                               s->chr_name, s->socket_path,
-                               chr_opts, s->chr_name, extra);
-    } else {
-        return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR
-                               QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem,
-                               s->mem_path, s->chr_name, s->socket_path,
-                               chr_opts, s->chr_name, extra);
-    }
+    g_string_append_printf(cmd_line, QEMU_CMD_CHR QEMU_CMD_NETDEV,
+                           s->chr_name, s->socket_path,
+                           chr_opts, s->chr_name);
 }
 
-static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_mask)
+static void append_mem_opts(TestServer *server, GString *cmd_line, int size, enum test_memfd memfd)
 {
-    uint32_t features;
-    int i;
-
-    s->bus = qpci_new_pc(qts, NULL);
-    g_assert_nonnull(s->bus);
-
-    s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
-    g_assert_nonnull(s->dev);
-
-    qvirtio_pci_device_enable(s->dev);
-    qvirtio_start_device(&s->dev->vdev);
-
-    pc_alloc_init(&s->alloc, qts, 0);
-
-    for (i = 0; i < s->queues * 2; i++) {
-        s->vq[i] = qvirtqueue_setup(&s->dev->vdev, &s->alloc, i);
+    if (memfd == TEST_MEMFD_AUTO) {
+        memfd = qemu_memfd_check(0) ? TEST_MEMFD_YES : TEST_MEMFD_NO;
     }
 
-    features = qvirtio_get_features(&s->dev->vdev);
-    features = features & features_mask;
-    qvirtio_set_features(&s->dev->vdev, features);
-
-    qvirtio_set_driver_ok(&s->dev->vdev);
-}
-
-static void uninit_virtio_dev(TestServer *s)
-{
-    int i;
+    if (memfd == TEST_MEMFD_YES) {
+        const char *root = init_hugepagefs() ? : server->tmpfs;
 
-    for (i = 0; i < s->queues * 2; i++) {
-        qvirtqueue_cleanup(s->dev->vdev.bus, s->vq[i], &s->alloc);
+        g_string_append_printf(cmd_line, QEMU_CMD_MEM, size, size, root);
+    } else {
+        g_string_append_printf(cmd_line, QEMU_CMD_MEMFD, size, size);
     }
-    alloc_destroy(&s->alloc);
-
-    qvirtio_pci_device_free(s->dev);
 }
 
 static bool wait_for_fds(TestServer *s)
@@ -460,17 +418,21 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
 
 static const char *init_hugepagefs(void)
 {
+    static const char *hugepagefs;
     const char *path = getenv("QTEST_HUGETLBFS_PATH");
     struct statfs fs;
     int ret;
 
+    if (hugepagefs) {
+        return hugepagefs;
+    }
     if (!path) {
         return NULL;
     }
 
     if (access(path, R_OK | W_OK | X_OK)) {
         g_test_message("access on path (%s): %s\n", path, strerror(errno));
-        abort();
+        g_test_fail();
         return NULL;
     }
 
@@ -480,17 +442,18 @@ static const char *init_hugepagefs(void)
 
     if (ret != 0) {
         g_test_message("statfs on path (%s): %s\n", path, strerror(errno));
-        abort();
+        g_test_fail();
         return NULL;
     }
 
     if (fs.f_type != HUGETLBFS_MAGIC) {
         g_test_message("Warning: path not on HugeTLBFS: %s\n", path);
-        abort();
+        g_test_fail();
         return NULL;
     }
 
-    return path;
+    hugepagefs = path;
+    return hugepagefs;
 }
 
 static TestServer *test_server_new(const gchar *name)
@@ -510,7 +473,6 @@ static TestServer *test_server_new(const gchar *name)
     g_assert(tmpfs);
 
     server->tmpfs = g_strdup(tmpfs);
-    server->mem_path = init_hugepagefs() ? : server->tmpfs;
     server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
     server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
     server->chr_name = g_strdup_printf("chr-%s", name);
@@ -590,8 +552,6 @@ static void test_server_free(TestServer *server)
     }
 
     g_free(server->chr_name);
-    g_assert(server->bus);
-    qpci_free_pc(server->bus);
 
     g_free(server);
 }
@@ -683,70 +643,79 @@ GSourceFuncs test_migrate_source_funcs = {
     .check = test_migrate_source_check,
 };
 
-static void test_read_guest_mem(const void *arg)
+static void vhost_user_test_cleanup(void *s)
 {
-    enum test_memfd memfd = GPOINTER_TO_INT(arg);
-    TestServer *server = NULL;
-    char *qemu_cmd = NULL;
-    QTestState *s = NULL;
+    TestServer *server = s;
+
+    qos_invalidate_command_line();
+    test_server_free(server);
+}
 
-    server = test_server_new(memfd == TEST_MEMFD_YES ?
-                             "read-guest-memfd" : "read-guest-mem");
+static void *vhost_user_test_setup(GString *cmd_line, void *arg)
+{
+    TestServer *server = test_server_new("vhost-user-test");
     test_server_listen(server);
 
-    qemu_cmd = get_qemu_cmd(server, 256, memfd, "", "");
+    append_mem_opts(server, cmd_line, 256, TEST_MEMFD_YES);
+    append_vhost_opts(server, cmd_line, "");
 
-    s = qtest_start(qemu_cmd);
-    g_free(qemu_cmd);
+    g_test_queue_destroy(vhost_user_test_cleanup, server);
 
-    init_virtio_dev(global_qtest, server, 1u << VIRTIO_NET_F_MAC);
+    return server;
+}
+
+static void *vhost_user_test_setup_memfd(GString *cmd_line, void *arg)
+{
+    TestServer *server = test_server_new("vhost-user-test");
+    test_server_listen(server);
+
+    append_mem_opts(server, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(server, cmd_line, "");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, server);
+
+    return server;
+}
+
+static void test_read_guest_mem(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *server = arg;
 
     if (!wait_for_fds(server)) {
-        goto exit;
+        return;
     }
 
     read_guest_mem_server(global_qtest, server);
-
-exit:
-    uninit_virtio_dev(server);
-
-    qtest_quit(s);
-    test_server_free(server);
 }
 
-static void test_migrate(void)
+static void test_migrate(void *obj, void *arg, QGuestAllocator *alloc)
 {
-    TestServer *s = test_server_new("src");
+    TestServer *s = arg;
     TestServer *dest = test_server_new("dest");
+    GString *dest_cmdline = g_string_new(qos_get_current_command_line());
     char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
-    QTestState *from, *to;
+    QTestState *to;
     GSource *source;
-    gchar *cmd, *tmp;
     QDict *rsp;
     guint8 *log;
     guint64 size;
 
-    test_server_listen(s);
-    test_server_listen(dest);
-
-    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, "", "");
-    from = qtest_start(cmd);
-    g_free(cmd);
-
-    init_virtio_dev(from, s, 1u << VIRTIO_NET_F_MAC);
     if (!wait_for_fds(s)) {
-        goto exit;
+        return;
     }
 
     size = get_log_size(s);
     g_assert_cmpint(size, ==, (256 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
 
-    tmp = g_strdup_printf(" -incoming %s", uri);
-    cmd = get_qemu_cmd(dest, 256, TEST_MEMFD_AUTO, "", tmp);
-    g_free(tmp);
-    to = qtest_init(cmd);
-    g_free(cmd);
-    init_virtio_dev(to, dest, 1u << VIRTIO_NET_F_MAC);
+    test_server_listen(dest);
+    g_string_append_printf(dest_cmdline, " -incoming %s", uri);
+    append_mem_opts(dest, dest_cmdline, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(dest, dest_cmdline, "");
+    to = qtest_init(dest_cmdline->str);
+
+    /* This would be where you call qos_allocate_objects(to, NULL), if you want
+     * to talk to the QVirtioNet object on the destination.
+     */
 
     source = g_source_new(&test_migrate_source_funcs,
                           sizeof(TestMigrateSource));
@@ -787,18 +756,11 @@ static void test_migrate(void)
     g_assert(wait_for_fds(dest));
     read_guest_mem_server(to, dest);
 
-    uninit_virtio_dev(dest);
-    qtest_quit(to);
-
     g_source_destroy(source);
     g_source_unref(source);
 
-exit:
-    uninit_virtio_dev(s);
-
+    qtest_quit(to);
     test_server_free(dest);
-    qtest_quit(from);
-    test_server_free(s);
     g_free(uri);
 }
 
@@ -846,19 +808,25 @@ connect_thread(gpointer data)
     return NULL;
 }
 
-static void test_reconnect_subprocess(void)
+static void *vhost_user_test_setup_reconnect(GString *cmd_line, void *arg)
 {
     TestServer *s = test_server_new("reconnect");
-    char *cmd;
 
     g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, ",server", "");
-    qtest_start(cmd);
-    g_free(cmd);
+    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(s, cmd_line, ",server");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, s);
+
+    return s;
+}
+
+static void test_reconnect(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *s = arg;
 
-    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
     if (!wait_for_fds(s)) {
-        goto exit;
+        return;
     }
 
     wait_for_rings_started(s, 2);
@@ -869,159 +837,111 @@ static void test_reconnect_subprocess(void)
     g_idle_add(reconnect_cb, s);
     g_assert(wait_for_fds(s));
     wait_for_rings_started(s, 2);
-
-exit:
-    uninit_virtio_dev(s);
-
-    qtest_end();
-    test_server_free(s);
-    return;
 }
 
-static void test_reconnect(void)
-{
-    gchar *path = g_strdup_printf("/%s/vhost-user/reconnect/subprocess",
-                                  qtest_get_arch());
-    g_test_trap_subprocess(path, 0, 0);
-    g_test_trap_assert_passed();
-    g_free(path);
-}
-
-static void test_connect_fail_subprocess(void)
+static void *vhost_user_test_setup_connect_fail(GString *cmd_line, void *arg)
 {
     TestServer *s = test_server_new("connect-fail");
-    char *cmd;
 
     s->test_fail = true;
-    g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, ",server", "");
-    qtest_start(cmd);
-    g_free(cmd);
 
-    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
-    if (!wait_for_fds(s)) {
-        goto exit;
-    }
-    wait_for_rings_started(s, 2);
+    g_thread_new("connect", connect_thread, s);
+    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(s, cmd_line, ",server");
 
-exit:
-    uninit_virtio_dev(s);
+    g_test_queue_destroy(vhost_user_test_cleanup, s);
 
-    qtest_end();
-    test_server_free(s);
+    return s;
 }
 
-static void test_connect_fail(void)
-{
-    gchar *path = g_strdup_printf("/%s/vhost-user/connect-fail/subprocess",
-                                  qtest_get_arch());
-    g_test_trap_subprocess(path, 0, 0);
-    g_test_trap_assert_passed();
-    g_free(path);
-}
-
-static void test_flags_mismatch_subprocess(void)
+static void *vhost_user_test_setup_flags_mismatch(GString *cmd_line, void *arg)
 {
     TestServer *s = test_server_new("flags-mismatch");
-    char *cmd;
 
     s->test_flags = TEST_FLAGS_DISCONNECT;
-    g_thread_new("connect", connect_thread, s);
-    cmd = get_qemu_cmd(s, 256, TEST_MEMFD_AUTO, ",server", "");
-    qtest_start(cmd);
-    g_free(cmd);
 
-    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
-    if (!wait_for_fds(s)) {
-        goto exit;
-    }
-    wait_for_rings_started(s, 2);
+    g_thread_new("connect", connect_thread, s);
+    append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO);
+    append_vhost_opts(s, cmd_line, ",server");
 
-exit:
-    uninit_virtio_dev(s);
+    g_test_queue_destroy(vhost_user_test_cleanup, s);
 
-    qtest_end();
-    test_server_free(s);
+    return s;
 }
 
-static void test_flags_mismatch(void)
+static void test_vhost_user_started(void *obj, void *arg, QGuestAllocator *alloc)
 {
-    gchar *path = g_strdup_printf("/%s/vhost-user/flags-mismatch/subprocess",
-                                  qtest_get_arch());
-    g_test_trap_subprocess(path, 0, 0);
-    g_test_trap_assert_passed();
-    g_free(path);
-}
+    TestServer *s = arg;
 
+    if (!wait_for_fds(s)) {
+        return;
+    }
+    wait_for_rings_started(s, 2);
+}
 
-static void test_multiqueue(void)
+static void *vhost_user_test_setup_multiqueue(GString *cmd_line, void *arg)
 {
-    TestServer *s = test_server_new("mq");
-    char *cmd;
-    uint32_t features_mask = ~(QVIRTIO_F_BAD_FEATURE |
-                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
-                            (1u << VIRTIO_RING_F_EVENT_IDX));
+    TestServer *s = vhost_user_test_setup_memfd(cmd_line, arg);
+
     s->queues = 2;
-    test_server_listen(s);
+    g_string_append_printf(cmd_line,
+                           " -set netdev.hs0.queues=%d"
+                           " -global virtio-net-pci.vectors=%d",
+                           s->queues, s->queues * 2 + 2);
 
-    if (qemu_memfd_check(0)) {
-        cmd = g_strdup_printf(
-            QEMU_CMD_MEMFD QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
-            "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
-            256, 256, s->chr_name,
-            s->socket_path, "", s->chr_name,
-            s->queues, s->queues * 2 + 2);
-    } else {
-        cmd = g_strdup_printf(
-            QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
-            "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
-            256, 256, s->mem_path, s->chr_name,
-            s->socket_path, "", s->chr_name,
-            s->queues, s->queues * 2 + 2);
-    }
-    qtest_start(cmd);
-    g_free(cmd);
+    return s;
+}
 
-    init_virtio_dev(global_qtest, s, features_mask);
+static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
+{
+    TestServer *s = arg;
 
     wait_for_rings_started(s, s->queues * 2);
-
-    uninit_virtio_dev(s);
-
-    qtest_end();
-
-    test_server_free(s);
 }
 
-int main(int argc, char **argv)
+static void register_vhost_user_test(void)
 {
-    g_test_init(&argc, &argv, NULL);
+    QOSGraphTestOptions opts = {
+        .before = vhost_user_test_setup,
+        .subprocess = true,
+    };
 
-    module_call_init(MODULE_INIT_QOM);
     qemu_add_opts(&qemu_chardev_opts);
 
+    qos_add_test("vhost-user/read-guest-mem/memfile",
+                 "virtio-net",
+                 test_read_guest_mem, &opts);
+
     if (qemu_memfd_check(0)) {
-        qtest_add_data_func("/vhost-user/read-guest-mem/memfd",
-                            GINT_TO_POINTER(TEST_MEMFD_YES),
-                            test_read_guest_mem);
+        opts.before = vhost_user_test_setup_memfd;
+        qos_add_test("vhost-user/read-guest-mem/memfd",
+                     "virtio-net",
+                     test_read_guest_mem, &opts);
     }
-    qtest_add_data_func("/vhost-user/read-guest-mem/memfile",
-                        GINT_TO_POINTER(TEST_MEMFD_NO), test_read_guest_mem);
-    qtest_add_func("/vhost-user/migrate", test_migrate);
-    qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
+
+    qos_add_test("vhost-user/migrate",
+                 "virtio-net",
+                 test_migrate, &opts);
 
     /* keeps failing on build-system since Aug 15 2017 */
     if (getenv("QTEST_VHOST_USER_FIXME")) {
-        qtest_add_func("/vhost-user/reconnect/subprocess",
-                       test_reconnect_subprocess);
-        qtest_add_func("/vhost-user/reconnect", test_reconnect);
-        qtest_add_func("/vhost-user/connect-fail/subprocess",
-                       test_connect_fail_subprocess);
-        qtest_add_func("/vhost-user/connect-fail", test_connect_fail);
-        qtest_add_func("/vhost-user/flags-mismatch/subprocess",
-                       test_flags_mismatch_subprocess);
-        qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
+        opts.before = vhost_user_test_setup_reconnect;
+        qos_add_test("vhost-user/reconnect", "virtio-net",
+                     test_reconnect, &opts);
+
+        opts.before = vhost_user_test_setup_connect_fail;
+        qos_add_test("vhost-user/connect-fail", "virtio-net",
+                     test_vhost_user_started, &opts);
+
+        opts.before = vhost_user_test_setup_flags_mismatch;
+        qos_add_test("vhost-user/flags-mismatch", "virtio-net",
+                     test_vhost_user_started, &opts);
     }
 
-    return g_test_run();
+    opts.before = vhost_user_test_setup_multiqueue;
+    opts.edge.extra_device_opts = "mq=on";
+    qos_add_test("vhost-user/multiqueue",
+                 "virtio-net",
+                 test_multiqueue, &opts);
 }
+libqos_init(register_vhost_user_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 55/71] tests/libqos: virtio-scsi driver and interface nodes
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (53 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 54/71] qos-test: vhost-user test node Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 56/71] qos-test: virtio-scsi test node Paolo Bonzini
                   ` (18 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Add qgraph nodes for virtio-scsi-pci and virtio-scsi-device.
Both nodes produce virtio-scsi, but virtio-scsi-pci receives
a pci-bus and uses virtio-pci QOSGraphObject and its functions,
while virtio-scsi-device receives a virtio and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include     |   1 +
 tests/libqos/virtio-scsi.c | 117 +++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-scsi.h |  39 +++++++++++++++
 3 files changed, 157 insertions(+)
 create mode 100644 tests/libqos/virtio-scsi.c
 create mode 100644 tests/libqos/virtio-scsi.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 070d93e..3d58798 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -669,6 +669,7 @@ qos-test-obj-y += tests/libqos/virtio-balloon.o
 qos-test-obj-y += tests/libqos/virtio-blk.o
 qos-test-obj-y += tests/libqos/virtio-net.o
 qos-test-obj-y += tests/libqos/virtio-rng.o
+qos-test-obj-y += tests/libqos/virtio-scsi.o
 qos-test-obj-y += tests/libqos/virtio-serial.o
 
 # Machines
diff --git a/tests/libqos/virtio-scsi.c b/tests/libqos/virtio-scsi.c
new file mode 100644
index 0000000..482684d
--- /dev/null
+++ b/tests/libqos/virtio-scsi.c
@@ -0,0 +1,117 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-scsi.h"
+
+/* virtio-scsi-device */
+static void *qvirtio_scsi_get_driver(QVirtioSCSI *v_scsi,
+                                     const char *interface)
+{
+    if (!g_strcmp0(interface, "virtio-scsi")) {
+        return v_scsi;
+    }
+    if (!g_strcmp0(interface, "virtio")) {
+        return v_scsi->vdev;
+    }
+
+    fprintf(stderr, "%s not present in virtio-scsi-device\n", interface);
+    g_assert_not_reached();
+}
+
+static void *qvirtio_scsi_device_get_driver(void *object,
+                                            const char *interface)
+{
+    QVirtioSCSIDevice *v_scsi = object;
+    return qvirtio_scsi_get_driver(&v_scsi->scsi, interface);
+}
+
+static void *virtio_scsi_device_create(void *virtio_dev,
+                                          QGuestAllocator *t_alloc,
+                                          void *addr)
+{
+    QVirtioSCSIDevice *virtio_bdevice = g_new0(QVirtioSCSIDevice, 1);
+    QVirtioSCSI *interface = &virtio_bdevice->scsi;
+
+    interface->vdev = virtio_dev;
+
+    virtio_bdevice->obj.get_driver = qvirtio_scsi_device_get_driver;
+
+    return &virtio_bdevice->obj;
+}
+
+/* virtio-scsi-pci */
+static void *qvirtio_scsi_pci_get_driver(void *object,
+                                         const char *interface)
+{
+    QVirtioSCSIPCI *v_scsi = object;
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_scsi->pci_vdev.pdev;
+    }
+    return qvirtio_scsi_get_driver(&v_scsi->scsi, interface);
+}
+
+static void *virtio_scsi_pci_create(void *pci_bus,
+                                    QGuestAllocator *t_alloc,
+                                    void *addr)
+{
+    QVirtioSCSIPCI *virtio_spci = g_new0(QVirtioSCSIPCI, 1);
+    QVirtioSCSI *interface = &virtio_spci->scsi;
+    QOSGraphObject *obj = &virtio_spci->pci_vdev.obj;
+
+    virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr);
+    interface->vdev = &virtio_spci->pci_vdev.vdev;
+
+    g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_SCSI);
+
+    obj->get_driver = qvirtio_scsi_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_scsi_register_nodes(void)
+{
+    QPCIAddress addr = {
+        .devfn = QPCI_DEVFN(4, 0),
+    };
+
+    QOSGraphEdgeOptions opts = {
+        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,format=raw",
+        .after_cmd_line = "-device scsi-hd,bus=vs0.0,drive=drv0",
+    };
+
+    /* virtio-scsi-device */
+    opts.extra_device_opts = "id=vs0";
+    qos_node_create_driver("virtio-scsi-device",
+                            virtio_scsi_device_create);
+    qos_node_consumes("virtio-scsi-device", "virtio-bus", &opts);
+    qos_node_produces("virtio-scsi-device", "virtio-scsi");
+
+    /* virtio-scsi-pci */
+    opts.extra_device_opts = "id=vs0,addr=04.0";
+    add_qpci_address(&opts, &addr);
+    qos_node_create_driver("virtio-scsi-pci", virtio_scsi_pci_create);
+    qos_node_consumes("virtio-scsi-pci", "pci-bus", &opts);
+    qos_node_produces("virtio-scsi-pci", "pci-device");
+    qos_node_produces("virtio-scsi-pci", "virtio-scsi");
+}
+
+libqos_init(virtio_scsi_register_nodes);
diff --git a/tests/libqos/virtio-scsi.h b/tests/libqos/virtio-scsi.h
new file mode 100644
index 0000000..17a47be
--- /dev/null
+++ b/tests/libqos/virtio-scsi.h
@@ -0,0 +1,39 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "libqos/qgraph.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-pci.h"
+
+typedef struct QVirtioSCSI QVirtioSCSI;
+typedef struct QVirtioSCSIPCI QVirtioSCSIPCI;
+typedef struct QVirtioSCSIDevice QVirtioSCSIDevice;
+
+struct QVirtioSCSI {
+    QVirtioDevice *vdev;
+};
+
+struct QVirtioSCSIPCI {
+    QVirtioPCIDevice pci_vdev;
+    QVirtioSCSI scsi;
+};
+
+struct QVirtioSCSIDevice {
+    QOSGraphObject obj;
+    QVirtioSCSI scsi;
+};
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 56/71] qos-test: virtio-scsi test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (54 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 55/71] tests/libqos: virtio-scsi driver and interface nodes Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 57/71] tests/libqos: remove pre-qgraph QVirtioPCIDevice API Paolo Bonzini
                   ` (17 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/virtio-scsi-test in qgraph test node,
virtio-scsi-test. This test consumes a virtio-scsi interface
and checks that its function return the expected values.

Some functions are implemented only for virtio-scsi-pci, so they
don't consume virtio-scsi, but virtio-scsi-pci

Note that this test does not allocate any virtio-scsi structure,
it's all done by the qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include   |   4 +-
 tests/virtio-scsi-test.c | 143 +++++++++++++++++++----------------------------
 2 files changed, 60 insertions(+), 87 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3d58798..34d1e5f 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -143,8 +143,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 
-check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
-
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
@@ -692,6 +690,7 @@ qos-test-obj-y += tests/virtio-9p-test.o
 qos-test-obj-y += tests/virtio-blk-test.o
 qos-test-obj-y += tests/virtio-net-test.o
 qos-test-obj-y += tests/virtio-rng-test.o
+qos-test-obj-y += tests/virtio-scsi-test.o
 qos-test-obj-y += tests/virtio-serial-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
@@ -738,7 +737,6 @@ tests/ne2000-test$(EXESUF): tests/ne2000-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
-tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 9298aa8..162b31c 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -18,6 +18,8 @@
 #include "standard-headers/linux/virtio_ids.h"
 #include "standard-headers/linux/virtio_pci.h"
 #include "standard-headers/linux/virtio_scsi.h"
+#include "libqos/virtio-scsi.h"
+#include "libqos/qgraph.h"
 
 #define PCI_SLOT                0x02
 #define PCI_FN                  0x00
@@ -27,55 +29,28 @@
 
 typedef struct {
     QVirtioDevice *dev;
-    QOSState *qs;
     int num_queues;
     QVirtQueue *vq[MAX_NUM_QUEUES + 2];
-} QVirtIOSCSI;
+} QVirtioSCSIQueues;
 
-static QOSState *qvirtio_scsi_start(const char *extra_opts)
-{
-    QOSState *qs;
-    const char *arch = qtest_get_arch();
-    const char *cmd = "-drive id=drv0,if=none,file=null-co://,format=raw "
-                      "-device virtio-scsi-pci,id=vs0 "
-                      "-device scsi-hd,bus=vs0.0,drive=drv0 %s";
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qs = qtest_pc_boot(cmd, extra_opts ? : "");
-    } else if (strcmp(arch, "ppc64") == 0) {
-        qs = qtest_spapr_boot(cmd, extra_opts ? : "");
-    } else {
-        g_printerr("virtio-scsi tests are only available on x86 or ppc64\n");
-        exit(EXIT_FAILURE);
-    }
-    global_qtest = qs->qts;
-    return qs;
-}
-
-static void qvirtio_scsi_stop(QOSState *qs)
-{
-    qtest_shutdown(qs);
-}
+static QGuestAllocator *alloc;
 
-static void qvirtio_scsi_pci_free(QVirtIOSCSI *vs)
+static void qvirtio_scsi_pci_free(QVirtioSCSIQueues *vs)
 {
     int i;
 
     for (i = 0; i < vs->num_queues + 2; i++) {
-        qvirtqueue_cleanup(vs->dev->bus, vs->vq[i], &vs->qs->alloc);
+        qvirtqueue_cleanup(vs->dev->bus, vs->vq[i], alloc);
     }
-    qvirtio_pci_device_disable(container_of(vs->dev, QVirtioPCIDevice, vdev));
-    qvirtio_pci_device_free((QVirtioPCIDevice *)vs->dev);
-    qvirtio_scsi_stop(vs->qs);
     g_free(vs);
 }
 
-static uint64_t qvirtio_scsi_alloc(QVirtIOSCSI *vs, size_t alloc_size,
+static uint64_t qvirtio_scsi_alloc(QVirtioSCSIQueues *vs, size_t alloc_size,
                                    const void *data)
 {
     uint64_t addr;
 
-    addr = guest_alloc(&vs->qs->alloc, alloc_size);
+    addr = guest_alloc(alloc, alloc_size);
     if (data) {
         memwrite(addr, data, alloc_size);
     }
@@ -83,7 +58,8 @@ static uint64_t qvirtio_scsi_alloc(QVirtIOSCSI *vs, size_t alloc_size,
     return addr;
 }
 
-static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb,
+static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs,
+                                      const uint8_t *cdb,
                                       const uint8_t *data_in,
                                       size_t data_in_len,
                                       uint8_t *data_out, size_t data_out_len,
@@ -133,40 +109,28 @@ static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb,
         memread(resp_addr, resp_out, sizeof(*resp_out));
     }
 
-    guest_free(&vs->qs->alloc, req_addr);
-    guest_free(&vs->qs->alloc, resp_addr);
-    guest_free(&vs->qs->alloc, data_in_addr);
-    guest_free(&vs->qs->alloc, data_out_addr);
+    guest_free(alloc, req_addr);
+    guest_free(alloc, resp_addr);
+    guest_free(alloc, data_in_addr);
+    guest_free(alloc, data_out_addr);
     return response;
 }
 
-static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
+static QVirtioSCSIQueues *qvirtio_scsi_init(QVirtioDevice *dev)
 {
+    QVirtioSCSIQueues *vs;
     const uint8_t test_unit_ready_cdb[VIRTIO_SCSI_CDB_SIZE] = {};
-    QVirtIOSCSI *vs;
-    QVirtioPCIDevice *dev;
     struct virtio_scsi_cmd_resp resp;
     int i;
 
-    vs = g_new0(QVirtIOSCSI, 1);
-
-    vs->qs = qvirtio_scsi_start("-drive file=blkdebug::null-co://,"
-                                "if=none,id=dr1,format=raw,file.align=4k "
-                                "-device scsi-hd,drive=dr1,lun=0,scsi-id=1");
-    dev = qvirtio_pci_device_find(vs->qs->pcibus, VIRTIO_ID_SCSI);
-    vs->dev = (QVirtioDevice *)dev;
-    g_assert(dev != NULL);
-    g_assert_cmphex(vs->dev->device_type, ==, VIRTIO_ID_SCSI);
-
-    qvirtio_pci_device_enable(dev);
-    qvirtio_start_device(vs->dev);
-
-    vs->num_queues = qvirtio_config_readl(vs->dev, 0);
+    vs = g_new0(QVirtioSCSIQueues, 1);
+    vs->dev = dev;
+    vs->num_queues = qvirtio_config_readl(dev, 0);
 
     g_assert_cmpint(vs->num_queues, <, MAX_NUM_QUEUES);
 
     for (i = 0; i < vs->num_queues + 2; i++) {
-        vs->vq[i] = qvirtqueue_setup(vs->dev, &vs->qs->alloc, i);
+        vs->vq[i] = qvirtqueue_setup(dev, alloc, i);
     }
 
     /* Clear the POWER ON OCCURRED unit attention */
@@ -182,30 +146,18 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
     return vs;
 }
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
-{
-    QOSState *qs;
-
-    qs = qvirtio_scsi_start(NULL);
-    qvirtio_scsi_stop(qs);
-}
-
-static void hotplug(void)
+static void hotplug(void *obj, void *data, QGuestAllocator *alloc)
 {
-    QOSState *qs;
-
-    qs = qvirtio_scsi_start(
-            "-drive id=drv1,if=none,file=null-co://,format=raw");
     qtest_qmp_device_add("scsi-hd", "scsihd", "{'drive': 'drv1'}");
     qtest_qmp_device_del("scsihd");
-    qvirtio_scsi_stop(qs);
 }
 
 /* Test WRITE SAME with the lba not aligned */
-static void test_unaligned_write_same(void)
+static void test_unaligned_write_same(void *obj, void *data,
+                                      QGuestAllocator *t_alloc)
 {
-    QVirtIOSCSI *vs;
+    QVirtioSCSI *scsi = obj;
+    QVirtioSCSIQueues *vs;
     uint8_t buf1[512] = { 0 };
     uint8_t buf2[512] = { 1 };
     const uint8_t write_same_cdb_1[VIRTIO_SCSI_CDB_SIZE] = {
@@ -218,27 +170,50 @@ static void test_unaligned_write_same(void)
         0x41, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0x00, 0x00
     };
 
-    vs = qvirtio_scsi_pci_init(PCI_SLOT);
+    alloc = t_alloc;
+    vs = qvirtio_scsi_init(scsi->vdev);
 
     g_assert_cmphex(0, ==,
-        virtio_scsi_do_command(vs, write_same_cdb_1, NULL, 0, buf1, 512, NULL));
+        virtio_scsi_do_command(vs, write_same_cdb_1, NULL, 0, buf1, 512,
+                               NULL));
 
     g_assert_cmphex(0, ==,
-        virtio_scsi_do_command(vs, write_same_cdb_2, NULL, 0, buf2, 512, NULL));
+        virtio_scsi_do_command(vs, write_same_cdb_2, NULL, 0, buf2, 512,
+                               NULL));
 
     g_assert_cmphex(0, ==,
-        virtio_scsi_do_command(vs, write_same_cdb_ndob, NULL, 0, NULL, 0, NULL));
+        virtio_scsi_do_command(vs, write_same_cdb_ndob, NULL, 0, NULL, 0,
+                               NULL));
 
     qvirtio_scsi_pci_free(vs);
 }
 
-int main(int argc, char **argv)
+static void *virtio_scsi_hotplug_setup(GString *cmd_line, void *arg)
 {
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/scsi/pci/nop", pci_nop);
-    qtest_add_func("/virtio/scsi/pci/hotplug", hotplug);
-    qtest_add_func("/virtio/scsi/pci/scsi-disk/unaligned-write-same",
-                   test_unaligned_write_same);
+    g_string_append(cmd_line,
+                    " -drive id=drv1,if=none,file=null-co://,format=raw");
+    return arg;
+}
 
-    return g_test_run();
+static void *virtio_scsi_setup(GString *cmd_line, void *arg)
+{
+    g_string_append(cmd_line,
+                    " -drive file=blkdebug::null-co://,"
+                    "if=none,id=dr1,format=raw,file.align=4k "
+                    "-device scsi-hd,drive=dr1,lun=0,scsi-id=1");
+    return arg;
 }
+
+static void register_virtio_scsi_test(void)
+{
+    QOSGraphTestOptions opts = { };
+
+    opts.before = virtio_scsi_hotplug_setup;
+    qos_add_test("hotplug", "virtio-scsi", hotplug, &opts);
+
+    opts.before = virtio_scsi_setup;
+    qos_add_test("unaligned-write-same", "virtio-scsi",
+                 test_unaligned_write_same, &opts);
+}
+
+libqos_init(register_virtio_scsi_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 57/71] tests/libqos: remove pre-qgraph QVirtioPCIDevice API
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (55 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 56/71] qos-test: virtio-scsi test node Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 58/71] tests: move virtio entirely to qos-test Paolo Bonzini
                   ` (16 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Remove the qvirtio_pci_device_find* and qvirtio_pci_device_free
APIs, now that they do not have any users.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/libqos/virtio-pci.c | 112 +++++++---------------------------------------
 tests/libqos/virtio-pci.h |   4 --
 2 files changed, 17 insertions(+), 99 deletions(-)

diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 0b58b74..993d347 100644
--- a/tests/libqos/virtio-pci.c
+++ b/tests/libqos/virtio-pci.c
@@ -35,14 +35,6 @@
  * original qvirtio_pci_destructor and qvirtio_pci_start_hw.
  */
 
-typedef struct QVirtioPCIForeachData {
-    void (*func)(QVirtioDevice *d, void *data);
-    uint16_t device_type;
-    bool has_slot;
-    int slot;
-    void *user_data;
-} QVirtioPCIForeachData;
-
 static inline bool qvirtio_pci_is_big_endian(QVirtioPCIDevice *dev)
 {
     QPCIBus *bus = dev->pdev->bus;
@@ -51,50 +43,6 @@ static inline bool qvirtio_pci_is_big_endian(QVirtioPCIDevice *dev)
     return qtest_big_endian(bus->qts);
 }
 
-void qvirtio_pci_device_free(QVirtioPCIDevice *dev)
-{
-    g_free(dev->pdev);
-}
-
-static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_dev)
-{
-    dev->pdev = pci_dev;
-    dev->vdev.device_type = qpci_config_readw(pci_dev, PCI_SUBSYSTEM_ID);
-
-    dev->config_msix_entry = -1;
-
-    dev->vdev.bus = &qvirtio_pci;
-    dev->vdev.big_endian = qvirtio_pci_is_big_endian(dev);
-
-    /* each virtio-xxx-pci device should override at least this function */
-    dev->obj.get_driver = NULL;
-    dev->obj.start_hw = qvirtio_pci_start_hw;
-    dev->obj.destructor = qvirtio_pci_destructor;
-}
-
-static void qvirtio_pci_foreach_callback(
-                        QPCIDevice *dev, int devfn, void *data)
-{
-    QVirtioPCIForeachData *d = data;
-    QVirtioPCIDevice *vpcidev = g_new0(QVirtioPCIDevice, 1);
-
-    qvirtio_pci_init_from_pcidev(vpcidev, dev);
-    if (vpcidev->vdev.device_type == d->device_type &&
-        (!d->has_slot || vpcidev->pdev->devfn == d->slot << 3)) {
-        d->func(&vpcidev->vdev, d->user_data);
-    } else {
-        qvirtio_pci_device_free(vpcidev);
-        g_free(vpcidev);
-    }
-}
-
-static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data)
-{
-    QVirtioPCIDevice **vpcidev = data;
-    assert(!*vpcidev);
-    *vpcidev = container_of(d, QVirtioPCIDevice, vdev);
-}
-
 #define CONFIG_BASE(dev) (VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled))
 
 static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off)
@@ -317,48 +265,6 @@ const QVirtioBus qvirtio_pci = {
     .virtqueue_kick = qvirtio_pci_virtqueue_kick,
 };
 
-/* TODO: delete this once qgraph is completed */
-static void qvirtio_pci_foreach(QPCIBus *bus, uint16_t device_type,
-                bool has_slot, int slot,
-                void (*func)(QVirtioDevice *d, void *data), void *data)
-{
-    QVirtioPCIForeachData d = { .func = func,
-                                .device_type = device_type,
-                                .has_slot = has_slot,
-                                .slot = slot,
-                                .user_data = data };
-
-    qpci_device_foreach(bus, PCI_VENDOR_ID_REDHAT_QUMRANET, -1,
-                        qvirtio_pci_foreach_callback, &d);
-}
-
-QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type)
-{
-    QVirtioPCIDevice *dev = NULL;
-
-    qvirtio_pci_foreach(bus, device_type, false, 0,
-                        qvirtio_pci_assign_device, &dev);
-
-    if (dev) {
-        dev->vdev.bus = &qvirtio_pci;
-    }
-
-    return dev;
-}
-
-QVirtioPCIDevice *qvirtio_pci_device_find_slot(QPCIBus *bus,
-                                               uint16_t device_type, int slot)
-{
-    QVirtioPCIDevice *dev = NULL;
-
-    qvirtio_pci_foreach(bus, device_type, true, slot,
-                        qvirtio_pci_assign_device, &dev);
-
-    dev->vdev.bus = &qvirtio_pci;
-
-    return dev;
-}
-
 void qvirtio_pci_device_enable(QVirtioPCIDevice *d)
 {
     qpci_device_enable(d->pdev);
@@ -445,7 +351,7 @@ void qvirtio_pci_destructor(QOSGraphObject *obj)
 {
     QVirtioPCIDevice *dev = (QVirtioPCIDevice *)obj;
     qvirtio_pci_device_disable(dev);
-    qvirtio_pci_device_free(dev);
+    g_free(dev->pdev);
 }
 
 void qvirtio_pci_start_hw(QOSGraphObject *obj)
@@ -455,6 +361,22 @@ void qvirtio_pci_start_hw(QOSGraphObject *obj)
     qvirtio_start_device(&dev->vdev);
 }
 
+static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_dev)
+{
+    dev->pdev = pci_dev;
+    dev->vdev.device_type = qpci_config_readw(pci_dev, PCI_SUBSYSTEM_ID);
+
+    dev->config_msix_entry = -1;
+
+    dev->vdev.bus = &qvirtio_pci;
+    dev->vdev.big_endian = qvirtio_pci_is_big_endian(dev);
+
+    /* each virtio-xxx-pci device should override at least this function */
+    dev->obj.get_driver = NULL;
+    dev->obj.start_hw = qvirtio_pci_start_hw;
+    dev->obj.destructor = qvirtio_pci_destructor;
+}
+
 void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr)
 {
     QPCIDevice *pci_dev = qpci_device_find(bus, addr->devfn);
diff --git a/tests/libqos/virtio-pci.h b/tests/libqos/virtio-pci.h
index 5631352..728b471 100644
--- a/tests/libqos/virtio-pci.h
+++ b/tests/libqos/virtio-pci.h
@@ -35,10 +35,6 @@ extern const QVirtioBus qvirtio_pci;
 
 void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr);
 QVirtioPCIDevice *virtio_pci_new(QPCIBus *bus, QPCIAddress * addr);
-QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type);
-QVirtioPCIDevice *qvirtio_pci_device_find_slot(QPCIBus *bus,
-                                               uint16_t device_type, int slot);
-void qvirtio_pci_device_free(QVirtioPCIDevice *dev);
 
 /* virtio-pci object functions available for subclasses that
  * override the original start_hw and destroy
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 58/71] tests: move virtio entirely to qos-test
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (56 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 57/71] tests/libqos: remove pre-qgraph QVirtioPCIDevice API Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 59/71] qos-test: ac97 test node Paolo Bonzini
                   ` (15 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

The only remaining test that needs libqos-virtio-obj-y is drive_del-test,
which really only needs a function.  Move that function to the test
and remove libqos-virtio-obj-y.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  9 ++++-----
 tests/drive_del-test.c | 25 +++++++++++++++++++------
 tests/libqos/virtio.c  | 18 ------------------
 tests/libqos/virtio.h  |  1 -
 4 files changed, 23 insertions(+), 30 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 34d1e5f..c0b370b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -151,7 +151,6 @@ check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
 check-qtest-pci-$(CONFIG_AC97) += tests/ac97-test$(EXESUF)
 check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
-check-qtest-pci-y += $(check-qtest-virtio-y)
 check-qtest-pci-$(CONFIG_IPACK) += tests/tpci200-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IPACK) += $(check-qtest-ipack-y)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
@@ -234,7 +233,6 @@ check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF)
 check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF)
 check-qtest-ppc64-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF)
 check-qtest-ppc64-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF)
-check-qtest-ppc64-y += $(check-qtest-virtio-y)
 check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
 check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
 check-qtest-ppc64-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF)
@@ -654,18 +652,19 @@ 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-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
-libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o
 
 # Devices
 qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
 qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/sdhci.o
-qos-test-obj-y += $(libqos-virtio-obj-y)
+qos-test-obj-y += tests/libqos/virtio.o
 qos-test-obj-y += tests/libqos/virtio-9p.o
 qos-test-obj-y += tests/libqos/virtio-balloon.o
 qos-test-obj-y += tests/libqos/virtio-blk.o
+qos-test-obj-y += tests/libqos/virtio-mmio.o
 qos-test-obj-y += tests/libqos/virtio-net.o
+qos-test-obj-y += tests/libqos/virtio-pci.o
 qos-test-obj-y += tests/libqos/virtio-rng.o
 qos-test-obj-y += tests/libqos/virtio-scsi.o
 qos-test-obj-y += tests/libqos/virtio-serial.o
@@ -743,7 +742,7 @@ tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
 tests/qom-test$(EXESUF): tests/qom-test.o
 tests/test-hmp$(EXESUF): tests/test-hmp.o
 tests/machine-none-test$(EXESUF): tests/machine-none-test.o
-tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y)
+tests/drive_del-test$(EXESUF): tests/drive_del-test.o
 tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
 tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
 tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c
index 4a1a088..2f9474e 100644
--- a/tests/drive_del-test.c
+++ b/tests/drive_del-test.c
@@ -63,6 +63,24 @@ static void test_drive_without_dev(void)
     qtest_end();
 }
 
+/*
+ * qvirtio_get_dev_type:
+ * Returns: the preferred virtio bus/device type for the current architecture.
+ * TODO: delete this
+ */
+static const char *qvirtio_get_dev_type(void)
+{
+    const char *arch = qtest_get_arch();
+
+    if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
+        return "device";  /* for virtio-mmio */
+    } else if (g_str_equal(arch, "s390x")) {
+        return "ccw";
+    } else {
+        return "pci";
+    }
+}
+
 static void test_after_failed_device_add(void)
 {
     char driver[32];
@@ -119,16 +137,11 @@ static void test_drive_del_device_del(void)
 
 int main(int argc, char **argv)
 {
-    const char *arch = qtest_get_arch();
-
     g_test_init(&argc, &argv, NULL);
 
     qtest_add_func("/drive_del/without-dev", test_drive_without_dev);
 
-    /* TODO I guess any arch with a hot-pluggable virtio bus would do */
-    if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64") ||
-        !strcmp(arch, "ppc") || !strcmp(arch, "ppc64") ||
-        !strcmp(arch, "s390x")) {
+    if (qvirtio_get_dev_type() != NULL) {
         qtest_add_func("/drive_del/after_failed_device_add",
                        test_after_failed_device_add);
         qtest_add_func("/blockdev/drive_del_device_del",
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index e4925d1..5e8f39b 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -350,24 +350,6 @@ void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx)
     writew(vq->avail + 4 + (2 * vq->size), idx);
 }
 
-/*
- * qvirtio_get_dev_type:
- * Returns: the preferred virtio bus/device type for the current architecture.
- * TODO: delete this
- */
-const char *qvirtio_get_dev_type(void)
-{
-    const char *arch = qtest_get_arch();
-
-    if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
-        return "device";  /* for virtio-mmio */
-    } else if (g_str_equal(arch, "s390x")) {
-        return "ccw";
-    } else {
-        return "pci";
-    }
-}
-
 void qvirtio_start_device(QVirtioDevice *vdev)
 {
     qvirtio_reset(vdev);
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 3f97d79..51d2359 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -142,7 +142,6 @@ bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len);
 
 void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx);
 
-const char *qvirtio_get_dev_type(void);
 void qvirtio_start_device(QVirtioDevice *vdev);
 
 #endif
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 59/71] qos-test: ac97 test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (57 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 58/71] tests: move virtio entirely to qos-test Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 60/71] qos-test: tpci200 " Paolo Bonzini
                   ` (14 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/ac97-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/ac97-test.c      | 47 ++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index c0b370b..5d65bd1 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -149,7 +149,6 @@ check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
 check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
-check-qtest-pci-$(CONFIG_AC97) += tests/ac97-test$(EXESUF)
 check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IPACK) += tests/tpci200-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IPACK) += $(check-qtest-ipack-y)
@@ -680,6 +679,7 @@ qos-test-obj-y += tests/libqos/ppc64_pseries-machine.o
 qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 # Tests
+qos-test-obj-y += tests/ac97-test.o
 qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
@@ -746,7 +746,6 @@ tests/drive_del-test$(EXESUF): tests/drive_del-test.o
 tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
 tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
 tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
-tests/ac97-test$(EXESUF): tests/ac97-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
diff --git a/tests/ac97-test.c b/tests/ac97-test.c
index e0d177b..532fb1c 100644
--- a/tests/ac97-test.c
+++ b/tests/ac97-test.c
@@ -9,23 +9,48 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
+typedef struct QAC97 QAC97;
+
+struct QAC97 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *ac97_get_driver(void *obj, const char *interface)
 {
+    QAC97 *ac97 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &ac97->dev;
+    }
+
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
 }
 
-int main(int argc, char **argv)
+static void *ac97_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    int ret;
+    QAC97 *ac97 = g_new0(QAC97, 1);
+    QPCIBus *bus = pci_bus;
 
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/ac97/nop", nop);
-
-    qtest_start("-device AC97");
-    ret = g_test_run();
+    qpci_device_init(&ac97->dev, bus, addr);
+    ac97->obj.get_driver = ac97_get_driver;
+    return &ac97->obj;
+}
 
-    qtest_end();
+static void ac97_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    return ret;
+    qos_node_create_driver("AC97", ac97_create);
+    qos_node_produces("AC97", "pci-device");
+    qos_node_consumes("AC97", "pci-bus", &opts);
 }
+
+libqos_init(ac97_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 60/71] qos-test: tpci200 test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (58 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 59/71] qos-test: ac97 test node Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 61/71] qos-test: ipoctal232 " Paolo Bonzini
                   ` (13 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/tpci200-test to a driver node; currently it runs
the PCI nop test only, but it also produces the ipack interface.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/libqos/tpci200.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/tpci200-test.c   | 31 ------------------------
 3 files changed, 66 insertions(+), 33 deletions(-)
 create mode 100644 tests/libqos/tpci200.c
 delete mode 100644 tests/tpci200-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 5d65bd1..d0b636e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -150,7 +150,6 @@ check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
 check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
-check-qtest-pci-$(CONFIG_IPACK) += tests/tpci200-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IPACK) += $(check-qtest-ipack-y)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
@@ -657,6 +656,7 @@ qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
 qos-test-obj-y += $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 qos-test-obj-y += tests/libqos/e1000e.o
 qos-test-obj-y += tests/libqos/sdhci.o
+qos-test-obj-y += tests/libqos/tpci200.o
 qos-test-obj-y += tests/libqos/virtio.o
 qos-test-obj-y += tests/libqos/virtio-9p.o
 qos-test-obj-y += tests/libqos/virtio-balloon.o
@@ -736,7 +736,6 @@ tests/ne2000-test$(EXESUF): tests/ne2000-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
-tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
 tests/qom-test$(EXESUF): tests/qom-test.o
diff --git a/tests/libqos/tpci200.c b/tests/libqos/tpci200.c
new file mode 100644
index 0000000..98dc532
--- /dev/null
+++ b/tests/libqos/tpci200.c
@@ -0,0 +1,65 @@
+/*
+ * QTest testcase for tpci200 PCI-IndustryPack bridge
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * 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/qgraph.h"
+#include "libqos/pci.h"
+
+typedef struct QTpci200 QTpci200;
+typedef struct QIpack QIpack;
+
+struct QIpack {
+
+};
+struct QTpci200 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+    QIpack ipack;
+};
+
+/* tpci200 */
+static void *tpci200_get_driver(void *obj, const char *interface)
+{
+    QTpci200 *tpci200 = obj;
+    if (!g_strcmp0(interface, "ipack")) {
+        return &tpci200->ipack;
+    }
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &tpci200->dev;
+    }
+
+    fprintf(stderr, "%s not present in tpci200\n", interface);
+    g_assert_not_reached();
+}
+
+static void *tpci200_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QTpci200 *tpci200 = g_new0(QTpci200, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&tpci200->dev, bus, addr);
+    tpci200->obj.get_driver = tpci200_get_driver;
+    return &tpci200->obj;
+}
+
+static void tpci200_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0,id=ipack0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("tpci200", tpci200_create);
+    qos_node_consumes("tpci200", "pci-bus", &opts);
+    qos_node_produces("tpci200", "ipack");
+    qos_node_produces("tpci200", "pci-device");
+}
+
+libqos_init(tpci200_register_nodes);
diff --git a/tests/tpci200-test.c b/tests/tpci200-test.c
deleted file mode 100644
index 0321ec2..0000000
--- a/tests/tpci200-test.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * QTest testcase for tpci200 PCI-IndustryPack bridge
- *
- * Copyright (c) 2014 SUSE LINUX Products GmbH
- *
- * 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"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
-{
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/tpci200/nop", nop);
-
-    qtest_start("-device tpci200");
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
-}
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 61/71] qos-test: ipoctal232 test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (59 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 60/71] qos-test: tpci200 " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 62/71] qos-test: ne2k_pci " Paolo Bonzini
                   ` (12 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/ipoctal232-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

This test creates a tpci200 node that produces an interface ipack
consumed by the ipoctal232 device.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include  |  5 +----
 tests/ipoctal232-test.c | 35 ++++++++++++++++++++++++++---------
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index d0b636e..fd76a34 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -141,8 +141,6 @@ check-qtest-generic-y += tests/qmp-cmd-test$(EXESUF)
 check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
 check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 
-check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
-
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
@@ -150,7 +148,6 @@ check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
 check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
-check-qtest-pci-$(CONFIG_IPACK) += $(check-qtest-ipack-y)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF)
@@ -681,6 +678,7 @@ qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 # Tests
 qos-test-obj-y += tests/ac97-test.o
 qos-test-obj-y += tests/e1000e-test.o
+qos-test-obj-y += tests/ipoctal232-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
@@ -737,7 +735,6 @@ tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
 tests/display-vga-test$(EXESUF): tests/display-vga-test.o
-tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
 tests/qom-test$(EXESUF): tests/qom-test.o
 tests/test-hmp$(EXESUF): tests/test-hmp.o
 tests/machine-none-test$(EXESUF): tests/machine-none-test.o
diff --git a/tests/ipoctal232-test.c b/tests/ipoctal232-test.c
index 6849141..42d5371 100644
--- a/tests/ipoctal232-test.c
+++ b/tests/ipoctal232-test.c
@@ -9,23 +9,40 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+
+typedef struct QIpoctal232 QIpoctal232;
+
+struct QIpoctal232 {
+    QOSGraphObject obj;
+};
 
 /* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
+static void nop(void *obj, void *data, QGuestAllocator *alloc)
 {
 }
 
-int main(int argc, char **argv)
+static void *ipoctal232_create(void *pci_bus, QGuestAllocator *alloc,
+                               void *addr)
 {
-    int ret;
+    QIpoctal232 *ipoctal232 = g_new0(QIpoctal232, 1);
 
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/ipoctal232/tpci200/nop", nop);
+    return &ipoctal232->obj;
+}
 
-    qtest_start("-device tpci200,id=ipack0 -device ipoctal232,bus=ipack0.0");
-    ret = g_test_run();
+static void ipoctal232_register_nodes(void)
+{
+    qos_node_create_driver("ipoctal232", ipoctal232_create);
+    qos_node_consumes("ipoctal232", "ipack", &(QOSGraphEdgeOptions) {
+        .extra_device_opts = "bus=ipack0.0",
+    });
+}
 
-    qtest_end();
+libqos_init(ipoctal232_register_nodes);
 
-    return ret;
+static void register_ipoctal232_test(void)
+{
+    qos_add_test("nop", "ipoctal232", nop, NULL);
 }
+
+libqos_init(register_ipoctal232_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 62/71] qos-test: ne2k_pci test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (60 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 61/71] qos-test: ipoctal232 " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 63/71] qos-test: nvme " Paolo Bonzini
                   ` (11 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/ne2000-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

The actual device consumed by the test is ne2k_pci.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/ne2000-test.c    | 46 ++++++++++++++++++++++++++++++++++++----------
 2 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index fd76a34..290e496 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -145,7 +145,6 @@ check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
 check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
-check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
 check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
@@ -679,6 +678,7 @@ qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 qos-test-obj-y += tests/ac97-test.o
 qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/ipoctal232-test.o
+qos-test-obj-y += tests/ne2000-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
@@ -730,7 +730,6 @@ tests/pcnet-test$(EXESUF): tests/pcnet-test.o
 tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
 tests/eepro100-test$(EXESUF): tests/eepro100-test.o
 tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
-tests/ne2000-test$(EXESUF): tests/ne2000-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
diff --git a/tests/ne2000-test.c b/tests/ne2000-test.c
index b7cf3dd..097c2ee 100644
--- a/tests/ne2000-test.c
+++ b/tests/ne2000-test.c
@@ -9,23 +9,49 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
+typedef struct QNe2k_pci QNe2k_pci;
+
+struct QNe2k_pci {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *ne2k_pci_get_driver(void *obj, const char *interface)
 {
+    QNe2k_pci *ne2k_pci = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &ne2k_pci->dev;
+    }
+
+    fprintf(stderr, "%s not present in ne2k_pci\n", interface);
+    g_assert_not_reached();
 }
 
-int main(int argc, char **argv)
+static void *ne2k_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    int ret;
+    QNe2k_pci *ne2k_pci = g_new0(QNe2k_pci, 1);
+    QPCIBus *bus = pci_bus;
 
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/ne2000/pci/nop", pci_nop);
+    qpci_device_init(&ne2k_pci->dev, bus, addr);
+    ne2k_pci->obj.get_driver = ne2k_pci_get_driver;
 
-    qtest_start("-device ne2k_pci");
-    ret = g_test_run();
+    return &ne2k_pci->obj;
+}
 
-    qtest_end();
+static void ne2000_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    return ret;
+    qos_node_create_driver("ne2k_pci", ne2k_pci_create);
+    qos_node_consumes("ne2k_pci", "pci-bus", &opts);
+    qos_node_produces("ne2k_pci", "pci-device");
 }
+
+libqos_init(ne2000_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 63/71] qos-test: nvme test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (61 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 62/71] qos-test: ne2k_pci " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 64/71] qos-test: pcnet " Paolo Bonzini
                   ` (10 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/nvme-test to a driver node; the code to discover the PCI
device is replaced by generic qgraph code, therefore we're not placing it in tests/libqos.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +-
 tests/nvme-test.c      | 78 +++++++++++++++++++++++++++-----------------------
 2 files changed, 43 insertions(+), 38 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 290e496..64eb8b6 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -145,7 +145,6 @@ check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
 check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
-check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
 check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
@@ -679,6 +678,7 @@ qos-test-obj-y += tests/ac97-test.o
 qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/ipoctal232-test.o
 qos-test-obj-y += tests/ne2000-test.o
+qos-test-obj-y += tests/nvme-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
@@ -738,7 +738,6 @@ tests/qom-test$(EXESUF): tests/qom-test.o
 tests/test-hmp$(EXESUF): tests/test-hmp.o
 tests/machine-none-test$(EXESUF): tests/machine-none-test.o
 tests/drive_del-test$(EXESUF): tests/drive_del-test.o
-tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
 tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
 tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
diff --git a/tests/nvme-test.c b/tests/nvme-test.c
index 2700ba8..b48d3a2 100644
--- a/tests/nvme-test.c
+++ b/tests/nvme-test.c
@@ -10,49 +10,47 @@
 #include "qemu/osdep.h"
 #include "qemu/units.h"
 #include "libqtest.h"
-#include "libqos/libqos-pc.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-static QOSState *qnvme_start(const char *extra_opts)
+typedef struct QNvme QNvme;
+
+struct QNvme {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *nvme_get_driver(void *obj, const char *interface)
 {
-    QOSState *qs;
-    const char *arch = qtest_get_arch();
-    const char *cmd = "-drive id=drv0,if=none,file=null-co://,format=raw "
-                      "-device nvme,addr=0x4.0,serial=foo,drive=drv0 %s";
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qs = qtest_pc_boot(cmd, extra_opts ? : "");
-        global_qtest = qs->qts;
-        return qs;
+    QNvme *nvme = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &nvme->dev;
     }
 
-    g_printerr("nvme tests are only available on x86\n");
-    exit(EXIT_FAILURE);
+    fprintf(stderr, "%s not present in nvme\n", interface);
+    g_assert_not_reached();
 }
 
-static void qnvme_stop(QOSState *qs)
+static void *nvme_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    qtest_shutdown(qs);
-}
+    QNvme *nvme = g_new0(QNvme, 1);
+    QPCIBus *bus = pci_bus;
 
-static void nop(void)
-{
-    QOSState *qs;
+    qpci_device_init(&nvme->dev, bus, addr);
+    nvme->obj.get_driver = nvme_get_driver;
 
-    qs = qnvme_start(NULL);
-    qnvme_stop(qs);
+    return &nvme->obj;
 }
 
-static void nvmetest_cmb_test(void)
+/* This used to cause a NULL pointer dereference.  */
+static void nvmetest_oob_cmb_test(void *obj, void *data, QGuestAllocator *alloc)
 {
     const int cmb_bar_size = 2 * MiB;
-    QOSState *qs;
-    QPCIDevice *pdev;
+    QNvme *nvme = obj;
+    QPCIDevice *pdev = &nvme->dev;
     QPCIBar bar;
 
-    qs = qnvme_start("-global nvme.cmb_size_mb=2");
-    pdev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4,0));
-    g_assert(pdev != NULL);
-
     qpci_device_enable(pdev);
     bar = qpci_iomap(pdev, 2, NULL);
 
@@ -65,16 +63,24 @@ static void nvmetest_cmb_test(void)
     g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11);
     g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211);
     g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211);
-    g_free(pdev);
-
-    qnvme_stop(qs);
 }
 
-int main(int argc, char **argv)
+static void nvme_register_nodes(void)
 {
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/nvme/nop", nop);
-    qtest_add_func("/nvme/cmb_test", nvmetest_cmb_test);
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0,drive=drv0,serial=foo",
+        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,format=raw",
+    };
+
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    return g_test_run();
+    qos_node_create_driver("nvme", nvme_create);
+    qos_node_consumes("nvme", "pci-bus", &opts);
+    qos_node_produces("nvme", "pci-device");
+
+    qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {
+        .edge.extra_device_opts = "cmb_size_mb=2"
+    });
 }
+
+libqos_init(nvme_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 64/71] qos-test: pcnet test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (62 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 63/71] qos-test: nvme " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 65/71] qos-test: spapr-phb " Paolo Bonzini
                   ` (9 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/pcnet-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/pcnet-test.c     | 46 ++++++++++++++++++++++++++++++++++++----------
 2 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 64eb8b6..351a729 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -143,7 +143,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
-check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
 check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
 check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
@@ -680,6 +679,7 @@ qos-test-obj-y += tests/ipoctal232-test.o
 qos-test-obj-y += tests/ne2000-test.o
 qos-test-obj-y += tests/nvme-test.o
 qos-test-obj-y += tests/pci-test.o
+qos-test-obj-y += tests/pcnet-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
 qos-test-obj-y += tests/virtio-test.o
@@ -726,7 +726,6 @@ tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
 tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
 tests/e1000-test$(EXESUF): tests/e1000-test.o
 tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y)
-tests/pcnet-test$(EXESUF): tests/pcnet-test.o
 tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
 tests/eepro100-test$(EXESUF): tests/eepro100-test.o
 tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
diff --git a/tests/pcnet-test.c b/tests/pcnet-test.c
index efb1ef4..484448c 100644
--- a/tests/pcnet-test.c
+++ b/tests/pcnet-test.c
@@ -9,23 +9,49 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
+typedef struct QPCNet QPCNet;
+
+struct QPCNet {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *pcnet_get_driver(void *obj, const char *interface)
 {
+    QPCNet *pcnet = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &pcnet->dev;
+    }
+
+    fprintf(stderr, "%s not present in pcnet\n", interface);
+    g_assert_not_reached();
 }
 
-int main(int argc, char **argv)
+static void *pcnet_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    int ret;
+    QPCNet *pcnet = g_new0(QPCNet, 1);
+    QPCIBus *bus = pci_bus;
 
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/pcnet/pci/nop", pci_nop);
+    qpci_device_init(&pcnet->dev, bus, addr);
+    pcnet->obj.get_driver = pcnet_get_driver;
 
-    qtest_start("-device pcnet");
-    ret = g_test_run();
+    return &pcnet->obj;
+}
 
-    qtest_end();
+static void pcnet_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    return ret;
+    qos_node_create_driver("pcnet", pcnet_create);
+    qos_node_consumes("pcnet", "pci-bus", &opts);
+    qos_node_produces("pcnet", "pci-device");
 }
+
+libqos_init(pcnet_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 65/71] qos-test: spapr-phb test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (63 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 64/71] qos-test: pcnet " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 66/71] qos-test: usb-hcd-ohci " Paolo Bonzini
                   ` (8 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/spapr-phb-test to a qgraph test node,
spapr-phb-test. This test adds another
spapr-pci-host-bridge device in the
ppc64/pseries machine

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/spapr-phb-test.c | 32 ++++++++++++++------------------
 2 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 351a729..9f19e31 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -217,7 +217,6 @@ check-qtest-ppc-y += tests/boot-serial-test$(EXESUF)
 check-qtest-ppc-y += tests/m48t59-test$(EXESUF)
 
 check-qtest-ppc64-y += $(check-qtest-ppc-y)
-check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF)
 check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF)
 check-qtest-ppc64-y += tests/migration-test$(EXESUF)
 check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
@@ -681,6 +680,7 @@ qos-test-obj-y += tests/nvme-test.o
 qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/pcnet-test.o
 qos-test-obj-y += tests/sdhci-test.o
+qos-test-obj-y += tests/spapr-phb-test.o
 qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
 qos-test-obj-y += tests/virtio-test.o
 qos-test-obj-y += tests/virtio-9p-test.o
@@ -703,7 +703,6 @@ tests/rtc-test$(EXESUF): tests/rtc-test.o
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/hexloader-test$(EXESUF): tests/hexloader-test.o
 tests/endianness-test$(EXESUF): tests/endianness-test.o
-tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
 tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
 tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
 tests/fdc-test$(EXESUF): tests/fdc-test.o
diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c
index d3522ea..39b5766 100644
--- a/tests/spapr-phb-test.c
+++ b/tests/spapr-phb-test.c
@@ -7,29 +7,25 @@
  * 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 "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
 
-#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
-
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void test_phb_device(void)
+/* Tests only initialization so far. TODO: Replace with functional tests,
+ * for example by producing pci-bus.
+ */
+static void test_phb_device(void *obj, void *data, QGuestAllocator *alloc)
 {
 }
 
-int main(int argc, char **argv)
+static void register_phb_test(void)
 {
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/spapr-phb/device", test_phb_device);
-
-    qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=30");
-
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
+    qos_add_test("spapr-phb-test", "ppc64/pseries",
+                 test_phb_device, &(QOSGraphTestOptions) {
+                     .edge.before_cmd_line = "-device spapr-pci-host-bridge"
+                                             ",index=30",
+                 });
 }
+
+libqos_init(register_phb_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 66/71] qos-test: usb-hcd-ohci test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (64 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 65/71] qos-test: spapr-phb " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 67/71] qos-test: vmxnet3 " Paolo Bonzini
                   ` (7 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/usb-hcd-ohci-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include    |  4 +---
 tests/usb-hcd-ohci-test.c | 54 +++++++++++++++++++++++++++++++++++------------
 2 files changed, 42 insertions(+), 16 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 9f19e31..47b4d12 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -172,7 +172,6 @@ check-qtest-i386-$(CONFIG_VMXNET3_PCI) += tests/vmxnet3-test$(EXESUF)
 check-qtest-i386-$(CONFIG_PVPANIC) += tests/pvpanic-test$(EXESUF)
 check-qtest-i386-$(CONFIG_I82801B11) += tests/i82801b11-test$(EXESUF)
 check-qtest-i386-$(CONFIG_IOH3420) += tests/ioh3420-test$(EXESUF)
-check-qtest-i386-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF)
 check-qtest-i386-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF)
 ifeq ($(CONFIG_USB_ECHI)$(CONFIG_USB_UHCI),yy)
 check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
@@ -221,7 +220,6 @@ check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF)
 check-qtest-ppc64-y += tests/migration-test$(EXESUF)
 check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
 check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF)
-check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF)
 check-qtest-ppc64-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF)
 check-qtest-ppc64-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF)
 check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
@@ -681,6 +679,7 @@ qos-test-obj-y += tests/pci-test.o
 qos-test-obj-y += tests/pcnet-test.o
 qos-test-obj-y += tests/sdhci-test.o
 qos-test-obj-y += tests/spapr-phb-test.o
+qos-test-obj-y += tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
 qos-test-obj-$(CONFIG_VHOST_NET_USER) += tests/vhost-user-test.o $(chardev-obj-y) $(test-io-obj-y)
 qos-test-obj-y += tests/virtio-test.o
 qos-test-obj-y += tests/virtio-9p-test.o
@@ -741,7 +740,6 @@ tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
-tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
diff --git a/tests/usb-hcd-ohci-test.c b/tests/usb-hcd-ohci-test.c
index 48ddbfd..98af02e 100644
--- a/tests/usb-hcd-ohci-test.c
+++ b/tests/usb-hcd-ohci-test.c
@@ -10,30 +10,58 @@
 #include "qemu/osdep.h"
 #include "libqtest.h"
 #include "libqos/usb.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
+typedef struct QOHCI_PCI QOHCI_PCI;
 
-static void test_ohci_init(void)
-{
+struct QOHCI_PCI {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
 
+static void test_ohci_hotplug(void *obj, void *data, QGuestAllocator *alloc)
+{
+    usb_test_hotplug("ohci", "1", NULL);
 }
 
-static void test_ohci_hotplug(void)
+static void *ohci_pci_get_driver(void *obj, const char *interface)
 {
-    usb_test_hotplug("ohci", "1", NULL);
+    QOHCI_PCI *ohci_pci = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &ohci_pci->dev;
+    }
+
+    fprintf(stderr, "%s not present in pci-ohci\n", interface);
+    g_assert_not_reached();
 }
 
-int main(int argc, char **argv)
+static void *ohci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    int ret;
+    QOHCI_PCI *ohci_pci = g_new0(QOHCI_PCI, 1);
+    ohci_pci->obj.get_driver = ohci_pci_get_driver;
 
-    g_test_init(&argc, &argv, NULL);
+    return &ohci_pci->obj;
+}
+
+static void ohci_pci_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0,id=ohci",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    qtest_add_func("/ohci/pci/init", test_ohci_init);
-    qtest_add_func("/ohci/pci/hotplug", test_ohci_hotplug);
+    qos_node_create_driver("pci-ohci", ohci_pci_create);
+    qos_node_consumes("pci-ohci", "pci-bus", &opts);
+    qos_node_produces("pci-ohci", "pci-device");
+}
 
-    qtest_start("-device pci-ohci,id=ohci");
-    ret = g_test_run();
-    qtest_end();
+libqos_init(ohci_pci_register_nodes);
 
-    return ret;
+static void register_ohci_pci_test(void)
+{
+    qos_add_test("ohci_pci-test-hotplug", "pci-ohci", test_ohci_hotplug, NULL);
 }
+
+libqos_init(register_ohci_pci_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 67/71] qos-test: vmxnet3 test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (65 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 66/71] qos-test: usb-hcd-ohci " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 68/71] qos-test: es1370 " Paolo Bonzini
                   ` (6 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/vmxnet3-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/vmxnet3-test.c   | 46 ++++++++++++++++++++++++++++++++++++----------
 2 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 47b4d12..8995132 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -168,7 +168,6 @@ check-qtest-i386-y += tests/drive_del-test$(EXESUF)
 check-qtest-i386-$(CONFIG_WDT_IB700) += tests/wdt_ib700-test$(EXESUF)
 check-qtest-i386-y += tests/tco-test$(EXESUF)
 check-qtest-i386-y += $(check-qtest-pci-y)
-check-qtest-i386-$(CONFIG_VMXNET3_PCI) += tests/vmxnet3-test$(EXESUF)
 check-qtest-i386-$(CONFIG_PVPANIC) += tests/pvpanic-test$(EXESUF)
 check-qtest-i386-$(CONFIG_I82801B11) += tests/i82801b11-test$(EXESUF)
 check-qtest-i386-$(CONFIG_IOH3420) += tests/ioh3420-test$(EXESUF)
@@ -688,6 +687,7 @@ qos-test-obj-y += tests/virtio-net-test.o
 qos-test-obj-y += tests/virtio-rng-test.o
 qos-test-obj-y += tests/virtio-scsi-test.o
 qos-test-obj-y += tests/virtio-serial-test.o
+qos-test-obj-y += tests/vmxnet3-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -726,7 +726,6 @@ tests/e1000-test$(EXESUF): tests/e1000-test.o
 tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y)
 tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
 tests/eepro100-test$(EXESUF): tests/eepro100-test.o
-tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
diff --git a/tests/vmxnet3-test.c b/tests/vmxnet3-test.c
index 159c0ad..35cdea9 100644
--- a/tests/vmxnet3-test.c
+++ b/tests/vmxnet3-test.c
@@ -9,23 +9,49 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
+typedef struct QVmxnet3 QVmxnet3;
+
+struct QVmxnet3 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *vmxnet3_get_driver(void *obj, const char *interface)
 {
+    QVmxnet3 *vmxnet3 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &vmxnet3->dev;
+    }
+
+    fprintf(stderr, "%s not present in vmxnet3\n", interface);
+    g_assert_not_reached();
 }
 
-int main(int argc, char **argv)
+static void *vmxnet3_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    int ret;
+    QVmxnet3 *vmxnet3 = g_new0(QVmxnet3, 1);
+    QPCIBus *bus = pci_bus;
 
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/vmxnet3/nop", nop);
+    qpci_device_init(&vmxnet3->dev, bus, addr);
+    vmxnet3->obj.get_driver = vmxnet3_get_driver;
 
-    qtest_start("-device vmxnet3");
-    ret = g_test_run();
+    return &vmxnet3->obj;
+}
 
-    qtest_end();
+static void vmxnet3_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    return ret;
+    qos_node_create_driver("vmxnet3", vmxnet3_create);
+    qos_node_consumes("vmxnet3", "pci-bus", &opts);
+    qos_node_produces("vmxnet3", "pci-device");
 }
+
+libqos_init(vmxnet3_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 68/71] qos-test: es1370 test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (66 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 67/71] qos-test: vmxnet3 " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 69/71] qos-test: eepro100 " Paolo Bonzini
                   ` (5 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/es1370-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/es1370-test.c    | 46 ++++++++++++++++++++++++++++++++++++----------
 2 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8995132..ee6871d 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -144,7 +144,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
-check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF)
@@ -671,6 +670,7 @@ qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 # Tests
 qos-test-obj-y += tests/ac97-test.o
 qos-test-obj-y += tests/e1000e-test.o
+qos-test-obj-y += tests/es1370-test.o
 qos-test-obj-y += tests/ipoctal232-test.o
 qos-test-obj-y += tests/ne2000-test.o
 qos-test-obj-y += tests/nvme-test.o
@@ -736,7 +736,6 @@ tests/machine-none-test$(EXESUF): tests/machine-none-test.o
 tests/drive_del-test$(EXESUF): tests/drive_del-test.o
 tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
 tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
-tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
 tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
diff --git a/tests/es1370-test.c b/tests/es1370-test.c
index 199fe19..d845cd0 100644
--- a/tests/es1370-test.c
+++ b/tests/es1370-test.c
@@ -9,23 +9,49 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void nop(void)
+typedef struct QES1370 QES1370;
+
+struct QES1370 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *es1370_get_driver(void *obj, const char *interface)
 {
+    QES1370 *es1370 = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &es1370->dev;
+    }
+
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
 }
 
-int main(int argc, char **argv)
+static void *es1370_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    int ret;
+    QES1370 *es1370 = g_new0(QES1370, 1);
+    QPCIBus *bus = pci_bus;
 
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/es1370/nop", nop);
+    qpci_device_init(&es1370->dev, bus, addr);
+    es1370->obj.get_driver = es1370_get_driver;
 
-    qtest_start("-device ES1370");
-    ret = g_test_run();
+    return &es1370->obj;
+}
 
-    qtest_end();
+static void es1370_register_nodes(void)
+{
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    return ret;
+    qos_node_create_driver("ES1370", es1370_create);
+    qos_node_consumes("ES1370", "pci-bus", &opts);
+    qos_node_produces("ES1370", "pci-device");
 }
+
+libqos_init(es1370_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 69/71] qos-test: eepro100 test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (67 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 68/71] qos-test: es1370 " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 70/71] qos-test: e1000 " Paolo Bonzini
                   ` (4 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/eepro100-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.
For now, all nodes share the same constructor and destructor.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/eepro100-test.c  | 65 +++++++++++++++++++++++++++++++-------------------
 2 files changed, 41 insertions(+), 27 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ee6871d..eefb503 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -143,7 +143,6 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
-check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF)
@@ -670,6 +669,7 @@ qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 # Tests
 qos-test-obj-y += tests/ac97-test.o
 qos-test-obj-y += tests/e1000e-test.o
+qos-test-obj-y += tests/eepro100-test.o
 qos-test-obj-y += tests/es1370-test.o
 qos-test-obj-y += tests/ipoctal232-test.o
 qos-test-obj-y += tests/ne2000-test.o
@@ -725,7 +725,6 @@ tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
 tests/e1000-test$(EXESUF): tests/e1000-test.o
 tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y)
 tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
-tests/eepro100-test$(EXESUF): tests/eepro100-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
 tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
 tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
diff --git a/tests/eepro100-test.c b/tests/eepro100-test.c
index bdc8a67..90b5c1a 100644
--- a/tests/eepro100-test.c
+++ b/tests/eepro100-test.c
@@ -9,23 +9,15 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-static void test_device(gconstpointer data)
-{
-    const char *model = data;
-    QTestState *s;
-    char *args;
-
-    args = g_strdup_printf("-device %s", model);
-    s = qtest_start(args);
-
-    /* Tests only initialization so far. TODO: Implement functional tests */
+typedef struct QEEPRO100 QEEPRO100;
 
-    if (s) {
-        qtest_quit(s);
-    }
-    g_free(args);
-}
+struct QEEPRO100 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
 
 static const char *models[] = {
     "i82550",
@@ -43,19 +35,42 @@ static const char *models[] = {
     "i82801",
 };
 
-int main(int argc, char **argv)
+static void *eepro100_get_driver(void *obj, const char *interface)
 {
-    int i;
+    QEEPRO100 *eepro100 = obj;
 
-    g_test_init(&argc, &argv, NULL);
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &eepro100->dev;
+    }
 
-    for (i = 0; i < ARRAY_SIZE(models); i++) {
-        char *path;
+    fprintf(stderr, "%s not present in eepro100\n", interface);
+    g_assert_not_reached();
+}
 
-        path = g_strdup_printf("eepro100/%s", models[i]);
-        qtest_add_data_func(path, models[i], test_device);
-        g_free(path);
-    }
+static void *eepro100_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QEEPRO100 *eepro100 = g_new0(QEEPRO100, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&eepro100->dev, bus, addr);
+    eepro100->obj.get_driver = eepro100_get_driver;
+
+    return &eepro100->obj;
+}
+
+static void eepro100_register_nodes(void)
+{
+    int i;
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
 
-    return g_test_run();
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+    for (i = 0; i < ARRAY_SIZE(models); i++) {
+        qos_node_create_driver(models[i], eepro100_create);
+        qos_node_consumes(models[i], "pci-bus", &opts);
+        qos_node_produces(models[i], "pci-device");
+    }
 }
+
+libqos_init(eepro100_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 70/71] qos-test: e1000 test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (68 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 69/71] qos-test: eepro100 " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 71/71] qos-test: megasas " Paolo Bonzini
                   ` (3 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Convert tests/e1000-test to a driver node; currently it runs
the PCI nop test only, therefore we're not placing it in tests/libqos.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +--
 tests/e1000-test.c     | 64 +++++++++++++++++++++++++++++++-------------------
 2 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index eefb503..0527342 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -141,7 +141,6 @@ check-qtest-generic-y += tests/qmp-cmd-test$(EXESUF)
 check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
 check-qtest-generic-y += tests/cdrom-test$(EXESUF)
 
-check-qtest-pci-y += tests/e1000-test$(EXESUF)
 check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
@@ -668,6 +667,7 @@ qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
 
 # Tests
 qos-test-obj-y += tests/ac97-test.o
+qos-test-obj-y += tests/e1000-test.o
 qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/eepro100-test.o
 qos-test-obj-y += tests/es1370-test.o
@@ -722,7 +722,6 @@ tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
 tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
-tests/e1000-test$(EXESUF): tests/e1000-test.o
 tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y)
 tests/pnv-xscom-test$(EXESUF): tests/pnv-xscom-test.o
 tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
diff --git a/tests/e1000-test.c b/tests/e1000-test.c
index 0c5fcdc..9e67916 100644
--- a/tests/e1000-test.c
+++ b/tests/e1000-test.c
@@ -9,22 +9,15 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void test_device(gconstpointer data)
-{
-    const char *model = data;
-    QTestState *s;
-    char *args;
-
-    args = g_strdup_printf("-device %s", model);
-    s = qtest_start(args);
+typedef struct QE1000 QE1000;
 
-    if (s) {
-        qtest_quit(s);
-    }
-    g_free(args);
-}
+struct QE1000 {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
 
 static const char *models[] = {
     "e1000",
@@ -33,19 +26,42 @@ static const char *models[] = {
     "e1000-82545em",
 };
 
-int main(int argc, char **argv)
+static void *e1000_get_driver(void *obj, const char *interface)
 {
-    int i;
+    QE1000 *e1000 = obj;
 
-    g_test_init(&argc, &argv, NULL);
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &e1000->dev;
+    }
 
-    for (i = 0; i < ARRAY_SIZE(models); i++) {
-        char *path;
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
+}
 
-        path = g_strdup_printf("e1000/%s", models[i]);
-        qtest_add_data_func(path, models[i], test_device);
-        g_free(path);
-    }
+static void *e1000_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
+{
+    QE1000 *e1000 = g_new0(QE1000, 1);
+    QPCIBus *bus = pci_bus;
+
+    qpci_device_init(&e1000->dev, bus, addr);
+    e1000->obj.get_driver = e1000_get_driver;
+
+    return &e1000->obj;
+}
+
+static void e1000_register_nodes(void)
+{
+    int i;
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0",
+    };
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
 
-    return g_test_run();
+    for (i = 0; i < ARRAY_SIZE(models); i++) {
+        qos_node_create_driver(models[i], e1000_create);
+        qos_node_consumes(models[i], "pci-bus", &opts);
+        qos_node_produces(models[i], "pci-device");
+    }
 }
+
+libqos_init(e1000_register_nodes);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH 71/71] qos-test: megasas test node
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (69 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 70/71] qos-test: e1000 " Paolo Bonzini
@ 2018-12-03 15:33 ` Paolo Bonzini
  2018-12-03 20:45 ` [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework no-reply
                   ` (2 subsequent siblings)
  73 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-03 15:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Thomas Huth

Convert tests/megasas-test to a driver node; the code to discover the PCI
device is replaced by generic qgraph code.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |  3 +-
 tests/megasas-test.c   | 80 +++++++++++++++++++++++++-------------------------
 2 files changed, 41 insertions(+), 42 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 0527342..014583f 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -145,7 +145,6 @@ check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
 check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
 check-qtest-pci-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF)
-check-qtest-pci-y += tests/megasas-test$(EXESUF)
 
 check-qtest-i386-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF)
 check-qtest-i386-y += tests/fdc-test$(EXESUF)
@@ -672,6 +671,7 @@ qos-test-obj-y += tests/e1000e-test.o
 qos-test-obj-y += tests/eepro100-test.o
 qos-test-obj-y += tests/es1370-test.o
 qos-test-obj-y += tests/ipoctal232-test.o
+qos-test-obj-y += tests/megasas-test.o
 qos-test-obj-y += tests/ne2000-test.o
 qos-test-obj-y += tests/nvme-test.o
 qos-test-obj-y += tests/pci-test.o
@@ -750,7 +750,6 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y)
 tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y)
 tests/test-x86-cpuid-compat$(EXESUF): tests/test-x86-cpuid-compat.o $(qtest-obj-y)
 tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
-tests/megasas-test$(EXESUF): tests/megasas-test.o $(libqos-spapr-obj-y) $(libqos-pc-obj-y)
 tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o $(test-util-obj-y) libvhost-user.a
 tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y)
 tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
diff --git a/tests/megasas-test.c b/tests/megasas-test.c
index 81837e1..33aa970 100644
--- a/tests/megasas-test.c
+++ b/tests/megasas-test.c
@@ -10,55 +10,49 @@
 #include "qemu/osdep.h"
 #include "libqtest.h"
 #include "qemu/bswap.h"
-#include "libqos/libqos-pc.h"
-#include "libqos/libqos-spapr.h"
+#include "libqos/qgraph.h"
+#include "libqos/pci.h"
 
-static QOSState *qmegasas_start(const char *extra_opts)
+typedef struct QMegasas QMegasas;
+
+struct QMegasas {
+    QOSGraphObject obj;
+    QPCIDevice dev;
+};
+
+static void *megasas_get_driver(void *obj, const char *interface)
 {
-    QOSState *qs;
-    const char *arch = qtest_get_arch();
-    const char *cmd = "-drive id=hd0,if=none,file=null-co://,format=raw "
-                      "-device megasas,id=scsi0,addr=04.0 "
-                      "-device scsi-hd,bus=scsi0.0,drive=hd0 %s";
-
-    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-        qs = qtest_pc_boot(cmd, extra_opts ? : "");
-        global_qtest = qs->qts;
-        return qs;
+    QMegasas *megasas = obj;
+
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &megasas->dev;
     }
 
-    g_printerr("virtio-scsi tests are only available on x86 or ppc64\n");
-    exit(EXIT_FAILURE);
+    fprintf(stderr, "%s not present in megasas\n", interface);
+    g_assert_not_reached();
 }
 
-static void qmegasas_stop(QOSState *qs)
+static void *megasas_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
-    qtest_shutdown(qs);
-}
+    QMegasas *megasas = g_new0(QMegasas, 1);
+    QPCIBus *bus = pci_bus;
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
-{
-    QOSState *qs;
+    qpci_device_init(&megasas->dev, bus, addr);
+    megasas->obj.get_driver = megasas_get_driver;
 
-    qs = qmegasas_start(NULL);
-    qmegasas_stop(qs);
+    return &megasas->obj;
 }
 
 /* This used to cause a NULL pointer dereference.  */
-static void megasas_pd_get_info_fuzz(void)
+static void megasas_pd_get_info_fuzz(void *obj, void *data, QGuestAllocator *alloc)
 {
-    QPCIDevice *dev;
-    QOSState *qs;
+    QMegasas *megasas = obj;
+    QPCIDevice *dev = &megasas->dev;
     QPCIBar bar;
     uint32_t context[256];
     uint64_t context_pa;
     int i;
 
-    qs = qmegasas_start(NULL);
-    dev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4,0));
-    g_assert(dev != NULL);
-
     qpci_device_enable(dev);
     bar = qpci_iomap(dev, 0, NULL);
 
@@ -71,19 +65,25 @@ static void megasas_pd_get_info_fuzz(void)
     context[6] = cpu_to_le32(0x02020000);
     context[7] = cpu_to_le32(0);
 
-    context_pa = qmalloc(qs, sizeof(context));
+    context_pa = guest_alloc(alloc, sizeof(context));
     memwrite(context_pa, context, sizeof(context));
     qpci_io_writel(dev, bar, 0x40, context_pa);
-
-    g_free(dev);
-    qmegasas_stop(qs);
 }
 
-int main(int argc, char **argv)
+static void megasas_register_nodes(void)
 {
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/megasas/pci/nop", pci_nop);
-    qtest_add_func("/megasas/dcmd/pd-get-info/fuzz", megasas_pd_get_info_fuzz);
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "addr=04.0,id=scsi0",
+        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,format=raw",
+        .after_cmd_line = "-device scsi-hd,bus=scsi0.0,drive=drv0",
+    };
+
+    add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
+
+    qos_node_create_driver("megasas", megasas_create);
+    qos_node_consumes("megasas", "pci-bus", &opts);
+    qos_node_produces("megasas", "pci-device");
 
-    return g_test_run();
+    qos_add_test("dcmd/pd-get-info/fuzz", "megasas", megasas_pd_get_info_fuzz, NULL);
 }
+libqos_init(megasas_register_nodes);
-- 
1.8.3.1

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

* Re: [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (70 preceding siblings ...)
  2018-12-03 15:33 ` [Qemu-devel] [PATCH 71/71] qos-test: megasas " Paolo Bonzini
@ 2018-12-03 20:45 ` no-reply
  2018-12-12 15:15 ` Philippe Mathieu-Daudé
  2018-12-12 15:31 ` Philippe Mathieu-Daudé
  73 siblings, 0 replies; 103+ messages in thread
From: no-reply @ 2018-12-03 20:45 UTC (permalink / raw)
  To: pbonzini; +Cc: famz, qemu-devel, thuth, e.emanuelegiuseppe, laurent

Patchew URL: https://patchew.org/QEMU/1543851204-41186-1-git-send-email-pbonzini@redhat.com/



Hi,

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

Subject: [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework
Message-id: 1543851204-41186-1-git-send-email-pbonzini@redhat.com
Type: series

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

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

git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --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
Switched to a new branch 'test'
2481c4f qos-test: megasas test node
eb1b2e2 qos-test: e1000 test node
adbe018 qos-test: eepro100 test node
4bc9a83 qos-test: es1370 test node
23f2225 qos-test: vmxnet3 test node
eaa4e82 qos-test: usb-hcd-ohci test node
5ba009f qos-test: spapr-phb test node
4ea3316 qos-test: pcnet test node
d3ac439 qos-test: nvme test node
a9f70fb qos-test: ne2k_pci test node
0ebd9c0 qos-test: ipoctal232 test node
c78a4e6 qos-test: tpci200 test node
d4ad0f6 qos-test: ac97 test node
6713c9b tests: move virtio entirely to qos-test
dc6c5f2 tests/libqos: remove pre-qgraph QVirtioPCIDevice API
388e7d2 qos-test: virtio-scsi test node
34e436c tests/libqos: virtio-scsi driver and interface nodes
24704ac qos-test: vhost-user test node
efc802d vhost-user-test: always use 256 MiB of guest memory
2ad03c4 tests/libqos: support multiqueue for virtio-net
e7bc9002 qos-test: virtio-net test node
451616b tests/libqos: virtio-net driver and interface nodes
1febccc qos-test: virtio-blk test node
577ec81 tests/libqos: virtio-blk driver and interface nodes
89ad44e qos-test: virtio-rng test node
c8bb1e8 tests/libqos: virtio-rng driver and interface nodes
3d32661 tests/qgraph: remove virtio-balloon-test
8eee4cb tests/libqos: virtio-balloon driver and interface nodes
9beaf3b qos-test: virtio-9p test node
9c82a2e tests/libqos: virtio-9p driver and interface nodes
5a8bbbc qos-test: virtio-console and virtio-serial test node
15ead1a tests/libqos: virtio-serial driver and interface nodes
e31028a tests/qgraph: add generic virtio testcases
0bad3d3 tests/libqos: arm/virt machine node
b27a3ae tests/libqos: virtio-mmio driver and interface nodes
f487f19 tests/libqos: remove global_qtest from virtio endianness checks
7089f84 tests/libqos: virtio-pci driver and interface nodes
1c8385d qos-test: e1000e test node
348aa8e tests/libqos: e1000e driver and interface nodes
390c855 tests/libqos: has_buggy_msi flag
75f1afb tests/qgraph: ppc64/pseries machine node
7a73b3a tests/libqos: pci-spapr driver and interface nodes
4141cf0 tests/qgraph: add generic PCI testcases
de3aefd qos-test: sdhci test node
41d4c33 tests/libqos: aarch64/xlnx-zcu102 machine node
bc28cc5 tests/libqos: arm/xilinx-zynq-a9 machine node
d4d45c2 tests/libqos: arm/sabrelite machine node
5d2f307 tests/libqos: arm/smdkc210 machine node
c3dfe87 tests/libqos: arm/raspi2 machine node
fe25242 tests/libqos: sdhci driver and interface nodes
c8b2b96 tests/libqos: x86_64/pc machine node
51d165a tests/libqos: pci-pc driver and interface nodes
dc0ef68 tests: qgraph API for the qtest driver framework
a9189d09 tests/libqos: embed allocators instead of malloc-ing them
68fcc14 tests: remove rule for nonexisting qdev-monitor-test
5800452 tests/libqos: rename qpci_init_pc and qpci_init_spapr functions
bc0a2b5 tests/libqos: introduce virtio_start_device
5a6e8da vhost-user-test: create a temporary directory per TestServer
c331c35 vhost-user-test: small changes to init_hugepagefs
dfcc9d9 vhost-user-test: create a main loop per TestServer
b9852f5 vhost-user-test: reduce usage of global_qtest
cfaadd5 vhost-user-test: skip if there is no memory at address 0
9326e61 vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
eff2596 vhost-user: support cross-endian vnet headers
6134cca vhost-user-test: signal data_cond when s->rings changes
1b7aa1e vhost-user-test: use g_cond_broadcast
a6d4bd9 vhost-net: revamp configure logic
96e94ca vhost-net: compile it on all targets that have virtio-net.
19a2ec5 vhost: restrict Linux dependency to kernel vhost
7577324 vhost-net-user: add stubs for when no virtio-net device is present
0b4471d vhost-net: move stubs to a separate file

=== OUTPUT BEGIN ===
Checking PATCH 1/71: vhost-net: move stubs to a separate file...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#40: 
new file mode 100644

total: 0 errors, 1 warnings, 115 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 2/71: vhost-net-user: add stubs for when no virtio-net device is present...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#99: 
new file mode 100644

total: 0 errors, 1 warnings, 75 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 3/71: vhost: restrict Linux dependency to kernel vhost...
Checking PATCH 4/71: vhost-net: compile it on all targets that have virtio-net....
Checking PATCH 5/71: vhost-net: revamp configure logic...
Checking PATCH 6/71: vhost-user-test: use g_cond_broadcast...
Checking PATCH 7/71: vhost-user-test: signal data_cond when s->rings changes...
Checking PATCH 8/71: vhost-user: support cross-endian vnet headers...
Checking PATCH 9/71: vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN...
Checking PATCH 10/71: vhost-user-test: skip if there is no memory at address 0...
Checking PATCH 11/71: vhost-user-test: reduce usage of global_qtest...
WARNING: line over 80 characters
#26: FILE: tests/vhost-user-test.c:190:
+static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_mask)

WARNING: line over 80 characters
#59: FILE: tests/vhost-user-test.c:296:
+            uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);

total: 0 errors, 2 warnings, 132 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 12/71: vhost-user-test: create a main loop per TestServer...
ERROR: space prohibited between function name and open parenthesis '('
#55: FILE: tests/vhost-user-test.c:551:
+        g_main_context_iteration (NULL, TRUE);

total: 1 errors, 0 warnings, 82 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 13/71: vhost-user-test: small changes to init_hugepagefs...
Checking PATCH 14/71: vhost-user-test: create a temporary directory per TestServer...
ERROR: Error messages should not contain newlines
#71: FILE: tests/vhost-user-test.c:510:
+        g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));

ERROR: Error messages should not contain newlines
#92: FILE: tests/vhost-user-test.c:580:
+        g_test_message("unable to rmdir: path (%s): %s\n",

total: 2 errors, 0 warnings, 179 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 15/71: tests/libqos: introduce virtio_start_device...
Checking PATCH 16/71: tests/libqos: rename qpci_init_pc and qpci_init_spapr functions...
Checking PATCH 17/71: tests: remove rule for nonexisting qdev-monitor-test...
Checking PATCH 18/71: tests/libqos: embed allocators instead of malloc-ing them...
ERROR: code indent should never use tabs
#339: FILE: tests/libqos/malloc-generic.c:19:
+^I^I^Iuint64_t size, uint32_t page_size)$

total: 1 errors, 0 warnings, 846 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 19/71: tests: qgraph API for the qtest driver framework...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#93: 
new file mode 100644

WARNING: line over 80 characters
#197: FILE: tests/libqos/qgraph.c:100:
+        opts->before_cmd_line ? g_strconcat(" ", opts->before_cmd_line, NULL) : NULL;

WARNING: line over 80 characters
#199: FILE: tests/libqos/qgraph.c:102:
+        opts->extra_device_opts ? g_strconcat(",", opts->extra_device_opts, NULL) : NULL;

WARNING: line over 80 characters
#201: FILE: tests/libqos/qgraph.c:104:
+        opts->after_cmd_line ? g_strconcat(" ", opts->after_cmd_line, NULL) : NULL;

ERROR: code indent should never use tabs
#1209: FILE: tests/libqos/qgraph.h:346:
+^I^I^I^I * and modify the argument to the test function.$

WARNING: line over 80 characters
#1930: FILE: tests/qos-test.c:202:
+static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)

WARNING: line over 80 characters
#2087: FILE: tests/qos-test.c:359:
+    /* etype set to QEDGE_CONSUMED_BY so that machine can add to the command line */

total: 1 errors, 6 warnings, 2559 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 20/71: tests/libqos: pci-pc driver and interface nodes...
Checking PATCH 21/71: tests/libqos: x86_64/pc machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#29: 
new file mode 100644

ERROR: code indent should never use tabs
#86: FILE: tests/libqos/x86_64_pc-machine.c:53:
+^I^I^I^I   QTestState *qts,$

total: 1 errors, 1 warnings, 119 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 22/71: tests/libqos: sdhci driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#28: 
new file mode 100644

ERROR: code indent should never use tabs
#98: FILE: tests/libqos/sdhci.c:66:
+^I^I       uint32_t addr, QSDHCIProperties *common)$

ERROR: code indent should never use tabs
#269: FILE: tests/libqos/sdhci.h:68:
+^I^I       uint32_t addr, QSDHCIProperties *common);$

total: 2 errors, 1 warnings, 240 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 23/71: tests/libqos: arm/raspi2 machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#27: 
new file mode 100644

total: 0 errors, 1 warnings, 98 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 24/71: tests/libqos: arm/smdkc210 machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#27: 
new file mode 100644

total: 0 errors, 1 warnings, 98 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 25/71: tests/libqos: arm/sabrelite machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#27: 
new file mode 100644

total: 0 errors, 1 warnings, 98 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 26/71: tests/libqos: arm/xilinx-zynq-a9 machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#27: 
new file mode 100644

total: 0 errors, 1 warnings, 101 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 27/71: tests/libqos: aarch64/xlnx-zcu102 machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#27: 
new file mode 100644

ERROR: line over 90 characters
#120: FILE: tests/libqos/aarch64-xlnx-zcu102-machine.c:89:
+    qos_node_create_machine("aarch64/xlnx-zcu102", qos_create_machine_aarch64_xlnx_zcu102);

total: 1 errors, 1 warnings, 100 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 28/71: qos-test: sdhci test node...
Checking PATCH 29/71: tests/qgraph: add generic PCI testcases...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#23: 
new file mode 100644

total: 0 errors, 1 warnings, 32 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 30/71: tests/libqos: pci-spapr driver and interface nodes...
Checking PATCH 31/71: tests/qgraph: ppc64/pseries machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#28: 
new file mode 100644

ERROR: code indent should never use tabs
#85: FILE: tests/libqos/ppc64_pseries-machine.c:53:
+^I^I^I^I   QGuestAllocator *alloc)$

total: 1 errors, 1 warnings, 118 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 32/71: tests/libqos: has_buggy_msi flag...
Checking PATCH 33/71: tests/libqos: e1000e driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#28: 
new file mode 100644

total: 0 errors, 1 warnings, 320 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 34/71: qos-test: e1000e test node...
WARNING: line over 80 characters
#259: FILE: tests/e1000e-test.c:37:
+static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)

WARNING: line over 80 characters
#281: FILE: tests/e1000e-test.c:101:
+static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)

ERROR: code indent should never use tabs
#458: FILE: tests/e1000e-test.c:255:
+^I^I^I   test_sockets[1]);$

total: 1 errors, 2 warnings, 445 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 35/71: tests/libqos: virtio-pci driver and interface nodes...
WARNING: line over 80 characters
#66: FILE: tests/libqos/virtio-pci.c:51:
+static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_dev)

total: 0 errors, 1 warnings, 322 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 36/71: tests/libqos: remove global_qtest from virtio endianness checks...
Checking PATCH 37/71: tests/libqos: virtio-mmio driver and interface nodes...
WARNING: line over 80 characters
#36: FILE: tests/libqos/virtio-mmio.c:21:
+    return qtest_readb(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);

WARNING: line over 80 characters
#44: FILE: tests/libqos/virtio-mmio.c:27:
+    return qtest_readw(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);

WARNING: line over 80 characters
#52: FILE: tests/libqos/virtio-mmio.c:33:
+    return qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);

WARNING: line over 80 characters
#60: FILE: tests/libqos/virtio-mmio.c:39:
+    return qtest_readq(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);

WARNING: line over 80 characters
#96: FILE: tests/libqos/virtio-mmio.c:66:
+    return (uint8_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS);

WARNING: line over 80 characters
#104: FILE: tests/libqos/virtio-mmio.c:72:
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status);

WARNING: line over 80 characters
#147: FILE: tests/libqos/virtio-mmio.c:108:
+    g_assert_cmphex(qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0);

WARNING: line over 80 characters
#155: FILE: tests/libqos/virtio-mmio.c:114:
+    return (uint16_t)qtest_readl(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX);

WARNING: line over 80 characters
#177: FILE: tests/libqos/virtio-mmio.c:132:
+    qtest_writel(dev->qts, dev->addr + QVIRTIO_MMIO_QUEUE_ALIGN, dev->page_size);

ERROR: code indent should never use tabs
#227: FILE: tests/libqos/virtio-mmio.c:207:
+^I^I^I      uint64_t addr, uint32_t page_size)$

ERROR: code indent should never use tabs
#283: FILE: tests/libqos/virtio-mmio.h:48:
+^I^I^I      uint64_t addr, uint32_t page_size);$

WARNING: line over 80 characters
#296: FILE: tests/virtio-blk-test.c:725:
+    qvirtio_mmio_init_device(dev, global_qtest, MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);

total: 2 errors, 10 warnings, 259 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 38/71: tests/libqos: arm/virt machine node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#27: 
new file mode 100644

ERROR: code indent should never use tabs
#103: FILE: tests/libqos/arm-virt-machine.c:72:
+^I       ARM_VIRT_RAM_ADDR,$

ERROR: code indent should never use tabs
#104: FILE: tests/libqos/arm-virt-machine.c:73:
+^I       ARM_VIRT_RAM_ADDR + ARM_VIRT_RAM_SIZE,$

ERROR: code indent should never use tabs
#105: FILE: tests/libqos/arm-virt-machine.c:74:
+^I       ARM_PAGE_SIZE);$

total: 3 errors, 1 warnings, 97 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 39/71: tests/qgraph: add generic virtio testcases...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#23: 
new file mode 100644

total: 0 errors, 1 warnings, 32 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 40/71: tests/libqos: virtio-serial driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

total: 0 errors, 1 warnings, 156 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 41/71: qos-test: virtio-console and virtio-serial test node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#78: 
deleted file mode 100644

total: 0 errors, 1 warnings, 90 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 42/71: tests/libqos: virtio-9p driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

total: 0 errors, 1 warnings, 222 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 43/71: qos-test: virtio-9p test node...
Checking PATCH 44/71: tests/libqos: virtio-balloon driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

total: 0 errors, 1 warnings, 159 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 45/71: tests/qgraph: remove virtio-balloon-test...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#43: 
deleted file mode 100644

total: 0 errors, 1 warnings, 21 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 46/71: tests/libqos: virtio-rng driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

total: 0 errors, 1 warnings, 156 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 47/71: qos-test: virtio-rng test node...
Checking PATCH 48/71: tests/libqos: virtio-blk driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

total: 0 errors, 1 warnings, 171 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 49/71: qos-test: virtio-blk test node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#69: 
deleted file mode 100644

WARNING: line over 80 characters
#763: FILE: tests/virtio-blk-test.c:576:
+                         &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });

ERROR: code indent should never use tabs
#868: FILE: tests/virtio-blk-test.c:643:
+^I^I^I   tmp_path);$

total: 1 errors, 2 warnings, 797 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 50/71: tests/libqos: virtio-net driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

total: 0 errors, 1 warnings, 244 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 51/71: qos-test: virtio-net test node...
Checking PATCH 52/71: tests/libqos: support multiqueue for virtio-net...
Checking PATCH 53/71: vhost-user-test: always use 256 MiB of guest memory...
Checking PATCH 54/71: qos-test: vhost-user test node...
ERROR: line over 90 characters
#106: FILE: tests/vhost-user-test.c:173:
+static void append_mem_opts(TestServer *server, GString *cmd_line, int size, enum test_memfd memfd)

WARNING: line over 80 characters
#494: FILE: tests/vhost-user-test.c:872:
+static void test_vhost_user_started(void *obj, void *arg, QGuestAllocator *alloc)

total: 1 errors, 1 warnings, 594 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 55/71: tests/libqos: virtio-scsi driver and interface nodes...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

total: 0 errors, 1 warnings, 163 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 56/71: qos-test: virtio-scsi test node...
Checking PATCH 57/71: tests/libqos: remove pre-qgraph QVirtioPCIDevice API...
WARNING: line over 80 characters
#145: FILE: tests/libqos/virtio-pci.c:364:
+static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_dev)

total: 0 errors, 1 warnings, 152 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 58/71: tests: move virtio entirely to qos-test...
Checking PATCH 59/71: qos-test: ac97 test node...
Checking PATCH 60/71: qos-test: tpci200 test node...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#43: 
new file mode 100644

total: 0 errors, 1 warnings, 86 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 61/71: qos-test: ipoctal232 test node...
Checking PATCH 62/71: qos-test: ne2k_pci test node...
Checking PATCH 63/71: qos-test: nvme test node...
WARNING: line over 80 characters
#150: FILE: tests/nvme-test.c:81:
+    qos_add_test("oob-cmb-access", "nvme", nvmetest_oob_cmb_test, &(QOSGraphTestOptions) {

total: 0 errors, 1 warnings, 129 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 64/71: qos-test: pcnet test node...
Checking PATCH 65/71: qos-test: spapr-phb test node...
Checking PATCH 66/71: qos-test: usb-hcd-ohci test node...
Checking PATCH 67/71: qos-test: vmxnet3 test node...
Checking PATCH 68/71: qos-test: es1370 test node...
Checking PATCH 69/71: qos-test: eepro100 test node...
Checking PATCH 70/71: qos-test: e1000 test node...
Checking PATCH 71/71: qos-test: megasas test node...
WARNING: line over 80 characters
#107: FILE: tests/megasas-test.c:47:
+static void megasas_pd_get_info_fuzz(void *obj, void *data, QGuestAllocator *alloc)

WARNING: line over 80 characters
#157: FILE: tests/megasas-test.c:87:
+    qos_add_test("dcmd/pd-get-info/fuzz", "megasas", megasas_pd_get_info_fuzz, NULL);

total: 0 errors, 2 warnings, 134 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.
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/1543851204-41186-1-git-send-email-pbonzini@redhat.com/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file Paolo Bonzini
@ 2018-12-03 21:10   ` Eric Blake
  2018-12-04 16:04   ` Thomas Huth
  1 sibling, 0 replies; 103+ messages in thread
From: Eric Blake @ 2018-12-03 21:10 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

On 12/3/18 9:32 AM, Paolo Bonzini wrote:
> There is no reason for CONFIG_VHOST_NET to be specific to a single target;
> it is a host feature that can be add to all targets, as long as they support

s/add/added/

> the virtio-net device.  Currently CONFIG_VHOST_NET depends on CONFIG_KVM,
> but ioeventfd support is present in the core memory API and works with
> other accelerators as well.
> 
> As a first step, move the vhost-net stubs to a separate file.  Later, they
> will become conditional on CONFIG_VIRTIO_NET, which is not available in .c
> files.
> 
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>   hw/net/Makefile.objs    |  4 ++-
>   hw/net/vhost_net-stub.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
>   hw/net/vhost_net.c      | 74 --------------------------------------
>   3 files changed, 98 insertions(+), 75 deletions(-)
>   create mode 100644 hw/net/vhost_net-stub.c
> 

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file Paolo Bonzini
  2018-12-03 21:10   ` Eric Blake
@ 2018-12-04 16:04   ` Thomas Huth
  1 sibling, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-04 16:04 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Michael S . Tsirkin

On 2018-12-03 16:32, Paolo Bonzini wrote:
> There is no reason for CONFIG_VHOST_NET to be specific to a single target;
> it is a host feature that can be add to all targets, as long as they support
> the virtio-net device.  Currently CONFIG_VHOST_NET depends on CONFIG_KVM,
> but ioeventfd support is present in the core memory API and works with
> other accelerators as well.
> 
> As a first step, move the vhost-net stubs to a separate file.  Later, they
> will become conditional on CONFIG_VIRTIO_NET, which is not available in .c
> files.
> 
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  hw/net/Makefile.objs    |  4 ++-
>  hw/net/vhost_net-stub.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/net/vhost_net.c      | 74 --------------------------------------
>  3 files changed, 98 insertions(+), 75 deletions(-)
>  create mode 100644 hw/net/vhost_net-stub.c
> 
> diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
> index fa461d4..c2705e6 100644
> --- a/hw/net/Makefile.objs
> +++ b/hw/net/Makefile.objs
> @@ -37,7 +37,9 @@ obj-$(CONFIG_PSERIES) += spapr_llan.o
>  obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
>  
>  obj-$(CONFIG_VIRTIO_NET) += virtio-net.o
> -obj-y += vhost_net.o
> +obj-$(CONFIG_VHOST_NET) += vhost_net.o
> +common-obj-$(call lnot,$(CONFIG_VHOST_NET)) += vhost_net-stub.o
> +common-obj-$(CONFIG_ALL) += vhost_net-stub.o
>  
>  obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
>  			fsl_etsec/rings.o fsl_etsec/miim.o
> diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c
> new file mode 100644
> index 0000000..4de1dfb
> --- /dev/null
> +++ b/hw/net/vhost_net-stub.c
> @@ -0,0 +1,95 @@
> +/*
> + * vhost-net support
> + *
> + * Copyright Red Hat, Inc. 2010
> + *
> + * Authors:
> + *  Michael S. Tsirkin <mst@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + * Contributions after 2012-01-13 are licensed under the terms of the
> + * GNU GPL, version 2 or (at your option) any later version.

According to "git blame", most of the stubs line have been added after
January in 2012, so if Michael agrees for the remaining lines, you could
maybe use a proper GPLv2+ text only for this file instead of the
confusing "dual" licensing?

Anyway,
Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 02/71] vhost-net-user: add stubs for when no virtio-net device is present
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 02/71] vhost-net-user: add stubs for when no virtio-net device is present Paolo Bonzini
@ 2018-12-06 13:29   ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-06 13:29 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> hw/net/vhost_net.c needs functions that are declared in net/vhost-user.c: the
> vhost-user code is always compiled into QEMU, only the constructor
> net_init_vhost_user is unreachable.  Also, net/vhost-user.c needs functions
> declared in hw/virtio/vhost-stub.c even if no virtio device exists.
> 
> Break this dependency.  First, add a minimal version of net/vhost-user.c,
> with no functionality and no dependency on vhost code.  Second, #ifdef out
> the calls back to net/vhost-user.c from hw/net/vhost_net.c.
> 
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  configure             |  2 +-
>  hw/net/vhost_net.c    |  4 ++++
>  net/Makefile.objs     |  4 +++-
>  net/net.c             |  2 +-
>  net/vhost-user-stub.c | 23 +++++++++++++++++++++++
>  5 files changed, 32 insertions(+), 3 deletions(-)
>  create mode 100644 net/vhost-user-stub.c
> 
> diff --git a/configure b/configure
> index 0a3c6a7..cda17ef 100755
> --- a/configure
> +++ b/configure
> @@ -6513,7 +6513,7 @@ if test "$vhost_scsi" = "yes" ; then
>    echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
>  fi
>  if test "$vhost_net" = "yes" -a "$vhost_user" = "yes"; then
> -  echo "CONFIG_VHOST_NET_USED=y" >> $config_host_mak
> +  echo "CONFIG_VHOST_NET_USER=y" >> $config_host_mak

Maybe mention this in the patch description, too?

>  fi
>  if test "$vhost_crypto" = "yes" ; then
>    echo "CONFIG_VHOST_CRYPTO=y" >> $config_host_mak
> diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
> index b901306..fe6202a 100644
> --- a/hw/net/vhost_net.c
> +++ b/hw/net/vhost_net.c
> @@ -193,6 +193,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
>      }
>  
>      /* Set sane init value. Override when guest acks. */
> +#ifdef CONFIG_VHOST_USER
>      if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
>          features = vhost_user_get_acked_features(net->nc);
>          if (~net->dev.features & features) {
> @@ -202,6 +203,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
>              goto fail;
>          }
>      }
> +#endif
>  
>      vhost_net_ack_features(net, features);
>  
> @@ -413,10 +415,12 @@ VHostNetState *get_vhost_net(NetClientState *nc)
>      case NET_CLIENT_DRIVER_TAP:
>          vhost_net = tap_get_vhost_net(nc);
>          break;
> +#ifdef CONFIG_VHOST_NET_USER
>      case NET_CLIENT_DRIVER_VHOST_USER:
>          vhost_net = vhost_user_get_vhost_net(nc);
>          assert(vhost_net);
>          break;
> +#endif
>      default:
>          break;
>      }
> diff --git a/net/Makefile.objs b/net/Makefile.objs
> index b2bf88a..df2b409 100644
> --- a/net/Makefile.objs
> +++ b/net/Makefile.objs
> @@ -3,7 +3,9 @@ common-obj-y += socket.o
>  common-obj-y += dump.o
>  common-obj-y += eth.o
>  common-obj-$(CONFIG_L2TPV3) += l2tpv3.o
> -common-obj-$(CONFIG_POSIX) += vhost-user.o
> +common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-user.o
> +common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o
> +common-obj-$(CONFIG_ALL) += vhost-user-stub.o
>  common-obj-$(CONFIG_SLIRP) += slirp.o
>  common-obj-$(CONFIG_VDE) += vde.o
>  common-obj-$(CONFIG_NETMAP) += netmap.o
> diff --git a/net/net.c b/net/net.c
> index 07c194a..95a74ad 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -955,7 +955,7 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
>          [NET_CLIENT_DRIVER_BRIDGE]    = net_init_bridge,
>  #endif
>          [NET_CLIENT_DRIVER_HUBPORT]   = net_init_hubport,
> -#ifdef CONFIG_VHOST_NET_USED
> +#ifdef CONFIG_VHOST_NET_USER
>          [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user,
>  #endif
>  #ifdef CONFIG_L2TPV3
> diff --git a/net/vhost-user-stub.c b/net/vhost-user-stub.c
> new file mode 100644
> index 0000000..52ab4e1
> --- /dev/null
> +++ b/net/vhost-user-stub.c
> @@ -0,0 +1,23 @@
> +/*
> + * vhost-user-stub.c
> + *
> + * Copyright (c) 2018 Red Hat, Inc.
> + *
> + * 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 "clients.h"
> +#include "net/vhost_net.h"
> +#include "net/vhost-user.h"
> +#include "qemu/error-report.h"
> +#include "qapi/error.h"
> +
> +int net_init_vhost_user(const Netdev *netdev, const char *name,
> +                        NetClientState *peer, Error **errp)
> +{
> +    error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
> +    return -1;
> +}
> 

It's a little bit sad that we need the stub in this case, but since
CONFIG_VIRTIO_NET is not available as a CPP macro, I also don't have any
better ideas.

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 03/71] vhost: restrict Linux dependency to kernel vhost
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 03/71] vhost: restrict Linux dependency to kernel vhost Paolo Bonzini
@ 2018-12-06 13:36   ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-06 13:36 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> vhost-user does not depend on Linux; it can run on any POSIX system.  Restrict
> vhost-kernel to Linux in hw/virtio/vhost-backend.c, everything else can be
> compiled on all POSIX systems.
> 
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  backends/Makefile.objs     |  5 ++---
>  default-configs/virtio.mak |  4 ++--
>  hw/net/vhost_net.c         |  2 +-
>  hw/virtio/Makefile.objs    |  5 +++--
>  hw/virtio/vhost-backend.c  | 11 +++++++++--
>  5 files changed, 17 insertions(+), 10 deletions(-)
[...]
> diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
> index fe6202a..2a300ee 100644
> --- a/hw/net/vhost_net.c
> +++ b/hw/net/vhost_net.c
> @@ -193,7 +193,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
>      }
>  
>      /* Set sane init value. Override when guest acks. */
> -#ifdef CONFIG_VHOST_USER
> +#ifdef CONFIG_VHOST_NET_USER

Merge this hunk with the previous patch?

Apart from that nit:

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 04/71] vhost-net: compile it on all targets that have virtio-net.
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 04/71] vhost-net: compile it on all targets that have virtio-net Paolo Bonzini
@ 2018-12-06 13:45   ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-06 13:45 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> This shows a preexisting bug: if a KVM target did not have virtio-net enabled,
> it would fail with undefined symbols when vhost was enabled.  This must now
> be fixed, lest targets that have no virtio-net fail to compile.
> 
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  configure              | 11 ++++-------
>  hw/net/Makefile.objs   |  4 ++--
>  include/exec/poison.h  |  1 -
>  tests/Makefile.include |  5 +----
>  4 files changed, 7 insertions(+), 14 deletions(-)

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 05/71] vhost-net: revamp configure logic
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 05/71] vhost-net: revamp configure logic Paolo Bonzini
@ 2018-12-06 16:12   ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-06 16:12 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Emanuele Giuseppe Esposito, Laurent Vivier, Michael S. Tsirkin

On 2018-12-03 16:32, Paolo Bonzini wrote:
> Detect all invalid configurations (e.g. mingw32 with vhost-user,
> non-Linux with vhost-kernel).  As a collateral benefit, all vhost-kernel
> backends can be now disabled if one wants to reduce the attack surface.
> 
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  configure                 | 89 +++++++++++++++++++++++++++++++----------------
>  hw/virtio/Makefile.objs   |  4 +--
>  hw/virtio/vhost-backend.c |  4 +--
>  3 files changed, 63 insertions(+), 34 deletions(-)
> 
> diff --git a/configure b/configure
> index b3b4464..d2c0fd3 100755
> --- a/configure
> +++ b/configure
> @@ -366,10 +366,10 @@ libattr=""
>  xfs=""
>  tcg="yes"
>  membarrier=""
> -vhost_net="no"
> -vhost_crypto="no"
> -vhost_scsi="no"
> -vhost_vsock="no"
> +vhost_net=""
> +vhost_crypto=""
> +vhost_scsi=""
> +vhost_vsock=""
>  vhost_user=""
>  kvm="no"
>  hax="no"
> @@ -774,6 +774,7 @@ case $targetos in
>  MINGW32*)
>    mingw32="yes"
>    hax="yes"
> +  vhost_user="no"
>    audio_possible_drivers="dsound sdl"
>    if check_include dsound.h; then
>      audio_drv_list="dsound"
> @@ -874,10 +875,6 @@ Linux)
>    linux="yes"
>    linux_user="yes"
>    kvm="yes"
> -  vhost_net="yes"
> -  vhost_crypto="yes"
> -  vhost_scsi="yes"
> -  vhost_vsock="yes"
>    QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$PWD/linux-headers $QEMU_INCLUDES"
>    supported_os="yes"
>    libudev="yes"
> @@ -1258,11 +1255,7 @@ for opt do
>    ;;
>    --disable-vhost-crypto) vhost_crypto="no"
>    ;;
> -  --enable-vhost-crypto)
> -      vhost_crypto="yes"
> -      if test "$mingw32" = "yes"; then
> -          error_exit "vhost-crypto isn't available on win32"
> -      fi
> +  --enable-vhost-crypto) vhost_crypto="yes"
>    ;;
>    --disable-vhost-scsi) vhost_scsi="no"
>    ;;
> @@ -1463,11 +1456,11 @@ for opt do
>    ;;
>    --disable-vhost-user) vhost_user="no"
>    ;;
> -  --enable-vhost-user)
> -      vhost_user="yes"
> -      if test "$mingw32" = "yes"; then
> -          error_exit "vhost-user isn't available on win32"
> -      fi
> +  --enable-vhost-user) vhost_user="yes"
> +  ;;
> +  --disable-vhost-kernel) vhost_kernel="no"
> +  ;;
> +  --enable-vhost-kernel) vhost_kernel="yes"
>    ;;
>    --disable-capstone) capstone="no"
>    ;;
> @@ -1499,14 +1492,6 @@ for opt do
>    esac
>  done
>  
> -if test "$vhost_user" = ""; then
> -    if test "$mingw32" = "yes"; then
> -        vhost_user="no"
> -    else
> -        vhost_user="yes"
> -    fi
> -fi
> -
>  case "$cpu" in
>      ppc)
>             CPU_CFLAGS="-m32"
> @@ -1731,8 +1716,12 @@ disabled with --disable-FEATURE, default is enabled if available:
>    linux-aio       Linux AIO support
>    cap-ng          libcap-ng support
>    attr            attr and xattr support
> -  vhost-net       vhost-net acceleration support
> -  vhost-crypto    vhost-crypto acceleration support
> +  vhost-net       vhost-net kernel acceleration support
> +  vhost-vsock     virtio sockets device support
> +  vhost-scsi      vhost-scsi kernel target support
> +  vhost-crypto    vhost-user-crypto backend support
> +  vhost-kernel    vhost kernel backend support
> +  vhost-user      vhost-user backend support
>    spice           spice
>    rbd             rados block device (rbd)
>    libiscsi        iscsi support
> @@ -1756,7 +1745,6 @@ disabled with --disable-FEATURE, default is enabled if available:
>    jemalloc        jemalloc support
>    avx2            AVX2 optimization support
>    replication     replication support
> -  vhost-vsock     virtio sockets device support
>    opengl          opengl support
>    virglrenderer   virgl rendering support
>    xfsctl          xfsctl support
> @@ -1773,7 +1761,6 @@ disabled with --disable-FEATURE, default is enabled if available:
>    parallels       parallels image format support
>    sheepdog        sheepdog block driver support
>    crypto-afalg    Linux AF_ALG crypto backend driver
> -  vhost-user      vhost-user support
>    capstone        capstone disassembler support
>    debug-mutex     mutex debugging support
>    libpmem         libpmem support
> @@ -2150,6 +2137,45 @@ else
>    l2tpv3=no
>  fi
>  
> +#########################################
> +# vhost interdependencies and host support
> +
> +# vhost backends
> +test "$vhost_user" = "" && vhost_user=yes
> +if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then
> +  error_exit "vhost-user isn't available on win32"
> +fi
> +test "$vhost_kernel" = "" && vhost_kernel=$linux
> +if test "$vhost_kernel" = "yes" && test "$linux" != "yes"; then
> +  error_exit "vhost-kernel is only available on Linux"
> +fi
> +
> +# vhost-kernel devices
> +test "$vhost_scsi" = "" && vhost_scsi=$vhost_kernel
> +if test "$vhost_scsi" = "yes" && test "$vhost_kernel" != "yes"; then
> +  error_exit "--enable-vhost-scsi requires --enable-vhost-kernel"
> +fi
> +test "$vhost_vsock" = "" && vhost_vsock=$vhost_kernel
> +if test "$vhost_vsock" = "yes" && test "$vhost_kernel" != "yes"; then
> +  error_exit "--enable-vhost-vsock requires --enable-vhost-kernel"
> +fi
> +
> +# vhost-user backends
> +test "$vhost_net_user" = "" && vhost_net_user=$vhost_user
> +if test "$vhost_net_user" = "yes" && test "$vhost_user" = "no"; then
> +  error_exit "--enable-vhost-net-user requires --enable-vhost-user"
> +fi
> +test "$vhost_crypto" = "" && vhost_crypto=$vhost_user
> +if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then
> +  error_exit "--enable-vhost-crypto requires --enable-vhost-user"
> +fi
> +
> +# OR the vhost-kernel and vhost-user values for simplicity
> +if test "$vhost_net" = ""; then
> +  test "$vhost_net_user" = "yes" && vhost_net=yes
> +  test "$vhost_kernel" = "yes" && vhost_net=yes
> +fi
> +
>  ##########################################
>  # MinGW / Mingw-w64 localtime_r/gmtime_r check
>  
> @@ -6524,6 +6550,9 @@ fi
>  if test "$vhost_vsock" = "yes" ; then
>    echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak
>  fi
> +if test "$vhost_kernel" = "yes" ; then
> +  echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak
> +fi
>  if test "$vhost_user" = "yes" ; then
>    echo "CONFIG_VHOST_USER=y" >> $config_host_mak
>  fi
> diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
> index e8eff80..87402d1 100644
> --- a/hw/virtio/Makefile.objs
> +++ b/hw/virtio/Makefile.objs
> @@ -11,8 +11,8 @@ obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-p
>  
>  obj-$(CONFIG_VHOST_USER) += vhost-user.o
>  obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
> -obj-$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) += vhost.o vhost-backend.o
> -common-obj-$(call lnot,$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))) += vhost-stub.o
> +obj-$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_VHOST_KERNEL)) += vhost.o vhost-backend.o
> +common-obj-$(call lnot,$(call lor,$(CONFIG_VHOST_USER),$(CONFIG_VHOST_KERNEL))) += vhost-stub.o
>  endif
>  
>  common-obj-$(CONFIG_ALL) += vhost-stub.o
> diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
> index b5d2e30..46d388b 100644
> --- a/hw/virtio/vhost-backend.c
> +++ b/hw/virtio/vhost-backend.c
> @@ -13,7 +13,7 @@
>  #include "hw/virtio/vhost-backend.h"
>  #include "qemu/error-report.h"
>  
> -#ifdef CONFIG_LINUX
> +#ifdef CONFIG_VHOST_KERNEL
>  #include <linux/vhost.h>
>  #include <sys/ioctl.h>
>  
> @@ -274,7 +274,7 @@ int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
>      int r = 0;
>  
>      switch (backend_type) {
> -#ifdef CONFIG_LINUX
> +#ifdef CONFIG_VHOST_KERNEL
>      case VHOST_BACKEND_TYPE_KERNEL:
>          dev->vhost_ops = &kernel_ops;
>          break;
> 

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN Paolo Bonzini
@ 2018-12-06 16:15   ` Thomas Huth
  2018-12-06 20:06     ` Paolo Bonzini
  0 siblings, 1 reply; 103+ messages in thread
From: Thomas Huth @ 2018-12-06 16:15 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> This will be useful to run the qtest for ppc64 targets on (for example)
> x86_64 hosts.
> 
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/vhost-user-test.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
> index 6a805e6..82fc6c5 100644
> --- a/tests/vhost-user-test.c
> +++ b/tests/vhost-user-test.c
> @@ -51,6 +51,7 @@
>  #define VHOST_USER_F_PROTOCOL_FEATURES 30
>  #define VHOST_USER_PROTOCOL_F_MQ 0
>  #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
> +#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
>  
>  #define VHOST_LOG_PAGE 0x1000
>  
> @@ -251,7 +252,7 @@ static void wait_for_fds(TestServer *s)
>  
>  static void read_guest_mem_server(TestServer *s)
>  {
> -    uint32_t *guest_mem;
> +    uint8_t *guest_mem;
>      int i, j;
>      size_t size;
>  
> @@ -278,8 +279,8 @@ static void read_guest_mem_server(TestServer *s)
>          g_assert(guest_mem != MAP_FAILED);
>          guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
>  
> -        for (j = 0; j < 256; j++) {
> -            uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
> +        for (j = 0; j < 1024; j++) {
> +            uint32_t a = readb(s->memory.regions[i].guest_phys_addr + j);

Can't you simply use memread() intead?

 Thomas

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

* Re: [Qemu-devel] [PATCH 10/71] vhost-user-test: skip if there is no memory at address 0
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 10/71] vhost-user-test: skip if there is no memory at address 0 Paolo Bonzini
@ 2018-12-06 16:26   ` Thomas Huth
  2018-12-06 20:06     ` Paolo Bonzini
  0 siblings, 1 reply; 103+ messages in thread
From: Thomas Huth @ 2018-12-06 16:26 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> The virt machine cannot run the vhost-user qtests because they hardcode
> the presence of memory at address 0.  Report the tests as a skip so that
> they can be converted to use qgraph.
> 
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/vhost-user-test.c | 58 ++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 45 insertions(+), 13 deletions(-)
> 
> diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
> index 82fc6c5..59e1aec 100644
> --- a/tests/vhost-user-test.c
> +++ b/tests/vhost-user-test.c
> @@ -228,9 +228,11 @@ static void uninit_virtio_dev(TestServer *s)
>      qvirtio_pci_device_free(s->dev);
>  }
>  
> -static void wait_for_fds(TestServer *s)
> +static bool wait_for_fds(TestServer *s)
>  {
>      gint64 end_time;
> +    bool got_region;
> +    int i;
>  
>      g_mutex_lock(&s->data_mutex);
>  
> @@ -248,6 +250,19 @@ static void wait_for_fds(TestServer *s)
>      g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
>  
>      g_mutex_unlock(&s->data_mutex);
> +
> +    got_region = false;
> +    for (i = 0; i < s->memory.nregions; ++i) {
> +        VhostUserMemoryRegion *reg = &s->memory.regions[i];
> +        if (reg->guest_phys_addr == 0) {
> +            got_region = true;
> +            break;
> +        }
> +    }
> +    if (!got_region) {
> +        g_test_skip("No memory at address 0x0");
> +    }

g_test_skip does not work with older versions of the gtester ... so this
patch series depends on your gtester replacement patches first?

 Thomas

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

* Re: [Qemu-devel] [PATCH 11/71] vhost-user-test: reduce usage of global_qtest
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 11/71] vhost-user-test: reduce usage of global_qtest Paolo Bonzini
@ 2018-12-06 16:36   ` Thomas Huth
  2018-12-06 20:08     ` Paolo Bonzini
  0 siblings, 1 reply; 103+ messages in thread
From: Thomas Huth @ 2018-12-06 16:36 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> Whenever the code can run on multiple QTestStates, use them explicitly instead of
> global_qtest.
> 
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/vhost-user-test.c | 38 +++++++++++++++++---------------------
>  1 file changed, 17 insertions(+), 21 deletions(-)
> 
> diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
> index 59e1aec..c3a8af3 100644
> --- a/tests/vhost-user-test.c
> +++ b/tests/vhost-user-test.c
> @@ -187,12 +187,12 @@ static char *get_qemu_cmd(TestServer *s,
>      }
>  }
>  
> -static void init_virtio_dev(TestServer *s, uint32_t features_mask)
> +static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_mask)
>  {
>      uint32_t features;
>      int i;
>  
> -    s->bus = qpci_init_pc(global_qtest, NULL);
> +    s->bus = qpci_init_pc(qts, NULL);
>      g_assert_nonnull(s->bus);
>  
>      s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
> @@ -203,7 +203,7 @@ static void init_virtio_dev(TestServer *s, uint32_t features_mask)
>      qvirtio_set_acknowledge(&s->dev->vdev);
>      qvirtio_set_driver(&s->dev->vdev);
>  
> -    s->alloc = pc_alloc_init(global_qtest);
> +    s->alloc = pc_alloc_init(qts);
>  
>      for (i = 0; i < s->queues * 2; i++) {
>          s->vq[i] = qvirtqueue_setup(&s->dev->vdev, s->alloc, i);
> @@ -265,7 +265,7 @@ static bool wait_for_fds(TestServer *s)
>      return got_region;
>  }
>  
> -static void read_guest_mem_server(TestServer *s)
> +static void read_guest_mem_server(QTestState *qts, TestServer *s)
>  {
>      uint8_t *guest_mem;
>      int i, j;
> @@ -293,7 +293,7 @@ static void read_guest_mem_server(TestServer *s)
>          guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
>  
>          for (j = 0; j < 1024; j++) {
> -            uint32_t a = readb(s->memory.regions[i].guest_phys_addr + j);
> +            uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);
>              uint32_t b = guest_mem[j];
>  
>              g_assert_cmpint(a, ==, b);
> @@ -670,13 +670,13 @@ static void test_read_guest_mem(const void *arg)
>      s = qtest_start(qemu_cmd);
>      g_free(qemu_cmd);
>  
> -    init_virtio_dev(server, 1u << VIRTIO_NET_F_MAC);
> +    init_virtio_dev(global_qtest, server, 1u << VIRTIO_NET_F_MAC);
>  
>      if (!wait_for_fds(server)) {
>          goto exit;
>      }
>  
> -    read_guest_mem_server(server);
> +    read_guest_mem_server(global_qtest, server);
>  
>  exit:
>      uninit_virtio_dev(server);
> @@ -690,7 +690,7 @@ static void test_migrate(void)
>      TestServer *s = test_server_new("src");
>      TestServer *dest = test_server_new("dest");
>      char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
> -    QTestState *global = global_qtest, *from, *to;
> +    QTestState *from, *to;
>      GSource *source;
>      gchar *cmd, *tmp;
>      QDict *rsp;
> @@ -704,7 +704,7 @@ static void test_migrate(void)
>      from = qtest_start(cmd);
>      g_free(cmd);
>  
> -    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
> +    init_virtio_dev(from, s, 1u << VIRTIO_NET_F_MAC);
>      if (!wait_for_fds(s)) {
>          goto exit;
>      }
> @@ -717,7 +717,7 @@ static void test_migrate(void)
>      g_free(tmp);
>      to = qtest_init(cmd);
>      g_free(cmd);
> -    init_virtio_dev(dest, 1u << VIRTIO_NET_F_MAC);
> +    init_virtio_dev(to, dest, 1u << VIRTIO_NET_F_MAC);
>  
>      source = g_source_new(&test_migrate_source_funcs,
>                            sizeof(TestMigrateSource));
> @@ -753,12 +753,10 @@ static void test_migrate(void)
>      qobject_unref(rsp);
>  
>      qmp_eventwait("STOP");
> +    qtest_qmp_eventwait(to, "RESUME");
>  
> -    global_qtest = to;
> -    qmp_eventwait("RESUME");
> -
> -    g_assert(wait_for_fds(s));
> -    read_guest_mem_server(dest);
> +    g_assert(wait_for_fds(dest));
> +    read_guest_mem_server(to, dest);
>  
>      uninit_virtio_dev(dest);
>      qtest_quit(to);
> @@ -773,8 +771,6 @@ exit:
>      qtest_quit(from);
>      test_server_free(s);
>      g_free(uri);
> -
> -    global_qtest = global;
>  }
>  
>  static void wait_for_rings_started(TestServer *s, size_t count)
> @@ -831,7 +827,7 @@ static void test_reconnect_subprocess(void)
>      qtest_start(cmd);
>      g_free(cmd);
>  
> -    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
> +    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
>      if (!wait_for_fds(s)) {
>          goto exit;
>      }
> @@ -873,7 +869,7 @@ static void test_connect_fail_subprocess(void)
>      qtest_start(cmd);
>      g_free(cmd);
>  
> -    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
> +    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
>      if (!wait_for_fds(s)) {
>          goto exit;
>      }
> @@ -906,7 +902,7 @@ static void test_flags_mismatch_subprocess(void)
>      qtest_start(cmd);
>      g_free(cmd);
>  
> -    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
> +    init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
>      if (!wait_for_fds(s)) {
>          goto exit;
>      }
> @@ -957,7 +953,7 @@ static void test_multiqueue(void)
>      qtest_start(cmd);
>      g_free(cmd);
>  
> -    init_virtio_dev(s, features_mask);
> +    init_virtio_dev(global_qtest, s, features_mask);
>  
>      wait_for_rings_started(s, s->queues * 2);

Looks like it should work. Maybe you could use this patch here first:

https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02199.html

... then you could likely get rid of global_qtest here completely, I think.

Anyway:

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 10/71] vhost-user-test: skip if there is no memory at address 0
  2018-12-06 16:26   ` Thomas Huth
@ 2018-12-06 20:06     ` Paolo Bonzini
  0 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-06 20:06 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 06/12/18 17:26, Thomas Huth wrote:
> g_test_skip does not work with older versions of the gtester ... so this
> patch series depends on your gtester replacement patches first?

Yes, that's how I got into that other mess. :)

Paolo

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

* Re: [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
  2018-12-06 16:15   ` Thomas Huth
@ 2018-12-06 20:06     ` Paolo Bonzini
  2018-12-07  5:50       ` Thomas Huth
  0 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-06 20:06 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 06/12/18 17:15, Thomas Huth wrote:
>>  
>> -        for (j = 0; j < 256; j++) {
>> -            uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
>> +        for (j = 0; j < 1024; j++) {
>> +            uint32_t a = readb(s->memory.regions[i].guest_phys_addr + j);
> Can't you simply use memread() intead?

Yes, I guess I could do memread + memcmp, but I wanted to change the
code as little as possible here.

Paolo

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

* Re: [Qemu-devel] [PATCH 11/71] vhost-user-test: reduce usage of global_qtest
  2018-12-06 16:36   ` Thomas Huth
@ 2018-12-06 20:08     ` Paolo Bonzini
  0 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-06 20:08 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 06/12/18 17:36, Thomas Huth wrote:
> Looks like it should work. Maybe you could use this patch here first:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2018-11/msg02199.html
> 
> ... then you could likely get rid of global_qtest here completely, I think.

Note that most of the global_qtest references disappear with the qgraph
conversion.  Each qgraph object already knows which QTestState it refers
to.  However there are a couple that remain, I'll check if there's
anything to improve in the QOSGraphObject APIs to remove them.

Paolo

> Anyway:
> 
> Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
  2018-12-06 20:06     ` Paolo Bonzini
@ 2018-12-07  5:50       ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-07  5:50 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-06 21:06, Paolo Bonzini wrote:
> On 06/12/18 17:15, Thomas Huth wrote:
>>>  
>>> -        for (j = 0; j < 256; j++) {
>>> -            uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
>>> +        for (j = 0; j < 1024; j++) {
>>> +            uint32_t a = readb(s->memory.regions[i].guest_phys_addr + j);
>> Can't you simply use memread() intead?
> 
> Yes, I guess I could do memread + memcmp, but I wanted to change the
> code as little as possible here.

OK, fair.

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 15/71] tests/libqos: introduce virtio_start_device
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 15/71] tests/libqos: introduce virtio_start_device Paolo Bonzini
@ 2018-12-07  9:16   ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-07  9:16 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> This function is intended to group all the qvirtio_* functions that
> start the qvirtio devices.
> Applied in all tests using this combination of functions.
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/libqos/virtio.c    |  7 +++++++
>  tests/libqos/virtio.h    |  1 +
>  tests/vhost-user-test.c  |  4 +---
>  tests/virtio-9p-test.c   |  4 +---
>  tests/virtio-blk-test.c  | 10 +++-------
>  tests/virtio-net-test.c  |  4 +---
>  tests/virtio-scsi-test.c |  4 +---
>  7 files changed, 15 insertions(+), 19 deletions(-)
[...]
> diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
> index 04c6087..f97c158 100644
> --- a/tests/virtio-blk-test.c
> +++ b/tests/virtio-blk-test.c
> @@ -116,10 +116,7 @@ static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
>      g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
>  
>      qvirtio_pci_device_enable(dev);
> -    qvirtio_reset(&dev->vdev);
> -    qvirtio_set_acknowledge(&dev->vdev);
> -    qvirtio_set_driver(&dev->vdev);
> -
> +    qvirtio_start_device(&dev->vdev);
>      return dev;
>  }
>  
> @@ -333,6 +330,7 @@ static void pci_indirect(void)
>      qvirtio_set_features(&dev->vdev, features);
>  
>      vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
> +
>      qvirtio_set_driver_ok(&dev->vdev);

Unnecessary white-space change. Apart from that nit:

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 16/71] tests/libqos: rename qpci_init_pc and qpci_init_spapr functions
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 16/71] tests/libqos: rename qpci_init_pc and qpci_init_spapr functions Paolo Bonzini
@ 2018-12-07  9:23   ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-07  9:23 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> Rename qpci_init_pc in qpci_pc_new and qpci_init_spapr in qpci_spapr_new,
> since theese function actually allocate a new pci struct and initialize it.

Matter of taste, I guess ... I'd also be fine if we keep "init" instead
of "new"... it's quite a bit of code churn ...

> diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
> index 491eeac..84cc300 100644
> --- a/tests/libqos/pci-pc.h
> +++ b/tests/libqos/pci-pc.h
> @@ -16,7 +16,14 @@
>  #include "libqos/pci.h"
>  #include "libqos/malloc.h"
>  
> -QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc);
> +/* qpci_new_pc():
> +* this function creates a new QPCIBusPC object,

... but please add at least a white space at the beginning of the above
line.

> + * and properly initialize its fields.
> + *
> + * returns the QPCIBus *bus field of a newly
> + * allocated QPCIBusPC.
> + */
> +QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc);
>  void     qpci_free_pc(QPCIBus *bus);

I'd prefer to drop this patch, but if you want to keep it:

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test Paolo Bonzini
@ 2018-12-07  9:24   ` Thomas Huth
  2018-12-12 14:12   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-07  9:24 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> This test was merged into drive_del-test in 2014.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/Makefile.include | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 3e3b16b..2718548 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -726,7 +726,6 @@ tests/qom-test$(EXESUF): tests/qom-test.o
>  tests/test-hmp$(EXESUF): tests/test-hmp.o
>  tests/machine-none-test$(EXESUF): tests/machine-none-test.o
>  tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y)
> -tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
>  tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
>  tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
>  tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [PATCH 18/71] tests/libqos: embed allocators instead of malloc-ing them
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 18/71] tests/libqos: embed allocators instead of malloc-ing them Paolo Bonzini
@ 2018-12-07 12:32   ` Thomas Huth
  2018-12-07 13:57     ` Paolo Bonzini
  0 siblings, 1 reply; 103+ messages in thread
From: Thomas Huth @ 2018-12-07 12:32 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> qgraph will embed these objects instead of allocating them in a separate
> object.  Expose a new API "generic_alloc_init" and "generic_alloc_destroy"
> for that, and rename the existing API with s/init/new/ and s/uninit/free/.

Could you please add a sentence *why* you are doing this? ... without
that information, this just looks like a lot of unnecessary code churn...

 Thomas

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

* Re: [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework Paolo Bonzini
@ 2018-12-07 12:42   ` Thomas Huth
  2018-12-07 13:57     ` Paolo Bonzini
  2018-12-07 15:38   ` Thomas Huth
  1 sibling, 1 reply; 103+ messages in thread
From: Thomas Huth @ 2018-12-07 12:42 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> Add qgraph API that allows to add/remove nodes and edges from the graph,
> implementation of Depth First Search to discover the paths and basic unit
> test to check correctness of the API.
> Included also a main executable that takes care of starting the framework,
> create the nodes, set the available drivers/machines, discover the path and
> run tests.
> 
> graph.h provides the public API to manage the graph nodes/edges
> graph_extra.h provides a more private API used successively by the gtest integration part
> qos-test.c provides the main executable
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> [Paolo's changes compared to the Google Summer of Code submission:
>  * added subprocess to test options
>  * refactored object creation to support live migration tests
>  * removed driver .before callback (unused)
>  * removed test .after callbacks (replaced by GTest destruction queue)]
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
[...]
> diff --git a/tests/libqos/qgraph.c b/tests/libqos/qgraph.c
> new file mode 100644
> index 0000000..03783f5
> --- /dev/null
> +++ b/tests/libqos/qgraph.c
> @@ -0,0 +1,760 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.

The license statement is inaccurate. There is no "GNU *Lesser* General
Public License version *2*" ... so I'm assuming you wanted to use one of
these two options:

- GNU Library General Public License, version 2.0
- GNU Lesser General Public License, version 2.1

I assume you wanted to use the latter, so please replace the "2" with
"2.1" in all license statements here.

 Thomas

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

* Re: [Qemu-devel] [PATCH 18/71] tests/libqos: embed allocators instead of malloc-ing them
  2018-12-07 12:32   ` Thomas Huth
@ 2018-12-07 13:57     ` Paolo Bonzini
  0 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-07 13:57 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 07/12/18 13:32, Thomas Huth wrote:
> On 2018-12-03 16:32, Paolo Bonzini wrote:
>> qgraph will embed these objects instead of allocating them in a separate
>> object.  Expose a new API "generic_alloc_init" and "generic_alloc_destroy"
>> for that, and rename the existing API with s/init/new/ and s/uninit/free/.
> 
> Could you please add a sentence *why* you are doing this? ... without
> that information, this just looks like a lot of unnecessary code churn...

The explanation is simply that if you allocate them separately you have
to define a destructor function to free it---more boilerplate and more
stuff that you can get wrong.  Therefore qgraph tries to use embedded
structs when something is always there (a "contains" edge).

The same is true for 16/71, you want to use heap-allocated PCI buses for
non-qgraph tests, but for a qgraph machine it would be very much
preferrable to embed it in the PCI host bridge QOSGraphObject.

Paolo

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

* Re: [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework
  2018-12-07 12:42   ` Thomas Huth
@ 2018-12-07 13:57     ` Paolo Bonzini
  0 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-07 13:57 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 07/12/18 13:42, Thomas Huth wrote:
> The license statement is inaccurate. There is no "GNU *Lesser* General
> Public License version *2*" ... so I'm assuming you wanted to use one of
> these two options:
> 
> - GNU Library General Public License, version 2.0
> - GNU Lesser General Public License, version 2.1
> 
> I assume you wanted to use the latter, so please replace the "2" with
> "2.1" in all license statements here.

Yes, I will change it to Lesser GPL 2.1.

Paolo

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

* Re: [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework Paolo Bonzini
  2018-12-07 12:42   ` Thomas Huth
@ 2018-12-07 15:38   ` Thomas Huth
  2018-12-12 11:09     ` Paolo Bonzini
  1 sibling, 1 reply; 103+ messages in thread
From: Thomas Huth @ 2018-12-07 15:38 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-03 16:32, Paolo Bonzini wrote:
> From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> Add qgraph API that allows to add/remove nodes and edges from the graph,
> implementation of Depth First Search to discover the paths and basic unit
> test to check correctness of the API.
> Included also a main executable that takes care of starting the framework,
> create the nodes, set the available drivers/machines, discover the path and
> run tests.
> 
> graph.h provides the public API to manage the graph nodes/edges
> graph_extra.h provides a more private API used successively by the gtest integration part
> qos-test.c provides the main executable
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> [Paolo's changes compared to the Google Summer of Code submission:
>  * added subprocess to test options
>  * refactored object creation to support live migration tests
>  * removed driver .before callback (unused)
>  * removed test .after callbacks (replaced by GTest destruction queue)]
[...]
> diff --git a/tests/libqos/qgraph.c b/tests/libqos/qgraph.c
> new file mode 100644
> index 0000000..03783f5
> --- /dev/null
> +++ b/tests/libqos/qgraph.c
> @@ -0,0 +1,760 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "qemu/queue.h"
> +#include "libqos/qgraph_internal.h"
> +#include "libqos/qgraph.h"
> +
> +#define QGRAPH_PRINT_DEBUG 0
> +#define QOS_ROOT ""
> +typedef struct QOSStackElement QOSStackElement;
> +
> +/* Graph Edge.*/
> +struct QOSGraphEdge {
> +    QOSEdgeType type;
> +    char *dest;
> +    void *arg;                /* just for QEDGE_CONTAINS
> +                               * and QEDGE_CONSUMED_BY */
> +    char *extra_device_opts;  /* added to -device option, "," is
> +                               * automatically added
> +                               */
> +    char *before_cmd_line;    /* added before node cmd_line */
> +    char *after_cmd_line;     /* added after -device options */
> +    char *edge_name;          /* used by QEDGE_CONTAINS */
> +    QSLIST_ENTRY(QOSGraphEdge) edge_list;
> +};
> +
> +/* Linked list grouping all edges with the same source node */
> +QSLIST_HEAD(QOSGraphEdgeList, QOSGraphEdge);
> +
> +
> +/**
> + * Stack used to keep track of the discovered path when using
> + * the DFS algorithm
> + */
> +struct QOSStackElement {
> +    QOSGraphNode *node;
> +    QOSStackElement *parent;
> +    QOSGraphEdge *parent_edge;
> +    int length;
> +};
> +
> +/* Each enty in these hash table will consist of <string, node/edge> pair. */
> +static GHashTable *edge_table;
> +static GHashTable *node_table;
> +
> +/* stack used by the DFS algorithm to store the path from machine to test */
> +static QOSStackElement qos_node_stack[QOS_PATH_MAX_ELEMENT_SIZE];
> +static int qos_node_tos;
> +
> +/**
> + * add_edge(): creates an edge of type @type
> + * from @source to @dest node, and inserts it in the
> + * edges hash table
> + *
> + * Nodes @source and @dest do not necessarily need to exist.
> + * Possibility to add also options (see #QOSGraphEdgeOptions)
> + * edge->edge_name is used as identifier for get_device relationships,
> + * so by default is equal to @dest.
> + */
> +static void add_edge(const char *source, const char *dest,
> +                     QOSEdgeType type, QOSGraphEdgeOptions *opts)
> +{
> +    char *key;
> +    QOSGraphEdgeList *list = g_hash_table_lookup(edge_table, source);
> +
> +    if (!list) {
> +        list = g_new0(QOSGraphEdgeList, 1);
> +        key = g_strdup(source);
> +        g_hash_table_insert(edge_table, key, list);
> +    }
> +
> +    if (!opts) {
> +        opts = &(QOSGraphEdgeOptions) { };
> +    }
> +
> +    QOSGraphEdge *edge = g_new0(QOSGraphEdge, 1);
> +    edge->type = type;
> +    edge->dest = g_strdup(dest);
> +    edge->edge_name = g_strdup(opts->edge_name ? : dest);
> +    edge->arg = g_memdup(opts->arg, opts->size_arg);
> +
> +    edge->before_cmd_line =
> +        opts->before_cmd_line ? g_strconcat(" ", opts->before_cmd_line, NULL) : NULL;
> +    edge->extra_device_opts =
> +        opts->extra_device_opts ? g_strconcat(",", opts->extra_device_opts, NULL) : NULL;
> +    edge->after_cmd_line =
> +        opts->after_cmd_line ? g_strconcat(" ", opts->after_cmd_line, NULL) : NULL;
> +
> +    QSLIST_INSERT_HEAD(list, edge, edge_list);
> +}
> +
> +/* destroy_edges(): frees all edges inside a given @list */
> +static void destroy_edges(void *list)
> +{
> +    QOSGraphEdge *temp;
> +    QOSGraphEdgeList *elist = list;
> +
> +    while (!QSLIST_EMPTY(elist)) {
> +        temp = QSLIST_FIRST(elist);
> +        QSLIST_REMOVE_HEAD(elist, edge_list);
> +        g_free(temp->dest);
> +        g_free(temp->before_cmd_line);
> +        g_free(temp->after_cmd_line);
> +        g_free(temp->extra_device_opts);
> +        g_free(temp->edge_name);
> +        g_free(temp->arg);
> +        g_free(temp);
> +    }
> +    g_free(elist);
> +}
> +
> +/**
> + * create_node(): creates a node @name of type @type
> + * and inserts it to the nodes hash table.
> + * By default, node is not available.
> + */
> +static QOSGraphNode *create_node(const char *name, QOSNodeType type)
> +{
> +    if (g_hash_table_lookup(node_table, name)) {
> +        g_printerr("Node %s already created\n", name);
> +        abort();
> +    }
> +
> +    QOSGraphNode *node = g_new0(QOSGraphNode, 1);
> +    node->type = type;
> +    node->available = FALSE;
> +    node->name = g_strdup(name);
> +    g_hash_table_insert(node_table, node->name, node);
> +    return node;
> +}
> +
> +/**
> + * destroy_node(): frees a node @val from the nodes hash table.
> + * Note that node->name is not free'd since it will represent the
> + * hash table key
> + */
> +static void destroy_node(void *val)
> +{
> +    QOSGraphNode *node = val;
> +    g_free(node->command_line);
> +    g_free(node);
> +}
> +
> +/**
> + * destroy_string(): frees @key from the nodes hash table.
> + * Actually frees the node->name
> + */
> +static void destroy_string(void *key)
> +{
> +    g_free(key);
> +}
> +
> +/**
> + * search_node(): search for a node @key in the nodes hash table
> + * Returns the QOSGraphNode if found, #NULL otherwise
> + */
> +static QOSGraphNode *search_node(const char *key)
> +{
> +    return g_hash_table_lookup(node_table, key);
> +}
> +
> +/**
> + * get_edgelist(): returns the edge list (value) assigned to
> + * the @key in the edge hash table.
> + * This list will contain all edges with source equal to @key
> + *
> + * Returns: on success: the %QOSGraphEdgeList
> + *          otherwise: abort()
> + */
> +static QOSGraphEdgeList *get_edgelist(const char *key)
> +{
> +    return g_hash_table_lookup(edge_table, key);
> +}
> +
> +/**
> + * search_list_edges(): search for an edge with destination @dest
> + * in the given @edgelist.
> + *
> + * Returns: on success: the %QOSGraphEdge
> + *          otherwise: #NULL
> + */
> +static QOSGraphEdge *search_list_edges(QOSGraphEdgeList *edgelist,
> +                                       const char *dest)
> +{
> +    QOSGraphEdge *tmp, *next;
> +    if (!edgelist) {
> +        return NULL;
> +    }
> +    QSLIST_FOREACH_SAFE(tmp, edgelist, edge_list, next) {
> +        if (g_strcmp0(tmp->dest, dest) == 0) {
> +            break;
> +        }
> +    }
> +    return tmp;
> +}
> +
> +/**
> + * search_machine(): search for a machine @name in the node hash
> + * table. A machine is the child of the root node.
> + * This function forces the research in the childs of the root,
> + * to check the node is a proper machine
> + *
> + * Returns: on success: the %QOSGraphNode
> + *          otherwise: #NULL
> + */
> +static QOSGraphNode *search_machine(const char *name)
> +{
> +    QOSGraphNode *n;
> +    QOSGraphEdgeList *root_list = get_edgelist(QOS_ROOT);
> +    QOSGraphEdge *e = search_list_edges(root_list, name);
> +    if (!e) {
> +        return NULL;
> +    }
> +    n = search_node(e->dest);
> +    if (n->type == QNODE_MACHINE) {
> +        return n;
> +    }
> +    return NULL;
> +}
> +
> +/**
> + * create_interface(): checks if there is already
> + * a node @node in the node hash table, if not
> + * creates a node @node of type #QNODE_INTERFACE
> + * and inserts it. If there is one, check it's
> + * a #QNODE_INTERFACE and abort() if it's not.
> + */
> +static void create_interface(const char *node)
> +{
> +    QOSGraphNode *interface;
> +    interface = search_node(node);
> +    if (!interface) {
> +        create_node(node, QNODE_INTERFACE);
> +    } else if (interface->type != QNODE_INTERFACE) {
> +        printf("Error: Node %s is not an interface\n", node);

fprintf to stderr? Or g_printerr() ?

> +        abort();
> +    }
> +}
> +
> +/**
> + * build_machine_cmd_line(): builds the command line for the machine
> + * @node. The node name must be a valid qemu identifier, since it
> + * will be used to build the command line.
> + *
> + * It is also possible to pass an optional @args that will be
> + * concatenated to the command line.
> + *
> + * For machines, prepend -M to the machine name. ", @rgs" is added
> + * after the -M <machine> command.
> + */
> +static void build_machine_cmd_line(QOSGraphNode *node, const char *args)
> +{
> +    char *arch, *machine;
> +    qos_separate_arch_machine(node->name, &arch, &machine);
> +    if (args) {
> +        node->command_line = g_strconcat("-M ", machine, ",", args, NULL);
> +    } else {
> +        node->command_line = g_strconcat("-M ", machine, " ", NULL);
> +    }
> +}
> +
> +/**
> + * build_driver_cmd_line(): builds the command line for the driver
> + * @node. The node name must be a valid qemu identifier, since it
> + * will be used to build the command line.
> + *
> + * Driver do not need additional command line, since it will be
> + * provided by the edge options.
> + *
> + * For drivers, prepend -device to the node name.
> + */
> +static void build_driver_cmd_line(QOSGraphNode *node)
> +{
> +    node->command_line = g_strconcat(" -device ", node->name, NULL);
> +}
> +
> +/* qos_print_cb(): callback prints all path found by the DFS algorithm. */
> +static void qos_print_cb(QOSGraphNode *path, int length)
> +{
> +    #if QGRAPH_PRINT_DEBUG
> +        printf("%d elements\n", length);
> +
> +        if (!path) {
> +            return;
> +        }
> +
> +        while (path->path_edge) {
> +            printf("%s ", path->name);
> +            switch (path->path_edge->type) {
> +            case QEDGE_PRODUCES:
> +                printf("--PRODUCES--> ");
> +                break;
> +            case QEDGE_CONSUMED_BY:
> +                printf("--CONSUMED_BY--> ");
> +                break;
> +            case QEDGE_CONTAINS:
> +                printf("--CONTAINS--> ");
> +                break;
> +            }
> +            path = search_node(path->path_edge->dest);
> +        }
> +
> +        printf("%s\n\n", path->name);
> +    #endif
> +}
> +
> +/* qos_push(): push a node @el and edge @e in the qos_node_stack */
> +static void qos_push(QOSGraphNode *el, QOSStackElement *parent,
> +                     QOSGraphEdge *e)
> +{
> +    int len = 0; /* root is not counted */
> +    if (qos_node_tos == QOS_PATH_MAX_ELEMENT_SIZE) {
> +        g_printerr("QOSStack: full stack, cannot push");
> +        abort();
> +    }
> +
> +    if (parent) {
> +        len = parent->length + 1;
> +    }
> +    qos_node_stack[qos_node_tos++] = (QOSStackElement) {
> +        .node = el,
> +        .parent = parent,
> +        .parent_edge = e,
> +        .length = len,
> +    };
> +}
> +
> +/* qos_tos(): returns the top of stack, without popping */
> +static QOSStackElement *qos_tos(void)
> +{
> +    return &qos_node_stack[(qos_node_tos - 1)];

No need for the round brackets here.

> +}
> +
> +/* qos_pop(): pops an element from the tos, setting it unvisited*/
> +static QOSStackElement *qos_pop(void)
> +{
> +    if (qos_node_tos == 0) {
> +        g_printerr("QOSStack: empty stack, cannot pop");
> +        abort();
> +    }
> +    QOSStackElement *e = qos_tos();
> +    e->node->visited = FALSE;
> +    qos_node_tos--;
> +    return e;
> +}
> +
> +/**
> + * qos_reverse_path(): reverses the found path, going from
> + * test-to-machine to machine-to-test
> + */
> +static QOSGraphNode *qos_reverse_path(QOSStackElement *el)
> +{
> +    if (!el) {
> +        return NULL;
> +    }
> +
> +    el->node->path_edge = NULL;
> +
> +    while (el->parent) {
> +        el->parent->node->path_edge = el->parent_edge;
> +        el = el->parent;
> +    }
> +
> +    return el->node;
> +}
> +
> +/**
> + * qos_traverse_graph(): graph-walking algorithm, using Depth First Search it
> + * starts from the root @machine and walks all possible path until it
> + * reaches a test node.
> + * At that point, it reverses the path found and invokes the @callback.
> + *
> + * Being Depth First Search, time complexity is O(|V| + |E|), while
> + * space is O(|V|). In this case, the maximum stack size is set by
> + * QOS_PATH_MAX_ELEMENT_SIZE.
> + */
> +static void qos_traverse_graph(QOSGraphNode *root, QOSTestCallback callback)
> +{
> +    QOSGraphNode *v, *dest_node, *path;
> +    QOSStackElement *s_el;
> +    QOSGraphEdge *e, *next;
> +    QOSGraphEdgeList *list;
> +
> +    qos_push(root, NULL, NULL);
> +
> +    while (qos_node_tos > 0) {
> +        s_el = qos_tos();
> +        v = s_el->node;
> +        if (v->visited) {
> +            qos_pop();
> +            continue;
> +        }
> +        v->visited = TRUE;
> +        list = get_edgelist(v->name);
> +        if (!list) {
> +            qos_pop();
> +            if (v->type == QNODE_TEST) {
> +                v->visited = FALSE;
> +                path = qos_reverse_path(s_el);
> +                callback(path, s_el->length);
> +            }
> +        } else {
> +            QSLIST_FOREACH_SAFE(e, list, edge_list, next) {
> +                dest_node = search_node(e->dest);
> +
> +                if (!dest_node) {
> +                    printf("node %s in %s -> %s does not exist\n",
> +                            e->dest, v->name, e->dest);

fprintf to stderr? Or g_printerr() ?

> +                    abort();
> +                }
> +
> +                if (!dest_node->visited && dest_node->available) {
> +                    qos_push(dest_node, s_el, e);
> +                }
> +            }
> +        }
> +    }
> +}
> +
> +/* QGRAPH API*/
> +
> +QOSGraphNode *qos_graph_get_node(const char *key)
> +{
> +    return search_node(key);
> +}
> +
> +bool qos_graph_has_node(const char *node)
> +{
> +    QOSGraphNode *n = search_node(node);
> +    return n != NULL;
> +}
> +
> +QOSNodeType qos_graph_get_node_type(const char *node)
> +{
> +    QOSGraphNode *n = search_node(node);
> +    if (n) {
> +        return n->type;
> +    }
> +    return -1;
> +}
> +
> +bool qos_graph_get_node_availability(const char *node)
> +{
> +    QOSGraphNode *n = search_node(node);
> +    if (n) {
> +        return n->available;
> +    }
> +    return FALSE;
> +}
> +
> +QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest)
> +{
> +    QOSGraphEdgeList *list = get_edgelist(node);
> +    return search_list_edges(list, dest);
> +}
> +
> +QOSEdgeType qos_graph_edge_get_type(QOSGraphEdge *edge)
> +{
> +    if (!edge) {
> +        return -1;
> +    }
> +    return edge->type;;
> +}
> +
> +char *qos_graph_edge_get_dest(QOSGraphEdge *edge)
> +{
> +    if (!edge) {
> +        return NULL;
> +    }
> +    return edge->dest;
> +}
> +
> +void *qos_graph_edge_get_arg(QOSGraphEdge *edge)
> +{
> +    if (!edge) {
> +        return NULL;
> +    }
> +    return edge->arg;
> +}
> +
> +char *qos_graph_edge_get_after_cmd_line(QOSGraphEdge *edge)
> +{
> +    if (!edge) {
> +        return NULL;
> +    }
> +    return edge->after_cmd_line;
> +}
> +
> +char *qos_graph_edge_get_before_cmd_line(QOSGraphEdge *edge)
> +{
> +    if (!edge) {
> +        return NULL;
> +    }
> +    return edge->before_cmd_line;
> +}
> +
> +char *qos_graph_edge_get_extra_device_opts(QOSGraphEdge *edge)
> +{
> +    if (!edge) {
> +        return NULL;
> +    }
> +    return edge->extra_device_opts;
> +}
> +
> +char *qos_graph_edge_get_name(QOSGraphEdge *edge)
> +{
> +    if (!edge) {
> +        return NULL;
> +    }
> +    return edge->edge_name;
> +}
> +
> +bool qos_graph_has_edge(const char *start, const char *dest)
> +{
> +    QOSGraphEdgeList *list = get_edgelist(start);
> +    QOSGraphEdge *e = search_list_edges(list, dest);
> +    if (e) {
> +        return TRUE;
> +    }
> +    return FALSE;
> +}
> +
> +QOSGraphNode *qos_graph_get_machine(const char *node)
> +{
> +    return search_machine(node);
> +}
> +
> +bool qos_graph_has_machine(const char *node)
> +{
> +    QOSGraphNode *m = search_machine(node);
> +    return m != NULL;
> +}
> +
> +void qos_print_graph(void)
> +{
> +    qos_graph_foreach_test_path(qos_print_cb);
> +}
> +
> +void qos_graph_init(void)
> +{
> +    if (!node_table) {
> +        node_table = g_hash_table_new_full(g_str_hash, g_str_equal,
> +                                           destroy_string, destroy_node);
> +        create_node(QOS_ROOT, QNODE_DRIVER);
> +    }
> +
> +    if (!edge_table) {
> +        edge_table = g_hash_table_new_full(g_str_hash, g_str_equal,
> +                                           destroy_string, destroy_edges);
> +    }
> +}
> +
> +void qos_graph_destroy(void)
> +{
> +    if (node_table) {
> +        g_hash_table_destroy(node_table);
> +    }
> +
> +    if (edge_table) {
> +        g_hash_table_destroy(edge_table);
> +    }
> +
> +    node_table = NULL;
> +    edge_table = NULL;
> +}
> +
> +void qos_node_destroy(void *key)
> +{
> +    g_hash_table_remove(node_table, key);
> +}
> +
> +void qos_edge_destroy(void *key)
> +{
> +    g_hash_table_remove(edge_table, key);
> +}
> +
> +void qos_add_test(const char *name, const char *interface,
> +                  QOSTestFunc test_func, QOSGraphTestOptions *opts)
> +{
> +    QOSGraphNode *node;
> +    char *test_name = g_strdup_printf("%s-tests/%s", interface, name);;
> +
> +    if (!opts) {
> +        opts = &(QOSGraphTestOptions) { };
> +    }
> +    node = create_node(test_name, QNODE_TEST);
> +    node->u.test.function = test_func;
> +    node->u.test.arg = opts->arg;
> +    assert(!opts->edge.arg);
> +    assert(!opts->edge.size_arg);
> +
> +    node->u.test.before = opts->before;
> +    node->u.test.subprocess = opts->subprocess;
> +    node->available = TRUE;
> +    add_edge(interface, test_name, QEDGE_CONSUMED_BY, &opts->edge);
> +    g_free(test_name);
> +}
> +
> +void qos_node_create_machine(const char *name, QOSCreateMachineFunc function)
> +{
> +    qos_node_create_machine_args(name, function, NULL);
> +}
> +
> +void qos_node_create_machine_args(const char *name,
> +                                  QOSCreateMachineFunc function,
> +                                  const char *opts)
> +{
> +    QOSGraphNode *node = create_node(name, QNODE_MACHINE);
> +    build_machine_cmd_line(node, opts);
> +    node->u.machine.constructor = function;
> +    add_edge(QOS_ROOT, name, QEDGE_CONTAINS, NULL);
> +}
> +
> +void qos_node_create_driver(const char *name, QOSCreateDriverFunc function)
> +{
> +    QOSGraphNode *node = create_node(name, QNODE_DRIVER);
> +    build_driver_cmd_line(node);
> +    node->u.driver.constructor = function;
> +}
> +
> +void qos_node_contains(const char *container, const char *contained,
> +                       ...)
> +{
> +    va_list va;
> +    va_start(va, contained);
> +    QOSGraphEdgeOptions *opts;
> +
> +    do {
> +        opts = va_arg(va, QOSGraphEdgeOptions *);
> +        add_edge(container, contained, QEDGE_CONTAINS, opts);
> +    } while (opts != NULL);
> +
> +    va_end(va);
> +}
> +
> +void qos_node_produces(const char *producer, const char *interface)
> +{
> +    create_interface(interface);
> +    add_edge(producer, interface, QEDGE_PRODUCES, NULL);
> +}
> +
> +void qos_node_consumes(const char *consumer, const char *interface,
> +                       QOSGraphEdgeOptions *opts)
> +{
> +    create_interface(interface);
> +    add_edge(interface, consumer, QEDGE_CONSUMED_BY, opts);
> +}
> +
> +void qos_graph_node_set_availability(const char *node, bool av)
> +{
> +    QOSGraphEdgeList *elist;
> +    QOSGraphNode *n = search_node(node);
> +    QOSGraphEdge *e, *next;
> +    if (!n) {
> +        return;
> +    }
> +    n->available = av;
> +    elist = get_edgelist(node);
> +    if (!elist) {
> +        return;
> +    }
> +    QSLIST_FOREACH_SAFE(e, elist, edge_list, next) {
> +        if (e->type == QEDGE_CONTAINS || e->type == QEDGE_PRODUCES) {
> +            qos_graph_node_set_availability(e->dest, av);
> +        }
> +    }
> +}
> +
> +void qos_graph_foreach_test_path(QOSTestCallback fn)
> +{
> +    QOSGraphNode *root = qos_graph_get_node(QOS_ROOT);
> +    qos_traverse_graph(root, fn);
> +}
> +
> +QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts)
> +{
> +    QOSGraphObject *obj;
> +
> +    g_assert(node->type == QNODE_MACHINE);
> +    obj = node->u.machine.constructor(qts);
> +    obj->free = g_free;
> +    return obj;
> +}
> +
> +QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
> +                               QGuestAllocator *alloc, void *arg)
> +{
> +    QOSGraphObject *obj;
> +
> +    g_assert(node->type == QNODE_DRIVER);
> +    obj = node->u.driver.constructor(parent, alloc, arg);
> +    obj->free = g_free;
> +    return obj;
> +}
> +
> +void qos_object_destroy(QOSGraphObject *obj)
> +{
> +    if (!obj) {
> +        return;
> +    }
> +    if (obj->destructor) {
> +        obj->destructor(obj);
> +    }
> +    if (obj->free) {
> +        obj->free(obj);
> +    }
> +}
> +
> +void qos_object_queue_destroy(QOSGraphObject *obj)
> +{
> +    g_test_queue_destroy((GDestroyNotify) qos_object_destroy, obj);
> +}
> +
> +void qos_object_start_hw(QOSGraphObject *obj)
> +{
> +    if (obj->start_hw) {
> +        obj->start_hw(obj);
> +    }
> +}
> +
> +void qos_separate_arch_machine(char *name, char **arch, char **machine)
> +{
> +    *arch = name;
> +    while (*name != '\0' && *name != '/') {
> +        name++;
> +    }
> +
> +    if (*name == '/' && (*name + 1) != '\0') {

Shouldn't that rather be *(name + 1) instead? Or rather use name[1] ?

> +        *machine = name + 1;
> +    } else {
> +        printf("Machine name has to be of the form <arch>/<machine>\n");

fprintf to stderr? Or g_printerr()?

> +        abort();
> +    }
> +}
> +
> +void qos_delete_abstract_cmd_line(const char *name, bool abstract)
> +{
> +    QOSGraphNode *node = search_node(name);
> +    if (node && abstract) {
> +        g_free(node->command_line);
> +        node->command_line = NULL;
> +    }
> +}
> diff --git a/tests/libqos/qgraph.h b/tests/libqos/qgraph.h
> new file mode 100644
> index 0000000..6ebb2e6
> --- /dev/null
> +++ b/tests/libqos/qgraph.h
> @@ -0,0 +1,575 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#ifndef QGRAPH_H
> +#define QGRAPH_H
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <gmodule.h>
> +#include <glib.h>
> +#include "qemu/module.h"
> +#include "malloc.h"
> +
> +/* maximum path length */
> +#define QOS_PATH_MAX_ELEMENT_SIZE 50
> +
> +typedef struct QOSGraphObject QOSGraphObject;
> +typedef struct QOSGraphNode QOSGraphNode;
> +typedef struct QOSGraphEdge QOSGraphEdge;
> +typedef struct QOSGraphNodeOptions QOSGraphNodeOptions;
> +typedef struct QOSGraphEdgeOptions QOSGraphEdgeOptions;
> +typedef struct QOSGraphTestOptions QOSGraphTestOptions;
> +
> +/* Constructor for drivers, machines and test */
> +typedef void *(*QOSCreateDriverFunc) (void *parent, QGuestAllocator *alloc,
> +                                      void *addr);
> +typedef void *(*QOSCreateMachineFunc) (QTestState *qts);
> +typedef void (*QOSTestFunc) (void *parent, void *arg, QGuestAllocator *alloc);
> +
> +/* QOSGraphObject functions */
> +typedef void *(*QOSGetDriver) (void *object, const char *interface);
> +typedef QOSGraphObject *(*QOSGetDevice) (void *object, const char *name);
> +typedef void (*QOSDestructorFunc) (QOSGraphObject *object);
> +typedef void (*QOSStartFunct) (QOSGraphObject *object);
> +
> +/* Test options functions */
> +typedef void *(*QOSBeforeTest) (GString *cmd_line, void *arg);
> +
> +/**
> + * SECTION: qgraph.h
> + * @title: Qtest Driver Framework
> + * @short_description: interfaces to organize drivers and tests
> + *                     as nodes in a graph
> + *
> + * This Qgraph API provides all basic functions to create a graph
> + * and instantiate nodes representing machines, drivers and tests
> + * representing their relations with CONSUMES, PRODUCES, and CONTAINS
> + * edges.
> + *
> + * The idea is to have a framework where each test asks for a specific
> + * driver, and the framework takes care of allocating the proper devices
> + * required and passing the correct command line arguments to QEMU.
> + *
> + * A node can be of four types:
> + * - QNODE_MACHINE:   for example "arm/raspi2"
> + * - QNODE_DRIVER:    for example "generic-sdhci"
> + * - QNODE_INTERFACE: for example "sdhci" (interface for all "-sdhci" drivers)
> + *                     an interface is not explicitly created, it will be auto-
> + *                     matically instantiated when a node consumes or produces
> + *                     it.
> + * - QNODE_TEST:      for example "sdhci-test", consumes an interface and tests
> + *                    the functions provided
> + *
> + * Notes for the nodes:
> + * - QNODE_MACHINE: each machine struct must have a QGuestAllocator and
> + *                  implement get_driver to return the allocator passing
> + *                  "memory". The function can also return NULL if the
> + *                  allocator is not set.
> + * - QNODE_DRIVER:  driver names must be unique, and machines and nodes
> + *                  planned to be "consumed" by other nodes must match QEMU
> + *                  drivers name, otherwise they won't be discovered
> + *
> + * An edge relation between two nodes (drivers or machines) X and Y can be:
> + * - X CONSUMES Y: Y can be plugged into X
> + * - X PRODUCES Y: X provides the interface Y
> + * - X CONTAINS Y: Y is part of X component
> + *
> + * Basic framework steps are the following:
> + * - All nodes and edges are created in their respective
> + *   machine/driver/test files
> + * - The framework starts QEMU and asks for a list of available devices
> + *   and machines (note that only machines and "consumed" nodes are mapped
> + *   1:1 with QEMU devices)
> + * - The framework walks the graph starting from the available machines and
> + *   performs a Depth First Search for tests
> + * - Once a test is found, the path is walked again and all drivers are
> + *   allocated accordingly and the final interface is passed to the test
> + * - The test is executed
> + * - Unused objects are cleaned and the path discovery is continued
> + *
> + * Depending on the QEMU binary used, only some drivers/machines will be
> + * available and only test that are reached by them will be executed.
> + *
> + * <example>
> + *   <title>Creating new driver an its interface</title>
> + *   <programlisting>
> + #include "libqos/qgraph.h"
> +
> + struct My_driver {
> +     QOSGraphObject obj;
> +     Node_produced prod;
> +     Node_contained cont;
> + }
> +
> + static void my_destructor(QOSGraphObject *obj)
> + {
> +    g_free(obj);
> + }
> +
> + static void my_get_driver(void *object, const char *interface) {
> +    My_driver *dev = object;
> +    if (!g_strcmp0(interface, "my_interface")) {
> +        return &dev->prod;
> +    }
> +    abort();
> + }

I'd rather write that as:

   My_driver *dev = object;
   g_assert(g_str_equal((interface, "my_interface"));
   return &dev->prod;

> + static void my_get_device(void *object, const char *device) {
> +    My_driver *dev = object;
> +    if (!g_strcmp0(device, "my_driver_contained")) {
> +        return &dev->cont;
> +    }
> +    abort();
> + }

dito.


> + static void *my_driver_constructor(void *node_consumed,
> +                                    QOSGraphObject *alloc)
> + {
> +    My_driver dev = g_new(My_driver, 1);
> +    // get the node pointed by the produce edge
> +    dev->obj.get_driver = my_get_driver;
> +    // get the node pointed by the contains
> +    dev->obj.get_device = my_get_device;
> +    // free the object
> +    dev->obj.destructor = my_destructor;
> +    do_something_with_node_consumed(node_consumed);
> +    // set all fields of contained device
> +    init_contained_device(&dev->cont);
> +    return &dev->obj;
> + }
> +
> + static void register_my_driver(void)
> + {
> +     qos_node_create_driver("my_driver", my_driver_constructor);
> +     // contained drivers don't need a constructor,
> +     // they will be init by the parent.
> +     qos_node_create_driver("my_driver_contained", NULL);
> +
> +    // For the sake of this example, assume machine x86_64/pc contains
> +    // "other_node".
> +    // This relation, along with the machine and "other_node" creation,
> +    // should be defined in the x86_64_pc-machine.c file.
> +    // "my_driver" will then consume "other_node"
> +    qos_node_contains("my_driver", "my_driver_contained");
> +    qos_node_produces("my_driver", "my_interface");
> +    qos_node_consumes("my_driver", "other_node");
> + }
> + *   </programlisting>
> + * </example>
> + *
> + * In the above example, all possible types of relations are created:
> + * node "my_driver" consumes, contains and produces other nodes.
> + * more specifically:
> + * x86_64/pc -->contains--> other_node <--consumes-- my_driver
> + *                                                       |
> + *                      my_driver_contained <--contains--+
> + *                                                       |
> + *                             my_interface <--produces--+
> + *
> + * or inverting the consumes edge in consumed_by:
> + *
> + * x86_64/pc -->contains--> other_node --consumed_by--> my_driver
> + *                                                           |
> + *                          my_driver_contained <--contains--+
> + *                                                           |
> + *                                 my_interface <--produces--+
> + *
> + * <example>
> + *   <title>Creating new test</title>
> + *   <programlisting>
> + * #include "libqos/qgraph.h"
> + *
> + * static void my_test_function(void *obj, void *data)
> + * {
> + *    Node_produced *interface_to_test = obj;
> + *    // test interface_to_test
> + * }
> + *
> + * static void register_my_test(void)
> + * {
> + *    qos_add_test("my_interface", "my_test", my_test_function);
> + * }
> + *
> + * libqos_init(register_my_test);
> + *
> + *   </programlisting>
> + * </example>
> + *
> + * Here a new test is created, consuming "my_interface" node
> + * and creating a valid path from a machine to a test.
> + * Final graph will be like this:
> + * x86_64/pc -->contains--> other_node <--consumes-- my_driver
> + *                                                        |
> + *                       my_driver_contained <--contains--+
> + *                                                        |
> + *        my_test --consumes--> my_interface <--produces--+
> + *
> + * or inverting the consumes edge in consumed_by:
> + *
> + * x86_64/pc -->contains--> other_node --consumed_by--> my_driver
> + *                                                           |
> + *                          my_driver_contained <--contains--+
> + *                                                           |
> + *        my_test <--consumed_by-- my_interface <--produces--+
> + *
> + * Assuming there the binary is
> + * QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64
> + * a valid test path will be:
> + * "/x86_64/pc/other_node/my_driver/my_interface/my_test".
> + *
> + * Additional examples are also in libqos/test-qgraph.c
> + *
> + * Command line:
> + * Command line is built by using node names and optional arguments
> + * passed by the user when building the edges.
> + *
> + * There are three types of command line arguments:
> + * - in node      : created from the node name. For example, machines will
> + *                  have "-M <machine>" to its command line, while devices
> + *                  "- device <device>". It is automatically done by the

s/- device/-device/


> + *                   framework.
> + * - after node   : added as additional argument to the node name.
> + *                  This argument is added optionally when creating edges,
> + *                  by setting the parameter @after_cmd_line and
> + *                  @extra_edge_opts in #QOSGraphEdgeOptions.
> + *                  The framework automatically adds
> + *                  a comma before @extra_edge_opts,
> + *                  because it is going to add attibutes
> + *                  after the destination node pointed by
> + *                  the edge containing these options, and automatically
> + *                  adds a space before @after_cmd_line, because it
> + *                  adds an additional device, not an attribute.
> + * - before node  : added as additional argument to the node name.
> + *                  This argument is added optionally when creating edges,
> + *                  by setting the parameter @before_cmd_line in
> + *                  #QOSGraphEdgeOptions. This attribute
> + *                  is going to add attibutes before the destination node
> + *                  pointed by the edge containing these options. It is
> + *                  helpful to commands that are not node-representable,
> + *                  such as "-fdsev" or "-netdev".
> + *
> + * While adding command line in edges is always used, not all nodes names are
> + * used in every path walk: this is because the contained or produced ones
> + * are already added by QEMU, so only nodes that "consumes" will be used to
> + * build the command line. Also, nodes that will have { "abstract" : true }
> + * as QMP attribute will loose their command line, since they are not proper
> + * devices to be added in QEMU.
> + *
> + * Example:
> + *
> + QOSGraphEdgeOptions opts = {
> +     .arg = NULL,
> +     .size_arg = 0,
> +     .after_cmd_line = "-device other",
> +     .before_cmd_line = "-netdev something",
> +     .extra_edge_opts = "addr=04.0",
> + };
> + QOSGraphNode * node = qos_node_create_driver("my_node", constructor);
> + qos_node_consumes_args("my_node", "interface", &opts);
> + *
> + * Will produce the following command line:
> + * "-netdev something -device my_node,addr=04.0 -device other"
> + */
> +
> +/**
> + * Edge options to be passed to the contains/consumes *_args function.
> + */
> +struct QOSGraphEdgeOptions {
> +    void *arg;                    /*
> +                                   * optional arg that will be used by
> +                                   * dest edge
> +                                   */
> +    uint32_t size_arg;            /*
> +                                   * optional arg size that will be used by
> +                                   * dest edge
> +                                   */
> +    const char *extra_device_opts;/*
> +                                   *optional additional command line for dest
> +                                   * edge, used to add additional attributes
> +                                   * *after* the node command line, the
> +                                   * framework automatically prepends ","
> +                                   * to this argument.
> +                                   */
> +    const char *before_cmd_line;  /*
> +                                   * optional additional command line for dest
> +                                   * edge, used to add additional attributes
> +                                   * *before* the node command line, usually
> +                                   * other non-node represented commands,
> +                                   * like "-fdsev synt"
> +                                   */
> +    const char *after_cmd_line;   /*
> +                                   * optional extra command line to be added
> +                                   * after the device command. This option
> +                                   * is used to add other devices
> +                                   * command line that depend on current node.
> +                                   * Automatically prepends " " to this
> +                                   * argument
> +                                   */
> +    const char *edge_name;        /*
> +                                   * optional edge to differentiate multiple
> +                                   * devices with same node name
> +                                   */
> +};
> +
> +/**
> + * Test options to be passed to the test functions.
> + */
> +struct QOSGraphTestOptions {
> +    QOSGraphEdgeOptions edge;   /* edge arguments that will be used by test.
> +                                 * Note that test *does not* use edge_name,
> +                                 * and uses instead arg and size_arg as
> +                                 * data arg for its test function.
> +                                 */
> +    void *arg;                  /* passed to the .before function, or to the
> +                                 * test function if there is no .before
> +                                 * function
> +                                 */
> +    QOSBeforeTest before;       /* executed before the test. Can add
> +                                 * additional parameters to the command line
> +				 * and modify the argument to the test function.
> +                                 */
> +    bool subprocess;            /* run the test in a subprocess */
> +};
> +
> +/**
> + * Each driver, test or machine of this framework will have a
> + * QOSGraphObject as first field.
> + *
> + * This set of functions offered by QOSGraphObject are executed
> + * in different stages of the framework:
> + * - get_driver / get_device : Once a machine-to-test path has been
> + * found, the framework traverses it again and allocates all the
> + * nodes, using the provided constructor. To satisfy their relations,
> + * i.e. for produces or contains, where a struct constructor needs
> + * an external parameter represented by the previous node,
> + * the framework will call get_device (for contains) or
> + * get_driver (for produces), depending on the edge type, passing
> + * them the name of the next node to be taken and getting from them
> + * the corresponding pointer to the actual structure of the next node to
> + * be used in the path.
> + *
> + * - start_hw: This function is executed after all the path objects
> + * have been allocated, but before the test is run. It starts the hw, setting
> + * the initial configurations (*_device_enable) and making it ready for the
> + * test.
> + *
> + * - destructor: Opposite to the node constructor, destroys the object.
> + * This function is called after the test has been executed, and performs
> + * a complete cleanup of each node allocated field. In case no constuctor
> + * is provided, no destructor will be called.
> + *
> + */
> +struct QOSGraphObject {
> +    /* for produces edges, returns void * */
> +    QOSGetDriver get_driver;
> +    /* for contains edges, returns a QOSGraphObject * */
> +    QOSGetDevice get_device;
> +    /* start the hw, get ready for the test */
> +    QOSStartFunct start_hw;
> +    /* destroy this QOSGraphObject */
> +    QOSDestructorFunc destructor;
> +    /* free the memory associated to the QOSGraphObject and its contained
> +     * children */
> +    GDestroyNotify free;
> +};
> +
> +/**
> + * qos_graph_init(): initialize the framework, creates two hash
> + * tables: one for the nodes and another for the edges.
> + */
> +void qos_graph_init(void);
> +
> +/**
> + * qos_graph_destroy(): deallocates all the hash tables,
> + * freeing all nodes and edges.
> + */
> +void qos_graph_destroy(void);
> +
> +/**
> + * qos_node_destroy(): removes and frees a node from the,
> + * nodes hash table.
> + */
> +void qos_node_destroy(void *key);
> +
> +/**
> + * qos_edge_destroy(): removes and frees an edge from the,
> + * edges hash table.
> + */
> +void qos_edge_destroy(void *key);
> +
> +/**
> + * qos_add_test(): adds a test node @name to the nodes hash table.
> + *
> + * The test will consume a @interface node, and once the
> + * graph walking algorithm has found it, the @test_func will be
> + * executed. It also has the possibility to
> + * add an optional @opts (see %QOSGraphNodeOptions).
> + *
> + * For tests, opts->edge.arg and size_arg represent the arg to pass
> + * to @test_func
> + */
> +void qos_add_test(const char *name, const char *interface,
> +                  QOSTestFunc test_func,
> +                  QOSGraphTestOptions *opts);
> +
> +/**
> + * qos_node_create_machine(): creates the machine @name and
> + * adds it to the node hash table.
> + *
> + * This node will be of type QNODE_MACHINE and have @function
> + * as constructor
> + */
> +void qos_node_create_machine(const char *name, QOSCreateMachineFunc function);
> +
> +/**
> + * qos_node_create_machine_args(): same as qos_node_create_machine,
> + * but with the possibility to add an optional ", @opts" after -M machine
> + * command line.
> + */
> +void qos_node_create_machine_args(const char *name,
> +                                  QOSCreateMachineFunc function,
> +                                  const char *opts);
> +
> +/**
> + * qos_node_create_driver(): creates the driver @name and
> + * adds it to the node hash table.
> + *
> + * This node will be of type QNODE_DRIVER and have @function
> + * as constructor
> + */
> +void qos_node_create_driver(const char *name, QOSCreateDriverFunc function);
> +
> +/**
> + * qos_node_contains(): creates an edge of type QEDGE_CONTAINS and
> + * adds it to the edge list mapped to @container in the
> + * edge hash table.
> + *
> + * This edge will have @container as source and @contained as destination.
> + *
> + * It also has the possibility to add optional NULL-terminated
> + * @opts parameters (see %QOSGraphEdgeOptions)
> + *
> + * This function can be useful whrn there are multiple devices

s/whrn/when/


> + * with the same node name contained in a machine/other node
> + *
> + * For example, if "arm/raspi2" contains 2 "generic-sdhci"
> + * devices, the right commands will be:
> + * qos_node_create_machine("arm/raspi2");
> + * qos_node_create_driver("generic-sdhci", constructor);
> + * //assume rest of the fields are set NULL
> + * QOSGraphEdgeOptions op1 = { .edge_name = "emmc" };
> + * QOSGraphEdgeOptions op2 = { .edge_name = "sdcard" };
> + * qos_node_contains("arm/raspi2", "generic-sdhci", &op1, &op2, NULL);
> + *
> + * Of course this also requires that the @container's get_device function
> + * should implement a case for "emmc" and "sdcard".
> + *
> + * For contains, op1.arg and op1.size_arg represent the arg to pass
> + * to @contained constructor to properly initialize it.
> + */
> +void qos_node_contains(const char *container, const char *contained, ...);
> +
> +/**
> + * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and
> + * adds it to the edge list mapped to @producer in the
> + * edge hash table.
> + *
> + * This edge will have @producer as source and @interface as destination.
> + */
> +void qos_node_produces(const char *producer, const char *interface);
> +
> +/**
> + * qos_node_consumes():  creates an edge of type QEDGE_CONSUMED_BY and
> + * adds it to the edge list mapped to @interface in the
> + * edge hash table.
> + *
> + * This edge will have @interface as source and @consumer as destination.
> + * It also has the possibility to add an optional @opts
> + * (see %QOSGraphEdgeOptions)
> + */
> +void qos_node_consumes(const char *consumer, const char *interface,
> +                       QOSGraphEdgeOptions *opts);
> +
> +/**
> + * qos_invalidate_command_line(): invalidates current command line, so that
> + * qgraph framework cannot try to cache the current command line and
> + * forces QEMU to restart.
> + */
> +void qos_invalidate_command_line(void);
> +
> +/**
> + * qos_get_current_command_line(): return the command line required by the
> + * machine and driver objects.  This is the same string that was passed to
> + * the test's "before" callback, if any.
> + */
> +const char *qos_get_current_command_line(void);
> +
> +/**
> + * qos_allocate_objects():
> + * @qts: The #QTestState that will be referred to by the machine object.
> + * @alloc: Where to store the allocator for the machine object, or %NULL.
> + *
> + * Allocate driver objects for the current test
> + * path, but relative to the QTestState @qts.
> + *
> + * Returns a test object just like the one that was passed to
> + * the test function, but relative to @qts.
> + */
> +void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc);
> +
> +/**
> + * qos_object_destroy(): calls the destructor for @obj
> + */
> +void qos_object_destroy(QOSGraphObject *obj);
> +
> +/**
> + * qos_object_queue_destroy(): queue the destructor for @obj so that it is
> + * called at the end of the test
> + */
> +void qos_object_queue_destroy(QOSGraphObject *obj);
> +
> +/**
> + * qos_object_start_hw(): calls the start_hw function for @obj
> + */
> +void qos_object_start_hw(QOSGraphObject *obj);
> +
> +/**
> + * qos_machine_new(): instantiate a new machine node
> + * @node: A machine node to be instantiated
> + * @qts: The #QTestState that will be referred to by the machine object.
> + *
> + * Returns a machine object.
> + */
> +QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts);
> +
> +/**
> + * qos_machine_new(): instantiate a new driver node
> + * @node: A driver node to be instantiated
> + * @parent: A #QOSGraphObject to be consumed by the new driver node
> + * @alloc: An allocator to be used by the new driver node.
> + * @arg: The argument for the consumed-by edge to @node.
> + *
> + * Calls the constructor for the driver object.
> + */
> +QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
> +                               QGuestAllocator *alloc, void *arg);
> +
> +
> +#endif
> diff --git a/tests/libqos/qgraph_internal.h b/tests/libqos/qgraph_internal.h
> new file mode 100644
> index 0000000..bb4d82c
> --- /dev/null
> +++ b/tests/libqos/qgraph_internal.h
> @@ -0,0 +1,264 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#ifndef QGRAPH_EXTRA_H
> +#define QGRAPH_EXTRA_H
> +
> +/* This header is declaring additional helper functions defined in
> + * libqos/qgraph.c
> + * It should not be included in tests
> + */
> +
> +#include "libqos/qgraph.h"
> +
> +typedef struct QOSGraphMachine QOSGraphMachine;
> +typedef struct QOSGraphEdgeList QOSGraphEdgeList;
> +typedef enum QOSEdgeType QOSEdgeType;
> +typedef enum QOSNodeType QOSNodeType;
> +
> +/* callback called when the walk path algorithm found a
> + * valid path
> + */
> +typedef void (*QOSTestCallback) (QOSGraphNode *path, int len);
> +
> +/* edge types*/
> +enum QOSEdgeType {
> +    QEDGE_CONTAINS,
> +    QEDGE_PRODUCES,
> +    QEDGE_CONSUMED_BY
> +};
> +
> +/* node types*/
> +enum QOSNodeType {
> +    QNODE_MACHINE,
> +    QNODE_DRIVER,
> +    QNODE_INTERFACE,
> +    QNODE_TEST
> +};
> +
> +/* Graph Node */
> +struct QOSGraphNode {
> +    QOSNodeType type;
> +    bool available;     /* set by QEMU via QMP, used during graph walk */
> +    bool visited;       /* used during graph walk */
> +    char *name;         /* used to identify the node */
> +    char *command_line; /* used to start QEMU at test execution */
> +    union {
> +        struct {
> +            QOSCreateDriverFunc constructor;
> +        } driver;
> +        struct {
> +            QOSCreateMachineFunc constructor;
> +        } machine;
> +        struct {
> +            QOSTestFunc function;
> +            void *arg;
> +            QOSBeforeTest before;
> +            bool subprocess;
> +        } test;
> +    } u;
> +
> +    /**
> +     * only used when traversing the path, never rely on that except in the
> +     * qos_traverse_graph callback function
> +     */
> +    QOSGraphEdge *path_edge;
> +};
> +
> +/**
> + * qos_graph_get_node(): returns the node mapped to that @key.
> + * It performs an hash map search O(1)
> + *
> + * Returns: on success: the %QOSGraphNode
> + *          otherwise: #NULL
> + */
> +QOSGraphNode *qos_graph_get_node(const char *key);
> +
> +/**
> + * qos_graph_has_node(): returns #TRUE if the node
> + * has map has a node mapped to that @key.
> + */
> +bool qos_graph_has_node(const char *node);
> +
> +/**
> + * qos_graph_get_node_type(): returns the %QOSNodeType
> + * of the node @node.
> + * It performs an hash map search O(1)
> + * Returns: on success: the %QOSNodeType
> + *          otherwise: #-1
> + */
> +QOSNodeType qos_graph_get_node_type(const char *node);
> +
> +/**
> + * qos_graph_get_node_availability(): returns the availability (boolean)
> + * of the node @node.
> + */
> +bool qos_graph_get_node_availability(const char *node);
> +
> +/**
> + * qos_graph_get_edge(): returns the edge
> + * linking of the node @node with @dest.
> + *
> + * Returns: on success: the %QOSGraphEdge
> + *          otherwise: #NULL
> + */
> +QOSGraphEdge *qos_graph_get_edge(const char *node, const char *dest);
> +
> +/**
> + * qos_graph_edge_get_type(): returns the edge type
> + * of the edge @edge.
> + *
> + * Returns: on success: the %QOSEdgeType
> + *          otherwise: #-1
> + */
> +QOSEdgeType qos_graph_edge_get_type(QOSGraphEdge *edge);
> +
> +/**
> + * qos_graph_edge_get_dest(): returns the name of the node
> + * pointed as destination of edge @edge.
> + *
> + * Returns: on success: the destination
> + *          otherwise: #NULL
> + */
> +char *qos_graph_edge_get_dest(QOSGraphEdge *edge);
> +
> +/**
> + * qos_graph_has_edge(): returns #TRUE if there
> + * exists an edge from @start to @dest.
> + */
> +bool qos_graph_has_edge(const char *start, const char *dest);
> +
> +/**
> + * qos_graph_edge_get_arg(): returns the args assigned
> + * to that @edge.
> + *
> + * Returns: on success: the arg
> + *          otherwise: #NULL
> + */
> +void *qos_graph_edge_get_arg(QOSGraphEdge *edge);
> +
> +/**
> + * qos_graph_edge_get_after_cmd_line(): returns the edge
> + * command line that will be added after all the node arguments
> + * and all the before_cmd_line arguments.
> + *
> + * Returns: on success: the char* arg
> + *          otherwise: #NULL
> + */
> +char *qos_graph_edge_get_after_cmd_line(QOSGraphEdge *edge);
> +
> +/**
> + * qos_graph_edge_get_before_cmd_line(): returns the edge
> + * command line that will be added before the node command
> + * line argument.
> + *
> + * Returns: on success: the char* arg
> + *          otherwise: #NULL
> + */
> +char *qos_graph_edge_get_before_cmd_line(QOSGraphEdge *edge);
> +
> +/**
> + * qos_graph_edge_get_extra_device_opts(): returns the arg
> + * command line that will be added to the node command
> + * line argument.
> + *
> + * Returns: on success: the char* arg
> + *          otherwise: #NULL
> + */
> +char *qos_graph_edge_get_extra_device_opts(QOSGraphEdge *edge);
> +
> +/**
> + * qos_graph_edge_get_name(): returns the name
> + * assigned to the destination node (different only)
> + * if there are multiple devices with the same node name
> + * e.g. a node has two "generic-sdhci", "emmc" and "sdcard"
> + * there will be two edges with edge_name ="emmc" and "sdcard"
> + *
> + * Returns always the char* edge_name
> + */
> +char *qos_graph_edge_get_name(QOSGraphEdge *edge);
> +
> +/**
> + * qos_graph_get_machine(): returns the machine assigned
> + * to that @node name.
> + *
> + * It performs a search only trough the list of machines
> + * (i.e. the QOS_ROOT child).
> + *
> + * Returns: on success: the %QOSGraphNode
> + *          otherwise: #NULL
> + */
> +QOSGraphNode *qos_graph_get_machine(const char *node);
> +
> +/**
> + * qos_graph_has_machine(): returns #TRUE if the node
> + * has map has a node mapped to that @node.
> + */
> +bool qos_graph_has_machine(const char *node);
> +
> +
> +/**
> + * qos_print_graph(): walks the graph and prints
> + * all machine-to-test paths.
> + */
> +void qos_print_graph(void);
> +
> +/**
> + * qos_graph_foreach_test_path(): executes the Depth First search
> + * algorithm and applies @fn to all discovered paths.
> + *
> + * See qos_traverse_graph() in qgraph.c for more info on
> + * how it works.
> + */
> +void qos_graph_foreach_test_path(QOSTestCallback fn);
> +
> +/**
> + * qos_separate_arch_machine(): separate arch from machine.
> + * This function requires every machine @name to be in the form
> + * <arch>/<machine_name>, like "arm/raspi2" or "x86_64/pc".
> + *
> + * The function will split then the string in two parts,
> + * assigning @arch to point to <arch>/<machine_name>, and
> + * @machine to <machine_name>.
> + *
> + * For example, "x86_64/pc" will be split in this way:
> + * *arch = "x86_64/pc"
> + * *machine = "pc"
> + *
> + * Note that this function *does not* allocate any new string,
> + * but just sets the pointer *arch and *machine to the respective
> + * part of the string.
> + */
> +void qos_separate_arch_machine(char *name, char **arch, char **machine);

The arch parameter looks unnecessary to me, since it will be the same
pointer like "name" afterwards, and the callers already know that one,
don't they?


> +/**
> + * qos_delete_abstract_cmd_line(): if @abstract is #TRUE, delete the
> + * command line present in node mapped with key @name.
> + *
> + * This function is called when the QMP query returns a node with
> + * { "abstract" : <boolean> } attribute.
> + */
> +void qos_delete_abstract_cmd_line(const char *name, bool abstract);
> +
> +/**
> + * qos_graph_node_set_availability(): sets the node identified
> + * by @node with availability @av.
> + */
> +void qos_graph_node_set_availability(const char *node, bool av);
> +
> +#endif
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index ed88ff9..2fd1e51 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -576,6 +576,9 @@ static inline QTestState *qtest_start(const char *args)
>   */
>  static inline void qtest_end(void)
>  {
> +    if (!global_qtest) {
> +        return;
> +    }
>      qtest_quit(global_qtest);
>      global_qtest = NULL;
>  }
> diff --git a/tests/qos-test.c b/tests/qos-test.c
> new file mode 100644
> index 0000000..d85ed71
> --- /dev/null
> +++ b/tests/qos-test.c
> @@ -0,0 +1,470 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <getopt.h>
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "qapi/qmp/qdict.h"
> +#include "qapi/qmp/qbool.h"
> +#include "qapi/qmp/qstring.h"
> +#include "qapi/qmp/qlist.h"
> +#include "libqos/malloc.h"
> +#include "libqos/qgraph.h"
> +#include "libqos/qgraph_internal.h"
> +
> +static char *old_path;
> +
> +/**
> + * create_machine_name(): appends the architecture to @name if
> + * @is_machine is valid.
> + */
> +static void create_machine_name(const char **name, bool is_machine)
> +{
> +    const char *arch;
> +    if (!is_machine) {
> +        return;
> +    }
> +    arch = qtest_get_arch();
> +    *name = g_strconcat(arch, "/", *name, NULL);
> +}

A void function which is returning a value via a char ** ? ... well, I'd
rather write that as:

static const char *create_machine_name(const char *name, bool is_machine)
{
    if (!is_machine) {
        return name;
    }
    return g_strconcat(qtest_get_arch(), "/", *name, NULL);
}


> +/**
> + * destroy_machine_name(): frees the given @name if
> + * @is_machine is valid.
> + */
> +static void destroy_machine_name(const char *name, bool is_machine)
> +{
> +    if (!is_machine) {
> +        return;
> +    }
> +    g_free((char *)name);
> +}
> +
> +/**
> + * apply_to_qlist(): using QMP queries QEMU for a list of
> + * machines and devices available, and sets the respective node
> + * as TRUE. If a node is found, also all its produced and contained
> + * child are marked available.
> + *
> + * See qos_graph_node_set_availability() for more info
> + */
> +static void apply_to_qlist(QList *list, bool is_machine)
> +{
> +    const QListEntry *p;
> +    const char *name;
> +    bool abstract;
> +    QDict *minfo;
> +    QObject *qobj;
> +    QString *qstr;
> +    QBool *qbol;
> +
> +    for (p = qlist_first(list); p; p = qlist_next(p)) {
> +        minfo = qobject_to(QDict, qlist_entry_obj(p));
> +        qobj = qdict_get(minfo, "name");
> +        qstr = qobject_to(QString, qobj);
> +        name = qstring_get_str(qstr);
> +
> +        create_machine_name(&name, is_machine);
> +        qos_graph_node_set_availability(name, TRUE);
> +
> +        qobj = qdict_get(minfo, "alias");
> +        if (qobj) {
> +            qstr = qobject_to(QString, qobj);
> +
> +            destroy_machine_name(name, is_machine);
> +            name = qstring_get_str(qstr);
> +
> +            create_machine_name(&name, is_machine);
> +            qos_graph_node_set_availability(name, TRUE);
> +        }
> +
> +        qobj = qdict_get(minfo, "abstract");
> +        if (qobj) {
> +            qbol = qobject_to(QBool, qobj);
> +            abstract = qbool_get_bool(qbol);
> +            qos_delete_abstract_cmd_line(name, abstract);
> +        }
> +
> +        destroy_machine_name(name, is_machine);
> +    }
> +}
> +
> +/**
> + * qos_set_machines_devices_available(): sets availability of qgraph
> + * machines and devices.
> + *
> + * This function firstly starts QEMU with "-machine none" option,
> + * and then executes the QMP protocol asking for the list of devices
> + * and machines available.
> + *
> + * for each of these items, it looks up the corresponding qgraph node,
> + * setting it as available. The list currently returns all devices that
> + * are either machines or QEDGE_CONSUMED_BY other nodes.
> + * Therefore, in order to mark all other nodes, it recursively sets
> + * all its QEDGE_CONTAINS and QEDGE_PRODUCES child as available too.
> + */
> +static void qos_set_machines_devices_available(void)
> +{
> +    QDict *response;
> +    QDict *args = qdict_new();
> +    QList *list;
> +
> +    qtest_start("-machine none");
> +    response = qmp("{ 'execute': 'query-machines' }");
> +    list = qdict_get_qlist(response, "return");
> +
> +    apply_to_qlist(list, TRUE);
> +
> +    qobject_unref(response);
> +
> +    qdict_put_bool(args, "abstract", TRUE);
> +    qdict_put_str(args, "implements", "device");
> +
> +    response = qmp("{'execute': 'qom-list-types',"
> +                   " 'arguments': %p }", args);
> +    g_assert(qdict_haskey(response, "return"));
> +    list = qdict_get_qlist(response, "return");
> +
> +    apply_to_qlist(list, FALSE);
> +
> +    qtest_end();
> +    qobject_unref(response);
> +
> +}
> +
> +static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj)
> +{
> +    if (obj->get_driver) {
> +        return obj->get_driver(obj, "memory");
> +    } else {
> +        return NULL;
> +    }
> +}
> +
> +static void restart_qemu_or_continue(char *path)
> +{
> +    /* compares the current command line with the
> +     * one previously executed: if they are the same,
> +     * don't restart QEMU, if they differ, stop previous
> +     * QEMU subprocess (if active) and start over with
> +     * the new command line
> +     */
> +    if (g_strcmp0(old_path, path)) {
> +        qtest_end();
> +        qos_invalidate_command_line();
> +        old_path = g_strdup(path);
> +        qtest_start(path);
> +    } else { /* if cmd line is the same, reset the guest */
> +        qobject_unref(qmp("{ 'execute': 'system_reset' }"));
> +        qmp_eventwait("RESET");
> +    }
> +}
> +
> +void qos_invalidate_command_line(void)
> +{
> +    g_free(old_path);
> +    old_path = NULL;
> +}
> +
> +/**
> + * allocate_objects(): given an array of nodes @arg,
> + * walks the path invoking all constructors and
> + * passing the corresponding parameter in order to
> + * continue the objects allocation.
> + * Once the test is reached, return the object it consumes.
> + *
> + * Since the machine and QEDGE_CONSUMED_BY nodes allocate
> + * memory in the constructor, g_test_queue_destroy is used so
> + * that after execution they can be safely free'd.  (The test's
> + * ->before callback is also welcome to use g_test_queue_destroy).
> + *
> + * Note: as specified in walk_path() too, @arg is an array of
> + * char *, where arg[0] is a pointer to the command line
> + * string that will be used to properly start QEMU when executing
> + * the test, and the remaining elements represent the actual objects
> + * that will be allocated.
> + */
> +static void *allocate_objects(QTestState *qts, char **path, QGuestAllocator **p_alloc)
> +{
> +    int current = 0;
> +    QGuestAllocator *alloc;
> +    QOSGraphObject *parent = NULL;
> +    QOSGraphEdge *edge;
> +    QOSGraphNode *node;
> +    void *edge_arg;
> +    void *obj;
> +
> +    node = qos_graph_get_node(path[current]);
> +    g_assert(node->type == QNODE_MACHINE);
> +
> +    obj = qos_machine_new(node, qts);
> +    qos_object_queue_destroy(obj);
> +
> +    alloc = get_machine_allocator(obj);
> +    if (p_alloc) {
> +        *p_alloc = alloc;
> +    }
> +
> +    for (;;) {
> +        if (node->type != QNODE_INTERFACE) {
> +            qos_object_start_hw(obj);
> +            parent = obj;
> +        }
> +
> +        /* follow edge and get object for next node constructor */
> +        current++;
> +        edge = qos_graph_get_edge(path[current - 1], path[current]);
> +        node = qos_graph_get_node(path[current]);
> +
> +        if (node->type == QNODE_TEST) {
> +            g_assert(qos_graph_edge_get_type(edge) == QEDGE_CONSUMED_BY);
> +            return obj;
> +        }
> +
> +        switch (qos_graph_edge_get_type(edge)) {
> +        case QEDGE_PRODUCES:
> +            obj = parent->get_driver(parent, path[current]);
> +            break;
> +
> +        case QEDGE_CONSUMED_BY:
> +            edge_arg = qos_graph_edge_get_arg(edge);
> +            obj = qos_driver_new(node, obj, alloc, edge_arg);
> +            qos_object_queue_destroy(obj);
> +            break;
> +
> +        case QEDGE_CONTAINS:
> +            obj = parent->get_device(parent, path[current]);
> +            break;
> +        }
> +    }
> +}
> +
> +/* The argument to run_one_test, which is the test function that is registered
> + * with GTest, is a vector of strings.  The first item is the initial command
> + * line (before it is modified by the test's "before" function), the remaining
> + * items are node names forming the path to the test node.
> + */
> +static char **current_path;
> +
> +const char *qos_get_current_command_line(void)
> +{
> +    return current_path[0];
> +}
> +
> +void *qos_allocate_objects(QTestState *qts, QGuestAllocator **p_alloc)
> +{
> +    return allocate_objects(qts, current_path + 1, p_alloc);
> +}
> +
> +/**
> + * run_one_test(): given an array of nodes @arg,
> + * walks the path invoking all constructors and
> + * passing the corresponding parameter in order to
> + * continue the objects allocation.
> + * Once the test is reached, its function is executed.
> + *
> + * Since the machine and QEDGE_CONSUMED_BY nodes allocate
> + * memory in the constructor, g_test_queue_destroy is used so
> + * that after execution they can be safely free'd.  The test's
> + * ->before callback is also welcome to use g_test_queue_destroy.
> + *
> + * Note: as specified in walk_path() too, @arg is an array of
> + * char *, where arg[0] is a pointer to the command line
> + * string that will be used to properly start QEMU when executing
> + * the test, and the remaining elements represent the actual objects
> + * that will be allocated.
> + *
> + * The order of execution is the following:
> + * 1) @before test function as defined in the given QOSGraphTestOptions
> + * 2) start QEMU
> + * 3) call all nodes constructor and get_driver/get_device depending on edge,
> + *    start the hardware (*_device_enable functions)
> + * 4) start test
> + */
> +static void run_one_test(const void *arg)
> +{
> +    QOSGraphNode *test_node;
> +    QGuestAllocator *alloc = NULL;
> +    void *obj;
> +    char **path = (char **) arg;
> +    GString *cmd_line = g_string_new(path[0]);
> +    void *test_arg;
> +
> +    /* Before test */
> +    current_path = path;
> +    test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]);
> +    test_arg = test_node->u.test.arg;
> +    if (test_node->u.test.before) {
> +        test_arg = test_node->u.test.before(cmd_line, test_arg);
> +    }
> +
> +    restart_qemu_or_continue(cmd_line->str);
> +    g_string_free(cmd_line, TRUE);
> +
> +    obj = qos_allocate_objects(global_qtest, &alloc);
> +    test_node->u.test.function(obj, test_arg, alloc);
> +}
> +
> +static void subprocess_run_one_test(const void *arg)
> +{
> +    const gchar *path = arg;
> +    g_test_trap_subprocess(path, 0, 0);
> +    g_test_trap_assert_passed();
> +}
> +
> +/*
> + * in this function, 2 path will be built:
> + * path_str, a one-string path (ex "pc/i440FX-pcihost/...")
> + * path_vec, a string-array path (ex [0] = "pc", [1] = "i440FX-pcihost").
> + *
> + * path_str will be only used to build the test name, and won't need the
> + * architecture name at beginning, since it will be added by qtest_add_func().
> + *
> + * path_vec is used to allocate all constructors of the path nodes.
> + * Each name in this array except position 0 must correspond to a valid
> + * QOSGraphNode name.
> + * Position 0 is special, initially contains just the <machine> name of
> + * the node, (ex for "x86_64/pc" it will be "pc"), used to build the test
> + * path (see below). After it will contain the command line used to start
> + * qemu with all required devices.
> + *
> + * Note that the machine node name must be with format <arch>/<machine>
> + * (ex "x86_64/pc"), because it will identify the node "x86_64/pc"
> + * and start QEMU with "-M pc". For this reason,
> + * when building path_str, path_vec
> + * initially contains the <machine> at position 0 ("pc"),
> + * and the node name at position 1 (<arch>/<machine>)
> + * ("x86_64/pc"), followed by the rest of the nodes.
> + */
> +static void walk_path(QOSGraphNode *orig_path, int len)
> +{
> +    QOSGraphNode *path;
> +    QOSGraphEdge *edge;
> +
> +    /* etype set to QEDGE_CONSUMED_BY so that machine can add to the command line */
> +    QOSEdgeType etype = QEDGE_CONSUMED_BY;
> +
> +    /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */
> +    char **path_vec = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2));
> +    int path_vec_size = 0;
> +
> +    char *machine = NULL, *arch = NULL;
> +    char *after_cmd = NULL, *before_cmd = NULL, *after_device = NULL;
> +    char *node_name = orig_path->name, *path_str;
> +
> +    GString *cmd_line = g_string_new("");
> +    GString *cmd_line2 = g_string_new("");
> +
> +    path = qos_graph_get_node(node_name); /* root */
> +    node_name = qos_graph_edge_get_dest(path->path_edge); /* machine name */
> +
> +    qos_separate_arch_machine(node_name, &arch, &machine);
> +    path_vec[path_vec_size++] = arch;
> +    path_vec[path_vec_size++] = machine;
> +
> +    for (;;) {
> +        path = qos_graph_get_node(node_name);
> +        if (!path->path_edge) {
> +            break;
> +        }
> +
> +        node_name = qos_graph_edge_get_dest(path->path_edge);
> +
> +        /* append node command line + previous edge command line */
> +        if (path->command_line && etype == QEDGE_CONSUMED_BY) {
> +            g_string_append(cmd_line, path->command_line);
> +            if (after_device) {
> +                g_string_append(cmd_line, after_device);
> +            }
> +        }
> +
> +        path_vec[path_vec_size++] = qos_graph_edge_get_name(path->path_edge);
> +        /* detect if edge has command line args */
> +        after_cmd = qos_graph_edge_get_after_cmd_line(path->path_edge);
> +        after_device = qos_graph_edge_get_extra_device_opts(path->path_edge);
> +        before_cmd = qos_graph_edge_get_before_cmd_line(path->path_edge);
> +        edge = qos_graph_get_edge(path->name, node_name);
> +        etype = qos_graph_edge_get_type(edge);
> +
> +        if (before_cmd) {
> +            g_string_append(cmd_line, before_cmd);
> +        }
> +        if (after_cmd) {
> +            g_string_append(cmd_line2, after_cmd);
> +        }
> +    }
> +
> +    path_vec[path_vec_size++] = NULL;
> +    if (after_device) {
> +        g_string_append(cmd_line, after_device);
> +    }
> +    g_string_append(cmd_line, cmd_line2->str);
> +    g_string_free(cmd_line2, TRUE);
> +
> +    /* here position 0 has <arch>/<machine>, position 1 has <machine>.
> +     * The path must not have the <arch>
> +     */
> +    path_str = g_strjoinv("/", path_vec + 1);
> +
> +    /* put arch/machine in position 1 so run_one_test can do its work
> +     * and add the command line at position 0.
> +     */
> +    path_vec[0] = g_string_free(cmd_line, FALSE);
> +    path_vec[1] = arch;
> +
> +    if (path->u.test.subprocess) {
> +        gchar *subprocess_path = g_strdup_printf("/%s/%s/subprocess",
> +                                                 qtest_get_arch(), path_str);
> +        qtest_add_data_func(path_str, subprocess_path, subprocess_run_one_test);
> +        g_test_add_data_func(subprocess_path, path_vec, run_one_test);
> +    } else {
> +        qtest_add_data_func(path_str, path_vec, run_one_test);
> +    }
> +
> +    g_free(path_str);
> +}
> +
> +
> +
> +/**
> + * main(): heart of the qgraph framework.
> + *
> + * - Initializes the glib test framework
> + * - Creates the graph by invoking the various _init constructors
> + * - Starts QEMU to mark the available devices
> + * - Walks the graph, and each path is added to
> + *   the glib test framework (walk_path)
> + * - Runs the tests, calling allocate_object() and allocating the
> + *   machine/drivers/test objects
> + * - Cleans up everything
> + */
> +int main(int argc, char **argv)
> +{
> +    g_test_init(&argc, &argv, NULL);
> +    qos_graph_init();
> +    module_call_init(MODULE_INIT_QOM);
> +    module_call_init(MODULE_INIT_LIBQOS);
> +    qos_set_machines_devices_available();
> +
> +    qos_graph_foreach_test_path(walk_path);
> +    g_test_run();
> +    qtest_end();
> +    qos_graph_destroy();
> +    g_free(old_path);
> +    return 0;
> +}
[...]

I did not do a very detailed review, but from a quick glance, this looks
quite good to me already (apart from the few minor issues that I've
mentioned above)

 Thomas

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

* Re: [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework
  2018-12-07 15:38   ` Thomas Huth
@ 2018-12-12 11:09     ` Paolo Bonzini
  2018-12-12 11:47       ` Thomas Huth
  0 siblings, 1 reply; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-12 11:09 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 07/12/18 16:38, Thomas Huth wrote:
> I did not do a very detailed review, but from a quick glance, this looks
> quite good to me already (apart from the few minor issues that I've
> mentioned above)
> 
>  Thomas

Good, if this is okay for you, my plan is the following:

- send patches 1-18 in my next pull request to Peter

- send patches 15-19 for review as v2, for inclusion in your qtest tree

- once that is done and the patches are included in your tree, send the
more "boring" patches 20-71 directly to you as a pull request, basically
the same as in this submission only with checkpatch fixed.

Thanks,

Paolo

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

* Re: [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework
  2018-12-12 11:09     ` Paolo Bonzini
@ 2018-12-12 11:47       ` Thomas Huth
  0 siblings, 0 replies; 103+ messages in thread
From: Thomas Huth @ 2018-12-12 11:47 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: Emanuele Giuseppe Esposito, Laurent Vivier

On 2018-12-12 12:09, Paolo Bonzini wrote:
> On 07/12/18 16:38, Thomas Huth wrote:
>> I did not do a very detailed review, but from a quick glance, this looks
>> quite good to me already (apart from the few minor issues that I've
>> mentioned above)
>>
>>  Thomas
> 
> Good, if this is okay for you, my plan is the following:
> 
> - send patches 1-18 in my next pull request to Peter
> 
> - send patches 15-19 for review as v2, for inclusion in your qtest tree
> 
> - once that is done and the patches are included in your tree, send the
> more "boring" patches 20-71 directly to you as a pull request, basically
> the same as in this submission only with checkpatch fixed.

Sounds like a plan, yes. (and yes, I still plan to review the remaining
patches, I just did not have enough spare time for that yet ...)

 Thomas

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

* Re: [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test Paolo Bonzini
  2018-12-07  9:24   ` Thomas Huth
@ 2018-12-12 14:12   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 103+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-12-12 14:12 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

On 12/3/18 4:32 PM, Paolo Bonzini wrote:
> This test was merged into drive_del-test in 2014.

in e2f3f221885.

> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

> ---
>  tests/Makefile.include | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 3e3b16b..2718548 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -726,7 +726,6 @@ tests/qom-test$(EXESUF): tests/qom-test.o
>  tests/test-hmp$(EXESUF): tests/test-hmp.o
>  tests/machine-none-test$(EXESUF): tests/machine-none-test.o
>  tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y)
> -tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
>  tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
>  tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
>  tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
> 

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

* Re: [Qemu-devel] [PATCH 28/71] qos-test: sdhci test node
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 28/71] qos-test: sdhci test node Paolo Bonzini
@ 2018-12-12 14:28   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 103+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-12-12 14:28 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

On 12/3/18 4:32 PM, Paolo Bonzini wrote:
> From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> Convert tests/sdhci-test in first qgraph test node, sdhci-test. This test
> consumes an sdhci interface and checks that its function return the
> expected values.
> 
> Note that this test does not allocate any sdhci structure, it's all done by the
> qtest walking graph mechanism
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>

> ---
>  tests/Makefile.include |   7 +-
>  tests/sdhci-test.c     | 185 ++++++-------------------------------------------
>  2 files changed, 24 insertions(+), 168 deletions(-)
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 752f2c2..e6be21c 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -216,7 +216,6 @@ check-qtest-i386-y += tests/migration-test$(EXESUF)
>  check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF)
>  check-qtest-i386-y += tests/numa-test$(EXESUF)
>  check-qtest-x86_64-y += $(check-qtest-i386-y)
> -check-qtest-x86_64-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
>  
>  check-qtest-alpha-y += tests/boot-serial-test$(EXESUF)
>  
> @@ -278,11 +277,9 @@ check-qtest-arm-y += tests/m25p80-test$(EXESUF)
>  check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
>  check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
>  check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
> -check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
>  check-qtest-arm-y += tests/hexloader-test$(EXESUF)
>  
>  check-qtest-aarch64-y = tests/numa-test$(EXESUF)
> -check-qtest-aarch64-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
>  check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
>  check-qtest-aarch64-y += tests/migration-test$(EXESUF)
>  
> @@ -688,6 +685,9 @@ qos-test-obj-y += tests/libqos/arm-smdkc210-machine.o
>  qos-test-obj-y += tests/libqos/arm-xilinx-zynq-a9-machine.o
>  qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
>  
> +# Tests
> +qos-test-obj-y += tests/sdhci-test.o
> +
>  check-unit-y += tests/test-qgraph$(EXESUF)
>  tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
>  
> @@ -780,7 +780,6 @@ tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o
>  tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y)
>  tests/numa-test$(EXESUF): tests/numa-test.o
>  tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
> -tests/sdhci-test$(EXESUF): tests/sdhci-test.o $(libqos-pc-obj-y)
>  tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
>  
>  tests/migration/stress$(EXESUF): tests/migration/stress.o
> diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c
> index 28d481b..2f177e5 100644
> --- a/tests/sdhci-test.c
> +++ b/tests/sdhci-test.c
> @@ -12,6 +12,8 @@
>  #include "libqtest.h"
>  #include "libqos/pci-pc.h"
>  #include "hw/pci/pci.h"
> +#include "libqos/qgraph.h"
> +#include "libqos/sdhci.h"
>  
>  #define SDHC_CAPAB                      0x40
>  FIELD(SDHC_CAPAB, BASECLKFREQ,               8, 8); /* since v2 */
> @@ -20,99 +22,11 @@ FIELD(SDHC_CAPAB, SDR,                      32, 3); /* since v3 */
>  FIELD(SDHC_CAPAB, DRIVER,                   36, 3); /* since v3 */
>  #define SDHC_HCVER                      0xFE
>  
> -static const struct sdhci_t {
> -    const char *arch, *machine;
> -    struct {
> -        uintptr_t addr;
> -        uint8_t version;
> -        uint8_t baseclock;
> -        struct {
> -            bool sdma;
> -            uint64_t reg;
> -        } capab;
> -    } sdhci;
> -    struct {
> -        uint16_t vendor_id, device_id;
> -    } pci;
> -} models[] = {
> -    /* PC via PCI */
> -    { "x86_64", "pc",
> -        {-1,         2, 0,  {1, 0x057834b4} },
> -        .pci = { PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_SDHCI } },
> -
> -    /* Exynos4210 */
> -    { "arm",    "smdkc210",
> -        {0x12510000, 2, 0,  {1, 0x5e80080} } },
> -
> -    /* i.MX 6 */
> -    { "arm",    "sabrelite",
> -        {0x02190000, 3, 0,  {1, 0x057834b4} } },
> -
> -    /* BCM2835 */
> -    { "arm",    "raspi2",
> -        {0x3f300000, 3, 52, {0, 0x052134b4} } },
> -
> -    /* Zynq-7000 */
> -    { "arm",    "xilinx-zynq-a9",   /* Datasheet: UG585 (v1.12.1) */
> -        {0xe0100000, 2, 0,  {1, 0x69ec0080} } },
> -
> -    /* ZynqMP */
> -    { "aarch64", "xlnx-zcu102",     /* Datasheet: UG1085 (v1.7) */
> -        {0xff160000, 3, 0,  {1, 0x280737ec6481} } },
> -
> -};
> -
> -typedef struct QSDHCI {
> -    struct {
> -        QPCIBus *bus;
> -        QPCIDevice *dev;
> -    } pci;
> -    union {
> -        QPCIBar mem_bar;
> -        uint64_t addr;
> -    };
> -} QSDHCI;
> -
> -static uint16_t sdhci_readw(QSDHCI *s, uint32_t reg)
> -{
> -    uint16_t val;
> -
> -    if (s->pci.dev) {
> -        val = qpci_io_readw(s->pci.dev, s->mem_bar, reg);
> -    } else {
> -        val = qtest_readw(global_qtest, s->addr + reg);
> -    }
> -
> -    return val;
> -}
> -
> -static uint64_t sdhci_readq(QSDHCI *s, uint32_t reg)
> -{
> -    uint64_t val;
> -
> -    if (s->pci.dev) {
> -        val = qpci_io_readq(s->pci.dev, s->mem_bar, reg);
> -    } else {
> -        val = qtest_readq(global_qtest, s->addr + reg);
> -    }
> -
> -    return val;
> -}
> -
> -static void sdhci_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
> -{
> -    if (s->pci.dev) {
> -        qpci_io_writeq(s->pci.dev, s->mem_bar, reg, val);
> -    } else {
> -        qtest_writeq(global_qtest, s->addr + reg, val);
> -    }
> -}
> -
>  static void check_specs_version(QSDHCI *s, uint8_t version)
>  {
>      uint32_t v;
>  
> -    v = sdhci_readw(s, SDHC_HCVER);
> +    v = s->readw(s, SDHC_HCVER);
>      v &= 0xff;
>      v += 1;
>      g_assert_cmpuint(v, ==, version);
> @@ -122,7 +36,7 @@ static void check_capab_capareg(QSDHCI *s, uint64_t expec_capab)
>  {
>      uint64_t capab;
>  
> -    capab = sdhci_readq(s, SDHC_CAPAB);
> +    capab = s->readq(s, SDHC_CAPAB);
>      g_assert_cmphex(capab, ==, expec_capab);
>  }
>  
> @@ -131,11 +45,11 @@ static void check_capab_readonly(QSDHCI *s)
>      const uint64_t vrand = 0x123456789abcdef;
>      uint64_t capab0, capab1;
>  
> -    capab0 = sdhci_readq(s, SDHC_CAPAB);
> +    capab0 = s->readq(s, SDHC_CAPAB);
>      g_assert_cmpuint(capab0, !=, vrand);
>  
> -    sdhci_writeq(s, SDHC_CAPAB, vrand);
> -    capab1 = sdhci_readq(s, SDHC_CAPAB);
> +    s->writeq(s, SDHC_CAPAB, vrand);
> +    capab1 = s->readq(s, SDHC_CAPAB);
>      g_assert_cmpuint(capab1, !=, vrand);
>      g_assert_cmpuint(capab1, ==, capab0);
>  }
> @@ -147,7 +61,7 @@ static void check_capab_baseclock(QSDHCI *s, uint8_t expec_freq)
>      if (!expec_freq) {
>          return;
>      }
> -    capab = sdhci_readq(s, SDHC_CAPAB);
> +    capab = s->readq(s, SDHC_CAPAB);
>      capab_freq = FIELD_EX64(capab, SDHC_CAPAB, BASECLKFREQ);
>      g_assert_cmpuint(capab_freq, ==, expec_freq);
>  }
> @@ -156,7 +70,7 @@ static void check_capab_sdma(QSDHCI *s, bool supported)
>  {
>      uint64_t capab, capab_sdma;
>  
> -    capab = sdhci_readq(s, SDHC_CAPAB);
> +    capab = s->readq(s, SDHC_CAPAB);
>      capab_sdma = FIELD_EX64(capab, SDHC_CAPAB, SDMA);
>      g_assert_cmpuint(capab_sdma, ==, supported);
>  }
> @@ -167,7 +81,7 @@ static void check_capab_v3(QSDHCI *s, uint8_t version)
>  
>      if (version < 3) {
>          /* before v3 those fields are RESERVED */
> -        capab = sdhci_readq(s, SDHC_CAPAB);
> +        capab = s->readq(s, SDHC_CAPAB);
>          capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, SDR);
>          g_assert_cmpuint(capab_v3, ==, 0);
>          capab_v3 = FIELD_EX64(capab, SDHC_CAPAB, DRIVER);
> @@ -175,78 +89,21 @@ static void check_capab_v3(QSDHCI *s, uint8_t version)
>      }
>  }
>  
> -static QSDHCI *machine_start(const struct sdhci_t *test)
> -{
> -    QSDHCI *s = g_new0(QSDHCI, 1);
> -
> -    if (test->pci.vendor_id) {
> -        /* PCI */
> -        uint16_t vendor_id, device_id;
> -        uint64_t barsize;
> -
> -        global_qtest = qtest_initf("-machine %s -device sdhci-pci",
> -                                   test->machine);
> -
> -        s->pci.bus = qpci_new_pc(global_qtest, NULL);
> -
> -        /* Find PCI device and verify it's the right one */
> -        s->pci.dev = qpci_device_find(s->pci.bus, QPCI_DEVFN(4, 0));
> -        g_assert_nonnull(s->pci.dev);
> -        vendor_id = qpci_config_readw(s->pci.dev, PCI_VENDOR_ID);
> -        device_id = qpci_config_readw(s->pci.dev, PCI_DEVICE_ID);
> -        g_assert(vendor_id == test->pci.vendor_id);
> -        g_assert(device_id == test->pci.device_id);
> -        s->mem_bar = qpci_iomap(s->pci.dev, 0, &barsize);
> -        qpci_device_enable(s->pci.dev);
> -    } else {
> -        /* SysBus */
> -        global_qtest = qtest_initf("-machine %s", test->machine);
> -        s->addr = test->sdhci.addr;
> -    }
> -
> -    return s;
> -}
> -
> -static void machine_stop(QSDHCI *s)
> -{
> -    qpci_free_pc(s->pci.bus);
> -    g_free(s->pci.dev);
> -    qtest_quit(global_qtest);
> -    g_free(s);
> -}
> -
> -static void test_machine(const void *data)
> +static void test_registers(void *obj, void *data, QGuestAllocator *alloc)
>  {
> -    const struct sdhci_t *test = data;
> -    QSDHCI *s;
> +    QSDHCI *s = obj;
>  
> -    s = machine_start(test);
> -
> -    check_specs_version(s, test->sdhci.version);
> -    check_capab_capareg(s, test->sdhci.capab.reg);
> +    check_specs_version(s, s->props.version);
> +    check_capab_capareg(s, s->props.capab.reg);
>      check_capab_readonly(s);
> -    check_capab_v3(s, test->sdhci.version);
> -    check_capab_sdma(s, test->sdhci.capab.sdma);
> -    check_capab_baseclock(s, test->sdhci.baseclock);
> -
> -    machine_stop(s);
> +    check_capab_v3(s, s->props.version);
> +    check_capab_sdma(s, s->props.capab.sdma);
> +    check_capab_baseclock(s, s->props.baseclock);
>  }
>  
> -int main(int argc, char *argv[])
> +static void register_sdhci_test(void)
>  {
> -    const char *arch = qtest_get_arch();
> -    char *name;
> -    int i;
> -
> -    g_test_init(&argc, &argv, NULL);
> -    for (i = 0; i < ARRAY_SIZE(models); i++) {
> -        if (strcmp(arch, models[i].arch)) {
> -            continue;
> -        }
> -        name = g_strdup_printf("sdhci/%s", models[i].machine);
> -        qtest_add_data_func(name, &models[i], test_machine);
> -        g_free(name);
> -    }
> -
> -    return g_test_run();
> +    qos_add_test("registers", "sdhci", test_registers, NULL);
>  }
> +
> +libqos_init(register_sdhci_test);
> 

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

* Re: [Qemu-devel] [PATCH 22/71] tests/libqos: sdhci driver and interface nodes
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 22/71] tests/libqos: sdhci driver and interface nodes Paolo Bonzini
@ 2018-12-12 14:35   ` Philippe Mathieu-Daudé
  2018-12-12 15:25     ` Paolo Bonzini
  0 siblings, 1 reply; 103+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-12-12 14:35 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

On 12/3/18 4:32 PM, Paolo Bonzini wrote:
> From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> Add qgraph nodes for sdhci-pci and generic-sdhci (memory mapped) drivers.
> Both drivers implement (produce) the same interface sdhci, that provides the
> readw - readq - writeq functions.
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/Makefile.include |   1 +
>  tests/libqos/sdhci.c   | 163 +++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/libqos/sdhci.h   |  70 +++++++++++++++++++++
>  3 files changed, 234 insertions(+)
>  create mode 100644 tests/libqos/sdhci.c
>  create mode 100644 tests/libqos/sdhci.h
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 1266109..66c7848 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -678,6 +678,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
>  # Devices
>  qos-test-obj-y = tests/qos-test.o $(libqgraph-obj-y)
>  qos-test-obj-y += $(libqos-pc-obj-y)
> +qos-test-obj-y += tests/libqos/sdhci.o
>  
>  # Machines
>  qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
> diff --git a/tests/libqos/sdhci.c b/tests/libqos/sdhci.c
> new file mode 100644
> index 0000000..0685bee
> --- /dev/null
> +++ b/tests/libqos/sdhci.c
> @@ -0,0 +1,163 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "libqos/qgraph.h"
> +#include "pci.h"
> +#include "sdhci.h"
> +#include "hw/pci/pci.h"
> +
> +static void set_qsdhci_fields(QSDHCI *s, uint8_t version, uint8_t baseclock,
> +                              bool sdma, uint64_t reg)
> +{
> +    s->props.version = version;
> +    s->props.baseclock = baseclock;
> +    s->props.capab.sdma = sdma;
> +    s->props.capab.reg = reg;
> +}
> +
> +/* Memory mapped implementation of QSDHCI */
> +
> +static uint16_t sdhci_mm_readw(QSDHCI *s, uint32_t reg)
> +{
> +    QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
> +    return qtest_readw(smm->qts, smm->addr + reg);
> +}
> +
> +static uint64_t sdhci_mm_readq(QSDHCI *s, uint32_t reg)
> +{
> +    QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
> +    return qtest_readq(smm->qts, smm->addr + reg);
> +}
> +
> +static void sdhci_mm_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
> +{
> +    QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
> +    qtest_writeq(smm->qts, smm->addr + reg, val);
> +}
> +
> +static void *sdhci_mm_get_driver(void *obj, const char *interface)
> +{
> +    QSDHCI_MemoryMapped *smm = obj;
> +    if (!g_strcmp0(interface, "sdhci")) {
> +        return &smm->sdhci;
> +    }
> +    fprintf(stderr, "%s not present in generic-sdhci\n", interface);
> +    g_assert_not_reached();
> +}
> +
> +void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts,
> +		       uint32_t addr, QSDHCIProperties *common)
> +{
> +    sdhci->obj.get_driver = sdhci_mm_get_driver;
> +    sdhci->sdhci.readw = sdhci_mm_readw;
> +    sdhci->sdhci.readq = sdhci_mm_readq;
> +    sdhci->sdhci.writeq = sdhci_mm_writeq;
> +    memcpy(&sdhci->sdhci.props, common, sizeof(QSDHCIProperties));
> +    sdhci->addr = addr;
> +    sdhci->qts = qts;
> +}
> +
> +/* PCI implementation of QSDHCI */
> +
> +static uint16_t sdhci_pci_readw(QSDHCI *s, uint32_t reg)
> +{
> +    QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
> +    return qpci_io_readw(&spci->dev, spci->mem_bar, reg);
> +}
> +
> +static uint64_t sdhci_pci_readq(QSDHCI *s, uint32_t reg)
> +{
> +    QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
> +    return qpci_io_readq(&spci->dev, spci->mem_bar, reg);
> +}
> +
> +static void sdhci_pci_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
> +{
> +    QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
> +    return qpci_io_writeq(&spci->dev, spci->mem_bar, reg, val);
> +}
> +
> +static void *sdhci_pci_get_driver(void *object, const char *interface)
> +{
> +    QSDHCI_PCI *spci = object;
> +    if (!g_strcmp0(interface, "sdhci")) {
> +        return &spci->sdhci;
> +    }
> +
> +    fprintf(stderr, "%s not present in sdhci-pci\n", interface);
> +    g_assert_not_reached();
> +}
> +
> +static void sdhci_pci_start_hw(QOSGraphObject *obj)
> +{
> +    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
> +    qpci_device_enable(&spci->dev);
> +}
> +
> +static void sdhci_destructor(QOSGraphObject *obj)

sdhci_pci_destructor()

> +{
> +    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
> +    qpci_iounmap(&spci->dev, spci->mem_bar);
> +}
> +
> +static void *sdhci_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
> +{
> +    QSDHCI_PCI *spci = g_new0(QSDHCI_PCI, 1);
> +    QPCIBus *bus = pci_bus;
> +    uint64_t barsize;
> +
> +    qpci_device_init(&spci->dev, bus, addr);
> +    spci->mem_bar = qpci_iomap(&spci->dev, 0, &barsize);
> +    spci->sdhci.readw = sdhci_pci_readw;
> +    spci->sdhci.readq = sdhci_pci_readq;
> +    spci->sdhci.writeq = sdhci_pci_writeq;
> +    set_qsdhci_fields(&spci->sdhci, 2, 0, 1, 0x057834b4);
> +
> +    spci->obj.get_driver = sdhci_pci_get_driver;
> +    spci->obj.start_hw = sdhci_pci_start_hw;
> +    spci->obj.destructor = sdhci_destructor;
> +    return &spci->obj;
> +}
> +
> +static void qsdhci_register_nodes(void)
> +{
> +    QPCIAddress addr = {
> +        .devfn = QPCI_DEVFN(4, 0),
> +        .vendor_id = PCI_VENDOR_ID_REDHAT,
> +        .device_id = PCI_DEVICE_ID_REDHAT_SDHCI,
> +    };
> +
> +    QOSGraphEdgeOptions opts = {
> +        .extra_device_opts = "addr=04.0",

Shouldn't this be formatted from the previous QPCIAddress?

> +    };
> +
> +    /* generic-sdhci */
> +    qos_node_create_driver("generic-sdhci", NULL);
> +    qos_node_produces("generic-sdhci", "sdhci");
> +
> +    /* sdhci-pci */
> +    add_qpci_address(&opts, &addr);
> +    qos_node_create_driver("sdhci-pci", sdhci_pci_create);
> +    qos_node_produces("sdhci-pci", "sdhci");
> +    qos_node_consumes("sdhci-pci", "pci-bus", &opts);
> +
> +}
> +
> +libqos_init(qsdhci_register_nodes);
> diff --git a/tests/libqos/sdhci.h b/tests/libqos/sdhci.h
> new file mode 100644
> index 0000000..e9880fc
> --- /dev/null
> +++ b/tests/libqos/sdhci.h
> @@ -0,0 +1,70 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#ifndef QGRAPH_QSDHCI
> +#define QGRAPH_QSDHCI
> +
> +#include "libqos/qgraph.h"
> +#include "pci.h"
> +
> +typedef struct QSDHCI QSDHCI;
> +typedef struct QSDHCI_MemoryMapped QSDHCI_MemoryMapped;
> +typedef struct QSDHCI_PCI  QSDHCI_PCI;
> +typedef struct QSDHCIProperties QSDHCIProperties;
> +
> +/* Properties common to all QSDHCI devices */
> +struct QSDHCIProperties {
> +    uint8_t version;
> +    uint8_t baseclock;
> +    struct {
> +        bool sdma;
> +        uint64_t reg;
> +    } capab;
> +};
> +
> +struct QSDHCI {
> +    uint16_t (*readw)(QSDHCI *s, uint32_t reg);
> +    uint64_t (*readq)(QSDHCI *s, uint32_t reg);
> +    void (*writeq)(QSDHCI *s, uint32_t reg, uint64_t val);
> +    QSDHCIProperties props;
> +};
> +
> +/* Memory Mapped implementation of QSDHCI */
> +struct QSDHCI_MemoryMapped {
> +    QOSGraphObject obj;
> +    QTestState *qts;

Maybe 'teststate' or 'state' rather than 'qts'.

> +    QSDHCI sdhci;
> +    uint64_t addr;
> +};
> +
> +/* PCI implementation of QSDHCI */
> +struct QSDHCI_PCI {
> +    QOSGraphObject obj;
> +    QPCIDevice dev;
> +    QSDHCI sdhci;
> +    QPCIBar mem_bar;
> +};
> +
> +/**
> + * qos_init_sdhci_mm(): external constructor used by all drivers/machines
> + * that "contain" a #QSDHCI_MemoryMapped driver
> + */
> +void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts,
> +		       uint32_t addr, QSDHCIProperties *common);
> +
> +#endif
> 

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>

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

* Re: [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (71 preceding siblings ...)
  2018-12-03 20:45 ` [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework no-reply
@ 2018-12-12 15:15 ` Philippe Mathieu-Daudé
  2018-12-12 15:31 ` Philippe Mathieu-Daudé
  73 siblings, 0 replies; 103+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-12-12 15:15 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

Hi Paolo,

On 12/3/18 4:32 PM, Paolo Bonzini wrote:
> Patches 1-14 are actually a refactoring of vhost and vhost-user-test so
> that it can be "qtested" on all targets that support virtio-net.
> 
> Patches 15-18 are other small refactorings to the libqos library and fixes
> to the Makefile.
> 
> Patch 19 is the framework, including unit tests, while the rest is conversions
> of existing tests.  We tried to pick tests that used a mix of features of
> qtest, and that cover as many use cases as possible within qgraph. 
> In particular:
> 
> - sdhci-test was the motivating example for the duplication between
>   PCI and MMIO versions of the same devices, so it come first
> 
> - all virtio tests were converted, since they also have both MMIO and
>   PCI variants and they taught us a lot about modeling devices within
>   qgraph
> 
> - all PCI devices that had "nop" tests only were converted, so that they
>   can avoid defining their copy of the test, and can instead use a
>   common test
> 
> - finally, three more PCI devices were converted as an example - e1000e,
>   nvme and megasas
> 
> This submission includes quite a few changes and cleanups that we did
> not manage to complete before Emanuele restarted classes, but this
> is almost entirely his baby; don't be fooled by the number of patches
> authored by him vs. myself.  I have noted my changes to the framework
> in the commit message to patch 19, to help people that followed the
> previous submissions; apart from that my changes consist of porting
> vhost-user-test and turning the nop tests into generic PCI and virtio
> tests (even though Emanuele had done the conversion to qgraph, he had
> left the tests in the nodes due to lack of time).

I'v tested the series and am quite happy with it.
I did not notice anything particular that could block it.
I'll send some comments in few patches that often apply to various patches.

Series:
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Regards,

Phil.

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

* Re: [Qemu-devel] [PATCH 22/71] tests/libqos: sdhci driver and interface nodes
  2018-12-12 14:35   ` Philippe Mathieu-Daudé
@ 2018-12-12 15:25     ` Paolo Bonzini
  0 siblings, 0 replies; 103+ messages in thread
From: Paolo Bonzini @ 2018-12-12 15:25 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

On 12/12/18 15:35, Philippe Mathieu-Daudé wrote:
>> +}
>> +
>> +static void qsdhci_register_nodes(void)
>> +{
>> +    QPCIAddress addr = {
>> +        .devfn = QPCI_DEVFN(4, 0),
>> +        .vendor_id = PCI_VENDOR_ID_REDHAT,
>> +        .device_id = PCI_DEVICE_ID_REDHAT_SDHCI,
>> +    };
>> +
>> +    QOSGraphEdgeOptions opts = {
>> +        .extra_device_opts = "addr=04.0",
> Shouldn't this be formatted from the previous QPCIAddress?
> 

Maybe, but there isn't a way to couple the two for now.  A device
address allocator is on the todo list. :)

Paolo

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

* Re: [Qemu-devel] [PATCH 23/71] tests/libqos: arm/raspi2 machine node
  2018-12-03 15:32 ` [Qemu-devel] [PATCH 23/71] tests/libqos: arm/raspi2 machine node Paolo Bonzini
@ 2018-12-12 15:26   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 103+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-12-12 15:26 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel, Peter Maydell
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

Hi Paolo,

On 12/3/18 4:32 PM, Paolo Bonzini wrote:
> From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> Add arm/raspi2 machine to the graph. This machine contains a generic-sdhci, so
> its constructor must take care of setting it properly when called.
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/Makefile.include            |  1 +
>  tests/libqos/arm-raspi2-machine.c | 91 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 92 insertions(+)
>  create mode 100644 tests/libqos/arm-raspi2-machine.c
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 66c7848..75951f8 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -681,6 +681,7 @@ qos-test-obj-y += $(libqos-pc-obj-y)
>  qos-test-obj-y += tests/libqos/sdhci.o
>  
>  # Machines
> +qos-test-obj-y += tests/libqos/arm-raspi2-machine.o
>  qos-test-obj-y += tests/libqos/x86_64_pc-machine.o
>  
>  check-unit-y += tests/test-qgraph$(EXESUF)
> diff --git a/tests/libqos/arm-raspi2-machine.c b/tests/libqos/arm-raspi2-machine.c
> new file mode 100644
> index 0000000..3aff670
> --- /dev/null
> +++ b/tests/libqos/arm-raspi2-machine.c
> @@ -0,0 +1,91 @@
> +/*
> + * libqos driver framework
> + *
> + * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "libqos/malloc.h"
> +#include "libqos/qgraph.h"
> +#include "sdhci.h"
> +
> +#define ARM_PAGE_SIZE             4096
> +#define RASPI2_RAM_ADDR           0
> +#define RASPI2_RAM_SIZE           0x20000000
> +
> +typedef struct QRaspi2Machine QRaspi2Machine;
> +
> +struct QRaspi2Machine {
> +    QOSGraphObject obj;
> +    QGuestAllocator alloc;
> +    QSDHCI_MemoryMapped sdhci;
> +};
> +
> +static void *raspi2_get_driver(void *object, const char *interface)
> +{
> +    QRaspi2Machine *machine = object;
> +    if (!g_strcmp0(interface, "memory")) {
> +        return &machine->alloc;
> +    }
> +
> +    fprintf(stderr, "%s not present in arm/raspi2\n", interface);

I'd cocci-replace fprintf(stderr) -> g_printerr()

> +    g_assert_not_reached();
> +}
> +
> +static QOSGraphObject *raspi2_get_device(void *obj, const char *device)
> +{
> +    QRaspi2Machine *machine = obj;
> +    if (!g_strcmp0(device, "generic-sdhci")) {
> +        return &machine->sdhci.obj;
> +    }
> +
> +    fprintf(stderr, "%s not present in arm/raspi2\n", device);
> +    g_assert_not_reached();
> +}
> +
> +static void raspi2_destructor(QOSGraphObject *obj)
> +{
> +    QRaspi2Machine *machine = (QRaspi2Machine *) obj;
> +    alloc_destroy(&machine->alloc);
> +}
> +
> +static void *qos_create_machine_arm_raspi2(QTestState *qts)
> +{
> +    QRaspi2Machine *machine = g_new0(QRaspi2Machine, 1);
> +
> +    alloc_init(&machine->alloc, 0,
> +               RASPI2_RAM_ADDR + (1 << 20),
> +               RASPI2_RAM_ADDR + RASPI2_RAM_SIZE,

This code is not obvious.

> +               ARM_PAGE_SIZE);
> +    machine->obj.get_device = raspi2_get_device;
> +    machine->obj.get_driver = raspi2_get_driver;
> +    machine->obj.destructor = raspi2_destructor;
> +    qos_init_sdhci_mm(&machine->sdhci, qts, 0x3f300000, &(QSDHCIProperties) {
> +        .version = 3,
> +        .baseclock = 52,
> +        .capab.sdma = false,
> +        .capab.reg = 0x052134b4
> +    });
> +    return &machine->obj;
> +}
> +
> +static void raspi2_register_nodes(void)
> +{
> +    qos_node_create_machine("arm/raspi2", qos_create_machine_arm_raspi2);
> +    qos_node_contains("arm/raspi2", "generic-sdhci", NULL);

Shouldn't we also register all the arm/ machines under the aarch64/
node? If we simply duplicate the same tests, then no.

> +}
> +
> +libqos_init(raspi2_register_nodes);
> 

We could generate this file from a YAML :)

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

* Re: [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework
  2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
                   ` (72 preceding siblings ...)
  2018-12-12 15:15 ` Philippe Mathieu-Daudé
@ 2018-12-12 15:31 ` Philippe Mathieu-Daudé
  73 siblings, 0 replies; 103+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-12-12 15:31 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: Thomas Huth, Emanuele Giuseppe Esposito, Laurent Vivier

On 12/3/18 4:32 PM, Paolo Bonzini wrote:
>   tests: qgraph API for the qtest driver framework
>   tests/libqos: pci-pc driver and interface nodes
>   tests/libqos: x86_64/pc machine node
>   tests/libqos: sdhci driver and interface nodes
>   tests/libqos: arm/raspi2 machine node
>   tests/libqos: arm/smdkc210 machine node
>   tests/libqos: arm/sabrelite machine node
>   tests/libqos: arm/xilinx-zynq-a9 machine node
>   tests/libqos: aarch64/xlnx-zcu102 machine node
>   qos-test: sdhci test node

For the previous patches:
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

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

end of thread, other threads:[~2018-12-12 15:31 UTC | newest]

Thread overview: 103+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-03 15:32 [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 01/71] vhost-net: move stubs to a separate file Paolo Bonzini
2018-12-03 21:10   ` Eric Blake
2018-12-04 16:04   ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 02/71] vhost-net-user: add stubs for when no virtio-net device is present Paolo Bonzini
2018-12-06 13:29   ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 03/71] vhost: restrict Linux dependency to kernel vhost Paolo Bonzini
2018-12-06 13:36   ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 04/71] vhost-net: compile it on all targets that have virtio-net Paolo Bonzini
2018-12-06 13:45   ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 05/71] vhost-net: revamp configure logic Paolo Bonzini
2018-12-06 16:12   ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 06/71] vhost-user-test: use g_cond_broadcast Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 07/71] vhost-user-test: signal data_cond when s->rings changes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 08/71] vhost-user: support cross-endian vnet headers Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 09/71] vhost-user-test: support VHOST_USER_PROTOCOL_F_CROSS_ENDIAN Paolo Bonzini
2018-12-06 16:15   ` Thomas Huth
2018-12-06 20:06     ` Paolo Bonzini
2018-12-07  5:50       ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 10/71] vhost-user-test: skip if there is no memory at address 0 Paolo Bonzini
2018-12-06 16:26   ` Thomas Huth
2018-12-06 20:06     ` Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 11/71] vhost-user-test: reduce usage of global_qtest Paolo Bonzini
2018-12-06 16:36   ` Thomas Huth
2018-12-06 20:08     ` Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 12/71] vhost-user-test: create a main loop per TestServer Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 13/71] vhost-user-test: small changes to init_hugepagefs Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 14/71] vhost-user-test: create a temporary directory per TestServer Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 15/71] tests/libqos: introduce virtio_start_device Paolo Bonzini
2018-12-07  9:16   ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 16/71] tests/libqos: rename qpci_init_pc and qpci_init_spapr functions Paolo Bonzini
2018-12-07  9:23   ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 17/71] tests: remove rule for nonexisting qdev-monitor-test Paolo Bonzini
2018-12-07  9:24   ` Thomas Huth
2018-12-12 14:12   ` Philippe Mathieu-Daudé
2018-12-03 15:32 ` [Qemu-devel] [PATCH 18/71] tests/libqos: embed allocators instead of malloc-ing them Paolo Bonzini
2018-12-07 12:32   ` Thomas Huth
2018-12-07 13:57     ` Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 19/71] tests: qgraph API for the qtest driver framework Paolo Bonzini
2018-12-07 12:42   ` Thomas Huth
2018-12-07 13:57     ` Paolo Bonzini
2018-12-07 15:38   ` Thomas Huth
2018-12-12 11:09     ` Paolo Bonzini
2018-12-12 11:47       ` Thomas Huth
2018-12-03 15:32 ` [Qemu-devel] [PATCH 20/71] tests/libqos: pci-pc driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 21/71] tests/libqos: x86_64/pc machine node Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 22/71] tests/libqos: sdhci driver and interface nodes Paolo Bonzini
2018-12-12 14:35   ` Philippe Mathieu-Daudé
2018-12-12 15:25     ` Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 23/71] tests/libqos: arm/raspi2 machine node Paolo Bonzini
2018-12-12 15:26   ` Philippe Mathieu-Daudé
2018-12-03 15:32 ` [Qemu-devel] [PATCH 24/71] tests/libqos: arm/smdkc210 " Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 25/71] tests/libqos: arm/sabrelite " Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 26/71] tests/libqos: arm/xilinx-zynq-a9 " Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 27/71] tests/libqos: aarch64/xlnx-zcu102 " Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 28/71] qos-test: sdhci test node Paolo Bonzini
2018-12-12 14:28   ` Philippe Mathieu-Daudé
2018-12-03 15:32 ` [Qemu-devel] [PATCH 29/71] tests/qgraph: add generic PCI testcases Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 30/71] tests/libqos: pci-spapr driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 31/71] tests/qgraph: ppc64/pseries machine node Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 32/71] tests/libqos: has_buggy_msi flag Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 33/71] tests/libqos: e1000e driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 34/71] qos-test: e1000e test node Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 35/71] tests/libqos: virtio-pci driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 36/71] tests/libqos: remove global_qtest from virtio endianness checks Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 37/71] tests/libqos: virtio-mmio driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 38/71] tests/libqos: arm/virt machine node Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 39/71] tests/qgraph: add generic virtio testcases Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 40/71] tests/libqos: virtio-serial driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 41/71] qos-test: virtio-console and virtio-serial test node Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 42/71] tests/libqos: virtio-9p driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 43/71] qos-test: virtio-9p test node Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 44/71] tests/libqos: virtio-balloon driver and interface nodes Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 45/71] tests/qgraph: remove virtio-balloon-test Paolo Bonzini
2018-12-03 15:32 ` [Qemu-devel] [PATCH 46/71] tests/libqos: virtio-rng driver and interface nodes Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 47/71] qos-test: virtio-rng test node Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 48/71] tests/libqos: virtio-blk driver and interface nodes Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 49/71] qos-test: virtio-blk test node Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 50/71] tests/libqos: virtio-net driver and interface nodes Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 51/71] qos-test: virtio-net test node Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 52/71] tests/libqos: support multiqueue for virtio-net Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 53/71] vhost-user-test: always use 256 MiB of guest memory Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 54/71] qos-test: vhost-user test node Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 55/71] tests/libqos: virtio-scsi driver and interface nodes Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 56/71] qos-test: virtio-scsi test node Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 57/71] tests/libqos: remove pre-qgraph QVirtioPCIDevice API Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 58/71] tests: move virtio entirely to qos-test Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 59/71] qos-test: ac97 test node Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 60/71] qos-test: tpci200 " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 61/71] qos-test: ipoctal232 " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 62/71] qos-test: ne2k_pci " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 63/71] qos-test: nvme " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 64/71] qos-test: pcnet " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 65/71] qos-test: spapr-phb " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 66/71] qos-test: usb-hcd-ohci " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 67/71] qos-test: vmxnet3 " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 68/71] qos-test: es1370 " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 69/71] qos-test: eepro100 " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 70/71] qos-test: e1000 " Paolo Bonzini
2018-12-03 15:33 ` [Qemu-devel] [PATCH 71/71] qos-test: megasas " Paolo Bonzini
2018-12-03 20:45 ` [Qemu-devel] [PATCH for-4.0 00/71] qtest: qgraph driver framework no-reply
2018-12-12 15:15 ` Philippe Mathieu-Daudé
2018-12-12 15:31 ` Philippe Mathieu-Daudé

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.