All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/34] Qtest driver framework
@ 2018-08-06 14:33 Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 01/34] tests: qgraph API for the qtest " Emanuele Giuseppe Esposito
                   ` (34 more replies)
  0 siblings, 35 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

qgraph API for the qtest driver framework

This series of patches introduce a different qtest driver
organization, viewing machines, drivers and tests as node in a
graph, each having one or multiple edges relations.

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:
- MACHINE:   for example "arm/raspi2"
- DRIVER:    for example "generic-sdhci"
- INTERFACE: for example "sdhci" (interface for all "-sdhci" drivers)
- TEST:      for example "sdhci-test", consumes an interface and tests
             the functions provided

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
- 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.

This work is being done as Google Summer of Code 2018 project for QEMU,
my mentors are Paolo Bonzini and Laurent Vivier.
Additional infos on the project can be found at:
https://wiki.qemu.org/Features/qtest_driver_framework

v2:
- added command line arguments caching
- converted all virtio tests
- converted e1000e test
- added two more machines (virt and ppc64)
- introduced separation between edge-name (used by get_driver) and
  node-name (matched with QMP query result)
- edge carries also additional arguments, like the pci address of
  destination device
- test now can execute a function before and after the command line
  is allocated, to allocate various file and sockets needed by command
  line and test
- better documentation with working example in qgraph.h
- removed esplicit creation of interfaces

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

Emanuele Giuseppe Esposito (33):
  tests: qgraph API for the qtest driver framework
  tests/qgraph: rename qpci_init_pc functions
  tests/qgraph: pci-pc driver and interface nodes
  tests/qgraph: x86_64/pc machine node
  tests/qgraph: sdhci driver and interface nodes
  tests/qgraph: sdhci test node
  tests/qgraph: arm/raspi2 machine node
  tests/qgraph: rename qpci_init_spapr functions
  tests/qgraph: pci-spapr driver and interface nodes
  tests/qgraph: ppc64/pseries machine node
  test/qgraph: e1000e driver and interface nodes
  test/qgraph: e1000e-test node
  test/qgraph: virtio_start_device function
  test/qgraph: virtio-pci driver and interface nodes
  tests/qgraph: rename qvirtio_mmio_init_device functions
  test/qgraph: virtio-mmio driver and interface nodes
  test/qgraph: arm/virt machine node
  test/qgraph: virtio-serial driver and interface nodes
  test/qgraph: virtio-console test node
  test/qgraph: virtio-serial test node
  test/qgraph: virtio-9p driver and interface nodes
  test/qgraph: virtio-9p test node
  test/qgraph: virtio-balloon driver and interface nodes
  test/qgraph: virtio-balloon test node
  test/qgraph: virtio-rng driver and interface nodes
  test/qgraph: virtio-rng test node
  test/qgraph: virtio-blk driver and interface nodes
  test/qgraph: virtio-blk test node
  test/qgraph: virtio-net driver and interface nodes
  test/qgraph: virtio-net test node
  test/qgraph: virtio-scsi driver and interface nodes
  test/qgraph: virtio-scsi test node
  test/qgraph: temporarly commented vhost-user-test

Paolo Bonzini (1):
  tests: virtio: separate ccw tests from libqos

 configure                            |   2 +-
 include/qemu/module.h                |   2 +
 tests/Makefile.include               |  79 +--
 tests/e1000e-test.c                  | 354 +++----------
 tests/i440fx-test.c                  |   2 +-
 tests/ide-test.c                     |   2 +-
 tests/libqos/ahci.c                  |   2 +-
 tests/libqos/e1000e.c                | 262 ++++++++++
 tests/libqos/e1000e.h                |  53 ++
 tests/libqos/libqos-pc.c             |   2 +-
 tests/libqos/libqos-spapr.c          |   2 +-
 tests/libqos/pci-pc.c                |  41 +-
 tests/libqos/pci-pc.h                |  22 +-
 tests/libqos/pci-spapr.c             |  57 ++-
 tests/libqos/pci-spapr.h             |  26 +-
 tests/libqos/pci.c                   |  48 +-
 tests/libqos/pci.h                   |  15 +
 tests/libqos/ppc64_pseries-machine.c | 111 +++++
 tests/libqos/qgraph.c                | 721 +++++++++++++++++++++++++++
 tests/libqos/qgraph.h                | 514 +++++++++++++++++++
 tests/libqos/qgraph_extra.h          | 263 ++++++++++
 tests/libqos/raspi2-machine.c        |  82 +++
 tests/libqos/sdhci.c                 | 163 ++++++
 tests/libqos/sdhci.h                 |  69 +++
 tests/libqos/virt-machine.c          |  90 ++++
 tests/libqos/virtio-9p.c             | 164 ++++++
 tests/libqos/virtio-9p.h             |  42 ++
 tests/libqos/virtio-balloon.c        | 111 +++++
 tests/libqos/virtio-balloon.h        |  39 ++
 tests/libqos/virtio-blk.c            | 126 +++++
 tests/libqos/virtio-blk.h            |  40 ++
 tests/libqos/virtio-mmio.c           |  72 ++-
 tests/libqos/virtio-mmio.h           |   6 +-
 tests/libqos/virtio-net.c            | 177 +++++++
 tests/libqos/virtio-net.h            |  41 ++
 tests/libqos/virtio-pci.c            |  80 ++-
 tests/libqos/virtio-pci.h            |  12 +
 tests/libqos/virtio-rng.c            | 108 ++++
 tests/libqos/virtio-rng.h            |  39 ++
 tests/libqos/virtio-scsi.c           | 117 +++++
 tests/libqos/virtio-scsi.h           |  39 ++
 tests/libqos/virtio-serial.c         | 109 ++++
 tests/libqos/virtio-serial.h         |  39 ++
 tests/libqos/virtio.c                |   9 +
 tests/libqos/virtio.h                |   1 +
 tests/libqos/x86_64_pc-machine.c     | 110 ++++
 tests/q35-test.c                     |   4 +-
 tests/qos-test.c                     | 480 ++++++++++++++++++
 tests/rtl8139-test.c                 |   2 +-
 tests/sdhci-test.c                   | 222 +++------
 tests/tco-test.c                     |   2 +-
 tests/test-qgraph.c                  | 446 +++++++++++++++++
 tests/usb-hcd-ehci-test.c            |   2 +-
 tests/vhost-user-test.c              |   7 +-
 tests/virtio-9p-test.c               | 221 +++-----
 tests/virtio-balloon-test.c          |  22 +-
 tests/virtio-blk-test.c              | 473 +++++++-----------
 tests/virtio-ccw-test.c              | 121 +++++
 tests/virtio-console-test.c          |  30 +-
 tests/virtio-net-test.c              | 163 ++----
 tests/virtio-rng-test.c              |  25 +-
 tests/virtio-scsi-test.c             | 155 +++---
 tests/virtio-serial-test.c           |  27 +-
 63 files changed, 5624 insertions(+), 1243 deletions(-)
 create mode 100644 tests/libqos/e1000e.c
 create mode 100644 tests/libqos/e1000e.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_extra.h
 create mode 100644 tests/libqos/raspi2-machine.c
 create mode 100644 tests/libqos/sdhci.c
 create mode 100644 tests/libqos/sdhci.h
 create mode 100644 tests/libqos/virt-machine.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/qos-test.c
 create mode 100644 tests/test-qgraph.c
 create mode 100644 tests/virtio-ccw-test.c

-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 01/34] tests: qgraph API for the qtest driver framework
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 02/34] tests/qgraph: rename qpci_init_pc functions Emanuele Giuseppe Esposito
                   ` (33 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 configure                   |   2 +-
 include/qemu/module.h       |   2 +
 tests/Makefile.include      |  12 +-
 tests/libqos/qgraph.c       | 721 ++++++++++++++++++++++++++++++++++++
 tests/libqos/qgraph.h       | 514 +++++++++++++++++++++++++
 tests/libqos/qgraph_extra.h | 263 +++++++++++++
 tests/qos-test.c            | 480 ++++++++++++++++++++++++
 tests/test-qgraph.c         | 446 ++++++++++++++++++++++
 8 files changed, 2437 insertions(+), 3 deletions(-)
 create mode 100644 tests/libqos/qgraph.c
 create mode 100644 tests/libqos/qgraph.h
 create mode 100644 tests/libqos/qgraph_extra.h
 create mode 100644 tests/qos-test.c
 create mode 100644 tests/test-qgraph.c

diff --git a/configure b/configure
index 2a7796ea80..85a108506a 100755
--- a/configure
+++ b/configure
@@ -7352,7 +7352,7 @@ if test "$ccache_cpp2" = "yes"; then
 fi
 
 # build tree in object directory in case the source is not in the current directory
-DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm"
+DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm 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 54300ab6e5..1fcdca084d 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 a49282704e..eabf9ed8b4 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -755,8 +755,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
-libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.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/i2c.o tests/libqos/libqos.o
 libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
 libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
 libqos-spapr-obj-y += tests/libqos/rtas.o
@@ -769,6 +771,12 @@ 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
 
+check-unit-y += tests/test-qgraph$(EXESUF)
+tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
+
+check-qtest-pci-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/device-introspect-test$(EXESUF): tests/device-introspect-test.o
 tests/rtc-test$(EXESUF): tests/rtc-test.o
diff --git a/tests/libqos/qgraph.c b/tests/libqos/qgraph.c
new file mode 100644
index 0000000000..786a1fdb45
--- /dev/null
+++ b/tests/libqos/qgraph.c
@@ -0,0 +1,721 @@
+/*
+ * 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_extra.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 *after_command_line; /* added after node cmd_line, "," is
+                               * automatically added
+                               */
+    char *before_command_line;/* added before node cmd_line */
+    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);
+    const char *comma;
+    const char *space;
+
+    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->before_command_line = g_strdup(opts->before_cmd_line);
+    edge->arg = g_memdup(opts->arg, opts->size_arg);
+
+    space = opts->after_cmd_line ? " " : "";
+    comma = opts->extra_device_opts ? "," : "";
+    opts->extra_device_opts =  opts->extra_device_opts ? : "";
+
+    edge->after_command_line = g_strconcat(comma, opts->extra_device_opts,
+                                           space, opts->after_cmd_line, 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_command_line);
+        g_free(temp->after_command_line);
+        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);
+    if (node->type == QNODE_TEST && node->u.test.arg) {
+        g_free(node->u.test.arg);
+    }
+    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_get_edge_type(const char *node1, const char *node2)
+{
+    QOSGraphEdgeList *list = get_edgelist(node1);
+    QOSGraphEdge *e = search_list_edges(list, node2);
+    if (e) {
+        return e->type;
+    }
+    return -1;
+}
+
+char *qos_graph_get_edge_dest(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->dest;
+}
+
+void *qos_graph_get_edge_arg(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->arg;
+}
+
+char *qos_graph_get_edge_after_cmd_line(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->after_command_line;
+}
+
+char *qos_graph_get_edge_before_cmd_line(QOSGraphEdge *edge)
+{
+    if (!edge) {
+        return NULL;
+    }
+    return edge->before_command_line;
+}
+
+char *qos_graph_get_edge_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;
+
+    if (!opts) {
+        opts = &(QOSGraphTestOptions) { };
+    }
+    node = create_node(name, QNODE_TEST);
+    node->u.test.function = test_func;
+    node->u.test.arg = g_memdup(opts->edge.arg, opts->edge.size_arg);
+
+    /* reset arg and size_arg since they are not needed by test */
+    opts->edge.arg = NULL;
+    opts->edge.size_arg = 0;
+
+    node->u.test.before = opts->before;
+    node->u.test.after = opts->after;
+    node->available = TRUE;
+    add_edge(interface, name, QEDGE_CONSUMED_BY, &opts->edge);
+}
+
+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);
+}
+
+void qos_destroy_object(QOSGraphObject *obj)
+{
+    if (!obj || !(obj->destructor)) {
+        return;
+    }
+    obj->destructor(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 0000000000..b2b5e66e96
--- /dev/null
+++ b/tests/libqos/qgraph.h
@@ -0,0 +1,514 @@
+/*
+ * 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) (void);
+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) (char **cmd_line);
+typedef void (*QOSAfterTest) (void);
+
+/* Driver options functions */
+typedef void *(*QOSBeforeDriver) (char **cmd_line);
+
+/**
+ * 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
+ *                  "guest_allocator"
+ * - 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.
+                                 */
+    QOSBeforeTest before;       /* executed before the test. Can also add
+                                 * additional parameters to the command line
+                                 */
+    QOSAfterTest after;         /* executed after the test, used to free
+                                 * things allocated by @before
+                                 */
+};
+
+/**
+ * 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;
+};
+
+/**
+ * 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 the edge 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 the edge 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 the edge 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);
+
+#endif
diff --git a/tests/libqos/qgraph_extra.h b/tests/libqos/qgraph_extra.h
new file mode 100644
index 0000000000..6dd0145a18
--- /dev/null
+++ b/tests/libqos/qgraph_extra.h
@@ -0,0 +1,263 @@
+/*
+ * 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 {
+            QOSBeforeDriver before; /* used when the driver needs additional
+                                     * command line mixed with file descriptors
+                                     * or reference made by invoking functions
+                                     */
+            QOSCreateDriverFunc constructor;
+        } driver;
+        struct {
+            QOSCreateMachineFunc constructor;
+        } machine;
+        struct {
+            QOSTestFunc function;
+            void *arg;
+            QOSBeforeTest before;
+            QOSAfterTest after;
+        } 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_get_edge_type(): returns the edge type
+ * of the edge linking of the node @start with @dest.
+ *
+ * Returns: on success: the %QOSEdgeType
+ *          otherwise: #-1
+ */
+QOSEdgeType qos_graph_get_edge_type(const char *start, const char *dest);
+
+/**
+ * qos_graph_get_edge_dest(): returns the name of the node
+ * pointed as destination of edge @edge.
+ *
+ * Returns: on success: the destination
+ *          otherwise: #NULL
+ */
+char *qos_graph_get_edge_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_get_edge_arg(): returns the args assigned
+ * to that @edge.
+ *
+ * Returns: on success: the arg
+ *          otherwise: #NULL
+ */
+void *qos_graph_get_edge_arg(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_get_edge_after_cmd_line(): returns the arg
+ * command line that will be added after the node cmd
+ * line.
+ *
+ * Returns: on success: the char* arg
+ *          otherwise: #NULL
+ */
+char *qos_graph_get_edge_after_cmd_line(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_get_edge_before_cmd_line(): returns the arg
+ * command line that will be added before the node cmd
+ * line.
+ *
+ * Returns: on success: the char* arg
+ *          otherwise: #NULL
+ */
+char *qos_graph_get_edge_before_cmd_line(QOSGraphEdge *edge);
+
+/**
+ * qos_graph_get_edge_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_get_edge_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_destroy_object(): calls the destructor for @obj
+ */
+void qos_destroy_object(QOSGraphObject *obj);
+
+/**
+ * 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/qos-test.c b/tests/qos-test.c
new file mode 100644
index 0000000000..1594d518f1
--- /dev/null
+++ b/tests/qos-test.c
@@ -0,0 +1,480 @@
+/*
+ * 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_extra.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));
+        g_assert(minfo);
+        qobj = qdict_get(minfo, "name");
+        g_assert(qobj);
+        qstr = qobject_to(QString, qobj);
+        g_assert(qstr);
+        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);
+            g_assert(qstr);
+
+            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);
+            g_assert(qbol);
+            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' }");
+    g_assert(response);
+    list = qdict_get_qlist(response, "return");
+    g_assert(list);
+
+    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);
+
+}
+
+/* small API to remember a subset of the allocated objects */
+typedef struct {
+    QOSGraphObject *obj;
+    char *name;
+} CollectorData;
+
+static CollectorData collector[(QOS_PATH_MAX_ELEMENT_SIZE * 2)];
+static int collector_size;
+
+static void destroy_objects(CollectorData *data)
+{
+    /* field @name is not free'd since it will be done when
+     * the node hash map will be destroyed
+     */
+    QOSGraphObject *obj = data->obj;
+    if (obj->destructor) {
+        obj->destructor(obj);
+    } else {
+        printf("Warning: Node %s allocates but does not provide"
+               " a destructor\n", data->name);
+    }
+}
+
+static void add_to_collector(QOSGraphObject *obj, char *name)
+{
+    if (collector_size == (QOS_PATH_MAX_ELEMENT_SIZE * 2)) {
+        printf("Warning: Collector full, more than %d object to allocate\n",
+               collector_size);
+        return;
+    }
+    collector[collector_size].name = name;
+    collector[collector_size].obj = obj;
+    collector_size++;
+}
+
+static void destroy_all_objects(void)
+{
+    int current = collector_size - 1;
+
+    while (current >= 0) {
+        destroy_objects(&collector[current]);
+        current--;
+    }
+}
+
+static void empty_collector(void)
+{
+    collector_size = 0;
+}
+
+static QGuestAllocator *get_machine_allocator(QOSGraphObject *obj, char *name)
+{
+    if (obj->get_driver) {
+        return obj->get_driver(obj, "guest_allocator");
+    } else {
+        printf("Warning: machine %s must produce"
+                "guest_allocator (returning NULL is fine)\n", name);
+    }
+    return NULL;
+}
+
+static void object_start_hw(QOSGraphObject *obj)
+{
+    if (obj->start_hw) {
+        obj->start_hw(obj);
+    }
+}
+
+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 execution (if active) and restart it with
+    * new command line
+    */
+    if (g_strcmp0(old_path, path)) {
+        if (old_path) {
+            qtest_end();
+            g_free(old_path);
+        }
+        old_path = path;
+        global_qtest = qtest_start(path);
+    } else { /* if cmd line is the same, reset the guest */
+        qmp_discard_response("{ 'execute': 'system_reset' }");
+        qmp_eventwait("RESET");
+    }
+}
+
+void qos_invalidate_command_line(void)
+{
+    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, its function is executed.
+ *
+ * Since only the machine and QEDGE_CONSUMED_BY nodes actually
+ * allocate something in the constructor, a garbage collector
+ * saves their pointer in an array, so that after execution
+ * they can be safely free'd.
+ *
+ * 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
+ * 4) start the hardware (*_device_enable functions)
+ * 5) start test
+ * 6) @after test function as defined in the given QOSGraphTestOptions
+ * 7) call all nodes destructor
+ *
+ */
+static void allocate_objects(const void *arg)
+{
+    QOSEdgeType etype;
+    QOSGraphEdge *edge = NULL;
+    QOSGraphNode *node, *test_node;
+    QOSGraphObject *obj;
+    QGuestAllocator *machine_a = NULL;
+    int current = 1, has_to_allocate = 0;
+    void *void_obj = NULL;
+    char **path = (char **) arg;
+
+    node = qos_graph_get_node(path[current]);
+
+    /* Before test */
+    test_node = qos_graph_get_node(path[(g_strv_length(path) - 1)]);
+    if (test_node->u.test.before) {
+        test_node->u.test.before(&path[0]);
+    }
+
+    while (current < QOS_PATH_MAX_ELEMENT_SIZE) {
+
+        /* Allocate objects */
+        switch (node->type) {
+        case QNODE_MACHINE:
+            restart_qemu_or_continue(path[0]);
+
+            void_obj = node->u.machine.constructor();
+            machine_a = get_machine_allocator(void_obj, node->name);
+            object_start_hw(void_obj);
+            add_to_collector(void_obj, node->name);
+            break;
+
+        case QNODE_DRIVER:
+            if (has_to_allocate) {
+                void_obj = node->u.driver.constructor(void_obj, machine_a,
+                                             qos_graph_get_edge_arg(edge));
+                add_to_collector(void_obj, node->name);
+            }
+            /* drivers can have an initializer even if they are contained */
+            object_start_hw(void_obj);
+            break;
+
+        case QNODE_TEST:
+            g_assert(test_node == node);
+            /* Execute test */
+            node->u.test.function(void_obj, node->u.test.arg, machine_a);
+
+            /* After test */
+            if (test_node->u.test.after) {
+                test_node->u.test.after();
+            }
+
+            /* Cleanup */
+            g_free(path);
+            destroy_all_objects();
+            empty_collector();
+            return;
+
+        default:
+            break;
+        }
+
+        edge = qos_graph_get_edge(path[current], path[(current + 1)]);
+        etype = qos_graph_get_edge_type(path[current], path[(current + 1)]);
+        current++;
+        node = qos_graph_get_node(path[current]);
+
+        obj = void_obj;
+
+        /* follow edge and get object for next node constructor */
+        switch (etype) {
+        case QEDGE_PRODUCES:
+            void_obj = obj->get_driver(void_obj, path[current]);
+            break;
+
+        case QEDGE_CONSUMED_BY:
+            has_to_allocate = 1;
+            break;
+
+        case QEDGE_CONTAINS:
+            void_obj = obj->get_device(void_obj, path[current]);
+            break;
+        }
+    }
+}
+
+/*
+ * in this function, 2 path will be built:
+ * str_path, a one-string path (ex "pc/i440FX-pcihost/...")
+ * ro_path, a string-array path (ex [0] = "pc", [1] = "i440FX-pcihost").
+ *
+ * str_path 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().
+ *
+ * ro_path 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 str_path, ro_path
+ * 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;
+
+    /* etype set to QEDGE_CONSUMED_BY so that machine can add command line */
+    QOSEdgeType etype = QEDGE_CONSUMED_BY;
+
+    /* twice QOS_PATH_MAX_ELEMENT_SIZE since each edge can have its arg */
+    char **ro_path = g_new0(char *, (QOS_PATH_MAX_ELEMENT_SIZE * 2));
+    int ro_path_size = 0;
+
+    char *machine = NULL, *arch = NULL;
+    char *after_cmd = NULL, *before_cmd = NULL;
+    char *node_name = orig_path->name, *gfreed, *str_path;
+
+    GString *cmd_line = g_string_new("");
+
+
+    path = qos_graph_get_node(node_name); /* root */
+    node_name = qos_graph_get_edge_dest(path->path_edge); /* machine name */
+
+    qos_separate_arch_machine(node_name, &arch, &machine);
+    ro_path[ro_path_size++] = arch;
+    ro_path[ro_path_size++] = machine;
+
+    do {
+        path = qos_graph_get_node(node_name);
+        node_name = qos_graph_get_edge_dest(path->path_edge);
+
+        if (before_cmd) {
+            g_string_append_printf(cmd_line, "%s ", before_cmd);
+        }
+
+        /* 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_cmd) {
+                g_string_append_printf(cmd_line, "%s ", after_cmd);
+            }
+        }
+
+        ro_path[ro_path_size++] = qos_graph_get_edge_name(path->path_edge);
+        /* detect if edge has command line args */
+        after_cmd = qos_graph_get_edge_after_cmd_line(path->path_edge);
+        before_cmd = qos_graph_get_edge_before_cmd_line(path->path_edge);
+        etype = qos_graph_get_edge_type(path->name, node_name);
+
+    } while (path->path_edge);
+
+
+    /* here position 0 has <arch>/<machine>, position 1 <machine>.
+     * the path must not have the <arch>, that's why ro_path  + 1
+     */
+    str_path = g_strjoinv("/", (ro_path + 1));
+    gfreed = g_string_free(cmd_line, FALSE);
+    /* put arch/machine in position 1 so allocate_objects can do its work
+     * and add the command line at position 0.
+     */
+    ro_path[0] = g_strdup(gfreed);
+    ro_path[1] = arch;
+
+    qtest_add_data_func(str_path, ro_path, allocate_objects);
+
+    g_free(str_path);
+}
+
+
+
+/**
+ * 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_LIBQOS);
+    qos_set_machines_devices_available();
+
+    qos_graph_foreach_test_path(walk_path);
+    g_test_run();
+    qos_graph_destroy();
+    return 0;
+}
diff --git a/tests/test-qgraph.c b/tests/test-qgraph.c
new file mode 100644
index 0000000000..c6aec3e9f5
--- /dev/null
+++ b/tests/test-qgraph.c
@@ -0,0 +1,446 @@
+/*
+ * 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_extra.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(void)
+{
+    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)
+{
+    qos_node_contains(machine, driver, NULL);
+    g_assert_nonnull(qos_graph_get_edge(machine, driver));
+    g_assert_cmpint(qos_graph_get_edge_type(machine, driver), ==,
+                    QEDGE_CONTAINS);
+    g_assert_cmpint(qos_graph_has_edge(machine, driver), ==, TRUE);
+}
+
+static void check_produces(const char *machine, const char *interface)
+{
+    qos_node_produces(machine, interface);
+    check_interface(interface);
+    g_assert_nonnull(qos_graph_get_edge(machine, interface));
+    g_assert_cmpint(qos_graph_get_edge_type(machine, interface), ==,
+                    QEDGE_PRODUCES);
+    g_assert_cmpint(qos_graph_has_edge(machine, interface), ==, TRUE);
+}
+
+static void check_consumes(const char *driver, const char *interface)
+{
+    qos_node_consumes(driver, interface, NULL);
+    check_interface(interface);
+    g_assert_nonnull(qos_graph_get_edge(interface, driver));
+    g_assert_cmpint(
+                    qos_graph_get_edge_type(interface, driver), ==,
+                    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)
+{
+    qos_add_test(test, interface, testfunct, NULL);
+    g_assert_cmpint(qos_graph_has_machine(test), ==, FALSE);
+    g_assert_nonnull(qos_graph_get_node(test));
+    g_assert_cmpint(qos_graph_has_node(test), ==, TRUE);
+    g_assert_cmpint(qos_graph_get_node_type(test), ==, QNODE_TEST);
+    g_assert_nonnull(qos_graph_get_edge(interface, test));
+    g_assert_cmpint(qos_graph_get_edge_type(interface, test), ==,
+                    QEDGE_CONSUMED_BY);
+    g_assert_cmpint(qos_graph_has_edge(interface, test), ==, TRUE);
+    g_assert_cmpint(qos_graph_get_node_availability(test), ==, TRUE);
+    qos_graph_node_set_availability(test, FALSE);
+    g_assert_cmpint(qos_graph_get_node_availability(test), ==, 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_full_alternative_path(void)
+{
+    qos_graph_init();
+    check_machine(MACHINE_RASPI2);
+    check_driver("B");
+    check_driver("C");
+    check_driver("E");
+    check_driver("F");
+    check_contains(MACHINE_RASPI2, "B");
+    check_contains("B", "C");
+    check_produces("C", "D");
+    check_contains("D", "E");
+    check_contains("D", "F");
+    check_contains("F", "G");
+    check_contains("E", "B");
+    qos_add_test("G", "D", 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_full_alternative_path",
+                    test_full_alternative_path);
+    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;
+}
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 02/34] tests/qgraph: rename qpci_init_pc functions
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 01/34] tests: qgraph API for the qtest " Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 15:04   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes Emanuele Giuseppe Esposito
                   ` (32 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

Rename qpci_init_pc in qpci_new_pc, since the function actually
allocates a new QPCIBusPC and initialize it.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.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/pci-pc.c     | 2 +-
 tests/libqos/pci-pc.h     | 9 ++++++++-
 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 +-
 13 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index 32aa738b72..51b9dda404 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_pc_new(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 4390e5591e..acee5e6572 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_pc_new(global_qtest, NULL);
 }
 
 static void test_i440fx_defaults(gconstpointer opaque)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 2384c2c3e2..fce9692ba2 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -150,7 +150,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_pc_new(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 42d3f76933..4ec516a8c9 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_pc_new(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 a9c1aceaa7..72b3eb46f5 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_init = qpci_pc_new,
     .qpci_free = qpci_free_pc,
     .shutdown = qtest_pc_shutdown,
 };
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index a7803308b7..83a3a32129 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_pc_new(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 491eeac756..88be29eaf3 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_pc_new():
+* this function creates a new QPCIBusPC object,
+ * and properly initialize its fields.
+ *
+ * returns the QPCIBus *bus field of a newly
+ * allocated QPCIBusPC.
+ */
+QPCIBus *qpci_pc_new(QTestState *qts, QGuestAllocator *alloc);
 void     qpci_free_pc(QPCIBus *bus);
 
 #endif
