xref: /qemu/docs/devel/qgraph.rst (revision b980c1ae)
1222455efSEmanuele Giuseppe Esposito.. _qgraph:
2222455efSEmanuele Giuseppe Esposito
3222455efSEmanuele Giuseppe EspositoQtest Driver Framework
4768f14f9SPaolo Bonzini======================
5222455efSEmanuele Giuseppe Esposito
6afdbd382SEmanuele Giuseppe EspositoIn order to test a specific driver, plain libqos tests need to
7afdbd382SEmanuele Giuseppe Espositotake care of booting QEMU with the right machine and devices.
8afdbd382SEmanuele Giuseppe EspositoThis makes each test "hardcoded" for a specific configuration, reducing
9afdbd382SEmanuele Giuseppe Espositothe possible coverage that it can reach.
10222455efSEmanuele Giuseppe Esposito
11afdbd382SEmanuele Giuseppe EspositoFor example, the sdhci device is supported on both x86_64 and ARM boards,
12afdbd382SEmanuele Giuseppe Espositotherefore a generic sdhci test should test all machines and drivers that
13afdbd382SEmanuele Giuseppe Espositosupport that device.
14afdbd382SEmanuele Giuseppe EspositoUsing only libqos APIs, the test has to manually take care of
15afdbd382SEmanuele Giuseppe Espositocovering all the setups, and build the correct command line.
16afdbd382SEmanuele Giuseppe Esposito
17*b980c1aeSStefan WeilThis also introduces backward compatibility issues: if a device/driver command
18afdbd382SEmanuele Giuseppe Espositoline name is changed, all tests that use that will not work
19afdbd382SEmanuele Giuseppe Espositoproperly anymore and need to be adjusted.
20afdbd382SEmanuele Giuseppe Esposito
21afdbd382SEmanuele Giuseppe EspositoThe aim of qgraph is to create a graph of drivers, machines and tests such that
22afdbd382SEmanuele Giuseppe Espositoa test aimed to a certain driver does not have to care of
23afdbd382SEmanuele Giuseppe Espositobooting the right QEMU machine, pick the right device, build the command line
24afdbd382SEmanuele Giuseppe Espositoand so on. Instead, it only defines what type of device it is testing
25afdbd382SEmanuele Giuseppe Esposito(interface in qgraph terms) and the framework takes care of
26afdbd382SEmanuele Giuseppe Espositocovering all supported types of devices and machine architectures.
27afdbd382SEmanuele Giuseppe Esposito
28afdbd382SEmanuele Giuseppe EspositoFollowing the above example, an interface would be ``sdhci``,
29afdbd382SEmanuele Giuseppe Espositoso the sdhci-test should only care of linking its qgraph node with
30afdbd382SEmanuele Giuseppe Espositothat interface. In this way, if the command line of a sdhci driver
31afdbd382SEmanuele Giuseppe Espositois changed, only the respective qgraph driver node has to be adjusted.
32afdbd382SEmanuele Giuseppe Esposito
33768f14f9SPaolo BonziniQGraph concepts
34768f14f9SPaolo Bonzini---------------
35768f14f9SPaolo Bonzini
36afdbd382SEmanuele Giuseppe EspositoThe graph is composed by nodes that represent machines, drivers, tests
37afdbd382SEmanuele Giuseppe Espositoand edges that define the relationships between them (``CONSUMES``, ``PRODUCES``, and
38afdbd382SEmanuele Giuseppe Esposito``CONTAINS``).
39afdbd382SEmanuele Giuseppe Esposito
40222455efSEmanuele Giuseppe EspositoNodes
41768f14f9SPaolo Bonzini~~~~~
42222455efSEmanuele Giuseppe Esposito
43222455efSEmanuele Giuseppe EspositoA node can be of four types:
44222455efSEmanuele Giuseppe Esposito
45cd066eeaSPhilippe Mathieu-Daudé- **QNODE_MACHINE**:   for example ``arm/raspi2b``
46222455efSEmanuele Giuseppe Esposito- **QNODE_DRIVER**:    for example ``generic-sdhci``
47222455efSEmanuele Giuseppe Esposito- **QNODE_INTERFACE**: for example ``sdhci`` (interface for all ``-sdhci``
48222455efSEmanuele Giuseppe Esposito  drivers).
49222455efSEmanuele Giuseppe Esposito  An interface is not explicitly created, it will be automatically
50222455efSEmanuele Giuseppe Esposito  instantiated when a node consumes or produces it.
51afdbd382SEmanuele Giuseppe Esposito  An interface is simply a struct that abstracts the various drivers
52afdbd382SEmanuele Giuseppe Esposito  for the same type of device, and offers an API to the nodes that
53afdbd382SEmanuele Giuseppe Esposito  use it ("consume" relation in qgraph terms) that is implemented/backed up by the drivers that implement it ("produce" relation in qgraph terms).
54afdbd382SEmanuele Giuseppe Esposito- **QNODE_TEST**:      for example ``sdhci-test``. A test consumes an interface
55afdbd382SEmanuele Giuseppe Esposito  and tests the functions provided by it.
56222455efSEmanuele Giuseppe Esposito
57222455efSEmanuele Giuseppe EspositoNotes for the nodes:
58222455efSEmanuele Giuseppe Esposito
59222455efSEmanuele Giuseppe Esposito- QNODE_MACHINE: each machine struct must have a ``QGuestAllocator`` and
60222455efSEmanuele Giuseppe Esposito  implement ``get_driver()`` to return the allocator mapped to the interface
61222455efSEmanuele Giuseppe Esposito  "memory". The function can also return ``NULL`` if the allocator
62222455efSEmanuele Giuseppe Esposito  is not set.
63222455efSEmanuele Giuseppe Esposito- QNODE_DRIVER:  driver names must be unique, and machines and nodes
64222455efSEmanuele Giuseppe Esposito  planned to be "consumed" by other nodes must match QEMU
65222455efSEmanuele Giuseppe Esposito  drivers name, otherwise they won't be discovered
66222455efSEmanuele Giuseppe Esposito
67222455efSEmanuele Giuseppe EspositoEdges
68768f14f9SPaolo Bonzini~~~~~
69222455efSEmanuele Giuseppe Esposito
701e235edaSPeter MaydellAn edge relation between two nodes (drivers or machines) ``X`` and ``Y`` can be:
71222455efSEmanuele Giuseppe Esposito
721e235edaSPeter Maydell- ``X CONSUMES Y``: ``Y`` can be plugged into ``X``
731e235edaSPeter Maydell- ``X PRODUCES Y``: ``X`` provides the interface ``Y``
741e235edaSPeter Maydell- ``X CONTAINS Y``: ``Y`` is part of ``X`` component
75222455efSEmanuele Giuseppe Esposito
76222455efSEmanuele Giuseppe EspositoExecution steps
77768f14f9SPaolo Bonzini~~~~~~~~~~~~~~~
78222455efSEmanuele Giuseppe Esposito
79222455efSEmanuele Giuseppe EspositoThe basic framework steps are the following:
80222455efSEmanuele Giuseppe Esposito
81222455efSEmanuele Giuseppe Esposito- All nodes and edges are created in their respective
82222455efSEmanuele Giuseppe Esposito  machine/driver/test files
83222455efSEmanuele Giuseppe Esposito- The framework starts QEMU and asks for a list of available devices
84222455efSEmanuele Giuseppe Esposito  and machines (note that only machines and "consumed" nodes are mapped
85222455efSEmanuele Giuseppe Esposito  1:1 with QEMU devices)
86222455efSEmanuele Giuseppe Esposito- The framework walks the graph starting from the available machines and
87222455efSEmanuele Giuseppe Esposito  performs a Depth First Search for tests
88222455efSEmanuele Giuseppe Esposito- Once a test is found, the path is walked again and all drivers are
89222455efSEmanuele Giuseppe Esposito  allocated accordingly and the final interface is passed to the test
90222455efSEmanuele Giuseppe Esposito- The test is executed
91222455efSEmanuele Giuseppe Esposito- Unused objects are cleaned and the path discovery is continued
92222455efSEmanuele Giuseppe Esposito
93222455efSEmanuele Giuseppe EspositoDepending on the QEMU binary used, only some drivers/machines will be
94222455efSEmanuele Giuseppe Espositoavailable and only test that are reached by them will be executed.
95222455efSEmanuele Giuseppe Esposito
96768f14f9SPaolo BonziniCommand line
97768f14f9SPaolo Bonzini~~~~~~~~~~~~
98768f14f9SPaolo Bonzini
99768f14f9SPaolo BonziniCommand line is built by using node names and optional arguments
100768f14f9SPaolo Bonzinipassed by the user when building the edges.
101768f14f9SPaolo Bonzini
102768f14f9SPaolo BonziniThere are three types of command line arguments:
103768f14f9SPaolo Bonzini
104768f14f9SPaolo Bonzini- ``in node``      : created from the node name. For example, machines will
105768f14f9SPaolo Bonzini  have ``-M <machine>`` to its command line, while devices
106768f14f9SPaolo Bonzini  ``-device <device>``. It is automatically done by the framework.
107768f14f9SPaolo Bonzini- ``after node``   : added as additional argument to the node name.
108768f14f9SPaolo Bonzini  This argument is added optionally when creating edges,
109768f14f9SPaolo Bonzini  by setting the parameter ``after_cmd_line`` and
110768f14f9SPaolo Bonzini  ``extra_edge_opts`` in ``QOSGraphEdgeOptions``.
111768f14f9SPaolo Bonzini  The framework automatically adds
112768f14f9SPaolo Bonzini  a comma before ``extra_edge_opts``,
113768f14f9SPaolo Bonzini  because it is going to add attributes
114768f14f9SPaolo Bonzini  after the destination node pointed by
115768f14f9SPaolo Bonzini  the edge containing these options, and automatically
116768f14f9SPaolo Bonzini  adds a space before ``after_cmd_line``, because it
117768f14f9SPaolo Bonzini  adds an additional device, not an attribute.
118768f14f9SPaolo Bonzini- ``before node``  : added as additional argument to the node name.
119768f14f9SPaolo Bonzini  This argument is added optionally when creating edges,
120768f14f9SPaolo Bonzini  by setting the parameter ``before_cmd_line`` in
121768f14f9SPaolo Bonzini  ``QOSGraphEdgeOptions``. This attribute
122768f14f9SPaolo Bonzini  is going to add attributes before the destination node
123768f14f9SPaolo Bonzini  pointed by the edge containing these options. It is
124768f14f9SPaolo Bonzini  helpful to commands that are not node-representable,
125768f14f9SPaolo Bonzini  such as ``-fdsev`` or ``-netdev``.
126768f14f9SPaolo Bonzini
127768f14f9SPaolo BonziniWhile adding command line in edges is always used, not all nodes names are
128768f14f9SPaolo Bonziniused in every path walk: this is because the contained or produced ones
129768f14f9SPaolo Bonziniare already added by QEMU, so only nodes that "consumes" will be used to
130768f14f9SPaolo Bonzinibuild the command line. Also, nodes that will have ``{ "abstract" : true }``
131768f14f9SPaolo Bonzinias QMP attribute will loose their command line, since they are not proper
132768f14f9SPaolo Bonzinidevices to be added in QEMU.
133768f14f9SPaolo Bonzini
134768f14f9SPaolo BonziniExample::
135768f14f9SPaolo Bonzini
136768f14f9SPaolo Bonzini    QOSGraphEdgeOptions opts = {
137768f14f9SPaolo Bonzini        .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
138768f14f9SPaolo Bonzini                           "file.read-zeroes=on,format=raw",
139768f14f9SPaolo Bonzini        .after_cmd_line = "-device scsi-hd,bus=vs0.0,drive=drv0",
140768f14f9SPaolo Bonzini
141768f14f9SPaolo Bonzini        opts.extra_device_opts = "id=vs0";
142768f14f9SPaolo Bonzini    };
143768f14f9SPaolo Bonzini
144768f14f9SPaolo Bonzini    qos_node_create_driver("virtio-scsi-device",
145768f14f9SPaolo Bonzini                            virtio_scsi_device_create);
146768f14f9SPaolo Bonzini    qos_node_consumes("virtio-scsi-device", "virtio-bus", &opts);
147768f14f9SPaolo Bonzini
148768f14f9SPaolo BonziniWill produce the following command line:
149768f14f9SPaolo Bonzini``-drive id=drv0,if=none,file=null-co://, -device virtio-scsi-device,id=vs0 -device scsi-hd,bus=vs0.0,drive=drv0``
150768f14f9SPaolo Bonzini
151ce508a3cSStefan HajnocziTroubleshooting unavailable tests
152768f14f9SPaolo Bonzini~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
153768f14f9SPaolo Bonzini
154ce508a3cSStefan HajnocziIf there is no path from an available machine to a test then that test will be
155ce508a3cSStefan Hajnocziunavailable and won't execute. This can happen if a test or driver did not set
156ce508a3cSStefan Hajnocziup its qgraph node correctly. It can also happen if the necessary machine type
157ce508a3cSStefan Hajnoczior device is missing from the QEMU binary because it was compiled out or
158ce508a3cSStefan Hajnocziotherwise.
159ce508a3cSStefan Hajnoczi
160ce508a3cSStefan HajnocziIt is possible to troubleshoot unavailable tests by running::
161ce508a3cSStefan Hajnoczi
162ce508a3cSStefan Hajnoczi  $ QTEST_QEMU_BINARY=build/qemu-system-x86_64 build/tests/qtest/qos-test --verbose
163ce508a3cSStefan Hajnoczi  # ALL QGRAPH EDGES: {
164ce508a3cSStefan Hajnoczi  #   src='virtio-net'
165ce508a3cSStefan Hajnoczi  #      |-> dest='virtio-net-tests/vhost-user/multiqueue' type=2 (node=0x559142109e30)
166ce508a3cSStefan Hajnoczi  #      |-> dest='virtio-net-tests/vhost-user/migrate' type=2 (node=0x559142109d00)
167ce508a3cSStefan Hajnoczi  #   src='virtio-net-pci'
168ce508a3cSStefan Hajnoczi  #      |-> dest='virtio-net' type=1 (node=0x55914210d740)
169ce508a3cSStefan Hajnoczi  #   src='pci-bus'
170ce508a3cSStefan Hajnoczi  #      |-> dest='virtio-net-pci' type=2 (node=0x55914210d880)
171ce508a3cSStefan Hajnoczi  #   src='pci-bus-pc'
172ce508a3cSStefan Hajnoczi  #      |-> dest='pci-bus' type=1 (node=0x559142103f40)
173ce508a3cSStefan Hajnoczi  #   src='i440FX-pcihost'
174ce508a3cSStefan Hajnoczi  #      |-> dest='pci-bus-pc' type=0 (node=0x55914210ac70)
175ce508a3cSStefan Hajnoczi  #   src='x86_64/pc'
176ce508a3cSStefan Hajnoczi  #      |-> dest='i440FX-pcihost' type=0 (node=0x5591421117f0)
177ce508a3cSStefan Hajnoczi  #   src=''
178ce508a3cSStefan Hajnoczi  #      |-> dest='x86_64/pc' type=0 (node=0x559142111600)
179cd066eeaSPhilippe Mathieu-Daudé  #      |-> dest='arm/raspi2b' type=0 (node=0x559142110740)
180ce508a3cSStefan Hajnoczi  ...
181ce508a3cSStefan Hajnoczi  # }
182ce508a3cSStefan Hajnoczi  # ALL QGRAPH NODES: {
183ce508a3cSStefan Hajnoczi  #   name='virtio-net-tests/announce-self' type=3 cmd_line='(null)' [available]
184cd066eeaSPhilippe Mathieu-Daudé  #   name='arm/raspi2b' type=0 cmd_line='-M raspi2b ' [UNAVAILABLE]
185ce508a3cSStefan Hajnoczi  ...
186ce508a3cSStefan Hajnoczi  # }
187ce508a3cSStefan Hajnoczi
188ce508a3cSStefan HajnocziThe ``virtio-net-tests/announce-self`` test is listed as "available" in the
189ce508a3cSStefan Hajnoczi"ALL QGRAPH NODES" output. This means the test will execute. We can follow the
190ce508a3cSStefan Hajnocziqgraph path in the "ALL QGRAPH EDGES" output as follows: '' -> 'x86_64/pc' ->
191ce508a3cSStefan Hajnoczi'i440FX-pcihost' -> 'pci-bus-pc' -> 'pci-bus' -> 'virtio-net-pci' ->
192ce508a3cSStefan Hajnoczi'virtio-net'. The root of the qgraph is '' and the depth first search begins
193ce508a3cSStefan Hajnoczithere.
194ce508a3cSStefan Hajnoczi
195cd066eeaSPhilippe Mathieu-DaudéThe ``arm/raspi2b`` machine node is listed as "UNAVAILABLE". Although it is
196cd066eeaSPhilippe Mathieu-Daudéreachable from the root via '' -> 'arm/raspi2b' the node is unavailable because
197ce508a3cSStefan Hajnoczithe QEMU binary did not list it when queried by the framework. This is expected
198ce508a3cSStefan Hajnoczibecause we used the ``qemu-system-x86_64`` binary which does not support ARM
199ce508a3cSStefan Hajnoczimachine types.
200ce508a3cSStefan Hajnoczi
201ce508a3cSStefan HajnocziIf a test is unexpectedly listed as "UNAVAILABLE", first check that the "ALL
202ce508a3cSStefan HajnocziQGRAPH EDGES" output reports edge connectivity from the root ('') to the test.
203ce508a3cSStefan HajnocziIf there is no connectivity then the qgraph nodes were not set up correctly and
204ce508a3cSStefan Hajnoczithe driver or test code is incorrect. If there is connectivity, check the
205ce508a3cSStefan Hajnocziavailability of each node in the path in the "ALL QGRAPH NODES" output. The
206ce508a3cSStefan Hajnoczifirst unavailable node in the path is the reason why the test is unavailable.
207ce508a3cSStefan HajnocziTypically this is because the QEMU binary lacks support for the necessary
208ce508a3cSStefan Hajnoczimachine type or device.
209ce508a3cSStefan Hajnoczi
210222455efSEmanuele Giuseppe EspositoCreating a new driver and its interface
211768f14f9SPaolo Bonzini---------------------------------------
212222455efSEmanuele Giuseppe Esposito
213afdbd382SEmanuele Giuseppe EspositoHere we continue the ``sdhci`` use case, with the following scenario:
214afdbd382SEmanuele Giuseppe Esposito
215afdbd382SEmanuele Giuseppe Esposito- ``sdhci-test`` aims to test the ``read[q,w], writeq`` functions
216afdbd382SEmanuele Giuseppe Esposito  offered by the ``sdhci`` drivers.
217afdbd382SEmanuele Giuseppe Esposito- The current ``sdhci`` device is supported by both ``x86_64/pc`` and ``ARM``
218cd066eeaSPhilippe Mathieu-Daudé  (in this example we focus on the ``arm-raspi2b``) machines.
219afdbd382SEmanuele Giuseppe Esposito- QEMU offers 2 types of drivers: ``QSDHCI_MemoryMapped`` for ``ARM`` and
220afdbd382SEmanuele Giuseppe Esposito  ``QSDHCI_PCI`` for ``x86_64/pc``. Both implement the
221afdbd382SEmanuele Giuseppe Esposito  ``read[q,w], writeq`` functions.
222afdbd382SEmanuele Giuseppe Esposito
223afdbd382SEmanuele Giuseppe EspositoIn order to implement such scenario in qgraph, the test developer needs to:
224afdbd382SEmanuele Giuseppe Esposito
225afdbd382SEmanuele Giuseppe Esposito- Create the ``x86_64/pc`` machine node. This machine uses the
226afdbd382SEmanuele Giuseppe Esposito  ``pci-bus`` architecture so it ``contains`` a PCI driver,
227afdbd382SEmanuele Giuseppe Esposito  ``pci-bus-pc``. The actual path is
228afdbd382SEmanuele Giuseppe Esposito
229afdbd382SEmanuele Giuseppe Esposito  ``x86_64/pc --contains--> 1440FX-pcihost --contains-->
230afdbd382SEmanuele Giuseppe Esposito  pci-bus-pc --produces--> pci-bus``.
231afdbd382SEmanuele Giuseppe Esposito
232afdbd382SEmanuele Giuseppe Esposito  For the sake of this example,
233afdbd382SEmanuele Giuseppe Esposito  we do not focus on the PCI interface implementation.
234afdbd382SEmanuele Giuseppe Esposito- Create the ``sdhci-pci`` driver node, representing ``QSDHCI_PCI``.
235afdbd382SEmanuele Giuseppe Esposito  The driver uses the PCI bus (and its API),
236afdbd382SEmanuele Giuseppe Esposito  so it must ``consume`` the ``pci-bus`` generic interface (which abstracts
237afdbd382SEmanuele Giuseppe Esposito  all the pci drivers available)
238afdbd382SEmanuele Giuseppe Esposito
239afdbd382SEmanuele Giuseppe Esposito  ``sdhci-pci --consumes--> pci-bus``
240cd066eeaSPhilippe Mathieu-Daudé- Create an ``arm/raspi2b`` machine node. This machine ``contains``
241afdbd382SEmanuele Giuseppe Esposito  a ``generic-sdhci`` memory mapped ``sdhci`` driver node, representing
242afdbd382SEmanuele Giuseppe Esposito  ``QSDHCI_MemoryMapped``.
243afdbd382SEmanuele Giuseppe Esposito
244cd066eeaSPhilippe Mathieu-Daudé  ``arm/raspi2b --contains--> generic-sdhci``
245afdbd382SEmanuele Giuseppe Esposito- Create the ``sdhci`` interface node. This interface offers the
246afdbd382SEmanuele Giuseppe Esposito  functions that are shared by all ``sdhci`` devices.
247afdbd382SEmanuele Giuseppe Esposito  The interface is produced by ``sdhci-pci`` and ``generic-sdhci``,
248afdbd382SEmanuele Giuseppe Esposito  the available architecture-specific drivers.
249afdbd382SEmanuele Giuseppe Esposito
250afdbd382SEmanuele Giuseppe Esposito  ``sdhci-pci --produces--> sdhci``
251afdbd382SEmanuele Giuseppe Esposito
252afdbd382SEmanuele Giuseppe Esposito  ``generic-sdhci --produces--> sdhci``
253afdbd382SEmanuele Giuseppe Esposito- Create the ``sdhci-test`` test node. The test ``consumes`` the
254afdbd382SEmanuele Giuseppe Esposito  ``sdhci`` interface, using its API. It doesn't need to look at
255afdbd382SEmanuele Giuseppe Esposito  the supported machines or drivers.
256afdbd382SEmanuele Giuseppe Esposito
257afdbd382SEmanuele Giuseppe Esposito  ``sdhci-test --consumes--> sdhci``
258afdbd382SEmanuele Giuseppe Esposito
259cd066eeaSPhilippe Mathieu-Daudé``arm-raspi2b`` machine, simplified from
260afdbd382SEmanuele Giuseppe Esposito``tests/qtest/libqos/arm-raspi2-machine.c``::
261222455efSEmanuele Giuseppe Esposito
262222455efSEmanuele Giuseppe Esposito    #include "qgraph.h"
263222455efSEmanuele Giuseppe Esposito
264afdbd382SEmanuele Giuseppe Esposito    struct QRaspi2Machine {
265222455efSEmanuele Giuseppe Esposito        QOSGraphObject obj;
266afdbd382SEmanuele Giuseppe Esposito        QGuestAllocator alloc;
267afdbd382SEmanuele Giuseppe Esposito        QSDHCI_MemoryMapped sdhci;
268afdbd382SEmanuele Giuseppe Esposito    };
269222455efSEmanuele Giuseppe Esposito
270afdbd382SEmanuele Giuseppe Esposito    static void *raspi2_get_driver(void *object, const char *interface)
271222455efSEmanuele Giuseppe Esposito    {
272afdbd382SEmanuele Giuseppe Esposito        QRaspi2Machine *machine = object;
273afdbd382SEmanuele Giuseppe Esposito        if (!g_strcmp0(interface, "memory")) {
274afdbd382SEmanuele Giuseppe Esposito            return &machine->alloc;
275222455efSEmanuele Giuseppe Esposito        }
276222455efSEmanuele Giuseppe Esposito
277cd066eeaSPhilippe Mathieu-Daudé        fprintf(stderr, "%s not present in arm/raspi2b\n", interface);
278afdbd382SEmanuele Giuseppe Esposito        g_assert_not_reached();
279222455efSEmanuele Giuseppe Esposito    }
280222455efSEmanuele Giuseppe Esposito
281afdbd382SEmanuele Giuseppe Esposito    static QOSGraphObject *raspi2_get_device(void *obj,
282afdbd382SEmanuele Giuseppe Esposito                                                const char *device)
283222455efSEmanuele Giuseppe Esposito    {
284afdbd382SEmanuele Giuseppe Esposito        QRaspi2Machine *machine = obj;
285afdbd382SEmanuele Giuseppe Esposito        if (!g_strcmp0(device, "generic-sdhci")) {
286afdbd382SEmanuele Giuseppe Esposito            return &machine->sdhci.obj;
287222455efSEmanuele Giuseppe Esposito        }
288222455efSEmanuele Giuseppe Esposito
289cd066eeaSPhilippe Mathieu-Daudé        fprintf(stderr, "%s not present in arm/raspi2b\n", device);
290afdbd382SEmanuele Giuseppe Esposito        g_assert_not_reached();
291afdbd382SEmanuele Giuseppe Esposito    }
292afdbd382SEmanuele Giuseppe Esposito
293afdbd382SEmanuele Giuseppe Esposito    static void *qos_create_machine_arm_raspi2(QTestState *qts)
294222455efSEmanuele Giuseppe Esposito    {
295afdbd382SEmanuele Giuseppe Esposito        QRaspi2Machine *machine = g_new0(QRaspi2Machine, 1);
296222455efSEmanuele Giuseppe Esposito
297afdbd382SEmanuele Giuseppe Esposito        alloc_init(&machine->alloc, ...);
298222455efSEmanuele Giuseppe Esposito
299afdbd382SEmanuele Giuseppe Esposito        /* Get node(s) contained inside (CONTAINS) */
300afdbd382SEmanuele Giuseppe Esposito        machine->obj.get_device = raspi2_get_device;
301afdbd382SEmanuele Giuseppe Esposito
302afdbd382SEmanuele Giuseppe Esposito        /* Get node(s) produced (PRODUCES) */
303afdbd382SEmanuele Giuseppe Esposito        machine->obj.get_driver = raspi2_get_driver;
304afdbd382SEmanuele Giuseppe Esposito
305afdbd382SEmanuele Giuseppe Esposito        /* free the object */
306afdbd382SEmanuele Giuseppe Esposito        machine->obj.destructor = raspi2_destructor;
307afdbd382SEmanuele Giuseppe Esposito        qos_init_sdhci_mm(&machine->sdhci, ...);
308afdbd382SEmanuele Giuseppe Esposito        return &machine->obj;
309222455efSEmanuele Giuseppe Esposito    }
310222455efSEmanuele Giuseppe Esposito
311afdbd382SEmanuele Giuseppe Esposito    static void raspi2_register_nodes(void)
312afdbd382SEmanuele Giuseppe Esposito    {
313cd066eeaSPhilippe Mathieu-Daudé        /* arm/raspi2b --contains--> generic-sdhci */
314cd066eeaSPhilippe Mathieu-Daudé        qos_node_create_machine("arm/raspi2b",
315afdbd382SEmanuele Giuseppe Esposito                                 qos_create_machine_arm_raspi2);
316cd066eeaSPhilippe Mathieu-Daudé        qos_node_contains("arm/raspi2b", "generic-sdhci", NULL);
317afdbd382SEmanuele Giuseppe Esposito    }
318222455efSEmanuele Giuseppe Esposito
319afdbd382SEmanuele Giuseppe Esposito    libqos_init(raspi2_register_nodes);
320afdbd382SEmanuele Giuseppe Esposito
321afdbd382SEmanuele Giuseppe Esposito``x86_64/pc`` machine, simplified from
322afdbd382SEmanuele Giuseppe Esposito``tests/qtest/libqos/x86_64_pc-machine.c``::
323afdbd382SEmanuele Giuseppe Esposito
324afdbd382SEmanuele Giuseppe Esposito    #include "qgraph.h"
325afdbd382SEmanuele Giuseppe Esposito
326afdbd382SEmanuele Giuseppe Esposito    struct i440FX_pcihost {
327afdbd382SEmanuele Giuseppe Esposito        QOSGraphObject obj;
328afdbd382SEmanuele Giuseppe Esposito        QPCIBusPC pci;
329afdbd382SEmanuele Giuseppe Esposito    };
330afdbd382SEmanuele Giuseppe Esposito
331afdbd382SEmanuele Giuseppe Esposito    struct QX86PCMachine {
332afdbd382SEmanuele Giuseppe Esposito        QOSGraphObject obj;
333afdbd382SEmanuele Giuseppe Esposito        QGuestAllocator alloc;
334afdbd382SEmanuele Giuseppe Esposito        i440FX_pcihost bridge;
335afdbd382SEmanuele Giuseppe Esposito    };
336afdbd382SEmanuele Giuseppe Esposito
337afdbd382SEmanuele Giuseppe Esposito    /* i440FX_pcihost */
338afdbd382SEmanuele Giuseppe Esposito
339afdbd382SEmanuele Giuseppe Esposito    static QOSGraphObject *i440FX_host_get_device(void *obj,
340afdbd382SEmanuele Giuseppe Esposito                                                const char *device)
341afdbd382SEmanuele Giuseppe Esposito    {
342afdbd382SEmanuele Giuseppe Esposito        i440FX_pcihost *host = obj;
343afdbd382SEmanuele Giuseppe Esposito        if (!g_strcmp0(device, "pci-bus-pc")) {
344afdbd382SEmanuele Giuseppe Esposito            return &host->pci.obj;
345afdbd382SEmanuele Giuseppe Esposito        }
346afdbd382SEmanuele Giuseppe Esposito        fprintf(stderr, "%s not present in i440FX-pcihost\n", device);
347afdbd382SEmanuele Giuseppe Esposito        g_assert_not_reached();
348afdbd382SEmanuele Giuseppe Esposito    }
349afdbd382SEmanuele Giuseppe Esposito
350afdbd382SEmanuele Giuseppe Esposito    /* x86_64/pc machine */
351afdbd382SEmanuele Giuseppe Esposito
352afdbd382SEmanuele Giuseppe Esposito    static void *pc_get_driver(void *object, const char *interface)
353afdbd382SEmanuele Giuseppe Esposito    {
354afdbd382SEmanuele Giuseppe Esposito        QX86PCMachine *machine = object;
355afdbd382SEmanuele Giuseppe Esposito        if (!g_strcmp0(interface, "memory")) {
356afdbd382SEmanuele Giuseppe Esposito            return &machine->alloc;
357afdbd382SEmanuele Giuseppe Esposito        }
358afdbd382SEmanuele Giuseppe Esposito
359afdbd382SEmanuele Giuseppe Esposito        fprintf(stderr, "%s not present in x86_64/pc\n", interface);
360afdbd382SEmanuele Giuseppe Esposito        g_assert_not_reached();
361afdbd382SEmanuele Giuseppe Esposito    }
362afdbd382SEmanuele Giuseppe Esposito
363afdbd382SEmanuele Giuseppe Esposito    static QOSGraphObject *pc_get_device(void *obj, const char *device)
364afdbd382SEmanuele Giuseppe Esposito    {
365afdbd382SEmanuele Giuseppe Esposito        QX86PCMachine *machine = obj;
366afdbd382SEmanuele Giuseppe Esposito        if (!g_strcmp0(device, "i440FX-pcihost")) {
367afdbd382SEmanuele Giuseppe Esposito            return &machine->bridge.obj;
368afdbd382SEmanuele Giuseppe Esposito        }
369afdbd382SEmanuele Giuseppe Esposito
370afdbd382SEmanuele Giuseppe Esposito        fprintf(stderr, "%s not present in x86_64/pc\n", device);
371afdbd382SEmanuele Giuseppe Esposito        g_assert_not_reached();
372afdbd382SEmanuele Giuseppe Esposito    }
373afdbd382SEmanuele Giuseppe Esposito
374afdbd382SEmanuele Giuseppe Esposito    static void *qos_create_machine_pc(QTestState *qts)
375afdbd382SEmanuele Giuseppe Esposito    {
376afdbd382SEmanuele Giuseppe Esposito        QX86PCMachine *machine = g_new0(QX86PCMachine, 1);
377afdbd382SEmanuele Giuseppe Esposito
378afdbd382SEmanuele Giuseppe Esposito        /* Get node(s) contained inside (CONTAINS) */
379afdbd382SEmanuele Giuseppe Esposito        machine->obj.get_device = pc_get_device;
380afdbd382SEmanuele Giuseppe Esposito
381afdbd382SEmanuele Giuseppe Esposito        /* Get node(s) produced (PRODUCES) */
382afdbd382SEmanuele Giuseppe Esposito        machine->obj.get_driver = pc_get_driver;
383afdbd382SEmanuele Giuseppe Esposito
384afdbd382SEmanuele Giuseppe Esposito        /* free the object */
385afdbd382SEmanuele Giuseppe Esposito        machine->obj.destructor = pc_destructor;
386afdbd382SEmanuele Giuseppe Esposito        pc_alloc_init(&machine->alloc, qts, ALLOC_NO_FLAGS);
387afdbd382SEmanuele Giuseppe Esposito
388afdbd382SEmanuele Giuseppe Esposito        /* Get node(s) contained inside (CONTAINS) */
389afdbd382SEmanuele Giuseppe Esposito        machine->bridge.obj.get_device = i440FX_host_get_device;
390afdbd382SEmanuele Giuseppe Esposito
391afdbd382SEmanuele Giuseppe Esposito        return &machine->obj;
392afdbd382SEmanuele Giuseppe Esposito    }
393afdbd382SEmanuele Giuseppe Esposito
394afdbd382SEmanuele Giuseppe Esposito    static void pc_machine_register_nodes(void)
395afdbd382SEmanuele Giuseppe Esposito    {
396afdbd382SEmanuele Giuseppe Esposito        /* x86_64/pc --contains--> 1440FX-pcihost --contains-->
397afdbd382SEmanuele Giuseppe Esposito         * pci-bus-pc [--produces--> pci-bus (in pci.h)] */
398afdbd382SEmanuele Giuseppe Esposito        qos_node_create_machine("x86_64/pc", qos_create_machine_pc);
399afdbd382SEmanuele Giuseppe Esposito        qos_node_contains("x86_64/pc", "i440FX-pcihost", NULL);
400afdbd382SEmanuele Giuseppe Esposito
401afdbd382SEmanuele Giuseppe Esposito        /* contained drivers don't need a constructor,
402afdbd382SEmanuele Giuseppe Esposito         * they will be init by the parent */
403afdbd382SEmanuele Giuseppe Esposito        qos_node_create_driver("i440FX-pcihost", NULL);
404afdbd382SEmanuele Giuseppe Esposito        qos_node_contains("i440FX-pcihost", "pci-bus-pc", NULL);
405afdbd382SEmanuele Giuseppe Esposito    }
406afdbd382SEmanuele Giuseppe Esposito
407afdbd382SEmanuele Giuseppe Esposito    libqos_init(pc_machine_register_nodes);
408afdbd382SEmanuele Giuseppe Esposito
409afdbd382SEmanuele Giuseppe Esposito``sdhci`` taken from ``tests/qtest/libqos/sdhci.c``::
410afdbd382SEmanuele Giuseppe Esposito
411afdbd382SEmanuele Giuseppe Esposito    /* Interface node, offers the sdhci API */
412afdbd382SEmanuele Giuseppe Esposito    struct QSDHCI {
413afdbd382SEmanuele Giuseppe Esposito        uint16_t (*readw)(QSDHCI *s, uint32_t reg);
414afdbd382SEmanuele Giuseppe Esposito        uint64_t (*readq)(QSDHCI *s, uint32_t reg);
415afdbd382SEmanuele Giuseppe Esposito        void (*writeq)(QSDHCI *s, uint32_t reg, uint64_t val);
416afdbd382SEmanuele Giuseppe Esposito        /* other fields */
417afdbd382SEmanuele Giuseppe Esposito    };
418afdbd382SEmanuele Giuseppe Esposito
419afdbd382SEmanuele Giuseppe Esposito    /* Memory Mapped implementation of QSDHCI */
420afdbd382SEmanuele Giuseppe Esposito    struct QSDHCI_MemoryMapped {
421afdbd382SEmanuele Giuseppe Esposito        QOSGraphObject obj;
422afdbd382SEmanuele Giuseppe Esposito        QSDHCI sdhci;
423afdbd382SEmanuele Giuseppe Esposito        /* other driver-specific fields */
424afdbd382SEmanuele Giuseppe Esposito    };
425afdbd382SEmanuele Giuseppe Esposito
426afdbd382SEmanuele Giuseppe Esposito    /* PCI implementation of QSDHCI */
427afdbd382SEmanuele Giuseppe Esposito    struct QSDHCI_PCI {
428afdbd382SEmanuele Giuseppe Esposito        QOSGraphObject obj;
429afdbd382SEmanuele Giuseppe Esposito        QSDHCI sdhci;
430afdbd382SEmanuele Giuseppe Esposito        /* other driver-specific fields */
431afdbd382SEmanuele Giuseppe Esposito    };
432afdbd382SEmanuele Giuseppe Esposito
433afdbd382SEmanuele Giuseppe Esposito    /* Memory mapped implementation of QSDHCI */
434afdbd382SEmanuele Giuseppe Esposito
435afdbd382SEmanuele Giuseppe Esposito    static void *sdhci_mm_get_driver(void *obj, const char *interface)
436afdbd382SEmanuele Giuseppe Esposito    {
437afdbd382SEmanuele Giuseppe Esposito        QSDHCI_MemoryMapped *smm = obj;
438afdbd382SEmanuele Giuseppe Esposito        if (!g_strcmp0(interface, "sdhci")) {
439afdbd382SEmanuele Giuseppe Esposito            return &smm->sdhci;
440afdbd382SEmanuele Giuseppe Esposito        }
441afdbd382SEmanuele Giuseppe Esposito        fprintf(stderr, "%s not present in generic-sdhci\n", interface);
442afdbd382SEmanuele Giuseppe Esposito        g_assert_not_reached();
443afdbd382SEmanuele Giuseppe Esposito    }
444afdbd382SEmanuele Giuseppe Esposito
445afdbd382SEmanuele Giuseppe Esposito    void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts,
446afdbd382SEmanuele Giuseppe Esposito                        uint32_t addr, QSDHCIProperties *common)
447afdbd382SEmanuele Giuseppe Esposito    {
448afdbd382SEmanuele Giuseppe Esposito        /* Get node contained inside (CONTAINS) */
449afdbd382SEmanuele Giuseppe Esposito        sdhci->obj.get_driver = sdhci_mm_get_driver;
450afdbd382SEmanuele Giuseppe Esposito
451afdbd382SEmanuele Giuseppe Esposito        /* SDHCI interface API */
452afdbd382SEmanuele Giuseppe Esposito        sdhci->sdhci.readw = sdhci_mm_readw;
453afdbd382SEmanuele Giuseppe Esposito        sdhci->sdhci.readq = sdhci_mm_readq;
454afdbd382SEmanuele Giuseppe Esposito        sdhci->sdhci.writeq = sdhci_mm_writeq;
455afdbd382SEmanuele Giuseppe Esposito        sdhci->qts = qts;
456afdbd382SEmanuele Giuseppe Esposito    }
457afdbd382SEmanuele Giuseppe Esposito
458afdbd382SEmanuele Giuseppe Esposito    /* PCI implementation of QSDHCI */
459afdbd382SEmanuele Giuseppe Esposito
460afdbd382SEmanuele Giuseppe Esposito    static void *sdhci_pci_get_driver(void *object,
461afdbd382SEmanuele Giuseppe Esposito                                      const char *interface)
462afdbd382SEmanuele Giuseppe Esposito    {
463afdbd382SEmanuele Giuseppe Esposito        QSDHCI_PCI *spci = object;
464afdbd382SEmanuele Giuseppe Esposito        if (!g_strcmp0(interface, "sdhci")) {
465afdbd382SEmanuele Giuseppe Esposito            return &spci->sdhci;
466afdbd382SEmanuele Giuseppe Esposito        }
467afdbd382SEmanuele Giuseppe Esposito
468afdbd382SEmanuele Giuseppe Esposito        fprintf(stderr, "%s not present in sdhci-pci\n", interface);
469afdbd382SEmanuele Giuseppe Esposito        g_assert_not_reached();
470afdbd382SEmanuele Giuseppe Esposito    }
471afdbd382SEmanuele Giuseppe Esposito
472afdbd382SEmanuele Giuseppe Esposito    static void *sdhci_pci_create(void *pci_bus,
473afdbd382SEmanuele Giuseppe Esposito                                  QGuestAllocator *alloc,
474afdbd382SEmanuele Giuseppe Esposito                                  void *addr)
475afdbd382SEmanuele Giuseppe Esposito    {
476afdbd382SEmanuele Giuseppe Esposito        QSDHCI_PCI *spci = g_new0(QSDHCI_PCI, 1);
477afdbd382SEmanuele Giuseppe Esposito        QPCIBus *bus = pci_bus;
478afdbd382SEmanuele Giuseppe Esposito        uint64_t barsize;
479afdbd382SEmanuele Giuseppe Esposito
480afdbd382SEmanuele Giuseppe Esposito        qpci_device_init(&spci->dev, bus, addr);
481afdbd382SEmanuele Giuseppe Esposito
482afdbd382SEmanuele Giuseppe Esposito        /* SDHCI interface API */
483afdbd382SEmanuele Giuseppe Esposito        spci->sdhci.readw = sdhci_pci_readw;
484afdbd382SEmanuele Giuseppe Esposito        spci->sdhci.readq = sdhci_pci_readq;
485afdbd382SEmanuele Giuseppe Esposito        spci->sdhci.writeq = sdhci_pci_writeq;
486afdbd382SEmanuele Giuseppe Esposito
487afdbd382SEmanuele Giuseppe Esposito        /* Get node(s) produced (PRODUCES) */
488afdbd382SEmanuele Giuseppe Esposito        spci->obj.get_driver = sdhci_pci_get_driver;
489afdbd382SEmanuele Giuseppe Esposito
490afdbd382SEmanuele Giuseppe Esposito        spci->obj.start_hw = sdhci_pci_start_hw;
491afdbd382SEmanuele Giuseppe Esposito        spci->obj.destructor = sdhci_destructor;
492afdbd382SEmanuele Giuseppe Esposito        return &spci->obj;
493afdbd382SEmanuele Giuseppe Esposito    }
494afdbd382SEmanuele Giuseppe Esposito
495afdbd382SEmanuele Giuseppe Esposito    static void qsdhci_register_nodes(void)
496afdbd382SEmanuele Giuseppe Esposito    {
497afdbd382SEmanuele Giuseppe Esposito        QOSGraphEdgeOptions opts = {
498afdbd382SEmanuele Giuseppe Esposito            .extra_device_opts = "addr=04.0",
499afdbd382SEmanuele Giuseppe Esposito        };
500afdbd382SEmanuele Giuseppe Esposito
501afdbd382SEmanuele Giuseppe Esposito        /* generic-sdhci */
502afdbd382SEmanuele Giuseppe Esposito        /* generic-sdhci --produces--> sdhci */
503afdbd382SEmanuele Giuseppe Esposito        qos_node_create_driver("generic-sdhci", NULL);
504afdbd382SEmanuele Giuseppe Esposito        qos_node_produces("generic-sdhci", "sdhci");
505afdbd382SEmanuele Giuseppe Esposito
506afdbd382SEmanuele Giuseppe Esposito        /* sdhci-pci */
507afdbd382SEmanuele Giuseppe Esposito        /* sdhci-pci --produces--> sdhci
508afdbd382SEmanuele Giuseppe Esposito         * sdhci-pci --consumes--> pci-bus */
509afdbd382SEmanuele Giuseppe Esposito        qos_node_create_driver("sdhci-pci", sdhci_pci_create);
510afdbd382SEmanuele Giuseppe Esposito        qos_node_produces("sdhci-pci", "sdhci");
511afdbd382SEmanuele Giuseppe Esposito        qos_node_consumes("sdhci-pci", "pci-bus", &opts);
512afdbd382SEmanuele Giuseppe Esposito    }
513afdbd382SEmanuele Giuseppe Esposito
514afdbd382SEmanuele Giuseppe Esposito    libqos_init(qsdhci_register_nodes);
515afdbd382SEmanuele Giuseppe Esposito
516afdbd382SEmanuele Giuseppe EspositoIn the above example, all possible types of relations are created::
517afdbd382SEmanuele Giuseppe Esposito
518afdbd382SEmanuele Giuseppe Esposito  x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc
519222455efSEmanuele Giuseppe Esposito                                                            |
520afdbd382SEmanuele Giuseppe Esposito               sdhci-pci --consumes--> pci-bus <--produces--+
521222455efSEmanuele Giuseppe Esposito                  |
522afdbd382SEmanuele Giuseppe Esposito                  +--produces--+
523afdbd382SEmanuele Giuseppe Esposito                               |
524afdbd382SEmanuele Giuseppe Esposito                               v
525afdbd382SEmanuele Giuseppe Esposito                             sdhci
526afdbd382SEmanuele Giuseppe Esposito                               ^
527afdbd382SEmanuele Giuseppe Esposito                               |
528afdbd382SEmanuele Giuseppe Esposito                               +--produces-- +
529afdbd382SEmanuele Giuseppe Esposito                                             |
530cd066eeaSPhilippe Mathieu-Daudé               arm/raspi2b --contains--> generic-sdhci
531222455efSEmanuele Giuseppe Esposito
532222455efSEmanuele Giuseppe Espositoor inverting the consumes edge in consumed_by::
533222455efSEmanuele Giuseppe Esposito
534afdbd382SEmanuele Giuseppe Esposito  x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc
535222455efSEmanuele Giuseppe Esposito                                                            |
536afdbd382SEmanuele Giuseppe Esposito            sdhci-pci <--consumed by-- pci-bus <--produces--+
537222455efSEmanuele Giuseppe Esposito                |
538afdbd382SEmanuele Giuseppe Esposito                +--produces--+
539afdbd382SEmanuele Giuseppe Esposito                             |
540afdbd382SEmanuele Giuseppe Esposito                             v
541afdbd382SEmanuele Giuseppe Esposito                            sdhci
542afdbd382SEmanuele Giuseppe Esposito                             ^
543afdbd382SEmanuele Giuseppe Esposito                             |
544afdbd382SEmanuele Giuseppe Esposito                             +--produces-- +
545afdbd382SEmanuele Giuseppe Esposito                                           |
546cd066eeaSPhilippe Mathieu-Daudé            arm/raspi2b --contains--> generic-sdhci
547222455efSEmanuele Giuseppe Esposito
548afdbd382SEmanuele Giuseppe EspositoAdding a new test
549768f14f9SPaolo Bonzini-----------------
550222455efSEmanuele Giuseppe Esposito
551afdbd382SEmanuele Giuseppe EspositoGiven the above setup, adding a new test is very simple.
552afdbd382SEmanuele Giuseppe Esposito``sdhci-test``, taken from ``tests/qtest/sdhci-test.c``::
553222455efSEmanuele Giuseppe Esposito
554afdbd382SEmanuele Giuseppe Esposito    static void check_capab_sdma(QSDHCI *s, bool supported)
555222455efSEmanuele Giuseppe Esposito    {
556afdbd382SEmanuele Giuseppe Esposito        uint64_t capab, capab_sdma;
557afdbd382SEmanuele Giuseppe Esposito
558afdbd382SEmanuele Giuseppe Esposito        capab = s->readq(s, SDHC_CAPAB);
559afdbd382SEmanuele Giuseppe Esposito        capab_sdma = FIELD_EX64(capab, SDHC_CAPAB, SDMA);
560afdbd382SEmanuele Giuseppe Esposito        g_assert_cmpuint(capab_sdma, ==, supported);
561222455efSEmanuele Giuseppe Esposito    }
562222455efSEmanuele Giuseppe Esposito
563afdbd382SEmanuele Giuseppe Esposito    static void test_registers(void *obj, void *data,
564afdbd382SEmanuele Giuseppe Esposito                                QGuestAllocator *alloc)
565222455efSEmanuele Giuseppe Esposito    {
566afdbd382SEmanuele Giuseppe Esposito        QSDHCI *s = obj;
567afdbd382SEmanuele Giuseppe Esposito
568afdbd382SEmanuele Giuseppe Esposito        /* example test */
569afdbd382SEmanuele Giuseppe Esposito        check_capab_sdma(s, s->props.capab.sdma);
570222455efSEmanuele Giuseppe Esposito    }
571222455efSEmanuele Giuseppe Esposito
572afdbd382SEmanuele Giuseppe Esposito    static void register_sdhci_test(void)
573afdbd382SEmanuele Giuseppe Esposito    {
574afdbd382SEmanuele Giuseppe Esposito        /* sdhci-test --consumes--> sdhci */
575afdbd382SEmanuele Giuseppe Esposito        qos_add_test("registers", "sdhci", test_registers, NULL);
576afdbd382SEmanuele Giuseppe Esposito    }
577222455efSEmanuele Giuseppe Esposito
578afdbd382SEmanuele Giuseppe Esposito    libqos_init(register_sdhci_test);
579afdbd382SEmanuele Giuseppe Esposito
580afdbd382SEmanuele Giuseppe EspositoHere a new test is created, consuming ``sdhci`` interface node
581afdbd382SEmanuele Giuseppe Espositoand creating a valid path from both machines to a test.
582222455efSEmanuele Giuseppe EspositoFinal graph will be like this::
583222455efSEmanuele Giuseppe Esposito
584afdbd382SEmanuele Giuseppe Esposito  x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc
585222455efSEmanuele Giuseppe Esposito                                                            |
586afdbd382SEmanuele Giuseppe Esposito               sdhci-pci --consumes--> pci-bus <--produces--+
587222455efSEmanuele Giuseppe Esposito                  |
588afdbd382SEmanuele Giuseppe Esposito                  +--produces--+
589afdbd382SEmanuele Giuseppe Esposito                               |
590afdbd382SEmanuele Giuseppe Esposito                               v
591afdbd382SEmanuele Giuseppe Esposito                             sdhci <--consumes-- sdhci-test
592afdbd382SEmanuele Giuseppe Esposito                               ^
593afdbd382SEmanuele Giuseppe Esposito                               |
594afdbd382SEmanuele Giuseppe Esposito                               +--produces-- +
595afdbd382SEmanuele Giuseppe Esposito                                             |
596cd066eeaSPhilippe Mathieu-Daudé               arm/raspi2b --contains--> generic-sdhci
597222455efSEmanuele Giuseppe Esposito
598222455efSEmanuele Giuseppe Espositoor inverting the consumes edge in consumed_by::
599222455efSEmanuele Giuseppe Esposito
600afdbd382SEmanuele Giuseppe Esposito  x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc
601222455efSEmanuele Giuseppe Esposito                                                            |
602afdbd382SEmanuele Giuseppe Esposito            sdhci-pci <--consumed by-- pci-bus <--produces--+
603222455efSEmanuele Giuseppe Esposito                |
604afdbd382SEmanuele Giuseppe Esposito                +--produces--+
605afdbd382SEmanuele Giuseppe Esposito                             |
606afdbd382SEmanuele Giuseppe Esposito                             v
607afdbd382SEmanuele Giuseppe Esposito                            sdhci --consumed by--> sdhci-test
608afdbd382SEmanuele Giuseppe Esposito                             ^
609afdbd382SEmanuele Giuseppe Esposito                             |
610afdbd382SEmanuele Giuseppe Esposito                             +--produces-- +
611afdbd382SEmanuele Giuseppe Esposito                                           |
612cd066eeaSPhilippe Mathieu-Daudé            arm/raspi2b --contains--> generic-sdhci
613222455efSEmanuele Giuseppe Esposito
614222455efSEmanuele Giuseppe EspositoAssuming there the binary is
615222455efSEmanuele Giuseppe Esposito``QTEST_QEMU_BINARY=./qemu-system-x86_64``
616222455efSEmanuele Giuseppe Espositoa valid test path will be:
617afdbd382SEmanuele Giuseppe Esposito``/x86_64/pc/1440FX-pcihost/pci-bus-pc/pci-bus/sdhci-pc/sdhci/sdhci-test``
618afdbd382SEmanuele Giuseppe Esposito
619afdbd382SEmanuele Giuseppe Espositoand for the binary ``QTEST_QEMU_BINARY=./qemu-system-arm``:
620afdbd382SEmanuele Giuseppe Esposito
621cd066eeaSPhilippe Mathieu-Daudé``/arm/raspi2b/generic-sdhci/sdhci/sdhci-test``
622222455efSEmanuele Giuseppe Esposito
623222455efSEmanuele Giuseppe EspositoAdditional examples are also in ``test-qgraph.c``
624222455efSEmanuele Giuseppe Esposito
625222455efSEmanuele Giuseppe EspositoQgraph API reference
626768f14f9SPaolo Bonzini--------------------
627222455efSEmanuele Giuseppe Esposito
628222455efSEmanuele Giuseppe Esposito.. kernel-doc:: tests/qtest/libqos/qgraph.h
629