diff --git a/tests/q35-test.c b/tests/q35-test.c
index 7ea7acc9d8..e3da12ee8c 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_pc_new(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_pc_new(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 68bfc42178..d9045b46c2 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_pc_new(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 1d825eb010..5e97590573 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_startf("-machine %s -device sdhci-pci",
                                     test->machine);
 
-        s->pci.bus = qpci_init_pc(global_qtest, NULL);
+        s->pci.bus = qpci_pc_new(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 9945fb8469..2f99824d54 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_pc_new(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 55d4743a2a..037e17f496 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_pc_new(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 fecc832d99..a01b81d342 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -191,7 +191,7 @@ static void init_virtio_dev(TestServer *s, uint32_t features_mask)
     uint32_t features;
     int i;
 
-    s->bus = qpci_init_pc(global_qtest, NULL);
+    s->bus = qpci_pc_new(global_qtest, NULL);
     g_assert_nonnull(s->bus);
 
     s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 01/34] tests: qgraph API for the qtest " Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 02/34] tests/qgraph: rename qpci_init_pc functions Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-08 17:39   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node Emanuele Giuseppe Esposito
                   ` (31 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include |  4 +++-
 tests/libqos/pci-pc.c  | 41 +++++++++++++++++++++++++++++-------
 tests/libqos/pci-pc.h  | 15 ++++++++++++-
 tests/libqos/pci.c     | 48 +++++++++++++++++++++++++++++++++++++++---
 tests/libqos/pci.h     | 15 +++++++++++++
 5 files changed, 110 insertions(+), 13 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index eabf9ed8b4..f04f9fbc3a 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -771,11 +771,13 @@ 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
 
+libqgraph-pci-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-pci-y += tests/qos-test$(EXESUF)
-tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-obj-y)
+tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-pci-obj-y)
 
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 83a3a32129..f5fb94eabc 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,12 +109,23 @@ static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint3
     outl(0xcfc, value);
 }
 
-QPCIBus *qpci_pc_new(QTestState *qts, QGuestAllocator *alloc)
+static void *qpci_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;
+    }
+    printf("%s not present in pci-bus-pc\n", interface);
+    abort();
+}
 
+void qpci_init_pc(QPCIBusPC *ret, QTestState *qts, QGuestAllocator *alloc)
+{
     assert(qts);
 
+    /* tests can use pci-bus */
+    ret->bus.has_buggy_msi = FALSE;
+
     ret->bus.pio_readb = qpci_pc_pio_readb;
     ret->bus.pio_readw = qpci_pc_pio_readw;
     ret->bus.pio_readl = qpci_pc_pio_readl;
@@ -147,11 +152,23 @@ QPCIBus *qpci_pc_new(QTestState *qts, QGuestAllocator *alloc)
     ret->bus.mmio_alloc_ptr = 0xE0000000;
     ret->bus.mmio_limit = 0x100000000ULL;
 
+    ret->obj.get_driver = qpci_get_driver;
+}
+
+QPCIBus *qpci_pc_new(QTestState *qts, QGuestAllocator *alloc)
+{
+    QPCIBusPC *ret = g_new0(QPCIBusPC, 1);
+    qpci_init_pc(ret, qts, alloc);
+
     return &ret->bus;
 }
 
 void qpci_free_pc(QPCIBus *bus)
 {
+    if (!bus) {
+        return;
+    }
+
     QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
 
     g_free(s);
@@ -176,3 +193,11 @@ void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
 
     qmp_eventwait("DEVICE_DELETED");
 }
+
+static void qpci_pc(void)
+{
+    qos_node_create_driver("pci-bus-pc", NULL);
+    qos_node_produces("pci-bus-pc", "pci-bus");
+}
+
+libqos_init(qpci_pc);
diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
index 88be29eaf3..a3754c1c86 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"
 
+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,
+ * 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 0b73cb23d0..91440ece5c 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,15 +51,31 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
     }
 }
 
-QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
+bool qpci_has_buggy_msi(QPCIDevice *dev)
 {
-    QPCIDevice *dev;
+    return dev->bus->has_buggy_msi;
+}
 
-    dev = g_malloc0(sizeof(*dev));
+/* returns TRUE if everything goes fine, FALSE if not */
+static bool qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
+{
     dev->bus = bus;
     dev->devfn = devfn;
 
     if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
+{
+    QPCIDevice *dev;
+
+    dev = g_malloc0(sizeof(*dev));
+
+    if (!qpci_device_set(dev, bus, devfn)) {
         g_free(dev);
         return NULL;
     }
@@ -66,6 +83,21 @@ 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;
+
+    if (!qpci_device_set(dev, bus, addr->devfn)) {
+        printf("PCI Device not found\n");
+        abort();
+    }
+
+    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
+    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
+    g_assert(vendor_id == addr->vendor_id);
+    g_assert(device_id == addr->device_id);
+}
+
 void qpci_device_enable(QPCIDevice *dev)
 {
     uint16_t cmd;
@@ -402,3 +434,13 @@ void qpci_plug_device_test(const char *driver, const char *id,
     qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot,
                          opts ? ", " : "", opts ? opts : "");
 }
+
+void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr)
+{
+    if (!addr || !opts) {
+        return;
+    }
+
+    opts->arg = addr;
+    opts->size_arg = sizeof(QPCIAddress);
+}
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
index 429c382282..5fb3c550c5 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,8 @@ 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 */
+
 };
 
 struct QPCIBar {
@@ -66,10 +70,19 @@ 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);
+/* returns the bus has_buggy_msi flag */
+bool qpci_has_buggy_msi(QPCIDevice *dev);
 
 void qpci_device_enable(QPCIDevice *dev);
 uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id);
@@ -112,4 +125,6 @@ QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr);
 void qpci_plug_device_test(const char *driver, const char *id,
                            uint8_t slot, const char *opts);
 void qpci_unplug_acpi_device_test(const char *id, uint8_t slot);
+
+void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr);
 #endif
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (2 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-08 19:27   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes Emanuele Giuseppe Esposito
                   ` (30 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 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 f04f9fbc3a..4e7b4bb614 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -771,7 +771,10 @@ 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
 
+libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
+
 libqgraph-pci-obj-y = $(libqos-pc-obj-y)
+libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
 
 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 0000000000..e3eddf2eba
--- /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;
+    }
+    printf("%s not present in i440FX-pcihost\n", device);
+    abort();
+}
+
+static void qos_create_i440FX_host(i440FX_pcihost *host,
+                                   QGuestAllocator *alloc)
+{
+    host->obj.get_device = i440FX_host_get_device;
+    qpci_init_pc(&host->pci, global_qtest, alloc);
+}
+
+/* x86_64/pc machine */
+
+static void pc_destroy(QOSGraphObject *obj)
+{
+    QX86_64_PCMachine *machine = (QX86_64_PCMachine *) obj;
+    pc_alloc_uninit(machine->alloc);
+    g_free(machine);
+}
+
+static void *pc_get_driver(void *object, const char *interface)
+{
+    QX86_64_PCMachine *machine = object;
+    if (!g_strcmp0(interface, "guest_allocator")) {
+        return machine->alloc;
+    }
+
+    printf("%s not present in x86_64/pc\n", interface);
+    abort();
+}
+
+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;
+    }
+
+    printf("%s not present in x86_64/pc\n", device);
+    abort();
+}
+
+static void *qos_create_machine_pc(void)
+{
+    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_destroy;
+    machine->alloc = pc_alloc_init_flags(global_qtest, ALLOC_NO_FLAGS);
+    qos_create_i440FX_host(&machine->bridge, machine->alloc);
+
+    return &machine->obj;
+}
+
+static void pc_machine(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);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (3 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 10:10   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 06/34] tests/qgraph: sdhci test node Emanuele Giuseppe Esposito
                   ` (29 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include |   1 +
 tests/libqos/sdhci.c   | 163 +++++++++++++++++++++++++++++++++++++++++
 tests/libqos/sdhci.h   |  69 +++++++++++++++++
 3 files changed, 233 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 4e7b4bb614..be00fb71ec 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -775,6 +775,7 @@ libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
 
 libqgraph-pci-obj-y = $(libqos-pc-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
+libqgraph-pci-obj-y += tests/libqos/sdhci.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
diff --git a/tests/libqos/sdhci.c b/tests/libqos/sdhci.c
new file mode 100644
index 0000000000..f5eb2c5459
--- /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(global_qtest, 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(global_qtest, 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(global_qtest, smm->addr + reg, val);
+}
+
+static void *sdhci_mm_get_driver(void *obj, const char *interface)
+{
+    QSDHCI_MemoryMapped *spci = obj;
+    if (!g_strcmp0(interface, "sdhci")) {
+        return &spci->sdhci;
+    }
+    printf("%s not present in generic-sdhci\n", interface);
+    abort();
+}
+
+void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, 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;
+}
+
+/* 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_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_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;
+    }
+
+    printf("%s not present in sdhci-pci\n", interface);
+    abort();
+}
+
+static void sdhci_start_hw(QOSGraphObject *obj)
+{
+    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
+    qpci_device_enable(&spci->dev);
+}
+
+static void sdhci_destroy(QOSGraphObject *obj)
+{
+    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
+    qpci_iounmap(&spci->dev, spci->mem_bar);
+    g_free(spci);
+}
+
+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_readq;
+    spci->sdhci.writeq = sdhci_writeq;
+    set_qsdhci_fields(&spci->sdhci, 2, 0, 1, 0x057834b4);
+
+    spci->obj.get_driver = sdhci_pci_get_driver;
+    spci->obj.start_hw = sdhci_start_hw;
+    spci->obj.destructor = sdhci_destroy;
+    return &spci->obj;
+}
+
+static void qsdhci(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);
diff --git a/tests/libqos/sdhci.h b/tests/libqos/sdhci.h
new file mode 100644
index 0000000000..57e8134dee
--- /dev/null
+++ b/tests/libqos/sdhci.h
@@ -0,0 +1,69 @@
+/*
+ * 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;
+    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, uint32_t addr,
+                       QSDHCIProperties *common);
+
+#endif
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 06/34] tests/qgraph: sdhci test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (4 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 11:16   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 07/34] tests/qgraph: arm/raspi2 machine node Emanuele Giuseppe Esposito
                   ` (28 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include |   9 +-
 tests/sdhci-test.c     | 222 ++++++++++++-----------------------------
 2 files changed, 68 insertions(+), 163 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index be00fb71ec..fec6cf35bb 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -311,7 +311,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-y += tests/sdhci-test$(EXESUF)
 gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
 gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
 
@@ -385,10 +384,8 @@ gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
 check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
 gcov-files-arm-y += hw/timer/arm_mptimer.c
 check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
-check-qtest-arm-y += tests/sdhci-test$(EXESUF)
 
 check-qtest-aarch64-y = tests/numa-test$(EXESUF)
-check-qtest-aarch64-y += tests/sdhci-test$(EXESUF)
 check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
 
 check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
@@ -777,11 +774,14 @@ libqgraph-pci-obj-y = $(libqos-pc-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
 libqgraph-pci-obj-y += tests/libqos/sdhci.o
 
+libqgraph-tests-obj-y = $(libqgraph-pci-obj-y)
+libqgraph-tests-obj-y += tests/sdhci-test.o
+
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
 
 check-qtest-pci-y += tests/qos-test$(EXESUF)
-tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-pci-obj-y)
+tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-tests-obj-y)
 
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
@@ -867,7 +867,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 5e97590573..77719bdb8b 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,60 @@ 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;
+/**
+ * Old sdhci_t structure:
+ *
+    struct sdhci_t {
+        const char *arch, *machine;
         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);
+            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;
     }
+ *
+ * implemented drivers:
+ *
+    PC via PCI
+        { "x86_64", "pc",
+            {-1,         2, 0,  {1, 0x057834b4} },
+            .pci = { PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_SDHCI } },
+
+    BCM2835
+        { "arm",    "raspi2",
+            {0x3f300000, 3, 52, {0, 0x052134b4} } },
+ *
+ * FIXME: the following drivers are missing:
+ *
+    Exynos4210
+        { "arm",    "smdkc210",
+            {0x12510000, 2, 0,  {1, 0x5e80080} } },
 
-    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);
-    }
+    i.MX 6
+        { "arm",    "sabrelite",
+            {0x02190000, 3, 0,  {1, 0x057834b4} } },
 
-    return val;
-}
+    Zynq-7000
+        { "arm",    "xilinx-zynq-a9",   Datasheet: UG585 (v1.12.1)
+            {0xe0100000, 2, 0,  {1, 0x69ec0080} } },
 
-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);
-    }
-}
+    ZynqMP
+        { "aarch64", "xlnx-zcu102",     Datasheet: UG1085 (v1.7)
+            {0xff160000, 3, 0,  {1, 0x280737ec6481} } },
+ */
 
 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 +85,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 +94,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 +110,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 +119,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 +130,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 +138,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_startf("-machine %s -device sdhci-pci",
-                                    test->machine);
-
-        s->pci.bus = qpci_pc_new(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_startf("-machine %s", test->machine);
-        s->addr = test->sdhci.addr;
-    }
-
-    return s;
-}
-
-static void machine_stop(QSDHCI *s)
+static void test_machine(void *obj, void *data, QGuestAllocator *alloc)
 {
-    qpci_free_pc(s->pci.bus);
-    g_free(s->pci.dev);
-    qtest_quit(global_qtest);
-    g_free(s);
-}
+    QSDHCI *s = obj;
 
-static void test_machine(const void *data)
-{
-    const struct sdhci_t *test = data;
-    QSDHCI *s;
-
-    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 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("sdhci-test", "sdhci", test_machine, NULL);
 }
+
+libqos_init(sdhci_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 07/34] tests/qgraph: arm/raspi2 machine node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (5 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 06/34] tests/qgraph: sdhci test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 12:35   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 08/34] tests/qgraph: rename qpci_init_spapr functions Emanuele Giuseppe Esposito
                   ` (27 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include        |  1 +
 tests/libqos/raspi2-machine.c | 82 +++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)
 create mode 100644 tests/libqos/raspi2-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index fec6cf35bb..d826a09919 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -769,6 +769,7 @@ 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
 
 libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
+libqgraph-machines-obj-y += tests/libqos/raspi2-machine.o
 
 libqgraph-pci-obj-y = $(libqos-pc-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/raspi2-machine.c b/tests/libqos/raspi2-machine.c
new file mode 100644
index 0000000000..0082315339
--- /dev/null
+++ b/tests/libqos/raspi2-machine.c
@@ -0,0 +1,82 @@
+/*
+ * 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 QRaspi2Machine QRaspi2Machine;
+
+struct QRaspi2Machine {
+    QOSGraphObject obj;
+    QGuestAllocator *alloc;
+    QSDHCI_MemoryMapped sdhci;
+};
+
+static void raspi2_destroy(QOSGraphObject *obj)
+{
+    g_free(obj);
+}
+
+static void *raspi2_get_driver(void *object, const char *interface)
+{
+    QRaspi2Machine *machine = object;
+    if (!g_strcmp0(interface, "guest_allocator")) {
+        return &machine->alloc;
+    }
+
+    printf("%s not present in arm/raspi2\n", interface);
+    abort();
+}
+
+static QOSGraphObject *raspi2_get_device(void *obj, const char *device)
+{
+    QRaspi2Machine *machine = obj;
+    if (!g_strcmp0(device, "generic-sdhci")) {
+        return &machine->sdhci.obj;
+    }
+
+    printf("%s not present in arm/raspi2\n", device);
+    abort();
+}
+
+static void *qos_create_machine_arm_raspi2(void)
+{
+    QRaspi2Machine *machine = g_new0(QRaspi2Machine, 1);
+
+    machine->obj.get_device = raspi2_get_device;
+    machine->obj.get_driver = raspi2_get_driver;
+    machine->obj.destructor = raspi2_destroy;
+    qos_init_sdhci_mm(&machine->sdhci, 0x3f300000, &(QSDHCIProperties) {
+        .version = 3,
+        .baseclock = 52,
+        .capab.sdma = false,
+        .capab.reg = 0x052134b4
+    });
+    return &machine->obj;
+}
+
+static void raspi2(void)
+{
+    qos_node_create_machine("arm/raspi2", qos_create_machine_arm_raspi2);
+    qos_node_contains("arm/raspi2", "generic-sdhci", NULL);
+}
+
+libqos_init(raspi2);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 08/34] tests/qgraph: rename qpci_init_spapr functions
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (6 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 07/34] tests/qgraph: arm/raspi2 machine node Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-08 15:30   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes Emanuele Giuseppe Esposito
                   ` (26 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

Rename qpci_init_spapr in qpci_new_spapr, since the function actually
allocates a new QPCIBusSPAPR and initialize it.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/libqos/libqos-spapr.c | 2 +-
 tests/libqos/pci-spapr.c    | 2 +-
 tests/libqos/pci-spapr.h    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c
index a37791e5d0..b3ba421cee 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_init = qpci_spapr_new,
     .qpci_free = qpci_free_spapr,
     .shutdown = qtest_spapr_shutdown,
 };
diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c
index c0f7e6db9b..30b6d5b5a7 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_spapr_new(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 387686dfc8..d5305d16f8 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_spapr_new(QTestState *qts, QGuestAllocator *alloc);
 void     qpci_free_spapr(QPCIBus *bus);
 
 #endif
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (7 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 08/34] tests/qgraph: rename qpci_init_spapr functions Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 12:57   ` Laurent Vivier
  2018-08-09 13:02   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 10/34] tests/qgraph: ppc64/pseries machine node Emanuele Giuseppe Esposito
                   ` (25 subsequent siblings)
  34 siblings, 2 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include   |  2 +-
 tests/libqos/pci-spapr.c | 57 ++++++++++++++++++++++++----------------
 tests/libqos/pci-spapr.h | 24 +++++++++++++++++
 3 files changed, 59 insertions(+), 24 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index d826a09919..5ce905bd82 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -771,7 +771,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
 libqgraph-machines-obj-y += tests/libqos/raspi2-machine.o
 
-libqgraph-pci-obj-y = $(libqos-pc-obj-y)
+libqgraph-pci-obj-y = $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
 libqgraph-pci-obj-y += tests/libqos/sdhci.o
 
diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c
index 30b6d5b5a7..108db6c9b6 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,12 +140,23 @@ 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_spapr_new(QTestState *qts, QGuestAllocator *alloc)
+static void *qspapr_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;
+    }
+    printf("%s not present in pci-bus-spapr", interface);
+    abort();
+}
 
+void qpci_init_spapr(QPCIBusSPAPR *ret, QTestState *qts, QGuestAllocator *alloc)
+{
     assert(qts);
 
+    /* tests cannot use spapr, needs to be fixed first */
+    ret->bus.has_buggy_msi = TRUE;
+
     ret->alloc = alloc;
 
     ret->bus.pio_readb = qpci_spapr_pio_readb;
@@ -208,12 +199,32 @@ QPCIBus *qpci_spapr_new(QTestState *qts, QGuestAllocator *alloc)
     ret->bus.mmio_alloc_ptr = ret->mmio32.pci_base;
     ret->bus.mmio_limit = ret->mmio32.pci_base + ret->mmio32.size;
 
+    ret->obj.get_driver = qspapr_get_driver;
+}
+
+QPCIBus *qpci_spapr_new(QTestState *qts, QGuestAllocator *alloc)
+{
+    QPCIBusSPAPR *ret = g_new0(QPCIBusSPAPR, 1);
+    qpci_init_spapr(ret, qts, alloc);
+
     return &ret->bus;
 }
 
 void qpci_free_spapr(QPCIBus *bus)
 {
+    if (!bus) {
+        return;
+    }
+
     QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
 
     g_free(s);
 }
+
+static void qpci_spapr(void)
+{
+    qos_node_create_driver("pci-bus-spapr", NULL);
+    qos_node_produces("pci-bus-spapr", "pci-bus");
+}
+
+libqos_init(qpci_spapr);
diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h
index d5305d16f8..74cd183c9a 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_spapr_new(QTestState *qts, QGuestAllocator *alloc);
 void     qpci_free_spapr(QPCIBus *bus);
 
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 10/34] tests/qgraph: ppc64/pseries machine node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (8 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 11/34] test/qgraph: e1000e driver and interface nodes Emanuele Giuseppe Esposito
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 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 5ce905bd82..b86aa52546 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -770,6 +770,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 
 libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
 libqgraph-machines-obj-y += tests/libqos/raspi2-machine.o
+libqgraph-machines-obj-y += tests/libqos/ppc64_pseries-machine.o
 
 libqgraph-pci-obj-y = $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/ppc64_pseries-machine.c b/tests/libqos/ppc64_pseries-machine.c
new file mode 100644
index 0000000000..689bb390bf
--- /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;
+    }
+    printf("%s not present in QSPAPR_pci_host\n", device);
+    abort();
+}
+
+static void qos_create_QSPAPR_host(QSPAPR_pci_host *host,
+                                   QGuestAllocator *alloc)
+{
+    host->obj.get_device = QSPAPR_host_get_device;
+    qpci_init_spapr(&host->pci, global_qtest, alloc);
+}
+
+/* ppc64/pseries machine */
+
+static void spapr_destroy(QOSGraphObject *obj)
+{
+    Qppc64_pseriesMachine *machine = (Qppc64_pseriesMachine *) obj;
+    spapr_alloc_uninit(machine->alloc);
+    g_free(obj);
+}
+
+static void *spapr_get_driver(void *object, const char *interface)
+{
+    Qppc64_pseriesMachine *machine = object;
+    if (!g_strcmp0(interface, "guest_allocator")) {
+        return machine->alloc;
+    }
+
+    printf("%s not present in ppc64/pseries\n", interface);
+    abort();
+}
+
+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;
+    }
+
+    printf("%s not present in ppc64/pseries\n", device);
+    abort();
+}
+
+static void *qos_create_machine_spapr(void)
+{
+    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_destroy;
+    machine->alloc =  spapr_alloc_init_flags(global_qtest,
+                                                ALLOC_NO_FLAGS);
+    qos_create_QSPAPR_host(&machine->bridge, machine->alloc);
+
+    return &machine->obj;
+}
+
+static void spapr_machine(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);
+
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 11/34] test/qgraph: e1000e driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (9 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 10/34] tests/qgraph: ppc64/pseries machine node Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 12/34] test/qgraph: e1000e-test node Emanuele Giuseppe Esposito
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include |   1 +
 tests/libqos/e1000e.c  | 262 +++++++++++++++++++++++++++++++++++++++++
 tests/libqos/e1000e.h  |  53 +++++++++
 3 files changed, 316 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 b86aa52546..66d6270ace 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -775,6 +775,7 @@ libqgraph-machines-obj-y += tests/libqos/ppc64_pseries-machine.o
 libqgraph-pci-obj-y = $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
 libqgraph-pci-obj-y += tests/libqos/sdhci.o
+libqgraph-pci-obj-y += tests/libqos/e1000e.o
 
 libqgraph-tests-obj-y = $(libqgraph-pci-obj-y)
 libqgraph-tests-obj-y += tests/sdhci-test.o
diff --git a/tests/libqos/e1000e.c b/tests/libqos/e1000e.c
new file mode 100644
index 0000000000..8aec82e7c2
--- /dev/null
+++ b/tests/libqos/e1000e.c
@@ -0,0 +1,262 @@
+/*
+ * 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/malloc-pc.h"
+#include "libqos/malloc-generic.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));
+}
+
+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_destroy(QOSGraphObject *obj)
+{
+    QE1000E_PCI *epci = (QE1000E_PCI *) obj;
+    qpci_iounmap(&epci->pci_dev, epci->mac_regs);
+    qpci_msix_disable(&epci->pci_dev);
+    g_free(epci);
+}
+
+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;
+    }
+
+    printf("%s not present in e1000e\n", interface);
+    abort();
+}
+
+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_destroy;
+
+    return &d->obj;
+}
+
+static void e1000e(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);
diff --git a/tests/libqos/e1000e.h b/tests/libqos/e1000e.h
new file mode 100644
index 0000000000..9d37094f43
--- /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
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 12/34] test/qgraph: e1000e-test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (10 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 11/34] test/qgraph: e1000e driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 13/34] test/qgraph: virtio_start_device function Emanuele Giuseppe Esposito
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include |   3 +-
 tests/e1000e-test.c    | 354 +++++++++--------------------------------
 2 files changed, 78 insertions(+), 279 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 66d6270ace..50f1af34be 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -213,7 +213,6 @@ gcov-files-virtio-y += $(gcov-files-virtioserial-y)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 gcov-files-pci-y += hw/net/e1000.c
-check-qtest-pci-y += tests/e1000e-test$(EXESUF)
 gcov-files-pci-y += hw/net/e1000e.c hw/net/e1000e_core.c
 check-qtest-pci-y += tests/rtl8139-test$(EXESUF)
 gcov-files-pci-y += hw/net/rtl8139.c
@@ -779,6 +778,7 @@ libqgraph-pci-obj-y += tests/libqos/e1000e.o
 
 libqgraph-tests-obj-y = $(libqgraph-pci-obj-y)
 libqgraph-tests-obj-y += tests/sdhci-test.o
+libqgraph-tests-obj-y += tests/e1000e-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -813,7 +813,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 51b9dda404..212d7db671 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -34,208 +34,11 @@
 #include "libqos/malloc.h"
 #include "libqos/malloc-pc.h"
 #include "libqos/malloc-generic.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;
+#include "libqos/e1000e.h"
 
 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, QGuestAllocator *alloc)
 {
     struct {
         uint64_t buffer_addr;
@@ -268,7 +71,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 +99,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, QGuestAllocator *alloc)
 {
     union {
         struct {
@@ -348,7 +151,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,113 +172,110 @@ 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);
-
-    test_alloc = pc_alloc_init(global_qtest);
-    g_assert_nonnull(test_alloc);
-
-    test_bus = qpci_pc_new(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]);
-    pc_alloc_uninit(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_has_buggy_msi(dev)) {
+        return;
+    }
 
-    data_test_init(&d);
-    e1000e_send_verify(&d);
-    data_test_clear(&d);
+    e1000e_send_verify(d, 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_has_buggy_msi(dev)) {
+        return;
+    }
 
-    data_test_init(&d);
-    e1000e_receive_verify(&d);
-    data_test_clear(&d);
+    e1000e_receive_verify(d, 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_has_buggy_msi(dev)) {
+        return;
+    }
 
     for (i = 0; i < iterations; i++) {
-        e1000e_send_verify(&d);
-        e1000e_receive_verify(&d);
+        e1000e_send_verify(d, alloc);
+        e1000e_receive_verify(d, alloc);
     }
 
-    data_test_clear(&d);
 }
 
-static void test_e1000e_hotplug(gconstpointer data)
+static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
 {
     static const uint8_t slot = 0x06;
 
-    qtest_start("-device e1000e");
-
     qpci_plug_device_test("e1000e", "e1000e_net", slot, NULL);
     qpci_unplug_acpi_device_test("e1000e_net", slot);
+}
+
+static void data_test_init(char **cmd_line)
+{
+    char *new_cmdline;
+
+    int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
+    g_assert_cmpint(ret, != , -1);
 
-    qtest_end();
+    new_cmdline = g_strdup_printf("%s -netdev socket,fd=%d,id=hs0 ", *cmd_line,
+                              test_sockets[1]);
+    g_assert_nonnull(new_cmdline);
+
+    g_free(*cmd_line);
+    *cmd_line = new_cmdline;
 }
 
-int main(int argc, char **argv)
+static void data_test_clear(void)
 {
-    g_test_init(&argc, &argv, NULL);
+    close(test_sockets[0]);
+    qos_invalidate_command_line();
+    close(test_sockets[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);
+static void e1000e_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = data_test_init,
+        .after = data_test_clear,
+    };
 
-    return g_test_run();
+    qos_add_test("e1000e-init", "e1000e", test_e1000e_init, &opts);
+    qos_add_test("e1000e-tx", "e1000e", test_e1000e_tx, &opts);
+    qos_add_test("e1000e-rx", "e1000e", test_e1000e_rx, &opts);
+    qos_add_test("e1000e-multiple_transfers", "e1000e",
+                      test_e1000e_multiple_transfers, &opts);
+    qos_add_test("e1000e-hotplug", "e1000e", test_e1000e_hotplug, &opts);
 }
+
+libqos_init(e1000e_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 13/34] test/qgraph: virtio_start_device function
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (11 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 12/34] test/qgraph: e1000e-test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 13:39   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 14/34] test/qgraph: virtio-pci driver and interface nodes Emanuele Giuseppe Esposito
                   ` (21 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/libqos/virtio.c    |  8 ++++++++
 tests/libqos/virtio.h    |  1 +
 tests/vhost-user-test.c  |  5 +----
 tests/virtio-9p-test.c   |  6 +-----
 tests/virtio-blk-test.c  | 18 ++----------------
 tests/virtio-net-test.c  |  6 +-----
 tests/virtio-scsi-test.c |  4 +---
 7 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 0dad5c19ac..56007ef11b 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -365,3 +365,11 @@ 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);
+    qvirtio_set_driver_ok(vdev);
+}
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 69b5b13840..2c68668de0 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 a01b81d342..c8270fa6ed 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -198,9 +198,7 @@ static void init_virtio_dev(TestServer *s, uint32_t features_mask)
     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(global_qtest);
 
@@ -212,7 +210,6 @@ static void init_virtio_dev(TestServer *s, uint32_t features_mask)
     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)
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index a2b31085f6..4f4a1fb8b4 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -65,14 +65,10 @@ 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);
 
-    qvirtio_set_driver_ok(v9p->dev);
-
     return v9p;
 }
 
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 9be9ffb378..3e8f98e528 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -112,10 +112,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;
 }
 
@@ -174,8 +171,6 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
                     (1u << VIRTIO_BLK_F_SCSI));
     qvirtio_set_features(dev, features);
 
-    qvirtio_set_driver_ok(dev);
-
     /* Write and read with 3 descriptor layout */
     /* Write request */
     req.type = VIRTIO_BLK_T_OUT;
@@ -329,7 +324,6 @@ 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 */
     req.type = VIRTIO_BLK_T_OUT;
@@ -407,8 +401,6 @@ static void pci_config(void)
     capacity = qvirtio_config_readq(&dev->vdev, 0);
     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 
-    qvirtio_set_driver_ok(&dev->vdev);
-
     qmp_discard_response("{ 'execute': 'block_resize', "
                          " 'arguments': { 'device': 'drive0', "
                          " 'size': %d } }", n_size);
@@ -457,8 +449,6 @@ static void pci_msix(void)
     vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
     qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
 
-    qvirtio_set_driver_ok(&dev->vdev);
-
     qmp_discard_response("{ 'execute': 'block_resize', "
                          " 'arguments': { 'device': 'drive0', "
                          " 'size': %d } }", n_size);
@@ -565,8 +555,6 @@ static void pci_idx(void)
     vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
     qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
 
-    qvirtio_set_driver_ok(&dev->vdev);
-
     /* Write request */
     req.type = VIRTIO_BLK_T_OUT;
     req.ioprio = 1;
@@ -715,9 +703,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 b285a262e9..b2a5f5a350 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;
 }
@@ -80,8 +78,6 @@ static void driver_init(QVirtioDevice *dev)
                             (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,
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 037872bb98..1581b6926c 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);
 
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 14/34] test/qgraph: virtio-pci driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (12 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 13/34] test/qgraph: virtio_start_device function Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 14:08   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 15/34] tests/qgraph: rename qvirtio_mmio_init_device functions Emanuele Giuseppe Esposito
                   ` (20 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include    |  2 +-
 tests/libqos/virtio-pci.c | 80 +++++++++++++++++++++++++++++++--------
 tests/libqos/virtio-pci.h | 12 ++++++
 3 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 50f1af34be..8dfbe049e7 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -771,7 +771,7 @@ libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
 libqgraph-machines-obj-y += tests/libqos/raspi2-machine.o
 libqgraph-machines-obj-y += tests/libqos/ppc64_pseries-machine.o
 
-libqgraph-pci-obj-y = $(libqos-pc-obj-y) $(libqos-spapr-obj-y)
+libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
 libqgraph-pci-obj-y += tests/libqos/sdhci.o
 libqgraph-pci-obj-y += tests/libqos/e1000e.o
diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 550dede0a2..02aac77c88 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_destroy and qvirtio_pci_start_hw.
+ */
+
 typedef struct QVirtioPCIForeachData {
     void (*func)(QVirtioDevice *d, void *data);
     uint16_t device_type;
@@ -32,7 +46,6 @@ typedef struct QVirtioPCIForeachData {
 void qvirtio_pci_device_free(QVirtioPCIDevice *dev)
 {
     g_free(dev->pdev);
-    g_free(dev);
 }
 
 static QVirtioPCIDevice *qpcidevice_to_qvirtiodevice(QPCIDevice *pdev)
@@ -76,7 +89,7 @@ static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data)
 
 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 +103,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 +115,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 +127,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 +140,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 +195,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 +219,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 +283,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 +307,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 +430,37 @@ 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_destroy(QOSGraphObject *obj)
+{
+    QVirtioPCIDevice *v9p = (QVirtioPCIDevice *)obj;
+    qvirtio_pci_device_disable(v9p);
+    qvirtio_pci_device_free(v9p);
+}
+
+void qvirtio_pci_start_hw(QOSGraphObject *obj)
+{
+    QVirtioPCIDevice *v9p = (QVirtioPCIDevice *)obj;
+    qvirtio_pci_device_enable(v9p);
+    qvirtio_start_device(&v9p->vdev);
+}
+
+void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr)
+{
+    QPCIDevice *pci_dev;
+    QVirtioPCIDevice *tmp;
+
+    pci_dev = qpci_device_find(bus, addr->devfn);
+    g_assert_nonnull(pci_dev);
+    tmp = qpcidevice_to_qvirtiodevice(pci_dev);
+    memcpy(dev, tmp, sizeof(QVirtioPCIDevice));
+    dev->pdev = pci_dev;
+    dev->vdev.bus = &qvirtio_pci;
+
+    /* 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_destroy;
+
+    g_free(tmp);
+}
diff --git a/tests/libqos/virtio-pci.h b/tests/libqos/virtio-pci.h
index 6ef19094cb..2df71861bf 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,10 +33,20 @@ typedef struct QVirtQueuePCI {
 
 extern const QVirtioBus qvirtio_pci;
 
+void virtio_pci_init(QVirtioPCIDevice *dev, 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_destroy(QOSGraphObject *obj);
+void qvirtio_pci_start_hw(QOSGraphObject *obj);
+
 
 void qvirtio_pci_device_enable(QVirtioPCIDevice *d);
 void qvirtio_pci_device_disable(QVirtioPCIDevice *d);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 15/34] tests/qgraph: rename qvirtio_mmio_init_device functions
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (13 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 14/34] test/qgraph: virtio-pci driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 14:13   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 16/34] test/qgraph: virtio-mmio driver and interface nodes Emanuele Giuseppe Esposito
                   ` (19 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

Rename qvirtio_mmio_init_device in qvirtio_mmio_device_new, since the function
actually allocates a new QVirtioMMIODevice and initialize it.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/libqos/virtio-mmio.c | 2 +-
 tests/libqos/virtio-mmio.h | 2 +-
 tests/virtio-blk-test.c    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c
index 7aa8383338..6f4c1b0955 100644
--- a/tests/libqos/virtio-mmio.c
+++ b/tests/libqos/virtio-mmio.c
@@ -187,7 +187,7 @@ const QVirtioBus qvirtio_mmio = {
     .virtqueue_kick = qvirtio_mmio_virtqueue_kick,
 };
 
-QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size)
+QVirtioMMIODevice *qvirtio_mmio_device_new(uint64_t addr, uint32_t page_size)
 {
     QVirtioMMIODevice *dev;
     uint32_t magic;
diff --git a/tests/libqos/virtio-mmio.h b/tests/libqos/virtio-mmio.h
index e3e52b9ce1..bcc09895fd 100644
--- a/tests/libqos/virtio-mmio.h
+++ b/tests/libqos/virtio-mmio.h
@@ -41,6 +41,6 @@ typedef struct QVirtioMMIODevice {
 
 extern const QVirtioBus qvirtio_mmio;
 
-QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size);
+QVirtioMMIODevice *qvirtio_mmio_device_new(uint64_t addr, uint32_t page_size);
 
 #endif
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 3e8f98e528..267cf28376 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -699,7 +699,7 @@ static void mmio_basic(void)
 
     arm_test_start();
 
-    dev = qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
+    dev = qvirtio_mmio_device_new(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
     g_assert(dev != NULL);
     g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
 
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 16/34] test/qgraph: virtio-mmio driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (14 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 15/34] tests/qgraph: rename qvirtio_mmio_init_device functions Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-09 14:47   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 17/34] test/qgraph: arm/virt machine node Emanuele Giuseppe Esposito
                   ` (18 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

Add virtio-mmio node in qgraph framework.
virtio-mmio produces virtio, 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>
---
 tests/libqos/virtio-mmio.c | 70 ++++++++++++++++++++++++++++----------
 tests/libqos/virtio-mmio.h |  4 +++
 2 files changed, 56 insertions(+), 18 deletions(-)

diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c
index 6f4c1b0955..68bceb9a17 100644
--- a/tests/libqos/virtio-mmio.c
+++ b/tests/libqos/virtio-mmio.c
@@ -13,42 +13,43 @@
 #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;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     return readb(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     return readw(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     return readl(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t off)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     return readq(dev->addr + QVIRTIO_MMIO_DEVICE_SPECIFIC + off);
 }
 
 static uint32_t qvirtio_mmio_get_features(QVirtioDevice *d)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     writel(dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0);
     return readl(dev->addr + QVIRTIO_MMIO_HOST_FEATURES);
 }
 
 static void qvirtio_mmio_set_features(QVirtioDevice *d, uint32_t 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);
@@ -56,25 +57,25 @@ static void qvirtio_mmio_set_features(QVirtioDevice *d, uint32_t 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;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     return (uint8_t)readl(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS);
 }
 
 static void qvirtio_mmio_set_status(QVirtioDevice *d, uint8_t status)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     writel(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;
@@ -88,7 +89,7 @@ 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;
@@ -102,7 +103,7 @@ 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;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     writel(dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index);
 
     g_assert_cmphex(readl(dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0);
@@ -110,20 +111,20 @@ static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index)
 
 static uint16_t qvirtio_mmio_get_queue_size(QVirtioDevice *d)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     return (uint16_t)readl(dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX);
 }
 
 static void qvirtio_mmio_set_queue_address(QVirtioDevice *d, uint32_t pfn)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     writel(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;
 
@@ -163,7 +164,7 @@ static void qvirtio_mmio_virtqueue_cleanup(QVirtQueue *vq,
 
 static void qvirtio_mmio_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
 {
-    QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+    QVirtioMMIODevice *dev = container_of(d, QVirtioMMIODevice, vdev);
     writel(dev->addr + QVIRTIO_MMIO_QUEUE_NOTIFY, vq->index);
 }
 
@@ -187,12 +188,36 @@ const QVirtioBus qvirtio_mmio = {
     .virtqueue_kick = qvirtio_mmio_virtqueue_kick,
 };
 
+static void *qvirtio_mmio_get_driver(void *obj, const char *interface)
+{
+    QVirtioMMIODevice *virtio_mmio = obj;
+    if (!g_strcmp0(interface, "virtio")) {
+        return &virtio_mmio->vdev;
+    }
+    printf("%s not present in virtio-mmio\n", interface);
+    abort();
+}
+
 QVirtioMMIODevice *qvirtio_mmio_device_new(uint64_t addr, uint32_t page_size)
 {
     QVirtioMMIODevice *dev;
-    uint32_t magic;
     dev = g_malloc0(sizeof(*dev));
 
+    qvirtio_mmio_init_device(dev, addr, page_size);
+
+    return dev;
+}
+
+static void qvirtio_mmio_start_hw(QOSGraphObject *obj)
+{
+    QVirtioMMIODevice *dev = (QVirtioMMIODevice *) obj;
+    qvirtio_start_device(&dev->vdev);
+}
+
+void qvirtio_mmio_init_device(QVirtioMMIODevice *dev, uint64_t addr,
+                             uint32_t page_size)
+{
+    uint32_t magic;
     magic = readl(addr + QVIRTIO_MMIO_MAGIC_VALUE);
     g_assert(magic == ('v' | 'i' << 8 | 'r' << 16 | 't' << 24));
 
@@ -203,5 +228,14 @@ QVirtioMMIODevice *qvirtio_mmio_device_new(uint64_t addr, uint32_t page_size)
 
     writel(addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size);
 
-    return dev;
+    dev->obj.get_driver = qvirtio_mmio_get_driver;
+    dev->obj.start_hw = qvirtio_mmio_start_hw;
 }
+
+static void virtio_mmio(void)
+{
+    qos_node_create_driver("virtio-mmio", NULL);
+    qos_node_produces("virtio-mmio", "virtio");
+}
+
+libqos_init(virtio_mmio);
diff --git a/tests/libqos/virtio-mmio.h b/tests/libqos/virtio-mmio.h
index bcc09895fd..9d5af70cfc 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,6 +34,7 @@
 #define QVIRTIO_MMIO_DEVICE_SPECIFIC    0x100
 
 typedef struct QVirtioMMIODevice {
+    QOSGraphObject obj;
     QVirtioDevice vdev;
     uint64_t addr;
     uint32_t page_size;
@@ -42,5 +44,7 @@ typedef struct QVirtioMMIODevice {
 extern const QVirtioBus qvirtio_mmio;
 
 QVirtioMMIODevice *qvirtio_mmio_device_new(uint64_t addr, uint32_t page_size);
+void qvirtio_mmio_init_device(QVirtioMMIODevice *dev, uint64_t addr,
+                             uint32_t page_size);
 
 #endif
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 17/34] test/qgraph: arm/virt machine node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (15 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 16/34] test/qgraph: virtio-mmio driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 18/34] tests: virtio: separate ccw tests from libqos Emanuele Giuseppe Esposito
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include      |  1 +
 tests/libqos/virt-machine.c | 90 +++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)
 create mode 100644 tests/libqos/virt-machine.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8dfbe049e7..4659785baf 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -770,6 +770,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt
 libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
 libqgraph-machines-obj-y += tests/libqos/raspi2-machine.o
 libqgraph-machines-obj-y += tests/libqos/ppc64_pseries-machine.o
+libqgraph-machines-obj-y += tests/libqos/virt-machine.o
 
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/virt-machine.c b/tests/libqos/virt-machine.c
new file mode 100644
index 0000000000..e23fb95191
--- /dev/null
+++ b/tests/libqos/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"
+#include "libqos/malloc-generic.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 QVirtioMachine QVirtioMachine;
+
+struct QVirtioMachine {
+    QOSGraphObject obj;
+    QGuestAllocator *alloc;
+    QVirtioMMIODevice virtio_mmio;
+};
+
+static void virtio_destroy(QOSGraphObject *obj)
+{
+    QVirtioMachine *machine = (QVirtioMachine *) obj;
+    generic_alloc_uninit(machine->alloc);
+    g_free(obj);
+}
+
+static void *virtio_get_driver(void *object, const char *interface)
+{
+    QVirtioMachine *machine = object;
+    if (!g_strcmp0(interface, "guest_allocator")) {
+        return machine->alloc;
+    }
+
+    printf("%s not present in arm/virtio\n", interface);
+    abort();
+}
+
+static QOSGraphObject *virtio_get_device(void *obj, const char *device)
+{
+    QVirtioMachine *machine = obj;
+    if (!g_strcmp0(device, "virtio-mmio")) {
+        return &machine->virtio_mmio.obj;
+    }
+
+    printf("%s not present in arm/virtio\n", device);
+    abort();
+}
+
+static void *qos_create_machine_arm_virt(void)
+{
+    QVirtioMachine *machine = g_new0(QVirtioMachine, 1);
+
+    machine->alloc = generic_alloc_init(ARM_VIRT_RAM_ADDR, ARM_VIRT_RAM_SIZE,
+                                        ARM_PAGE_SIZE);
+    qvirtio_mmio_init_device(&machine->virtio_mmio, VIRTIO_MMIO_BASE_ADDR,
+                             VIRTIO_MMIO_SIZE);
+
+    machine->obj.get_device = virtio_get_device;
+    machine->obj.get_driver = virtio_get_driver;
+    machine->obj.destructor = virtio_destroy;
+    return machine;
+}
+
+static void virtio_machine(void)
+{
+    qos_node_create_machine("arm/virt", qos_create_machine_arm_virt);
+    qos_node_contains("arm/virt", "virtio-mmio", NULL);
+}
+
+libqos_init(virtio_machine);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 18/34] tests: virtio: separate ccw tests from libqos
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (16 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 17/34] test/qgraph: arm/virt machine node Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-08 19:34   ` Laurent Vivier
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 19/34] test/qgraph: virtio-serial driver and interface nodes Emanuele Giuseppe Esposito
                   ` (16 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

From: Paolo Bonzini <pbonzini@redhat.com>

Because qtest does not support s390 channel I/O, s390 only performs smoke tests on
those few devices that do not have any functional tests.  Therefore, every time we
add functional tests for a virtio device, the choice is between removing
those tests from the s390 suite (so that s390 actually _loses_ coverage)
or sprinkling the test with architecture checks.

This patch simply creates a ccw-specific test that only performs smoke tests on
all virtio-ccw devices.  If channel I/O support is ever added to qtest and libqos,
then this file can go away.  In the meanwhile, it simplifies maintenance and
makes sure that all virtio devices are tested.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include  |   5 +-
 tests/virtio-ccw-test.c | 121 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 3 deletions(-)
 create mode 100644 tests/virtio-ccw-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 4659785baf..d72d0d65b4 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -397,9 +397,7 @@ check-qtest-s390x-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
 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-balloon-test$(EXESUF)
-check-qtest-s390x-y += tests/virtio-console-test$(EXESUF)
-check-qtest-s390x-y += tests/virtio-serial-test$(EXESUF)
+check-qtest-s390x-y += tests/virtio-ccw-test$(EXESUF)
 check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF)
 
 check-qtest-generic-y += tests/machine-none-test$(EXESUF)
@@ -824,6 +822,7 @@ 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)
 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)
diff --git a/tests/virtio-ccw-test.c b/tests/virtio-ccw-test.c
new file mode 100644
index 0000000000..88602f3235
--- /dev/null
+++ b/tests/virtio-ccw-test.c
@@ -0,0 +1,121 @@
+/*
+ * QTest testcase for VirtIO CCW
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ * 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.
+ */
+
+/* Until we have a full libqos implementation of virtio-ccw (which requires
+ * also to add support for I/O channels to qtest), we can only do simple
+ * tests that initialize the devices.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/virtio.h"
+
+static void virtio_balloon_nop(void)
+{
+    global_qtest = qtest_startf("-device virtio-balloon-ccw");
+    qtest_end();
+}
+
+static void virtconsole_nop(void)
+{
+    global_qtest = qtest_startf("-device virtio-serial-ccw,id=vser0 "
+                                "-device virtconsole,bus=vser0.0");
+    qtest_end();
+}
+
+static void virtserialport_nop(void)
+{
+    global_qtest = qtest_startf("-device virtio-serial-ccw,id=vser0 "
+                                "-device virtserialport,bus=vser0.0");
+    qtest_end();
+}
+
+static void virtio_serial_nop(void)
+{
+    global_qtest = qtest_startf("-device virtio-serial-ccw");
+    qtest_end();
+}
+
+static void virtio_serial_hotplug(void)
+{
+    global_qtest = qtest_startf("-device virtio-serial-ccw");
+    qtest_qmp_device_add("virtserialport", "hp-port", NULL);
+    qtest_qmp_device_del("hp-port");
+    qtest_end();
+}
+
+static void virtio_blk_nop(void)
+{
+    global_qtest = qtest_startf("-drive if=none,id=drv0,"
+                                "file=null-co://,format=raw "
+                                "-device virtio-blk-ccw,drive=drv0");
+    qtest_end();
+}
+
+static void virtio_net_nop(void)
+{
+    global_qtest = qtest_startf("-device virtio-net-ccw");
+    qtest_end();
+}
+
+static void virtio_9p_nop(void)
+{
+    global_qtest = qtest_startf("-fsdev synth,id=fsdev0 "
+                                "-device virtio-9p-ccw,fsdev=fsdev0,mount_tag=qtest");
+    qtest_end();
+}
+
+static void virtio_rng_nop(void)
+{
+    global_qtest = qtest_startf("-device virtio-rng-ccw");
+    qtest_end();
+}
+
+static void virtio_scsi_nop(void)
+{
+    global_qtest = qtest_startf("-device virtio-scsi-ccw");
+    qtest_end();
+}
+
+static void virtio_scsi_hotplug(void)
+{
+    global_qtest = qtest_startf("-drive if=none,id=drv0,"
+                                "file=null-co://,format=raw "
+                                "-drive if=none,id=drv1,"
+                                "file=null-co://,format=raw "
+                                "-device virtio-scsi-ccw "
+                                "-device scsi-hd,drive=drv0");
+    qtest_qmp_device_add("scsi-hd", "scsihd", "'drive': 'drv1'");
+    qtest_qmp_device_del("scsihd");
+
+    qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/balloon/nop", virtio_balloon_nop);
+    qtest_add_func("/virtio/console/nop", virtconsole_nop);
+    qtest_add_func("/virtio/serialport/nop", virtserialport_nop);
+    qtest_add_func("/virtio/serial/nop", virtio_serial_nop);
+    qtest_add_func("/virtio/serial/hotplug", virtio_serial_hotplug);
+    qtest_add_func("/virtio/block/nop", virtio_blk_nop);
+    qtest_add_func("/virtio/net/nop", virtio_net_nop);
+    qtest_add_func("/virtio/9p/nop", virtio_9p_nop);
+    qtest_add_func("/virtio/rng/nop", virtio_rng_nop);
+    qtest_add_func("/virtio/scsi/nop", virtio_scsi_nop);
+    qtest_add_func("/virtio/scsi/hotplug", virtio_scsi_hotplug);
+
+    ret = g_test_run();
+
+    return ret;
+}
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 19/34] test/qgraph: virtio-serial driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (17 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 18/34] tests: virtio: separate ccw tests from libqos Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 20/34] test/qgraph: virtio-console test node Emanuele Giuseppe Esposito
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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 and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include       |   3 +
 tests/libqos/virtio-serial.c | 109 +++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-serial.h |  39 +++++++++++++
 3 files changed, 151 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 d72d0d65b4..ad784a3e84 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -770,8 +770,11 @@ libqgraph-machines-obj-y += tests/libqos/raspi2-machine.o
 libqgraph-machines-obj-y += tests/libqos/ppc64_pseries-machine.o
 libqgraph-machines-obj-y += tests/libqos/virt-machine.o
 
+libqgraph-virtio-obj-y = tests/libqos/virtio-serial.o
+
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
+libqgraph-pci-obj-y += $(libqgraph-virtio-obj-y)
 libqgraph-pci-obj-y += tests/libqos/sdhci.o
 libqgraph-pci-obj-y += tests/libqos/e1000e.o
 
diff --git a/tests/libqos/virtio-serial.c b/tests/libqos/virtio-serial.c
new file mode 100644
index 0000000000..6dd4582d15
--- /dev/null
+++ b/tests/libqos/virtio-serial.c
@@ -0,0 +1,109 @@
+/*
+ * 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"
+
+/* virtio-serial-device */
+static void qvirtio_serial_device_destroy(QOSGraphObject *obj)
+{
+    QVirtioSerialDevice *v_serial = (QVirtioSerialDevice *) obj;
+
+    g_free(v_serial);
+}
+
+static void *qvirtio_serial_device_get_driver(void *object,
+                                              const char *interface)
+{
+    QVirtioSerialDevice *v_serial = object;
+    if (!g_strcmp0(interface, "virtio-serial")) {
+        return &v_serial->serial;
+    }
+
+    printf("%s not present in virtio-serial-device\n", interface);
+    abort();
+}
+
+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.destructor = qvirtio_serial_device_destroy;
+    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, "virtio-serial")) {
+        return &v_serial->serial;
+    }
+
+    printf("%s not present in virtio-serial-pci\n", interface);
+    abort();
+}
+
+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(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", &edge_opts);
+    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", "virtio-serial");
+}
+
+libqos_init(virtio_serial);
diff --git a/tests/libqos/virtio-serial.h b/tests/libqos/virtio-serial.h
new file mode 100644
index 0000000000..b7e2a5d178
--- /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;
+};
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 20/34] test/qgraph: virtio-console test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (18 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 19/34] test/qgraph: virtio-serial driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 21/34] test/qgraph: virtio-serial " Emanuele Giuseppe Esposito
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

Convert tests/virtio-console-test in qgraph test node,
virtio-console-test. 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 structure,
it's all done by the qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include      |  5 +++--
 tests/libqos/virtio.c       |  1 +
 tests/virtio-console-test.c | 30 +++++++++++++++---------------
 3 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ad784a3e84..6742f97058 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -187,7 +187,6 @@ gcov-files-ipack-y += hw/ipack/ipack.c
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 gcov-files-ipack-y += hw/char/ipoctal232.c
 
-check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF)
 gcov-files-virtioserial-y += hw/char/virtio-console.c
 
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio.c
@@ -398,6 +397,8 @@ 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/virtio-serial-test$(EXESUF)
 check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF)
 
 check-qtest-generic-y += tests/machine-none-test$(EXESUF)
@@ -781,6 +782,7 @@ libqgraph-pci-obj-y += tests/libqos/e1000e.o
 libqgraph-tests-obj-y = $(libqgraph-pci-obj-y)
 libqgraph-tests-obj-y += tests/sdhci-test.o
 libqgraph-tests-obj-y += tests/e1000e-test.o
+libqgraph-tests-obj-y += tests/virtio-console-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -831,7 +833,6 @@ 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 56007ef11b..9b97ab0625 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
index 945bae5a15..55d5c0f138 100644
--- a/tests/virtio-console-test.c
+++ b/tests/virtio-console-test.c
@@ -10,29 +10,29 @@
 #include "qemu/osdep.h"
 #include "libqtest.h"
 #include "libqos/virtio.h"
+#include "libqos/qgraph.h"
 
 /* Tests only initialization so far. TODO: Replace with functional tests */
-static void console_nop(void)
+static void console_nop(void *obj, void *data, QGuestAllocator *alloc)
 {
-    global_qtest = qtest_startf("-device virtio-serial-%s,id=vser0 "
-                                "-device virtconsole,bus=vser0.0",
-                                qvirtio_get_dev_type());
-    qtest_end();
+    /* no operation */
 }
 
-static void serialport_nop(void)
+static void serialport_nop(void *obj, void *data, QGuestAllocator *alloc)
 {
-    global_qtest = qtest_startf("-device virtio-serial-%s,id=vser0 "
-                                "-device virtserialport,bus=vser0.0",
-                                qvirtio_get_dev_type());
-    qtest_end();
+    /* no operation */
 }
 
-int main(int argc, char **argv)
+static void virtio_console_test(void)
 {
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/console/nop", console_nop);
-    qtest_add_func("/virtio/serialport/nop", serialport_nop);
+    QOSGraphTestOptions opts = { };
+    QOSGraphEdgeOptions *edge_opts = &opts.edge;
 
-    return g_test_run();
+    edge_opts->before_cmd_line = "-device virtconsole,bus=vser0.0";
+    qos_add_test("console-nop", "virtio-serial", console_nop, &opts);
+
+    edge_opts->before_cmd_line = "-device virtserialport,bus=vser0.0";
+    qos_add_test("serialport-nop", "virtio-serial", serialport_nop, &opts);
 }
+
+libqos_init(virtio_console_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 21/34] test/qgraph: virtio-serial test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (19 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 20/34] test/qgraph: virtio-console test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:33 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 22/34] test/qgraph: virtio-9p driver and interface nodes Emanuele Giuseppe Esposito
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

Convert tests/virtio-serial-test in qgraph test node,
virtio-serial-test. 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-serial structure,
it's all done by the qtest walking graph mechanism

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include     |  4 +---
 tests/virtio-serial-test.c | 27 +++++++++------------------
 2 files changed, 10 insertions(+), 21 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 6742f97058..f258a7778e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -205,7 +205,6 @@ check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF)
 gcov-files-virtio-y += hw/9pfs/virtio-9p.c
 gcov-files-virtio-y += i386-softmmu/hw/9pfs/virtio-9p-device.c
 endif
-check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/char/virtio-serial-bus.c
 check-qtest-virtio-y += $(check-qtest-virtioserial-y)
 gcov-files-virtio-y += $(gcov-files-virtioserial-y)
@@ -398,7 +397,6 @@ 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/virtio-serial-test$(EXESUF)
 check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF)
 
 check-qtest-generic-y += tests/machine-none-test$(EXESUF)
@@ -782,6 +780,7 @@ libqgraph-pci-obj-y += tests/libqos/e1000e.o
 libqgraph-tests-obj-y = $(libqgraph-pci-obj-y)
 libqgraph-tests-obj-y += tests/sdhci-test.o
 libqgraph-tests-obj-y += tests/e1000e-test.o
+libqgraph-tests-obj-y += tests/virtio-serial-test.o
 libqgraph-tests-obj-y += tests/virtio-console-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
@@ -832,7 +831,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/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-serial-test.c b/tests/virtio-serial-test.c
index 7cc7060264..1691811f85 100644
--- a/tests/virtio-serial-test.c
+++ b/tests/virtio-serial-test.c
@@ -9,33 +9,24 @@
 
 #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", NULL);
-
     qtest_qmp_device_del("hp-port");
 }
 
-int main(int argc, char **argv)
+static void 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);
-
-    global_qtest = qtest_startf("-device virtio-serial-%s",
-                                qvirtio_get_dev_type());
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
+    qos_add_test("serial-nop", "virtio-serial", virtio_serial_nop, NULL);
+    qos_add_test("serial-hotplug", "virtio-serial", serial_hotplug, NULL);
 }
+
+libqos_init(virtio_serial_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 22/34] test/qgraph: virtio-9p driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (20 preceding siblings ...)
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 21/34] test/qgraph: virtio-serial " Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 23/34] test/qgraph: virtio-9p test node Emanuele Giuseppe Esposito
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include   |   1 +
 tests/libqos/virtio-9p.c | 164 +++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-9p.h |  42 ++++++++++
 3 files changed, 207 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 f258a7778e..e4385555e3 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -770,6 +770,7 @@ libqgraph-machines-obj-y += tests/libqos/ppc64_pseries-machine.o
 libqgraph-machines-obj-y += tests/libqos/virt-machine.o
 
 libqgraph-virtio-obj-y = tests/libqos/virtio-serial.o
+libqgraph-virtio-obj-y += tests/libqos/virtio-9p.o
 
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/virtio-9p.c b/tests/libqos/virtio-9p.c
new file mode 100644
index 0000000000..88437d58af
--- /dev/null
+++ b/tests/libqos/virtio-9p.c
@@ -0,0 +1,164 @@
+/*
+ * 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);
+}
+
+/* virtio-9p-device */
+static void virtio_9p_device_destroy(QOSGraphObject *obj)
+{
+    QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj;
+    QVirtio9P *interface = &v_9p->v9p;
+    virtio_9p_cleanup(interface);
+
+    g_free(v_9p);
+}
+
+static void virtio_9p_device_start_hw(QOSGraphObject *obj)
+{
+    QVirtio9PDevice *v_9p = (QVirtio9PDevice *) obj;
+    QVirtio9P *interface = &v_9p->v9p;
+
+    virtio_9p_setup(interface);
+}
+
+static void *virtio_9p_device_get_driver(void *object, const char *interface)
+{
+    QVirtio9PDevice *v_9p = object;
+    if (!g_strcmp0(interface, "virtio-9p")) {
+        return &v_9p->v9p;
+    }
+
+    printf("%s not present in virtio-9p-device\n", interface);
+    abort();
+}
+
+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_destroy;
+    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_destroy(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_destroy(pci_vobj);
+    g_free(v9_pci);
+}
+
+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 *v9p = object;
+    if (!g_strcmp0(interface, "virtio-9p")) {
+        return &v9p->v9p;
+    }
+
+    printf("%s not present in virtio-9p-pci\n", interface);
+    abort();
+}
+
+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_destroy;
+    obj->start_hw = virtio_9p_pci_start_hw;
+    obj->get_driver = virtio_9p_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_9p(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", &opts);
+    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", "virtio-9p");
+
+}
+
+libqos_init(virtio_9p);
diff --git a/tests/libqos/virtio-9p.h b/tests/libqos/virtio-9p.h
new file mode 100644
index 0000000000..dba22772b5
--- /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;
+};
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 23/34] test/qgraph: virtio-9p test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (21 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 22/34] test/qgraph: virtio-9p driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 24/34] test/qgraph: virtio-balloon driver and interface nodes Emanuele Giuseppe Esposito
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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 uses virtio-pci QOSGraphObject and functions,
while virtio-9p-device receives a virtio and implements
its own functions

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include |   3 +-
 tests/virtio-9p-test.c | 217 +++++++++++++++--------------------------
 2 files changed, 82 insertions(+), 138 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index e4385555e3..f367e9e321 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -201,7 +201,6 @@ gcov-files-virtio-y += hw/virtio/virtio-rng.c
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/scsi/virtio-scsi.c
 ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
-check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF)
 gcov-files-virtio-y += hw/9pfs/virtio-9p.c
 gcov-files-virtio-y += i386-softmmu/hw/9pfs/virtio-9p-device.c
 endif
@@ -783,6 +782,7 @@ libqgraph-tests-obj-y += tests/sdhci-test.o
 libqgraph-tests-obj-y += tests/e1000e-test.o
 libqgraph-tests-obj-y += tests/virtio-serial-test.o
 libqgraph-tests-obj-y += tests/virtio-console-test.o
+libqgraph-tests-obj-y += tests/virtio-9p-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -831,7 +831,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 4f4a1fb8b4..8ed545d838 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -9,97 +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)
+static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    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);
-
-    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)
-{
-    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;
@@ -202,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);
@@ -220,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;
@@ -228,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;
 }
 
@@ -253,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);
 }
 
@@ -286,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);
 }
 
@@ -302,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;
@@ -337,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 */
@@ -366,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;
@@ -408,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;
@@ -436,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;
@@ -464,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;
 
@@ -481,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;
@@ -497,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;
@@ -519,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);
@@ -533,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);
@@ -549,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);
@@ -570,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);
@@ -587,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);
@@ -613,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);
@@ -648,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);
@@ -683,39 +638,29 @@ 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 virtio_nop(void *obj, void *data, QGuestAllocator *t_alloc)
 {
-    v9fs_test_fn fn = data;
-    QVirtIO9P *v9p = qvirtio_9p_pci_start();
-
-    if (fn) {
-        fn(v9p);
-    }
-    qvirtio_9p_pci_stop(v9p);
+    /* no operation */
 }
 
-static void v9fs_qtest_pci_add(const char *path, v9fs_test_fn fn)
-{
-    qtest_add_data_func(path, fn, v9fs_run_pci_test);
-}
 
-int main(int argc, char **argv)
+static void virtio_9p_test(void)
 {
-    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();
+    qos_add_test("virtio-9p-nop", "virtio-9p", virtio_nop, NULL);
+    qos_add_test("virtio-9p-config", "virtio-9p", pci_config, NULL);
+    qos_add_test("virtio-9p-fs/version/basic", "virtio-9p", fs_version, NULL);
+    qos_add_test("virtio-9p-fs/attach/basic", "virtio-9p", fs_attach, NULL);
+    qos_add_test("virtio-9p-fs/walk/basic", "virtio-9p", fs_walk, NULL);
+    qos_add_test("virtio-9p-fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
+                 NULL);
+    qos_add_test("virtio-9p-fs/walk/dotdot_from_root", "virtio-9p",
+                 fs_walk_dotdot, NULL);
+    qos_add_test("virtio-9p-fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
+    qos_add_test("virtio-9p-fs/write/basic", "virtio-9p", fs_write, NULL);
+    qos_add_test("virtio-9p-fs/flush/success", "virtio-9p", fs_flush_success,
+                 NULL);
+    qos_add_test("virtio-9p-fs/flush/ignored", "virtio-9p", fs_flush_ignored,
+                 NULL);
 }
+
+libqos_init(virtio_9p_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 24/34] test/qgraph: virtio-balloon driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (22 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 23/34] test/qgraph: virtio-9p test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 25/34] test/qgraph: virtio-balloon test node Emanuele Giuseppe Esposito
                   ` (10 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include        |   1 +
 tests/libqos/virtio-balloon.c | 111 ++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-balloon.h |  39 ++++++++++++
 3 files changed, 151 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 f367e9e321..a3d425918f 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -770,6 +770,7 @@ libqgraph-machines-obj-y += tests/libqos/virt-machine.o
 
 libqgraph-virtio-obj-y = tests/libqos/virtio-serial.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-9p.o
+libqgraph-virtio-obj-y += tests/libqos/virtio-balloon.o
 
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/virtio-balloon.c b/tests/libqos/virtio-balloon.c
new file mode 100644
index 0000000000..e97a9038fc
--- /dev/null
+++ b/tests/libqos/virtio-balloon.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 "libqos/virtio-balloon.h"
+
+/* virtio-balloon-device */
+static void qvirtio_balloon_device_destroy(QOSGraphObject *obj)
+{
+    QVirtioBalloonDevice *v_balloon = (QVirtioBalloonDevice *) obj;
+
+    g_free(v_balloon);
+}
+
+static void *qvirtio_balloon_device_get_driver(void *object,
+                                               const char *interface)
+{
+    QVirtioBalloonDevice *v_balloon = object;
+    if (!g_strcmp0(interface, "virtio-balloon")) {
+        return &v_balloon->balloon;
+    }
+
+    printf("%s not present in virtio-balloon-device\n", interface);
+    abort();
+}
+
+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.destructor = qvirtio_balloon_device_destroy;
+    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, "virtio-balloon")) {
+        return &v_balloon->balloon;
+    }
+
+    printf("%s not present in virtio-balloon-pci\n", interface);
+    abort();
+}
+
+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(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", NULL);
+    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", "virtio-balloon");
+}
+
+libqos_init(virtio_balloon);
diff --git a/tests/libqos/virtio-balloon.h b/tests/libqos/virtio-balloon.h
new file mode 100644
index 0000000000..e8066c42bb
--- /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;
+};
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 25/34] test/qgraph: virtio-balloon test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (23 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 24/34] test/qgraph: virtio-balloon driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 26/34] test/qgraph: virtio-rng driver and interface nodes Emanuele Giuseppe Esposito
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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

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

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include      |  4 +---
 tests/virtio-balloon-test.c | 22 +++++++---------------
 2 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index a3d425918f..5b33ffbc57 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -192,7 +192,6 @@ gcov-files-virtioserial-y += hw/char/virtio-console.c
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio.c
 check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c
-check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c
 check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c
@@ -395,7 +394,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-generic-y += tests/machine-none-test$(EXESUF)
@@ -784,6 +782,7 @@ libqgraph-tests-obj-y += tests/e1000e-test.o
 libqgraph-tests-obj-y += tests/virtio-serial-test.o
 libqgraph-tests-obj-y += tests/virtio-console-test.o
 libqgraph-tests-obj-y += tests/virtio-9p-test.o
+libqgraph-tests-obj-y += tests/virtio-balloon-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -826,7 +825,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
index 0a07e036bb..1604b7f430 100644
--- a/tests/virtio-balloon-test.c
+++ b/tests/virtio-balloon-test.c
@@ -9,25 +9,17 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
-#include "libqos/virtio.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-balloon.h"
 
 /* Tests only initialization so far. TODO: Replace with functional tests */
-static void balloon_nop(void)
+static void balloon_nop(void *obj, void *data, QGuestAllocator *alloc)
 {
 }
 
-int main(int argc, char **argv)
+static void virtio_balloon_test(void)
 {
-    int ret;
-
-    g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/virtio/balloon/nop", balloon_nop);
-
-    global_qtest = qtest_startf("-device virtio-balloon-%s",
-                                qvirtio_get_dev_type());
-    ret = g_test_run();
-
-    qtest_end();
-
-    return ret;
+    qos_add_test("balloon-nop", "virtio-balloon", balloon_nop, NULL);
 }
+
+libqos_init(virtio_balloon_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 26/34] test/qgraph: virtio-rng driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (24 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 25/34] test/qgraph: virtio-balloon test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 27/34] test/qgraph: virtio-rng test node Emanuele Giuseppe Esposito
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include    |   1 +
 tests/libqos/virtio-rng.c | 108 ++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-rng.h |  39 ++++++++++++++
 3 files changed, 148 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 5b33ffbc57..6ebd6463a9 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -769,6 +769,7 @@ libqgraph-machines-obj-y += tests/libqos/virt-machine.o
 libqgraph-virtio-obj-y = tests/libqos/virtio-serial.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-9p.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-balloon.o
+libqgraph-virtio-obj-y += tests/libqos/virtio-rng.o
 
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/virtio-rng.c b/tests/libqos/virtio-rng.c
new file mode 100644
index 0000000000..5bf8efb6da
--- /dev/null
+++ b/tests/libqos/virtio-rng.c
@@ -0,0 +1,108 @@
+/*
+ * 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_device_destroy(QOSGraphObject *obj)
+{
+    QVirtioRngDevice *v_rng = (QVirtioRngDevice *) obj;
+
+    g_free(v_rng);
+}
+
+static void *qvirtio_rng_device_get_driver(void *object,
+                                              const char *interface)
+{
+    QVirtioRngDevice *v_rng = object;
+    if (!g_strcmp0(interface, "virtio-rng")) {
+        return &v_rng->rng;
+    }
+
+    printf("%s not present in virtio-rng-device\n", interface);
+    abort();
+}
+
+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.destructor = qvirtio_rng_device_destroy;
+    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, "virtio-rng")) {
+        return &v_rng->rng;
+    }
+
+    printf("%s not present in virtio-rng-pci\n", interface);
+    abort();
+}
+
+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(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", NULL);
+    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", "virtio-rng");
+}
+
+libqos_init(virtio_rng);
diff --git a/tests/libqos/virtio-rng.h b/tests/libqos/virtio-rng.h
new file mode 100644
index 0000000000..fbba988875
--- /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;
+};
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 27/34] test/qgraph: virtio-rng test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (25 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 26/34] test/qgraph: virtio-rng driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 28/34] test/qgraph: virtio-blk driver and interface nodes Emanuele Giuseppe Esposito
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include  |  3 +--
 tests/virtio-rng-test.c | 25 +++++++++----------------
 2 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 6ebd6463a9..3a1a99b8c8 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -195,7 +195,6 @@ gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c
 check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c
-check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
 gcov-files-virtio-y += hw/virtio/virtio-rng.c
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/scsi/virtio-scsi.c
@@ -784,6 +783,7 @@ libqgraph-tests-obj-y += tests/virtio-serial-test.o
 libqgraph-tests-obj-y += tests/virtio-console-test.o
 libqgraph-tests-obj-y += tests/virtio-9p-test.o
 libqgraph-tests-obj-y += tests/virtio-balloon-test.o
+libqgraph-tests-obj-y += tests/virtio-rng-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -829,7 +829,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 dcecf77463..24fd62f44f 100644
--- a/tests/virtio-rng-test.c
+++ b/tests/virtio-rng-test.c
@@ -9,16 +9,17 @@
 
 #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 nop(void *obj, void *data, QGuestAllocator *alloc)
 {
 }
 
-static void hotplug(void)
+static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc)
 {
     const char *arch = qtest_get_arch();
 
@@ -29,18 +30,10 @@ static void hotplug(void)
     }
 }
 
-int main(int argc, char **argv)
+static void 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("rng-nop", "virtio-rng", nop, NULL);
+    qos_add_test("rng-hotplug", "virtio-rng-pci", rng_hotplug, NULL);
 }
+
+libqos_init(virtio_rng_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 28/34] test/qgraph: virtio-blk driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (26 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 27/34] test/qgraph: virtio-rng test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node Emanuele Giuseppe Esposito
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include    |   1 +
 tests/libqos/virtio-blk.c | 126 ++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-blk.h |  40 ++++++++++++
 3 files changed, 167 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 3a1a99b8c8..1d68e7d223 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -769,6 +769,7 @@ libqgraph-virtio-obj-y = tests/libqos/virtio-serial.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-9p.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-balloon.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-rng.o
+libqgraph-virtio-obj-y += tests/libqos/virtio-blk.o
 
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/virtio-blk.c b/tests/libqos/virtio-blk.c
new file mode 100644
index 0000000000..991fa01809
--- /dev/null
+++ b/tests/libqos/virtio-blk.c
@@ -0,0 +1,126 @@
+/*
+ * 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_device_destroy(QOSGraphObject *obj)
+{
+    QVirtioBlkDevice *v_blk = (QVirtioBlkDevice *) obj;
+    g_free(v_blk);
+}
+
+static void *qvirtio_blk_device_get_driver(void *object,
+                                           const char *interface)
+{
+    QVirtioBlkDevice *v_blk = object;
+    if (!g_strcmp0(interface, "virtio-blk")) {
+        return &v_blk->blk;
+    }
+
+    printf("%s not present in virtio-blk-device\n", interface);
+    abort();
+}
+
+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.destructor = qvirtio_blk_device_destroy;
+    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, "virtio-blk")) {
+        return &v_blk->blk;
+    }
+
+    /* implicit contains */
+    if (!g_strcmp0(interface, "pci-device")) {
+        return v_blk->pci_vdev.pdev;
+    }
+
+    printf("%s not present in virtio-blk-pci\n", interface);
+    abort();
+}
+
+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(void)
+{
+    /* FIXME: every test using these two nodes needs to setup a
+     * -drive,id=drive0 otherwise QEMU is not going to start */
+
+    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", &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);
diff --git a/tests/libqos/virtio-blk.h b/tests/libqos/virtio-blk.h
new file mode 100644
index 0000000000..dc258496ba
--- /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;
+};
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (27 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 28/34] test/qgraph: virtio-blk driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-09 14:16   ` Laurent Vivier
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 30/34] test/qgraph: virtio-net driver and interface nodes Emanuele Giuseppe Esposito
                   ` (5 subsequent siblings)
  34 siblings, 1 reply; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include  |   4 +-
 tests/virtio-blk-test.c | 459 ++++++++++++++++------------------------
 2 files changed, 186 insertions(+), 277 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 1d68e7d223..b628d2b821 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -193,7 +193,6 @@ gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio.c
 check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c
-check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c
 gcov-files-virtio-y += hw/virtio/virtio-rng.c
 check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
@@ -373,7 +372,6 @@ check-qtest-arm-y += tests/pca9552-test$(EXESUF)
 check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
-check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
 gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
 check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
 gcov-files-arm-y += hw/timer/arm_mptimer.c
@@ -785,6 +783,7 @@ libqgraph-tests-obj-y += tests/virtio-console-test.o
 libqgraph-tests-obj-y += tests/virtio-9p-test.o
 libqgraph-tests-obj-y += tests/virtio-balloon-test.o
 libqgraph-tests-obj-y += tests/virtio-rng-test.o
+libqgraph-tests-obj-y += tests/virtio-blk-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -827,7 +826,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/virtio-blk-test.c b/tests/virtio-blk-test.c
index 267cf28376..37c10b8152 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -10,29 +10,17 @@
 
 #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-generic.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 "qemu/bswap.h"
 #include "standard-headers/linux/virtio_blk.h"
 #include "standard-headers/linux/virtio_pci.h"
+#include "libqos/qgraph.h"
+#include "libqos/virtio-blk.h"
 
 #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
+static char *tmp_path;
 
 typedef struct QVirtioBlkReq {
     uint32_t type;
@@ -45,75 +33,16 @@ typedef struct QVirtioBlkReq {
 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_startf("-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;
+    return t_path;
 }
 
 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
@@ -275,31 +204,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);
-    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;
@@ -309,21 +228,17 @@ 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);
 
     /* Write request */
     req.type = VIRTIO_BLK_T_OUT;
@@ -332,23 +247,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;
@@ -357,17 +272,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);
@@ -378,48 +293,35 @@ 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);
-    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);
 
     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);
-
-    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;
@@ -428,34 +330,37 @@ 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);
+    /* FIXME: add spapr support */
+    if (qpci_has_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);
 
     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 */
@@ -465,22 +370,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;
@@ -488,18 +393,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);
@@ -510,21 +415,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);
-    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;
@@ -534,26 +437,29 @@ 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);
+    /* FIXME: add spapr support */
+    if (qpci_has_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);
 
     /* Write request */
     req.type = VIRTIO_BLK_T_OUT;
@@ -562,16 +468,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 */
@@ -581,25 +487,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;
@@ -607,20 +513,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);
@@ -631,121 +537,126 @@ 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);
-    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)
 {
+    QVirtioBlkPCI *blk = obj;
+    QVirtioPCIDevice *pdev = &blk->pci_vdev;
     QVirtioPCIDevice *dev;
-    QOSState *qs;
-    const char *arch = qtest_get_arch();
-
-    qs = pci_test_start();
 
     /* plug secondary disk */
     qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
                           "'drive': 'drive1'");
 
-    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT_HP);
+    dev = qvirtio_pci_device_find_slot(pdev->pdev->bus, VIRTIO_ID_BLOCK,
+                                    PCI_SLOT_HP);
     g_assert(dev);
     qvirtio_pci_device_disable(dev);
     qvirtio_pci_device_free(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 basic_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 = qvirtio_mmio_device_new(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);
-
-    alloc = generic_alloc_init(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);
-    generic_alloc_uninit(alloc);
-    test_end();
+    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+
 }
 
-int main(int argc, char **argv)
+static void virtio_blk_test_setup(char **cmd_line)
 {
-    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 *new_cmdline;
+
+    tmp_path = drive_create();
 
-    return g_test_run();
+    new_cmdline =
+        g_strdup_printf("%s "
+                        "-drive if=none,id=drive0,file=%s,format=raw "
+                        "-drive if=none,id=drive1,file=null-co://,format=raw ",
+                        *cmd_line, tmp_path);
+
+    g_assert_nonnull(new_cmdline);
+
+    g_free(*cmd_line);
+    *cmd_line = new_cmdline;
 }
+
+static void virtio_blk_test_cleanup(void)
+{
+    unlink(tmp_path);
+    g_free(tmp_path);
+}
+
+static void virtio_blk_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = virtio_blk_test_setup,
+        .after = virtio_blk_test_cleanup,
+    };
+
+    qos_add_test("blk-indirect", "virtio-blk", indirect, &opts);
+    qos_add_test("blk-config", "virtio-blk", config, &opts);
+    qos_add_test("blk-basic", "virtio-blk", basic, &opts);
+    qos_add_test("blk-basic-resize", "virtio-blk", basic_resize, &opts);
+
+    /* tests just for virtio-blk-pci */
+    qos_add_test("blk-msix", "virtio-blk-pci", msix, &opts);
+    qos_add_test("blk-idx", "virtio-blk-pci", idx, &opts);
+    qos_add_test("blk-nxvirtq", "virtio-blk-pci",
+                      test_nonexistent_virtqueue, &opts);
+    qos_add_test("blk-hotplug", "virtio-blk-pci", pci_hotplug, &opts);
+}
+
+libqos_init(virtio_blk_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 30/34] test/qgraph: virtio-net driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (28 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 31/34] test/qgraph: virtio-net test node Emanuele Giuseppe Esposito
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include    |   1 +
 tests/libqos/virtio-net.c | 177 ++++++++++++++++++++++++++++++++++++++
 tests/libqos/virtio-net.h |  41 +++++++++
 3 files changed, 219 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 b628d2b821..ecab26b7b2 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -768,6 +768,7 @@ libqgraph-virtio-obj-y += tests/libqos/virtio-9p.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-balloon.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-rng.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-blk.o
+libqgraph-virtio-obj-y += tests/libqos/virtio-net.o
 
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/virtio-net.c b/tests/libqos/virtio-net.c
new file mode 100644
index 0000000000..12eb6e0530
--- /dev/null
+++ b/tests/libqos/virtio-net.c
@@ -0,0 +1,177 @@
+/*
+ * 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 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);
+}
+
+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)
+{
+    interface->rx = qvirtqueue_setup(interface->vdev, alloc, 0);
+    interface->tx = qvirtqueue_setup(interface->vdev, alloc, 1);
+    driver_init(interface->vdev);
+}
+
+/* virtio-net-device */
+static void qvirtio_net_device_destroy(QOSGraphObject *obj)
+{
+    QVirtioNetDevice *v_net = (QVirtioNetDevice *) obj;
+    virtio_net_cleanup(&v_net->net);
+    g_free(v_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_device_get_driver(void *object,
+                                               const char *interface)
+{
+    QVirtioNetDevice *v_net = object;
+    if (!g_strcmp0(interface, "virtio-net")) {
+        return &v_net->net;
+    }
+
+    printf("%s not present in virtio-net-device\n", interface);
+    abort();
+}
+
+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_destroy;
+    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_destroy(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_destroy(pci_vobj);
+    g_free(v_net);
+}
+
+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);
+    driver_init(interface->vdev);
+}
+
+static void *qvirtio_net_pci_get_driver(void *object,
+                                            const char *interface)
+{
+    QVirtioNetPCI *v_net = object;
+    if (!g_strcmp0(interface, "virtio-net")) {
+        return &v_net->net;
+    }
+
+    printf("%s not present in virtio-net-pci\n", interface);
+    abort();
+}
+
+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_destroy;
+    obj->start_hw = qvirtio_net_pci_start_hw;
+    obj->get_driver = qvirtio_net_pci_get_driver;
+
+    return obj;
+}
+
+static void virtio_net(void)
+{
+    /* FIXME: every test using these nodes needs to setup a
+     * -netdev socket,id=hs0 otherwise QEMU is not going to start */
+    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", &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);
diff --git a/tests/libqos/virtio-net.h b/tests/libqos/virtio-net.h
new file mode 100644
index 0000000000..e6905cd82e
--- /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;
+};
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 31/34] test/qgraph: virtio-net test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (29 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 30/34] test/qgraph: virtio-net driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 32/34] test/qgraph: virtio-scsi driver and interface nodes Emanuele Giuseppe Esposito
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include  |   3 +-
 tests/virtio-net-test.c | 159 ++++++++++++----------------------------
 2 files changed, 49 insertions(+), 113 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ecab26b7b2..4634fd8ef1 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -190,7 +190,6 @@ gcov-files-ipack-y += hw/char/ipoctal232.c
 gcov-files-virtioserial-y += hw/char/virtio-console.c
 
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio.c
-check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c
 gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c
@@ -785,6 +784,7 @@ libqgraph-tests-obj-y += tests/virtio-9p-test.o
 libqgraph-tests-obj-y += tests/virtio-balloon-test.o
 libqgraph-tests-obj-y += tests/virtio-rng-test.o
 libqgraph-tests-obj-y += tests/virtio-blk-test.o
+libqgraph-tests-obj-y += tests/virtio-net-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -828,7 +828,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 b2a5f5a350..4f451395b9 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,57 +22,10 @@
 #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();
-}
+static int sv[2];
 
 #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);
-}
-
 static void rx_test(QVirtioDevice *dev,
                     QGuestAllocator *alloc, QVirtQueue *vq,
                     int socket)
@@ -189,80 +135,71 @@ 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;
+    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;
+    rx_stop_cont_test(dev, t_alloc, rx, sv[0]);
 }
 
-static void pci_basic(gconstpointer data)
-{
-    QVirtioPCIDevice *dev;
-    QOSState *qs;
-    QVirtQueuePCI *tx, *rx;
-    void (*func) (QVirtioDevice *dev,
-                  QGuestAllocator *alloc,
-                  QVirtQueue *rvq,
-                  QVirtQueue *tvq,
-                  int socket) = data;
-    int sv[2], ret;
-
-    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
-    g_assert_cmpint(ret, !=, -1);
-
-    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);
-
-    driver_init(&dev->vdev);
-    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);
-    qvirtio_pci_device_disable(dev);
-    g_free(dev->pdev);
-    g_free(dev);
-    qtest_shutdown(qs);
-}
 #endif
 
-static void hotplug(void)
+static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
 {
     const char *arch = qtest_get_arch();
 
-    qtest_start("-device virtio-net-pci");
-
     qpci_plug_device_test("virtio-net-pci", "net1", PCI_SLOT_HP, NULL);
 
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
         qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP);
     }
 
-    test_end();
 }
 
-int main(int argc, char **argv)
+static void virtio_net_test_setup(char **cmd_line)
 {
-    g_test_init(&argc, &argv, NULL);
+    int ret;
+    char *new_cmdline;
+
+    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
+    g_assert_cmpint(ret, !=, -1);
+
+    new_cmdline = g_strdup_printf("%s -netdev socket,fd=%d,id=hs0 ",
+                                  *cmd_line, sv[1]);
+    g_assert_nonnull(new_cmdline);
+
+    g_free(*cmd_line);
+    *cmd_line = new_cmdline;
+}
+
+static void virtio_net_test_cleanup(void)
+{
+    close(sv[0]);
+    close(sv[1]);
+}
+static void virtio_net_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = virtio_net_test_setup,
+        .after = virtio_net_test_cleanup,
+    };
+
 #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("net-basic", "virtio-net", send_recv_test, &opts);
+    qos_add_test("net-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("net-hotplug", "virtio-pci", hotplug, &opts);
 }
+
+libqos_init(virtio_net_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 32/34] test/qgraph: virtio-scsi driver and interface nodes
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (30 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 31/34] test/qgraph: virtio-net test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 33/34] test/qgraph: virtio-scsi test node Emanuele Giuseppe Esposito
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 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 4634fd8ef1..c5aa9f18b7 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -768,6 +768,7 @@ libqgraph-virtio-obj-y += tests/libqos/virtio-balloon.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-rng.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-blk.o
 libqgraph-virtio-obj-y += tests/libqos/virtio-net.o
+libqgraph-virtio-obj-y += tests/libqos/virtio-scsi.o
 
 libqgraph-pci-obj-y = $(libqos-virtio-obj-y)
 libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
diff --git a/tests/libqos/virtio-scsi.c b/tests/libqos/virtio-scsi.c
new file mode 100644
index 0000000000..e751ef639d
--- /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_device_destroy(QOSGraphObject *obj)
+{
+    QVirtioSCSIDevice *v_scsi = (QVirtioSCSIDevice *) obj;
+
+    g_free(v_scsi);
+}
+
+static void *qvirtio_scsi_device_get_driver(void *object,
+                                               const char *interface)
+{
+    QVirtioSCSIDevice *v_scsi = object;
+    if (!g_strcmp0(interface, "virtio-scsi")) {
+        return &v_scsi->scsi;
+    }
+
+    printf("%s not present in virtio-scsi-device\n", interface);
+    abort();
+}
+
+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.destructor = qvirtio_scsi_device_destroy;
+    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, "virtio-scsi")) {
+        return &v_scsi->scsi;
+    }
+
+    printf("%s not present in virtio-scsi-pci\n", interface);
+    abort();
+}
+
+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(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", &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", "virtio-scsi");
+}
+
+libqos_init(virtio_scsi);
diff --git a/tests/libqos/virtio-scsi.h b/tests/libqos/virtio-scsi.h
new file mode 100644
index 0000000000..17a47beddc
--- /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;
+};
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 33/34] test/qgraph: virtio-scsi test node
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (31 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 32/34] test/qgraph: virtio-scsi driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 34/34] test/qgraph: temporarly commented vhost-user-test Emanuele Giuseppe Esposito
  2018-08-09  8:57 ` [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Paolo Bonzini
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

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>
---
 tests/Makefile.include   |   3 +-
 tests/virtio-scsi-test.c | 153 +++++++++++++++++++--------------------
 2 files changed, 75 insertions(+), 81 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index c5aa9f18b7..69877b3702 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -194,7 +194,6 @@ gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c
 gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c
 gcov-files-virtio-y += hw/virtio/virtio-rng.c
-check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/scsi/virtio-scsi.c
 ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
 gcov-files-virtio-y += hw/9pfs/virtio-9p.c
@@ -786,6 +785,7 @@ libqgraph-tests-obj-y += tests/virtio-balloon-test.o
 libqgraph-tests-obj-y += tests/virtio-rng-test.o
 libqgraph-tests-obj-y += tests/virtio-blk-test.o
 libqgraph-tests-obj-y += tests/virtio-net-test.o
+libqgraph-tests-obj-y += tests/virtio-scsi-test.o
 
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
@@ -829,7 +829,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 1581b6926c..29e75064c8 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 QGuestAllocator *alloc;
 
-static void qvirtio_scsi_stop(QOSState *qs)
-{
-    qtest_shutdown(qs);
-}
-
-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 */
@@ -183,29 +147,23 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot)
 }
 
 /* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
+static void pci_nop(void *obj, void *data, QGuestAllocator *alloc)
 {
-    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 +176,64 @@ 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(char **cmd_line)
 {
-    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);
+    char *new_cmdline;
 
-    return g_test_run();
+    new_cmdline = g_strdup_printf("%s -drive id=drv1,if=none,file=null-co://,"
+                                  "format=raw", *cmd_line);
+
+    g_assert_nonnull(new_cmdline);
+
+    g_free(*cmd_line);
+    *cmd_line = new_cmdline;
 }
+
+static void virtio_scsi_setup(char **cmd_line)
+{
+    char *new_cmdline;
+
+    new_cmdline = g_strdup_printf("%s -drive file=blkdebug::null-co://,"
+                                  "if=none,id=dr1,format=raw,file.align=4k "
+                                  "-device scsi-hd,drive=dr1,lun=0,scsi-id=1",
+                                  *cmd_line);
+
+    g_assert_nonnull(new_cmdline);
+
+    g_free(*cmd_line);
+    *cmd_line = new_cmdline;
+}
+
+static void virtio_scsi_test(void)
+{
+    QOSGraphTestOptions opts = { };
+
+    qos_add_test("scsi-nop", "virtio-scsi", pci_nop, NULL);
+
+    opts.before = virtio_scsi_hotplug_setup;
+    qos_add_test("scsi-hotplug", "virtio-scsi", hotplug, &opts);
+
+    opts.before = virtio_scsi_setup;
+    qos_add_test("scsi-unaligned-write-same", "virtio-scsi",
+                 test_unaligned_write_same, &opts);
+}
+
+libqos_init(virtio_scsi_test);
-- 
2.17.1

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

* [Qemu-devel] [PATCH v2 34/34] test/qgraph: temporarly commented vhost-user-test
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (32 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 33/34] test/qgraph: virtio-scsi test node Emanuele Giuseppe Esposito
@ 2018-08-06 14:34 ` Emanuele Giuseppe Esposito
  2018-08-09  8:57 ` [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Paolo Bonzini
  34 siblings, 0 replies; 71+ messages in thread
From: Emanuele Giuseppe Esposito @ 2018-08-06 14:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé,
	qemu-devel, Stefan Hajnoczi, Emanuele Giuseppe Esposito

vhost-user-test has not converted to qgraph yet, and since
it uses virtio interface, it won't work, causing make check
to fail.
Commented out until it does not get converted to graph node.

Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
---
 tests/Makefile.include | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 69877b3702..14f19ebcdb 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -287,10 +287,10 @@ 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)
 gcov-files-i386-y += hw/pci-host/q35.c
-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_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_TPM) += tests/tpm-crb-swtpm-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM) += tests/tpm-crb-test$(EXESUF)
 check-qtest-i386-$(CONFIG_TPM) += tests/tpm-tis-swtpm-test$(EXESUF)
-- 
2.17.1

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

* Re: [Qemu-devel] [PATCH v2 02/34] tests/qgraph: rename qpci_init_pc functions
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 02/34] tests/qgraph: rename qpci_init_pc functions Emanuele Giuseppe Esposito
@ 2018-08-06 15:04   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-06 15:04 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> Rename qpci_init_pc in qpci_new_pc, since the function actually
> allocates a new QPCIBusPC and initialize it.
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.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/pci-pc.c     | 2 +-
>  tests/libqos/pci-pc.h     | 9 ++++++++-
>  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 +-
>  13 files changed, 21 insertions(+), 14 deletions(-)
> 
...
> diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
> index a9c1aceaa7..72b3eb46f5 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_init = qpci_pc_new,
>      .qpci_free = qpci_free_pc,
>      .shutdown = qtest_pc_shutdown,
>  };

I think you should also rename the "qpci_init" field to "qpci_new".
And as we have "qpci_free_pc", it should be "qpci_new_pc", and you
should do the same for qpci_init_spapr -> qpci_new_spapr.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 08/34] tests/qgraph: rename qpci_init_spapr functions
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 08/34] tests/qgraph: rename qpci_init_spapr functions Emanuele Giuseppe Esposito
@ 2018-08-08 15:30   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-08 15:30 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> Rename qpci_init_spapr in qpci_new_spapr, since the function actually
> allocates a new QPCIBusSPAPR and initialize it.
> 

I think you should merge this one with 02/34.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-08 17:39   ` Laurent Vivier
  2018-08-09 12:17     ` Emanuele
  0 siblings, 1 reply; 71+ messages in thread
From: Laurent Vivier @ 2018-08-08 17:39 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> 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>
> ---
>  tests/Makefile.include |  4 +++-
>  tests/libqos/pci-pc.c  | 41 +++++++++++++++++++++++++++++-------
>  tests/libqos/pci-pc.h  | 15 ++++++++++++-
>  tests/libqos/pci.c     | 48 +++++++++++++++++++++++++++++++++++++++---
>  tests/libqos/pci.h     | 15 +++++++++++++
>  5 files changed, 110 insertions(+), 13 deletions(-)
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index eabf9ed8b4..f04f9fbc3a 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -771,11 +771,13 @@ 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
>  
> +libqgraph-pci-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-pci-y += tests/qos-test$(EXESUF)
> -tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-obj-y)
> +tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-pci-obj-y)
>  
>  tests/qmp-test$(EXESUF): tests/qmp-test.o
>  tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
> diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
> index 83a3a32129..f5fb94eabc 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,12 +109,23 @@ static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint3
>      outl(0xcfc, value);
>  }
>  
> -QPCIBus *qpci_pc_new(QTestState *qts, QGuestAllocator *alloc)
> +static void *qpci_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;
> +    }
> +    printf("%s not present in pci-bus-pc\n", interface);

fprintf(stderr, ...) ?

> +    abort();

You should use g_assert_not_reached().

> +}
>  
> +void qpci_init_pc(QPCIBusPC *ret, QTestState *qts, QGuestAllocator *alloc)
> +{
>      assert(qts);
>  
> +    /* tests can use pci-bus */
> +    ret->bus.has_buggy_msi = FALSE;

I think you should introduce the field has_buggy_msi when it will be
really needed: with patch 09/34 adn pci-spapr.

> +
>      ret->bus.pio_readb = qpci_pc_pio_readb;
>      ret->bus.pio_readw = qpci_pc_pio_readw;
>      ret->bus.pio_readl = qpci_pc_pio_readl;
> @@ -147,11 +152,23 @@ QPCIBus *qpci_pc_new(QTestState *qts, QGuestAllocator *alloc)
>      ret->bus.mmio_alloc_ptr = 0xE0000000;
>      ret->bus.mmio_limit = 0x100000000ULL;
>  
> +    ret->obj.get_driver = qpci_get_driver;
> +}
> +
> +QPCIBus *qpci_pc_new(QTestState *qts, QGuestAllocator *alloc)

As I said for 02/34, I think qpci_new_pc() should be a better name to
like the one we have for qpci_free_pc().

> +{
> +    QPCIBusPC *ret = g_new0(QPCIBusPC, 1);

perhaps you can rename "ret" to "qpci"?

> +    qpci_init_pc(ret, qts, alloc);
> +
>      return &ret->bus;
>  }
>  
>  void qpci_free_pc(QPCIBus *bus)
>  {
> +    if (!bus) {
> +        return;
> +    }
> +
>      QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);

Generally, gcc doesn't like to mix declarations and instructions. I
think something like this would be nicer:

    QPCIBusPC *s;

    if (!bus) {
        return;
    }
    s = container_of(bus, QPCIBusPC, bus);

>  
>      g_free(s);
> @@ -176,3 +193,11 @@ void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
>  
>      qmp_eventwait("DEVICE_DELETED");
>  }
> +
> +static void qpci_pc(void)

This name is not very clear, for the qemu part, type_init() is generally
used with XXX_register_types name.

Perhaps you can use something like "qpci_pc_register_nodes" name?

> +{
> +    qos_node_create_driver("pci-bus-pc", NULL);
> +    qos_node_produces("pci-bus-pc", "pci-bus");
> +}
> +
> +libqos_init(qpci_pc);
> diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
> index 88be29eaf3..a3754c1c86 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"
>  
> +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,
> + * 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 0b73cb23d0..91440ece5c 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,15 +51,31 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
>      }
>  }
>  
> -QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
> +bool qpci_has_buggy_msi(QPCIDevice *dev)
>  {
> -    QPCIDevice *dev;
> +    return dev->bus->has_buggy_msi;
> +}

As above, introduce this when you need it.

> -    dev = g_malloc0(sizeof(*dev));
> +/* returns TRUE if everything goes fine, FALSE if not */
> +static bool qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
> +{
>      dev->bus = bus;
>      dev->devfn = devfn;
>  
>      if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
> +        return FALSE;
> +    }

I think what we check here is to see if the PCI device is available.
0xFFFF means there is a problem.

I think you should add a function "qpci_device_available(devn, bus)"

> +
> +    return TRUE;
> +}
> +
> +QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
> +{
> +    QPCIDevice *dev;
> +
> +    dev = g_malloc0(sizeof(*dev));
> +
> +    if (!qpci_device_set(dev, bus, devfn)) {
>          g_free(dev);
>          return NULL;
>      }
> @@ -66,6 +83,21 @@ 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;
> +
> +    if (!qpci_device_set(dev, bus, addr->devfn)) {
> +        printf("PCI Device not found\n");
> +        abort();
> +    }

so, here, you should use qpci_device_set() and qpci_device_available()...

> +
> +    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);

or you can only check vendor_id to see it is 0xffff or not...

> +    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
> +    g_assert(vendor_id == addr->vendor_id);

that should be in fact detected by this g_assert().

> +    g_assert(device_id == addr->device_id);
> +}
> +
>  void qpci_device_enable(QPCIDevice *dev)
>  {
>      uint16_t cmd;
> @@ -402,3 +434,13 @@ void qpci_plug_device_test(const char *driver, const char *id,
>      qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot,
>                           opts ? ", " : "", opts ? opts : "");
>  }
> +
> +void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr)
> +{
> +    if (!addr || !opts) {
> +        return;
> +    }

Should it be an error case and fails (g_assert())?

> +
> +    opts->arg = addr;
> +    opts->size_arg = sizeof(QPCIAddress);
> +}
> diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
> index 429c382282..5fb3c550c5 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,8 @@ 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 */

as above, introduce it when you need it.

> +
>  };
>  
>  struct QPCIBar {
> @@ -66,10 +70,19 @@ 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);
> +/* returns the bus has_buggy_msi flag */
> +bool qpci_has_buggy_msi(QPCIDevice *dev);
>  
>  void qpci_device_enable(QPCIDevice *dev);
>  uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id);
> @@ -112,4 +125,6 @@ QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr);
>  void qpci_plug_device_test(const char *driver, const char *id,
>                             uint8_t slot, const char *opts);
>  void qpci_unplug_acpi_device_test(const char *id, uint8_t slot);
> +
> +void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr);
>  #endif
> 

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

* Re: [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node Emanuele Giuseppe Esposito
@ 2018-08-08 19:27   ` Laurent Vivier
  2018-08-09 12:23     ` Emanuele
  0 siblings, 1 reply; 71+ messages in thread
From: Laurent Vivier @ 2018-08-08 19:27 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> 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>
> ---
>  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 f04f9fbc3a..4e7b4bb614 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -771,7 +771,10 @@ 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
>  
> +libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
> +
>  libqgraph-pci-obj-y = $(libqos-pc-obj-y)
> +libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
>  
>  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 0000000000..e3eddf2eba
> --- /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;
> +    }
> +    printf("%s not present in i440FX-pcihost\n", device);

fprintf(stderr, ...

> +    abort();

g_assert_not_reached()

> +}
> +
> +static void qos_create_i440FX_host(i440FX_pcihost *host,
> +                                   QGuestAllocator *alloc)
> +{
> +    host->obj.get_device = i440FX_host_get_device;
> +    qpci_init_pc(&host->pci, global_qtest, alloc);
> +}
> +
> +/* x86_64/pc machine */
> +
> +static void pc_destroy(QOSGraphObject *obj)
> +{
> +    QX86_64_PCMachine *machine = (QX86_64_PCMachine *) obj;
> +    pc_alloc_uninit(machine->alloc);
> +    g_free(machine);
> +}
> +
> +static void *pc_get_driver(void *object, const char *interface)
> +{
> +    QX86_64_PCMachine *machine = object;
> +    if (!g_strcmp0(interface, "guest_allocator")) {

Perhaps we can call that "memory"  rather than "guest_allocator", as it
gives access to the memory of the guest?

> +        return machine->alloc;
> +    }
> +
> +    printf("%s not present in x86_64/pc\n", interface);

fprintf(stderr, ...

> +    abort();

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;
> +    }
> +
> +    printf("%s not present in x86_64/pc\n", device);

fprintf(stderr, ...

> +    abort();

g_assert_not_reached()

> +}
> +
> +static void *qos_create_machine_pc(void)
> +{
> +    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_destroy;
> +    machine->alloc = pc_alloc_init_flags(global_qtest, ALLOC_NO_FLAGS);
> +    qos_create_i440FX_host(&machine->bridge, machine->alloc);
> +
> +    return &machine->obj;
> +}
> +
> +static void pc_machine(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);

and qos_node_produces("x86_64/pc", "memory");  (or "guest_allocator")?

and perhaps later, a qos_add_test("test-memory-allocator", "memory",
test_memory_allocator, NULL)?

> +}
> +
> +libqos_init(pc_machine);

pc_machine_register_nodes?

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 18/34] tests: virtio: separate ccw tests from libqos
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 18/34] tests: virtio: separate ccw tests from libqos Emanuele Giuseppe Esposito
@ 2018-08-08 19:34   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-08 19:34 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> From: Paolo Bonzini <pbonzini@redhat.com>
> 
> Because qtest does not support s390 channel I/O, s390 only performs smoke tests on
> those few devices that do not have any functional tests.  Therefore, every time we
> add functional tests for a virtio device, the choice is between removing
> those tests from the s390 suite (so that s390 actually _loses_ coverage)
> or sprinkling the test with architecture checks.
> 
> This patch simply creates a ccw-specific test that only performs smoke tests on
> all virtio-ccw devices.  If channel I/O support is ever added to qtest and libqos,
> then this file can go away.  In the meanwhile, it simplifies maintenance and
> makes sure that all virtio devices are tested.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>

You can add the "Acked-by" from Cornelia and the "Reviewed-by" from Thomas.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 00/34] Qtest driver framework
  2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
                   ` (33 preceding siblings ...)
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 34/34] test/qgraph: temporarly commented vhost-user-test Emanuele Giuseppe Esposito
@ 2018-08-09  8:57 ` Paolo Bonzini
  2018-08-09  9:20   ` Emanuele
  34 siblings, 1 reply; 71+ messages in thread
From: Paolo Bonzini @ 2018-08-09  8:57 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> qgraph API for the qtest driver framework
> 
> This series of patches introduce a different qtest driver
> organization, viewing machines, drivers and tests as node in a
> graph, each having one or multiple edges relations.
> 
> 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:
> - MACHINE:   for example "arm/raspi2"
> - DRIVER:    for example "generic-sdhci"
> - INTERFACE: for example "sdhci" (interface for all "-sdhci" drivers)
> - TEST:      for example "sdhci-test", consumes an interface and tests
>              the functions provided
> 
> 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
> - 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.
> 
> This work is being done as Google Summer of Code 2018 project for QEMU,
> my mentors are Paolo Bonzini and Laurent Vivier.
> Additional infos on the project can be found at:
> https://wiki.qemu.org/Features/qtest_driver_framework

Tests are not cleaning up properly.  There are two bugs, both related to
qtest_end not being called (from main in one case, after 
qos_invalidate_command_line in the other).  I tried this fix but then
the e1000e tests start failing:

diff --git a/tests/libqtest.h b/tests/libqtest.h
index ac52872..7a6fa6e 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -555,6 +555,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
index 1c3a7fc..a22d176 100644
--- a/tests/qos-test.c
+++ b/tests/qos-test.c
@@ -233,10 +233,7 @@ static void restart_qemu_or_continue(char *path)
     * new command line
     */
     if (g_strcmp0(old_path, path)) {
-        if (old_path) {
-            qtest_end();
-            g_free(old_path);
-        }
+        qtest_end();
         old_path = path;
         global_qtest = qtest_start(path);
     } else { /* if cmd line is the same, reset the guest */
@@ -247,7 +244,10 @@ static void restart_qemu_or_continue(char *path)
 
 void qos_invalidate_command_line(void)
 {
-    old_path = NULL;
+    if (old_path) {
+        g_free(old_path);
+        old_path = NULL;
+    }
 }
 
 /**
@@ -475,6 +475,7 @@ int main(int argc, char **argv)
 
     qos_graph_foreach_test_path(walk_path);
     g_test_run();
+    qtest_end();
     qos_graph_destroy();
     return 0;
 }


Also, qos-test can be added to check-qtest-generic-y, since it is not 
PCI-specific.

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 14f19eb..6012f6e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -182,6 +182,7 @@ gcov-files-generic-y = monitor.c qapi/qmp-dispatch.c
 check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
 gcov-files-generic-y = qdev-monitor.c qmp.c
 check-qtest-generic-y += tests/cdrom-test$(EXESUF)
+check-qtest-generic-y += tests/qos-test$(EXESUF)
 
 gcov-files-ipack-y += hw/ipack/ipack.c
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
@@ -790,9 +791,6 @@ libqgraph-tests-obj-y += tests/virtio-scsi-test.o
 check-unit-y += tests/test-qgraph$(EXESUF)
 tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
 
-check-qtest-pci-y += tests/qos-test$(EXESUF)
-tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-tests-obj-y)
-
 tests/qmp-test$(EXESUF): tests/qmp-test.o
 tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
 tests/rtc-test$(EXESUF): tests/rtc-test.o

Another small bug is that virtio-net-test should also call 
qos_invalidate_command_line, since it is closing the socket that
is opened in virtio_net_test_setup.

Paolo

> v2:
> - added command line arguments caching
> - converted all virtio tests
> - converted e1000e test
> - added two more machines (virt and ppc64)
> - introduced separation between edge-name (used by get_driver) and
>   node-name (matched with QMP query result)
> - edge carries also additional arguments, like the pci address of
>   destination device
> - test now can execute a function before and after the command line
>   is allocated, to allocate various file and sockets needed by command
>   line and test
> - better documentation with working example in qgraph.h
> - removed esplicit creation of interfaces
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> 
> Emanuele Giuseppe Esposito (33):
>   tests: qgraph API for the qtest driver framework
>   tests/qgraph: rename qpci_init_pc functions
>   tests/qgraph: pci-pc driver and interface nodes
>   tests/qgraph: x86_64/pc machine node
>   tests/qgraph: sdhci driver and interface nodes
>   tests/qgraph: sdhci test node
>   tests/qgraph: arm/raspi2 machine node
>   tests/qgraph: rename qpci_init_spapr functions
>   tests/qgraph: pci-spapr driver and interface nodes
>   tests/qgraph: ppc64/pseries machine node
>   test/qgraph: e1000e driver and interface nodes
>   test/qgraph: e1000e-test node
>   test/qgraph: virtio_start_device function
>   test/qgraph: virtio-pci driver and interface nodes
>   tests/qgraph: rename qvirtio_mmio_init_device functions
>   test/qgraph: virtio-mmio driver and interface nodes
>   test/qgraph: arm/virt machine node
>   test/qgraph: virtio-serial driver and interface nodes
>   test/qgraph: virtio-console test node
>   test/qgraph: virtio-serial test node
>   test/qgraph: virtio-9p driver and interface nodes
>   test/qgraph: virtio-9p test node
>   test/qgraph: virtio-balloon driver and interface nodes
>   test/qgraph: virtio-balloon test node
>   test/qgraph: virtio-rng driver and interface nodes
>   test/qgraph: virtio-rng test node
>   test/qgraph: virtio-blk driver and interface nodes
>   test/qgraph: virtio-blk test node
>   test/qgraph: virtio-net driver and interface nodes
>   test/qgraph: virtio-net test node
>   test/qgraph: virtio-scsi driver and interface nodes
>   test/qgraph: virtio-scsi test node
>   test/qgraph: temporarly commented vhost-user-test
> 
> Paolo Bonzini (1):
>   tests: virtio: separate ccw tests from libqos
> 
>  configure                            |   2 +-
>  include/qemu/module.h                |   2 +
>  tests/Makefile.include               |  79 +--
>  tests/e1000e-test.c                  | 354 +++----------
>  tests/i440fx-test.c                  |   2 +-
>  tests/ide-test.c                     |   2 +-
>  tests/libqos/ahci.c                  |   2 +-
>  tests/libqos/e1000e.c                | 262 ++++++++++
>  tests/libqos/e1000e.h                |  53 ++
>  tests/libqos/libqos-pc.c             |   2 +-
>  tests/libqos/libqos-spapr.c          |   2 +-
>  tests/libqos/pci-pc.c                |  41 +-
>  tests/libqos/pci-pc.h                |  22 +-
>  tests/libqos/pci-spapr.c             |  57 ++-
>  tests/libqos/pci-spapr.h             |  26 +-
>  tests/libqos/pci.c                   |  48 +-
>  tests/libqos/pci.h                   |  15 +
>  tests/libqos/ppc64_pseries-machine.c | 111 +++++
>  tests/libqos/qgraph.c                | 721 +++++++++++++++++++++++++++
>  tests/libqos/qgraph.h                | 514 +++++++++++++++++++
>  tests/libqos/qgraph_extra.h          | 263 ++++++++++
>  tests/libqos/raspi2-machine.c        |  82 +++
>  tests/libqos/sdhci.c                 | 163 ++++++
>  tests/libqos/sdhci.h                 |  69 +++
>  tests/libqos/virt-machine.c          |  90 ++++
>  tests/libqos/virtio-9p.c             | 164 ++++++
>  tests/libqos/virtio-9p.h             |  42 ++
>  tests/libqos/virtio-balloon.c        | 111 +++++
>  tests/libqos/virtio-balloon.h        |  39 ++
>  tests/libqos/virtio-blk.c            | 126 +++++
>  tests/libqos/virtio-blk.h            |  40 ++
>  tests/libqos/virtio-mmio.c           |  72 ++-
>  tests/libqos/virtio-mmio.h           |   6 +-
>  tests/libqos/virtio-net.c            | 177 +++++++
>  tests/libqos/virtio-net.h            |  41 ++
>  tests/libqos/virtio-pci.c            |  80 ++-
>  tests/libqos/virtio-pci.h            |  12 +
>  tests/libqos/virtio-rng.c            | 108 ++++
>  tests/libqos/virtio-rng.h            |  39 ++
>  tests/libqos/virtio-scsi.c           | 117 +++++
>  tests/libqos/virtio-scsi.h           |  39 ++
>  tests/libqos/virtio-serial.c         | 109 ++++
>  tests/libqos/virtio-serial.h         |  39 ++
>  tests/libqos/virtio.c                |   9 +
>  tests/libqos/virtio.h                |   1 +
>  tests/libqos/x86_64_pc-machine.c     | 110 ++++
>  tests/q35-test.c                     |   4 +-
>  tests/qos-test.c                     | 480 ++++++++++++++++++
>  tests/rtl8139-test.c                 |   2 +-
>  tests/sdhci-test.c                   | 222 +++------
>  tests/tco-test.c                     |   2 +-
>  tests/test-qgraph.c                  | 446 +++++++++++++++++
>  tests/usb-hcd-ehci-test.c            |   2 +-
>  tests/vhost-user-test.c              |   7 +-
>  tests/virtio-9p-test.c               | 221 +++-----
>  tests/virtio-balloon-test.c          |  22 +-
>  tests/virtio-blk-test.c              | 473 +++++++-----------
>  tests/virtio-ccw-test.c              | 121 +++++
>  tests/virtio-console-test.c          |  30 +-
>  tests/virtio-net-test.c              | 163 ++----
>  tests/virtio-rng-test.c              |  25 +-
>  tests/virtio-scsi-test.c             | 155 +++---
>  tests/virtio-serial-test.c           |  27 +-
>  63 files changed, 5624 insertions(+), 1243 deletions(-)
>  create mode 100644 tests/libqos/e1000e.c
>  create mode 100644 tests/libqos/e1000e.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_extra.h
>  create mode 100644 tests/libqos/raspi2-machine.c
>  create mode 100644 tests/libqos/sdhci.c
>  create mode 100644 tests/libqos/sdhci.h
>  create mode 100644 tests/libqos/virt-machine.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/qos-test.c
>  create mode 100644 tests/test-qgraph.c
>  create mode 100644 tests/virtio-ccw-test.c
> 

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

* Re: [Qemu-devel] [PATCH v2 00/34] Qtest driver framework
  2018-08-09  8:57 ` [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Paolo Bonzini
@ 2018-08-09  9:20   ` Emanuele
  2018-08-09  9:44     ` Paolo Bonzini
  0 siblings, 1 reply; 71+ messages in thread
From: Emanuele @ 2018-08-09  9:20 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi



On 08/09/2018 10:57 AM, Paolo Bonzini wrote:
> On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
>> qgraph API for the qtest driver framework
>>
>> This series of patches introduce a different qtest driver
>> organization, viewing machines, drivers and tests as node in a
>> graph, each having one or multiple edges relations.
>>
>> 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:
>> - MACHINE:   for example "arm/raspi2"
>> - DRIVER:    for example "generic-sdhci"
>> - INTERFACE: for example "sdhci" (interface for all "-sdhci" drivers)
>> - TEST:      for example "sdhci-test", consumes an interface and tests
>>               the functions provided
>>
>> 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
>> - 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.
>>
>> This work is being done as Google Summer of Code 2018 project for QEMU,
>> my mentors are Paolo Bonzini and Laurent Vivier.
>> Additional infos on the project can be found at:
>> https://wiki.qemu.org/Features/qtest_driver_framework
> Tests are not cleaning up properly.  There are two bugs, both related to
> qtest_end not being called (from main in one case, after
> qos_invalidate_command_line in the other).  I tried this fix but then
> the e1000e tests start failing:
>
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index ac52872..7a6fa6e 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -555,6 +555,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
> index 1c3a7fc..a22d176 100644
> --- a/tests/qos-test.c
> +++ b/tests/qos-test.c
> @@ -233,10 +233,7 @@ static void restart_qemu_or_continue(char *path)
>       * new command line
>       */
>       if (g_strcmp0(old_path, path)) {
> -        if (old_path) {
> -            qtest_end();
> -            g_free(old_path);
> -        }
> +        qtest_end();
Why this? Shouldn't it be:

if (g_strcmp0(old_path, path)) {
         qtest_end(); /* handles global_qtest = NULL */
         g_free(old_path); /* handles NULL */
         old_path = path;
         global_qtest = qtest_start(path);
} else ....

>           old_path = path;
>           global_qtest = qtest_start(path);
>       } else { /* if cmd line is the same, reset the guest */
> @@ -247,7 +244,10 @@ static void restart_qemu_or_continue(char *path)
>   
>   void qos_invalidate_command_line(void)
>   {
> -    old_path = NULL;
> +    if (old_path) {
> +        g_free(old_path);
> +        old_path = NULL;
> +    }
>   }
Same here, just

{
     g_free(old_path);
     old_path=NULL;
}

  should be enough I think.
>   
>   /**
> @@ -475,6 +475,7 @@ int main(int argc, char **argv)
>   
>       qos_graph_foreach_test_path(walk_path);
>       g_test_run();
> +    qtest_end();
>       qos_graph_destroy();
>       return 0;
>   }
>
>
> Also, qos-test can be added to check-qtest-generic-y, since it is not
> PCI-specific.
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 14f19eb..6012f6e 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -182,6 +182,7 @@ gcov-files-generic-y = monitor.c qapi/qmp-dispatch.c
>   check-qtest-generic-y += tests/device-introspect-test$(EXESUF)
>   gcov-files-generic-y = qdev-monitor.c qmp.c
>   check-qtest-generic-y += tests/cdrom-test$(EXESUF)
> +check-qtest-generic-y += tests/qos-test$(EXESUF)
>   
>   gcov-files-ipack-y += hw/ipack/ipack.c
>   check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
> @@ -790,9 +791,6 @@ libqgraph-tests-obj-y += tests/virtio-scsi-test.o
>   check-unit-y += tests/test-qgraph$(EXESUF)
>   tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
>   
> -check-qtest-pci-y += tests/qos-test$(EXESUF)

> -tests/qos-test$(EXESUF): tests/qos-test.o $(libqgraph-tests-obj-y)
Why did you comment this line? To me it does not compile without it.
> -
>   tests/qmp-test$(EXESUF): tests/qmp-test.o
>   tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
>   tests/rtc-test$(EXESUF): tests/rtc-test.o
>
> Another small bug is that virtio-net-test should also call
> qos_invalidate_command_line, since it is closing the socket that
> is opened in virtio_net_test_setup.
Right, I forgot. Also virtio-blk-test needs to do it.

I tried to apply your changes with my suggested modifications, and 
everything seems to work to me.
>> v2:
>> - added command line arguments caching
>> - converted all virtio tests
>> - converted e1000e test
>> - added two more machines (virt and ppc64)
>> - introduced separation between edge-name (used by get_driver) and
>>    node-name (matched with QMP query result)
>> - edge carries also additional arguments, like the pci address of
>>    destination device
>> - test now can execute a function before and after the command line
>>    is allocated, to allocate various file and sockets needed by command
>>    line and test
>> - better documentation with working example in qgraph.h
>> - removed esplicit creation of interfaces
>>
>> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
>>
>> Emanuele Giuseppe Esposito (33):
>>    tests: qgraph API for the qtest driver framework
>>    tests/qgraph: rename qpci_init_pc functions
>>    tests/qgraph: pci-pc driver and interface nodes
>>    tests/qgraph: x86_64/pc machine node
>>    tests/qgraph: sdhci driver and interface nodes
>>    tests/qgraph: sdhci test node
>>    tests/qgraph: arm/raspi2 machine node
>>    tests/qgraph: rename qpci_init_spapr functions
>>    tests/qgraph: pci-spapr driver and interface nodes
>>    tests/qgraph: ppc64/pseries machine node
>>    test/qgraph: e1000e driver and interface nodes
>>    test/qgraph: e1000e-test node
>>    test/qgraph: virtio_start_device function
>>    test/qgraph: virtio-pci driver and interface nodes
>>    tests/qgraph: rename qvirtio_mmio_init_device functions
>>    test/qgraph: virtio-mmio driver and interface nodes
>>    test/qgraph: arm/virt machine node
>>    test/qgraph: virtio-serial driver and interface nodes
>>    test/qgraph: virtio-console test node
>>    test/qgraph: virtio-serial test node
>>    test/qgraph: virtio-9p driver and interface nodes
>>    test/qgraph: virtio-9p test node
>>    test/qgraph: virtio-balloon driver and interface nodes
>>    test/qgraph: virtio-balloon test node
>>    test/qgraph: virtio-rng driver and interface nodes
>>    test/qgraph: virtio-rng test node
>>    test/qgraph: virtio-blk driver and interface nodes
>>    test/qgraph: virtio-blk test node
>>    test/qgraph: virtio-net driver and interface nodes
>>    test/qgraph: virtio-net test node
>>    test/qgraph: virtio-scsi driver and interface nodes
>>    test/qgraph: virtio-scsi test node
>>    test/qgraph: temporarly commented vhost-user-test
>>
>> Paolo Bonzini (1):
>>    tests: virtio: separate ccw tests from libqos
>>
>>   configure                            |   2 +-
>>   include/qemu/module.h                |   2 +
>>   tests/Makefile.include               |  79 +--
>>   tests/e1000e-test.c                  | 354 +++----------
>>   tests/i440fx-test.c                  |   2 +-
>>   tests/ide-test.c                     |   2 +-
>>   tests/libqos/ahci.c                  |   2 +-
>>   tests/libqos/e1000e.c                | 262 ++++++++++
>>   tests/libqos/e1000e.h                |  53 ++
>>   tests/libqos/libqos-pc.c             |   2 +-
>>   tests/libqos/libqos-spapr.c          |   2 +-
>>   tests/libqos/pci-pc.c                |  41 +-
>>   tests/libqos/pci-pc.h                |  22 +-
>>   tests/libqos/pci-spapr.c             |  57 ++-
>>   tests/libqos/pci-spapr.h             |  26 +-
>>   tests/libqos/pci.c                   |  48 +-
>>   tests/libqos/pci.h                   |  15 +
>>   tests/libqos/ppc64_pseries-machine.c | 111 +++++
>>   tests/libqos/qgraph.c                | 721 +++++++++++++++++++++++++++
>>   tests/libqos/qgraph.h                | 514 +++++++++++++++++++
>>   tests/libqos/qgraph_extra.h          | 263 ++++++++++
>>   tests/libqos/raspi2-machine.c        |  82 +++
>>   tests/libqos/sdhci.c                 | 163 ++++++
>>   tests/libqos/sdhci.h                 |  69 +++
>>   tests/libqos/virt-machine.c          |  90 ++++
>>   tests/libqos/virtio-9p.c             | 164 ++++++
>>   tests/libqos/virtio-9p.h             |  42 ++
>>   tests/libqos/virtio-balloon.c        | 111 +++++
>>   tests/libqos/virtio-balloon.h        |  39 ++
>>   tests/libqos/virtio-blk.c            | 126 +++++
>>   tests/libqos/virtio-blk.h            |  40 ++
>>   tests/libqos/virtio-mmio.c           |  72 ++-
>>   tests/libqos/virtio-mmio.h           |   6 +-
>>   tests/libqos/virtio-net.c            | 177 +++++++
>>   tests/libqos/virtio-net.h            |  41 ++
>>   tests/libqos/virtio-pci.c            |  80 ++-
>>   tests/libqos/virtio-pci.h            |  12 +
>>   tests/libqos/virtio-rng.c            | 108 ++++
>>   tests/libqos/virtio-rng.h            |  39 ++
>>   tests/libqos/virtio-scsi.c           | 117 +++++
>>   tests/libqos/virtio-scsi.h           |  39 ++
>>   tests/libqos/virtio-serial.c         | 109 ++++
>>   tests/libqos/virtio-serial.h         |  39 ++
>>   tests/libqos/virtio.c                |   9 +
>>   tests/libqos/virtio.h                |   1 +
>>   tests/libqos/x86_64_pc-machine.c     | 110 ++++
>>   tests/q35-test.c                     |   4 +-
>>   tests/qos-test.c                     | 480 ++++++++++++++++++
>>   tests/rtl8139-test.c                 |   2 +-
>>   tests/sdhci-test.c                   | 222 +++------
>>   tests/tco-test.c                     |   2 +-
>>   tests/test-qgraph.c                  | 446 +++++++++++++++++
>>   tests/usb-hcd-ehci-test.c            |   2 +-
>>   tests/vhost-user-test.c              |   7 +-
>>   tests/virtio-9p-test.c               | 221 +++-----
>>   tests/virtio-balloon-test.c          |  22 +-
>>   tests/virtio-blk-test.c              | 473 +++++++-----------
>>   tests/virtio-ccw-test.c              | 121 +++++
>>   tests/virtio-console-test.c          |  30 +-
>>   tests/virtio-net-test.c              | 163 ++----
>>   tests/virtio-rng-test.c              |  25 +-
>>   tests/virtio-scsi-test.c             | 155 +++---
>>   tests/virtio-serial-test.c           |  27 +-
>>   63 files changed, 5624 insertions(+), 1243 deletions(-)
>>   create mode 100644 tests/libqos/e1000e.c
>>   create mode 100644 tests/libqos/e1000e.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_extra.h
>>   create mode 100644 tests/libqos/raspi2-machine.c
>>   create mode 100644 tests/libqos/sdhci.c
>>   create mode 100644 tests/libqos/sdhci.h
>>   create mode 100644 tests/libqos/virt-machine.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/qos-test.c
>>   create mode 100644 tests/test-qgraph.c
>>   create mode 100644 tests/virtio-ccw-test.c
>>

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

* Re: [Qemu-devel] [PATCH v2 00/34] Qtest driver framework
  2018-08-09  9:20   ` Emanuele
@ 2018-08-09  9:44     ` Paolo Bonzini
  2018-08-09 10:27       ` Emanuele
  2018-08-10 10:40       ` Emanuele
  0 siblings, 2 replies; 71+ messages in thread
From: Paolo Bonzini @ 2018-08-09  9:44 UTC (permalink / raw)
  To: Emanuele
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 11:20, Emanuele wrote:
>>
> Why this? Shouldn't it be:
> 
> if (g_strcmp0(old_path, path)) {
>         qtest_end(); /* handles global_qtest = NULL */
>         g_free(old_path); /* handles NULL */
>         old_path = path;
>         global_qtest = qtest_start(path);
> } else ....

Yes, of course.  Though I'd have thought that my version has "just" a
memory leak.  Even better, this could call qos_invalidate_command_line.

Can you post the fixes to a separate commit on github?

Paolo

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

* Re: [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-09 10:10   ` Laurent Vivier
  2018-08-09 10:15     ` Paolo Bonzini
  2018-08-09 13:27     ` Emanuele
  0 siblings, 2 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 10:10 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> 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>
> ---
>  tests/Makefile.include |   1 +
>  tests/libqos/sdhci.c   | 163 +++++++++++++++++++++++++++++++++++++++++
>  tests/libqos/sdhci.h   |  69 +++++++++++++++++
>  3 files changed, 233 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 4e7b4bb614..be00fb71ec 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -775,6 +775,7 @@ libqgraph-machines-obj-y = tests/libqos/x86_64_pc-machine.o
>  
>  libqgraph-pci-obj-y = $(libqos-pc-obj-y)
>  libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
> +libqgraph-pci-obj-y += tests/libqos/sdhci.o

The file also implements memory mapped SDHCI, should we split the file
in two files, one added to libqgraph-pci-obj-y and the other to
check-qtest-arm-y and check-qtest-aarch64-y?

>  check-unit-y += tests/test-qgraph$(EXESUF)
>  tests/test-qgraph$(EXESUF): tests/test-qgraph.o $(libqgraph-obj-y)
> diff --git a/tests/libqos/sdhci.c b/tests/libqos/sdhci.c
> new file mode 100644
> index 0000000000..f5eb2c5459
> --- /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;
> +}
> +
...
> +static void sdhci_mm_writeq(QSDHCI *s, uint32_t reg, uint64_t val)
> +{
> +    QSDHCI_MemoryMapped *smm = container_of(s, QSDHCI_MemoryMapped, sdhci);
> +    qtest_writeq(global_qtest, smm->addr + reg, val);
> +}
> +
> +static void *sdhci_mm_get_driver(void *obj, const char *interface)
> +{
> +    QSDHCI_MemoryMapped *spci = obj;

You should call it "smm" rather than "spci"

> +    if (!g_strcmp0(interface, "sdhci")) {
> +        return &spci->sdhci;
> +    }
> +    printf("%s not present in generic-sdhci\n", interface);

fprintf(stderr, ....

> +    abort();

g_assert_not_reached()

> +}
> +
> +void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, uint32_t addr,

To be consistent with previous functions, you should it "smm" rather
than "sdhci".

...
> +/* PCI implementation of QSDHCI */
...
> +
> +static uint64_t sdhci_readq(QSDHCI *s, uint32_t reg)

"sdhci_pci_readq()"

> +{
> +    QSDHCI_PCI *spci = container_of(s, QSDHCI_PCI, sdhci);
> +    return qpci_io_readq(&spci->dev, spci->mem_bar, reg);
> +}
> +
> +static void sdhci_writeq(QSDHCI *s, uint32_t reg, uint64_t val)

"sdhci_pci_writeq()"

> +{
> +    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;
> +    }
> +
> +    printf("%s not present in sdhci-pci\n", interface);

fprintf(stderr, ...

> +    abort();

g_assert_not_reached()

> +}
> +
> +static void sdhci_start_hw(QOSGraphObject *obj)

perhaps you can call this "sdhci_pci_start_hw()"?

> +{
> +    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
> +    qpci_device_enable(&spci->dev);
> +}
> +
> +static void sdhci_destroy(QOSGraphObject *obj)

"sdhci_pci_destructor()"?

> +{
> +    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
> +    qpci_iounmap(&spci->dev, spci->mem_bar);
> +    g_free(spci);
> +}
> +
> +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_readq;

 ... = sdhci_pci_readq;

> +    spci->sdhci.writeq = 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_start_hw;
> +    spci->obj.destructor = sdhci_destroy;
> +    return &spci->obj;
> +}
> +
> +static void qsdhci(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);

Perhaps we can have two functions qsdhci_mm_register_nodes() and
qsdhci_pci_register_nodes(), with two libqos_init() and split the file
in two files sdhci_pci.c and sdhci_mm.c?

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes
  2018-08-09 10:10   ` Laurent Vivier
@ 2018-08-09 10:15     ` Paolo Bonzini
  2018-08-09 11:01       ` Laurent Vivier
  2018-08-09 13:27     ` Emanuele
  1 sibling, 1 reply; 71+ messages in thread
From: Paolo Bonzini @ 2018-08-09 10:15 UTC (permalink / raw)
  To: Laurent Vivier, Emanuele Giuseppe Esposito
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 12:10, Laurent Vivier wrote:
>>  libqgraph-pci-obj-y = $(libqos-pc-obj-y)
>>  libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
>> +libqgraph-pci-obj-y += tests/libqos/sdhci.o
> The file also implements memory mapped SDHCI, should we split the file
> in two files, one added to libqgraph-pci-obj-y and the other to
> check-qtest-arm-y and check-qtest-aarch64-y?
> 

No, there is only one libqgraph.  The same test (qos-test) can run for
both PCI and non-PCI machines, and will cull the unnecessary part of the
graph automatically simply because there is no path from a machine to a
PCI device.

Paolo

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

* Re: [Qemu-devel] [PATCH v2 00/34] Qtest driver framework
  2018-08-09  9:44     ` Paolo Bonzini
@ 2018-08-09 10:27       ` Emanuele
  2018-08-10 10:40       ` Emanuele
  1 sibling, 0 replies; 71+ messages in thread
From: Emanuele @ 2018-08-09 10:27 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 08/09/2018 11:44 AM, Paolo Bonzini wrote:
> On 09/08/2018 11:20, Emanuele wrote:
>> Why this? Shouldn't it be:
>>
>> if (g_strcmp0(old_path, path)) {
>>          qtest_end(); /* handles global_qtest = NULL */
>>          g_free(old_path); /* handles NULL */
>>          old_path = path;
>>          global_qtest = qtest_start(path);
>> } else ....
> Yes, of course.  Though I'd have thought that my version has "just" a
> memory leak.  Even better, this could call qos_invalidate_command_line.
>
> Can you post the fixes to a separate commit on github?
https://github.com/esposem/qemu/commit/4389e83522c06ce7001382284153d59105692061

I also added g_free(old_path); in qos-test main function, since last 
old_path is not free'd.
This commit is part of qgraph-v3, where I am also applying Laurent's 
suggestions.

Emanuele

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

* Re: [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes
  2018-08-09 10:15     ` Paolo Bonzini
@ 2018-08-09 11:01       ` Laurent Vivier
  2018-08-10 10:16         ` Paolo Bonzini
  0 siblings, 1 reply; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 11:01 UTC (permalink / raw)
  To: Paolo Bonzini, Emanuele Giuseppe Esposito
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 12:15, Paolo Bonzini wrote:
> On 09/08/2018 12:10, Laurent Vivier wrote:
>>>  libqgraph-pci-obj-y = $(libqos-pc-obj-y)
>>>  libqgraph-pci-obj-y += $(libqgraph-machines-obj-y)
>>> +libqgraph-pci-obj-y += tests/libqos/sdhci.o
>> The file also implements memory mapped SDHCI, should we split the file
>> in two files, one added to libqgraph-pci-obj-y and the other to
>> check-qtest-arm-y and check-qtest-aarch64-y?
>>
> 
> No, there is only one libqgraph.  The same test (qos-test) can run for
> both PCI and non-PCI machines, and will cull the unnecessary part of the
> graph automatically simply because there is no path from a machine to a
> PCI device.

So, all libqgraph files should be added to check-qtest-generic-y?

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 06/34] tests/qgraph: sdhci test node
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 06/34] tests/qgraph: sdhci test node Emanuele Giuseppe Esposito
@ 2018-08-09 11:16   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 11:16 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> 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>
> ---
>  tests/Makefile.include |   9 +-
>  tests/sdhci-test.c     | 222 ++++++++++++-----------------------------
>  2 files changed, 68 insertions(+), 163 deletions(-)
...
> +
> +libqos_init(sdhci_test);

"libqos_init(register_sdhci_tests)"?

Reviewed-by: Laurent Vivier <lvivier@redhat.com>

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes
  2018-08-08 17:39   ` Laurent Vivier
@ 2018-08-09 12:17     ` Emanuele
  2018-08-09 12:29       ` Laurent Vivier
  0 siblings, 1 reply; 71+ messages in thread
From: Emanuele @ 2018-08-09 12:17 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi


>> +    return TRUE;
>> +}
>> +
>> +QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
>> +{
>> +    QPCIDevice *dev;
>> +
>> +    dev = g_malloc0(sizeof(*dev));
>> +
>> +    if (!qpci_device_set(dev, bus, devfn)) {
>>           g_free(dev);
>>           return NULL;
>>       }
>> @@ -66,6 +83,21 @@ 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;
>> +
>> +    if (!qpci_device_set(dev, bus, addr->devfn)) {
>> +        printf("PCI Device not found\n");
>> +        abort();
>> +    }
> so, here, you should use qpci_device_set() and qpci_device_available()...
I changed qpci_device_set to just set the fields, while 
qpci_device_available simply is doing
{
     return qpci_config_readw(...) != 0xFFFF
}
Now both qpci_device_init and qpci_device_find call qpci_device_set, and 
check that  qpci_device_available is not false, otherwise it will 
trigger g_assert_not_reached().
>
>> +
>> +    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
> or you can only check vendor_id to see it is 0xffff or not...
>
>> +    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
>> +    g_assert(vendor_id == addr->vendor_id);
> that should be in fact detected by this g_assert().
since this case is covered by qpci_device_available, I don't think 
there's the need to insert the assertion.

Thank you,
Emanuele

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

* Re: [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node
  2018-08-08 19:27   ` Laurent Vivier
@ 2018-08-09 12:23     ` Emanuele
  2018-08-09 12:32       ` Laurent Vivier
  0 siblings, 1 reply; 71+ messages in thread
From: Emanuele @ 2018-08-09 12:23 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

> Perhaps we can call that "memory"  rather than "guest_allocator", as it
> gives access to the memory of the guest?
> and qos_node_produces("x86_64/pc", "memory");  (or "guest_allocator")?
>
> and perhaps later, a qos_add_test("test-memory-allocator", "memory",
> test_memory_allocator, NULL)?
I don't know, is there a test for the memory allocator? I gave it that 
name just because the actual structure representing it is called 
QGuestAllocator.

Thank you,
Emanuele

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

* Re: [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes
  2018-08-09 12:17     ` Emanuele
@ 2018-08-09 12:29       ` Laurent Vivier
  2018-08-09 12:33         ` Emanuele
  0 siblings, 1 reply; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 12:29 UTC (permalink / raw)
  To: Emanuele
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 14:17, Emanuele wrote:
> 
>>> +    return TRUE;
>>> +}
>>> +
>>> +QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
>>> +{
>>> +    QPCIDevice *dev;
>>> +
>>> +    dev = g_malloc0(sizeof(*dev));
>>> +
>>> +    if (!qpci_device_set(dev, bus, devfn)) {
>>>           g_free(dev);
>>>           return NULL;
>>>       }
>>> @@ -66,6 +83,21 @@ 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;
>>> +
>>> +    if (!qpci_device_set(dev, bus, addr->devfn)) {
>>> +        printf("PCI Device not found\n");
>>> +        abort();
>>> +    }
>> so, here, you should use qpci_device_set() and qpci_device_available()...
> I changed qpci_device_set to just set the fields, while
> qpci_device_available simply is doing
> {
>     return qpci_config_readw(...) != 0xFFFF
> }
> Now both qpci_device_init and qpci_device_find call qpci_device_set, and
> check that  qpci_device_available is not false, otherwise it will
> trigger g_assert_not_reached().
>>
>>> +
>>> +    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
>> or you can only check vendor_id to see it is 0xffff or not...
>>
>>> +    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
>>> +    g_assert(vendor_id == addr->vendor_id);
>> that should be in fact detected by this g_assert().
> since this case is covered by qpci_device_available, I don't think
> there's the need to insert the assertion.

What I mean is you don't need the qpci_device_available().

The 0xffff case is detected by "g_assert(vendor_id == addr->vendor_id)".

The functions could be:

static void qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
{
     dev->bus = bus;
     dev->devfn = devfn;
}

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(vendor_id == addr->vendor_id);
    g_assert(device_id == addr->device_id);
}

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node
  2018-08-09 12:23     ` Emanuele
@ 2018-08-09 12:32       ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 12:32 UTC (permalink / raw)
  To: Emanuele
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 14:23, Emanuele wrote:
>> Perhaps we can call that "memory"  rather than "guest_allocator", as it
>> gives access to the memory of the guest?
>> and qos_node_produces("x86_64/pc", "memory");  (or "guest_allocator")?
>>
>> and perhaps later, a qos_add_test("test-memory-allocator", "memory",
>> test_memory_allocator, NULL)?
> I don't know, is there a test for the memory allocator? I gave it that

No, I don't think so.

> name just because the actual structure representing it is called
> QGuestAllocator.

Yes, you can give the name you want, but for me "memory" sounds nicer
than "guest_allocator"...

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes
  2018-08-09 12:29       ` Laurent Vivier
@ 2018-08-09 12:33         ` Emanuele
  2018-08-09 12:42           ` Laurent Vivier
  0 siblings, 1 reply; 71+ messages in thread
From: Emanuele @ 2018-08-09 12:33 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi



On 08/09/2018 02:29 PM, Laurent Vivier wrote:
> On 09/08/2018 14:17, Emanuele wrote:
>>>> +    return TRUE;
>>>> +}
>>>> +
>>>> +QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
>>>> +{
>>>> +    QPCIDevice *dev;
>>>> +
>>>> +    dev = g_malloc0(sizeof(*dev));
>>>> +
>>>> +    if (!qpci_device_set(dev, bus, devfn)) {
>>>>            g_free(dev);
>>>>            return NULL;
>>>>        }
>>>> @@ -66,6 +83,21 @@ 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;
>>>> +
>>>> +    if (!qpci_device_set(dev, bus, addr->devfn)) {
>>>> +        printf("PCI Device not found\n");
>>>> +        abort();
>>>> +    }
>>> so, here, you should use qpci_device_set() and qpci_device_available()...
>> I changed qpci_device_set to just set the fields, while
>> qpci_device_available simply is doing
>> {
>>      return qpci_config_readw(...) != 0xFFFF
>> }
>> Now both qpci_device_init and qpci_device_find call qpci_device_set, and
>> check that  qpci_device_available is not false, otherwise it will
>> trigger g_assert_not_reached().
>>>> +
>>>> +    vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
>>> or you can only check vendor_id to see it is 0xffff or not...
>>>
>>>> +    device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
>>>> +    g_assert(vendor_id == addr->vendor_id);
>>> that should be in fact detected by this g_assert().
>> since this case is covered by qpci_device_available, I don't think
>> there's the need to insert the assertion.
> What I mean is you don't need the qpci_device_available().
>
> The 0xffff case is detected by "g_assert(vendor_id == addr->vendor_id)".
>
> The functions could be:
>
> static void qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
> {
>       dev->bus = bus;
>       dev->devfn = devfn;
> }
>
> 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(vendor_id == addr->vendor_id);
>      g_assert(device_id == addr->device_id);
> }
Ok, makes sense for qpci_device_init, but I still need to perform that 
check for qpci_device_find.
Emanuele

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

* Re: [Qemu-devel] [PATCH v2 07/34] tests/qgraph: arm/raspi2 machine node
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 07/34] tests/qgraph: arm/raspi2 machine node Emanuele Giuseppe Esposito
@ 2018-08-09 12:35   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 12:35 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> 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>
> ---
>  tests/Makefile.include        |  1 +
>  tests/libqos/raspi2-machine.c | 82 +++++++++++++++++++++++++++++++++++
>  2 files changed, 83 insertions(+)
>  create mode 100644 tests/libqos/raspi2-machine.c

globally, same cosmetic comments (destructor, fprintf, register, ...) as
for PC, otherwise it looks good.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes
  2018-08-09 12:33         ` Emanuele
@ 2018-08-09 12:42           ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 12:42 UTC (permalink / raw)
  To: Emanuele
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 14:33, Emanuele wrote:
> Ok, makes sense for qpci_device_init, but I still need to perform that
> check for qpci_device_find.

Yes, you're right.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-09 12:57   ` Laurent Vivier
  2018-08-09 13:02   ` Laurent Vivier
  1 sibling, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 12:57 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> 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>
> ---
>  tests/Makefile.include   |  2 +-
>  tests/libqos/pci-spapr.c | 57 ++++++++++++++++++++++++----------------
>  tests/libqos/pci-spapr.h | 24 +++++++++++++++++
>  3 files changed, 59 insertions(+), 24 deletions(-)

globally, same comments as for pci-pc.c

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes Emanuele Giuseppe Esposito
  2018-08-09 12:57   ` Laurent Vivier
@ 2018-08-09 13:02   ` Laurent Vivier
  2018-08-09 13:19     ` Emanuele
  1 sibling, 1 reply; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 13:02 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> +void qpci_init_spapr(QPCIBusSPAPR *ret, QTestState *qts, QGuestAllocator *alloc)
> +{
>      assert(qts);
>  
> +    /* tests cannot use spapr, needs to be fixed first */
> +    ret->bus.has_buggy_msi = TRUE;
> +

Perhaps you can revert the logic and call that "msi_is_available"?
It's more generic than "buggy". It says if we can or not use MSI.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes
  2018-08-09 13:02   ` Laurent Vivier
@ 2018-08-09 13:19     ` Emanuele
  2018-08-10  7:14       ` Paolo Bonzini
  0 siblings, 1 reply; 71+ messages in thread
From: Emanuele @ 2018-08-09 13:19 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi



On 08/09/2018 03:02 PM, Laurent Vivier wrote:
> On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
>> +void qpci_init_spapr(QPCIBusSPAPR *ret, QTestState *qts, QGuestAllocator *alloc)
>> +{
>>       assert(qts);
>>   
>> +    /* tests cannot use spapr, needs to be fixed first */
>> +    ret->bus.has_buggy_msi = TRUE;
>> +
> Perhaps you can revert the logic and call that "msi_is_available"?
> It's more generic than "buggy". It says if we can or not use MSI.
This name was suggested by Paolo, I honestly don't know which is better, 
maybe it's better to ask him for this.
> Thanks,
> Laurent

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

* Re: [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes
  2018-08-09 10:10   ` Laurent Vivier
  2018-08-09 10:15     ` Paolo Bonzini
@ 2018-08-09 13:27     ` Emanuele
  2018-08-09 13:58       ` Laurent Vivier
  1 sibling, 1 reply; 71+ messages in thread
From: Emanuele @ 2018-08-09 13:27 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi


>> +{
>> +    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
>> +    qpci_device_enable(&spci->dev);
>> +}
>> +
>> +static void sdhci_destroy(QOSGraphObject *obj)
> "sdhci_pci_destructor()"?
In general, I called the constructor name  *_create, so in theory to 
keep it consistent the destructor should be *_destroy, no?

Thank you,
Emanuele

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

* Re: [Qemu-devel] [PATCH v2 13/34] test/qgraph: virtio_start_device function
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 13/34] test/qgraph: virtio_start_device function Emanuele Giuseppe Esposito
@ 2018-08-09 13:39   ` Laurent Vivier
  2018-08-09 15:00     ` Emanuele
  0 siblings, 1 reply; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 13:39 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> 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>
> ---
>  tests/libqos/virtio.c    |  8 ++++++++
>  tests/libqos/virtio.h    |  1 +
>  tests/vhost-user-test.c  |  5 +----
>  tests/virtio-9p-test.c   |  6 +-----
>  tests/virtio-blk-test.c  | 18 ++----------------
>  tests/virtio-net-test.c  |  6 +-----
>  tests/virtio-scsi-test.c |  4 +---
>  7 files changed, 15 insertions(+), 33 deletions(-)
> 
> diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
> index 0dad5c19ac..56007ef11b 100644
> --- a/tests/libqos/virtio.c
> +++ b/tests/libqos/virtio.c
> @@ -365,3 +365,11 @@ 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);
> +    qvirtio_set_driver_ok(vdev);

I'm not sure you can put qvirtio_set_driver_ok() here.

qvirtio_set_driver_ok() must be called when the driver is OK, it means
that the virtio device must be fully initialized before (features,
virtqueue, MSI, ...).

http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf

3.1.1 Driver Requirements: Device Initialization

The driver MUST follow this sequence to initialize a device:

1. Reset the device.

2. Set the ACKNOWLEDGE status bit: the guest OS has notice the device.

3. Set the DRIVER status bit: the guest OS knows how to drive the device.

4. Read device feature bits, and write the subset of feature bits
understood by the OS and driver to the
device. During this step the driver MAY read (but MUST NOT write) the
device-specific configuration
fields to check that it can support the device before accepting it.

5. Set the FEATURES_OK status bit. The driver MUST NOT accept new
feature bits after this step.

6. Re-read device status to ensure the FEATURES_OK bit is still set:
otherwise, the device does not
support our subset of features and the device is unusable.

7. Perform device-specific setup, including discovery of virtqueues for
the device, optional per-bus setup,
reading and possibly writing the device’s virtio configuration space,
and population of virtqueues.

8. Set the DRIVER_OK status bit. At this point the device is “live”.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes
  2018-08-09 13:27     ` Emanuele
@ 2018-08-09 13:58       ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 13:58 UTC (permalink / raw)
  To: Emanuele
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 15:27, Emanuele wrote:
> 
>>> +{
>>> +    QSDHCI_PCI *spci = (QSDHCI_PCI *)obj;
>>> +    qpci_device_enable(&spci->dev);
>>> +}
>>> +
>>> +static void sdhci_destroy(QOSGraphObject *obj)
>> "sdhci_pci_destructor()"?
> In general, I called the constructor name  *_create, so in theory to
> keep it consistent the destructor should be *_destroy, no?

Yes, but the field name in QOSGraphObject is "destructor".

You have:

    obj.get_device = XXX_get_device;
    obj.get_driver = XXX_get_driver;
    obj.start_hw   = XXX_start_hw;

So we can expect:

   obj.destructor = XXX_destructor;

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 14/34] test/qgraph: virtio-pci driver and interface nodes
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 14/34] test/qgraph: virtio-pci driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-09 14:08   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 14:08 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> +void qvirtio_pci_destroy(QOSGraphObject *obj)
> +{
> +    QVirtioPCIDevice *v9p = (QVirtioPCIDevice *)obj;
> +    qvirtio_pci_device_disable(v9p);
> +    qvirtio_pci_device_free(v9p);
> +}
> +
> +void qvirtio_pci_start_hw(QOSGraphObject *obj)
> +{
> +    QVirtioPCIDevice *v9p = (QVirtioPCIDevice *)obj;
> +    qvirtio_pci_device_enable(v9p);
> +    qvirtio_start_device(&v9p->vdev);
> +}

Perhaps you can use a generic name rather than v9p?

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 15/34] tests/qgraph: rename qvirtio_mmio_init_device functions
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 15/34] tests/qgraph: rename qvirtio_mmio_init_device functions Emanuele Giuseppe Esposito
@ 2018-08-09 14:13   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 14:13 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> Rename qvirtio_mmio_init_device in qvirtio_mmio_device_new, since the function
> actually allocates a new QVirtioMMIODevice and initialize it.
> 
> Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
> ---
>  tests/libqos/virtio-mmio.c | 2 +-
>  tests/libqos/virtio-mmio.h | 2 +-
>  tests/virtio-blk-test.c    | 2 +-
>  3 files changed, 3 insertions(+), 3 deletions(-)

I think you can merge this patch with the following one because the only
reason you do that is to be able to define a new qvirtio_mmio_init() of
your own.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node
  2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node Emanuele Giuseppe Esposito
@ 2018-08-09 14:16   ` Laurent Vivier
  2018-08-10  9:45     ` Emanuele
  0 siblings, 1 reply; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 14:16 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:34, Emanuele Giuseppe Esposito wrote:
> -static void mmio_basic(void)
> +static void basic_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 = qvirtio_mmio_device_new(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);

This is the only user of qvirtio_mmio_device_new(), so if you remove the
call here, you could also remove the function definition.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 16/34] test/qgraph: virtio-mmio driver and interface nodes
  2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 16/34] test/qgraph: virtio-mmio driver and interface nodes Emanuele Giuseppe Esposito
@ 2018-08-09 14:47   ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-09 14:47 UTC (permalink / raw)
  To: Emanuele Giuseppe Esposito, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
> Add virtio-mmio node in qgraph framework.
> virtio-mmio produces virtio, 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>
> ---
>  tests/libqos/virtio-mmio.c | 70 ++++++++++++++++++++++++++++----------
>  tests/libqos/virtio-mmio.h |  4 +++
>  2 files changed, 56 insertions(+), 18 deletions(-)

Reviewed-by: Laurent Vivier <lvivier@redhat.com>

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

* Re: [Qemu-devel] [PATCH v2 13/34] test/qgraph: virtio_start_device function
  2018-08-09 13:39   ` Laurent Vivier
@ 2018-08-09 15:00     ` Emanuele
  0 siblings, 0 replies; 71+ messages in thread
From: Emanuele @ 2018-08-09 15:00 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi



On 08/09/2018 03:39 PM, Laurent Vivier wrote:
> On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
>> 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>
>> ---
>>   tests/libqos/virtio.c    |  8 ++++++++
>>   tests/libqos/virtio.h    |  1 +
>>   tests/vhost-user-test.c  |  5 +----
>>   tests/virtio-9p-test.c   |  6 +-----
>>   tests/virtio-blk-test.c  | 18 ++----------------
>>   tests/virtio-net-test.c  |  6 +-----
>>   tests/virtio-scsi-test.c |  4 +---
>>   7 files changed, 15 insertions(+), 33 deletions(-)
>>
>> diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
>> index 0dad5c19ac..56007ef11b 100644
>> --- a/tests/libqos/virtio.c
>> +++ b/tests/libqos/virtio.c
>> @@ -365,3 +365,11 @@ 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);
>> +    qvirtio_set_driver_ok(vdev);
> I'm not sure you can put qvirtio_set_driver_ok() here.
>
> qvirtio_set_driver_ok() must be called when the driver is OK, it means
> that the virtio device must be fully initialized before (features,
> virtqueue, MSI, ...).
>
> http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
>
> 3.1.1 Driver Requirements: Device Initialization
>
> The driver MUST follow this sequence to initialize a device:
>
> 1. Reset the device.
>
> 2. Set the ACKNOWLEDGE status bit: the guest OS has notice the device.
>
> 3. Set the DRIVER status bit: the guest OS knows how to drive the device.
>
> 4. Read device feature bits, and write the subset of feature bits
> understood by the OS and driver to the
> device. During this step the driver MAY read (but MUST NOT write) the
> device-specific configuration
> fields to check that it can support the device before accepting it.
>
> 5. Set the FEATURES_OK status bit. The driver MUST NOT accept new
> feature bits after this step.
>
> 6. Re-read device status to ensure the FEATURES_OK bit is still set:
> otherwise, the device does not
> support our subset of features and the device is unusable.
>
> 7. Perform device-specific setup, including discovery of virtqueues for
> the device, optional per-bus setup,
> reading and possibly writing the device’s virtio configuration space,
> and population of virtqueues.
>
> 8. Set the DRIVER_OK status bit. At this point the device is “live”.
>
> Thanks,
> Laurent
You're right, I removed qvirtio_set_driver_ok from qvirtio_start_device 
and put it back where it was before.
I noticed that while virtqueues need to have features set before they 
are setup, the device still works even though features are set after the ok.

Thank you,
Emanuele

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

* Re: [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes
  2018-08-09 13:19     ` Emanuele
@ 2018-08-10  7:14       ` Paolo Bonzini
  0 siblings, 0 replies; 71+ messages in thread
From: Paolo Bonzini @ 2018-08-10  7:14 UTC (permalink / raw)
  To: Emanuele, Laurent Vivier
  Cc: Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 09/08/2018 15:19, Emanuele wrote:
> 
> 
> On 08/09/2018 03:02 PM, Laurent Vivier wrote:
>> On 06/08/2018 16:33, Emanuele Giuseppe Esposito wrote:
>>> +void qpci_init_spapr(QPCIBusSPAPR *ret, QTestState *qts,
>>> QGuestAllocator *alloc)
>>> +{
>>>       assert(qts);
>>>   +    /* tests cannot use spapr, needs to be fixed first */
>>> +    ret->bus.has_buggy_msi = TRUE;
>>> +
>> Perhaps you can revert the logic and call that "msi_is_available"?
>> It's more generic than "buggy". It says if we can or not use MSI.
> This name was suggested by Paolo, I honestly don't know which is better,
> maybe it's better to ask him for this.

The MSIs here are not interrupts, they are just random memory writes.
Even if it's not clear if the bug is in libqos or QEMU, there is no
reason why they shouldn't work.

Paolo

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

* Re: [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node
  2018-08-09 14:16   ` Laurent Vivier
@ 2018-08-10  9:45     ` Emanuele
  2018-08-10  9:52       ` Laurent Vivier
  0 siblings, 1 reply; 71+ messages in thread
From: Emanuele @ 2018-08-10  9:45 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 08/09/2018 04:16 PM, Laurent Vivier wrote:
> On 06/08/2018 16:34, Emanuele Giuseppe Esposito wrote:
>> -static void mmio_basic(void)
>> +static void basic_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 = qvirtio_mmio_device_new(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
> This is the only user of qvirtio_mmio_device_new(), so if you remove the
> call here, you could also remove the function definition.
So you suggest to get rid completely of qvirtio_mmio_device_new() in 
virtio-mmio.c  ?
Couldn't it be useful in future maybe?

Emanuele

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

* Re: [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node
  2018-08-10  9:45     ` Emanuele
@ 2018-08-10  9:52       ` Laurent Vivier
  0 siblings, 0 replies; 71+ messages in thread
From: Laurent Vivier @ 2018-08-10  9:52 UTC (permalink / raw)
  To: Emanuele
  Cc: Paolo Bonzini, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 10/08/2018 11:45, Emanuele wrote:
> On 08/09/2018 04:16 PM, Laurent Vivier wrote:
>> On 06/08/2018 16:34, Emanuele Giuseppe Esposito wrote:
>>> -static void mmio_basic(void)
>>> +static void basic_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 = qvirtio_mmio_device_new(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
>> This is the only user of qvirtio_mmio_device_new(), so if you remove the
>> call here, you could also remove the function definition.
> So you suggest to get rid completely of qvirtio_mmio_device_new() in
> virtio-mmio.c  ?

Yes.

> Couldn't it be useful in future maybe?

We'll be able to use qvirtio_mmio_init_device() instead, so I don't
think it's a problem.

Thanks,
Laurent

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

* Re: [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes
  2018-08-09 11:01       ` Laurent Vivier
@ 2018-08-10 10:16         ` Paolo Bonzini
  0 siblings, 0 replies; 71+ messages in thread
From: Paolo Bonzini @ 2018-08-10 10:16 UTC (permalink / raw)
  To: Laurent Vivier, Emanuele Giuseppe Esposito
  Cc: Stefan Hajnoczi, Philippe Mathieu-Daudé, qemu-devel

On 09/08/2018 13:01, Laurent Vivier wrote:
>> No, there is only one libqgraph.  The same test (qos-test) can run for
>> both PCI and non-PCI machines, and will cull the unnecessary part of the
>> graph automatically simply because there is no path from a machine to a
>> PCI device.
> So, all libqgraph files should be added to check-qtest-generic-y?

Yes.

Paolo

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

* Re: [Qemu-devel] [PATCH v2 00/34] Qtest driver framework
  2018-08-09  9:44     ` Paolo Bonzini
  2018-08-09 10:27       ` Emanuele
@ 2018-08-10 10:40       ` Emanuele
  1 sibling, 0 replies; 71+ messages in thread
From: Emanuele @ 2018-08-10 10:40 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, qemu-devel, Stefan Hajnoczi

On 08/09/2018 11:44 AM, Paolo Bonzini wrote:
> On 09/08/2018 11:20, Emanuele wrote:
>> Why this? Shouldn't it be:
>>
>> if (g_strcmp0(old_path, path)) {
>>          qtest_end(); /* handles global_qtest = NULL */
>>          g_free(old_path); /* handles NULL */
>>          old_path = path;
>>          global_qtest = qtest_start(path);
>> } else ....
> Yes, of course.  Though I'd have thought that my version has "just" a
> memory leak.  Even better, this could call qos_invalidate_command_line.
>
> Can you post the fixes to a separate commit on github?
Paolo, did you have a chance to test the fixes? I tried, it seems to be 
working fine.
About valgrind, it only detects an "invalide read of size 8" in 
blk-hotplug test (tests/virtio-blk-test.c), but I don't know why is it 
doing this.
For the rest, there shouldn't be any memory leak.

Should I rebase them in the proper commits? I am ready to submit patch v3.

Emanuele

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

end of thread, other threads:[~2018-08-10 10:40 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-06 14:33 [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 01/34] tests: qgraph API for the qtest " Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 02/34] tests/qgraph: rename qpci_init_pc functions Emanuele Giuseppe Esposito
2018-08-06 15:04   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 03/34] tests/qgraph: pci-pc driver and interface nodes Emanuele Giuseppe Esposito
2018-08-08 17:39   ` Laurent Vivier
2018-08-09 12:17     ` Emanuele
2018-08-09 12:29       ` Laurent Vivier
2018-08-09 12:33         ` Emanuele
2018-08-09 12:42           ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 04/34] tests/qgraph: x86_64/pc machine node Emanuele Giuseppe Esposito
2018-08-08 19:27   ` Laurent Vivier
2018-08-09 12:23     ` Emanuele
2018-08-09 12:32       ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 05/34] tests/qgraph: sdhci driver and interface nodes Emanuele Giuseppe Esposito
2018-08-09 10:10   ` Laurent Vivier
2018-08-09 10:15     ` Paolo Bonzini
2018-08-09 11:01       ` Laurent Vivier
2018-08-10 10:16         ` Paolo Bonzini
2018-08-09 13:27     ` Emanuele
2018-08-09 13:58       ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 06/34] tests/qgraph: sdhci test node Emanuele Giuseppe Esposito
2018-08-09 11:16   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 07/34] tests/qgraph: arm/raspi2 machine node Emanuele Giuseppe Esposito
2018-08-09 12:35   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 08/34] tests/qgraph: rename qpci_init_spapr functions Emanuele Giuseppe Esposito
2018-08-08 15:30   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 09/34] tests/qgraph: pci-spapr driver and interface nodes Emanuele Giuseppe Esposito
2018-08-09 12:57   ` Laurent Vivier
2018-08-09 13:02   ` Laurent Vivier
2018-08-09 13:19     ` Emanuele
2018-08-10  7:14       ` Paolo Bonzini
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 10/34] tests/qgraph: ppc64/pseries machine node Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 11/34] test/qgraph: e1000e driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 12/34] test/qgraph: e1000e-test node Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 13/34] test/qgraph: virtio_start_device function Emanuele Giuseppe Esposito
2018-08-09 13:39   ` Laurent Vivier
2018-08-09 15:00     ` Emanuele
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 14/34] test/qgraph: virtio-pci driver and interface nodes Emanuele Giuseppe Esposito
2018-08-09 14:08   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 15/34] tests/qgraph: rename qvirtio_mmio_init_device functions Emanuele Giuseppe Esposito
2018-08-09 14:13   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 16/34] test/qgraph: virtio-mmio driver and interface nodes Emanuele Giuseppe Esposito
2018-08-09 14:47   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 17/34] test/qgraph: arm/virt machine node Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 18/34] tests: virtio: separate ccw tests from libqos Emanuele Giuseppe Esposito
2018-08-08 19:34   ` Laurent Vivier
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 19/34] test/qgraph: virtio-serial driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 20/34] test/qgraph: virtio-console test node Emanuele Giuseppe Esposito
2018-08-06 14:33 ` [Qemu-devel] [PATCH v2 21/34] test/qgraph: virtio-serial " Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 22/34] test/qgraph: virtio-9p driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 23/34] test/qgraph: virtio-9p test node Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 24/34] test/qgraph: virtio-balloon driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 25/34] test/qgraph: virtio-balloon test node Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 26/34] test/qgraph: virtio-rng driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 27/34] test/qgraph: virtio-rng test node Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 28/34] test/qgraph: virtio-blk driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 29/34] test/qgraph: virtio-blk test node Emanuele Giuseppe Esposito
2018-08-09 14:16   ` Laurent Vivier
2018-08-10  9:45     ` Emanuele
2018-08-10  9:52       ` Laurent Vivier
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 30/34] test/qgraph: virtio-net driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 31/34] test/qgraph: virtio-net test node Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 32/34] test/qgraph: virtio-scsi driver and interface nodes Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 33/34] test/qgraph: virtio-scsi test node Emanuele Giuseppe Esposito
2018-08-06 14:34 ` [Qemu-devel] [PATCH v2 34/34] test/qgraph: temporarly commented vhost-user-test Emanuele Giuseppe Esposito
2018-08-09  8:57 ` [Qemu-devel] [PATCH v2 00/34] Qtest driver framework Paolo Bonzini
2018-08-09  9:20   ` Emanuele
2018-08-09  9:44     ` Paolo Bonzini
2018-08-09 10:27       ` Emanuele
2018-08-10 10:40       ` Emanuele

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.