18fcfc823SAlex Bennée /*
28fcfc823SAlex Bennée * virtio-gpio nodes for testing
38fcfc823SAlex Bennée *
48fcfc823SAlex Bennée * Copyright (c) 2022 Linaro Ltd
58fcfc823SAlex Bennée *
68fcfc823SAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later
78fcfc823SAlex Bennée */
88fcfc823SAlex Bennée
98fcfc823SAlex Bennée #include "qemu/osdep.h"
108fcfc823SAlex Bennée #include "standard-headers/linux/virtio_config.h"
118fcfc823SAlex Bennée #include "../libqtest.h"
128fcfc823SAlex Bennée #include "qemu/module.h"
138fcfc823SAlex Bennée #include "qgraph.h"
148fcfc823SAlex Bennée #include "virtio-gpio.h"
158fcfc823SAlex Bennée
168fcfc823SAlex Bennée static QGuestAllocator *alloc;
178fcfc823SAlex Bennée
virtio_gpio_cleanup(QVhostUserGPIO * gpio)188fcfc823SAlex Bennée static void virtio_gpio_cleanup(QVhostUserGPIO *gpio)
198fcfc823SAlex Bennée {
208fcfc823SAlex Bennée QVirtioDevice *vdev = gpio->vdev;
218fcfc823SAlex Bennée int i;
228fcfc823SAlex Bennée
238fcfc823SAlex Bennée for (i = 0; i < 2; i++) {
248fcfc823SAlex Bennée qvirtqueue_cleanup(vdev->bus, gpio->queues[i], alloc);
258fcfc823SAlex Bennée }
268fcfc823SAlex Bennée g_free(gpio->queues);
278fcfc823SAlex Bennée }
288fcfc823SAlex Bennée
298fcfc823SAlex Bennée /*
308fcfc823SAlex Bennée * This handles the VirtIO setup from the point of view of the driver
31*96420a30SMichael Tokarev * frontend and therefore doesn't present any vhost specific features
328fcfc823SAlex Bennée * and in fact masks of the re-used bit.
338fcfc823SAlex Bennée */
virtio_gpio_setup(QVhostUserGPIO * gpio)348fcfc823SAlex Bennée static void virtio_gpio_setup(QVhostUserGPIO *gpio)
358fcfc823SAlex Bennée {
368fcfc823SAlex Bennée QVirtioDevice *vdev = gpio->vdev;
378fcfc823SAlex Bennée uint64_t features;
388fcfc823SAlex Bennée int i;
398fcfc823SAlex Bennée
408fcfc823SAlex Bennée features = qvirtio_get_features(vdev);
418fcfc823SAlex Bennée features &= ~QVIRTIO_F_BAD_FEATURE;
428fcfc823SAlex Bennée qvirtio_set_features(vdev, features);
438fcfc823SAlex Bennée
448fcfc823SAlex Bennée gpio->queues = g_new(QVirtQueue *, 2);
458fcfc823SAlex Bennée for (i = 0; i < 2; i++) {
468fcfc823SAlex Bennée gpio->queues[i] = qvirtqueue_setup(vdev, alloc, i);
478fcfc823SAlex Bennée }
488fcfc823SAlex Bennée qvirtio_set_driver_ok(vdev);
498fcfc823SAlex Bennée }
508fcfc823SAlex Bennée
qvirtio_gpio_get_driver(QVhostUserGPIO * v_gpio,const char * interface)518fcfc823SAlex Bennée static void *qvirtio_gpio_get_driver(QVhostUserGPIO *v_gpio,
528fcfc823SAlex Bennée const char *interface)
538fcfc823SAlex Bennée {
548fcfc823SAlex Bennée if (!g_strcmp0(interface, "vhost-user-gpio")) {
558fcfc823SAlex Bennée return v_gpio;
568fcfc823SAlex Bennée }
578fcfc823SAlex Bennée if (!g_strcmp0(interface, "virtio")) {
588fcfc823SAlex Bennée return v_gpio->vdev;
598fcfc823SAlex Bennée }
608fcfc823SAlex Bennée
618fcfc823SAlex Bennée g_assert_not_reached();
628fcfc823SAlex Bennée }
638fcfc823SAlex Bennée
qvirtio_gpio_device_get_driver(void * object,const char * interface)648fcfc823SAlex Bennée static void *qvirtio_gpio_device_get_driver(void *object,
658fcfc823SAlex Bennée const char *interface)
668fcfc823SAlex Bennée {
678fcfc823SAlex Bennée QVhostUserGPIODevice *v_gpio = object;
688fcfc823SAlex Bennée return qvirtio_gpio_get_driver(&v_gpio->gpio, interface);
698fcfc823SAlex Bennée }
708fcfc823SAlex Bennée
718fcfc823SAlex Bennée /* virtio-gpio (mmio) */
qvirtio_gpio_device_destructor(QOSGraphObject * obj)728fcfc823SAlex Bennée static void qvirtio_gpio_device_destructor(QOSGraphObject *obj)
738fcfc823SAlex Bennée {
748fcfc823SAlex Bennée QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj;
758fcfc823SAlex Bennée virtio_gpio_cleanup(&gpio_dev->gpio);
768fcfc823SAlex Bennée }
778fcfc823SAlex Bennée
qvirtio_gpio_device_start_hw(QOSGraphObject * obj)788fcfc823SAlex Bennée static void qvirtio_gpio_device_start_hw(QOSGraphObject *obj)
798fcfc823SAlex Bennée {
808fcfc823SAlex Bennée QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj;
818fcfc823SAlex Bennée virtio_gpio_setup(&gpio_dev->gpio);
828fcfc823SAlex Bennée }
838fcfc823SAlex Bennée
virtio_gpio_device_create(void * virtio_dev,QGuestAllocator * t_alloc,void * addr)848fcfc823SAlex Bennée static void *virtio_gpio_device_create(void *virtio_dev,
858fcfc823SAlex Bennée QGuestAllocator *t_alloc,
868fcfc823SAlex Bennée void *addr)
878fcfc823SAlex Bennée {
888fcfc823SAlex Bennée QVhostUserGPIODevice *virtio_device = g_new0(QVhostUserGPIODevice, 1);
898fcfc823SAlex Bennée QVhostUserGPIO *interface = &virtio_device->gpio;
908fcfc823SAlex Bennée
918fcfc823SAlex Bennée interface->vdev = virtio_dev;
928fcfc823SAlex Bennée alloc = t_alloc;
938fcfc823SAlex Bennée
948fcfc823SAlex Bennée virtio_device->obj.get_driver = qvirtio_gpio_device_get_driver;
958fcfc823SAlex Bennée virtio_device->obj.start_hw = qvirtio_gpio_device_start_hw;
968fcfc823SAlex Bennée virtio_device->obj.destructor = qvirtio_gpio_device_destructor;
978fcfc823SAlex Bennée
988fcfc823SAlex Bennée return &virtio_device->obj;
998fcfc823SAlex Bennée }
1008fcfc823SAlex Bennée
1018fcfc823SAlex Bennée /* virtio-gpio-pci */
qvirtio_gpio_pci_destructor(QOSGraphObject * obj)1028fcfc823SAlex Bennée static void qvirtio_gpio_pci_destructor(QOSGraphObject *obj)
1038fcfc823SAlex Bennée {
1048fcfc823SAlex Bennée QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj;
1058fcfc823SAlex Bennée QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj;
1068fcfc823SAlex Bennée
1078fcfc823SAlex Bennée virtio_gpio_cleanup(&gpio_pci->gpio);
1088fcfc823SAlex Bennée qvirtio_pci_destructor(pci_vobj);
1098fcfc823SAlex Bennée }
1108fcfc823SAlex Bennée
qvirtio_gpio_pci_start_hw(QOSGraphObject * obj)1118fcfc823SAlex Bennée static void qvirtio_gpio_pci_start_hw(QOSGraphObject *obj)
1128fcfc823SAlex Bennée {
1138fcfc823SAlex Bennée QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj;
1148fcfc823SAlex Bennée QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj;
1158fcfc823SAlex Bennée
1168fcfc823SAlex Bennée qvirtio_pci_start_hw(pci_vobj);
1178fcfc823SAlex Bennée virtio_gpio_setup(&gpio_pci->gpio);
1188fcfc823SAlex Bennée }
1198fcfc823SAlex Bennée
qvirtio_gpio_pci_get_driver(void * object,const char * interface)1208fcfc823SAlex Bennée static void *qvirtio_gpio_pci_get_driver(void *object, const char *interface)
1218fcfc823SAlex Bennée {
1228fcfc823SAlex Bennée QVhostUserGPIOPCI *v_gpio = object;
1238fcfc823SAlex Bennée
1248fcfc823SAlex Bennée if (!g_strcmp0(interface, "pci-device")) {
1258fcfc823SAlex Bennée return v_gpio->pci_vdev.pdev;
1268fcfc823SAlex Bennée }
1278fcfc823SAlex Bennée return qvirtio_gpio_get_driver(&v_gpio->gpio, interface);
1288fcfc823SAlex Bennée }
1298fcfc823SAlex Bennée
virtio_gpio_pci_create(void * pci_bus,QGuestAllocator * t_alloc,void * addr)1308fcfc823SAlex Bennée static void *virtio_gpio_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
1318fcfc823SAlex Bennée void *addr)
1328fcfc823SAlex Bennée {
1338fcfc823SAlex Bennée QVhostUserGPIOPCI *virtio_spci = g_new0(QVhostUserGPIOPCI, 1);
1348fcfc823SAlex Bennée QVhostUserGPIO *interface = &virtio_spci->gpio;
1358fcfc823SAlex Bennée QOSGraphObject *obj = &virtio_spci->pci_vdev.obj;
1368fcfc823SAlex Bennée
1378fcfc823SAlex Bennée virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr);
1388fcfc823SAlex Bennée interface->vdev = &virtio_spci->pci_vdev.vdev;
1398fcfc823SAlex Bennée alloc = t_alloc;
1408fcfc823SAlex Bennée
1418fcfc823SAlex Bennée obj->get_driver = qvirtio_gpio_pci_get_driver;
1428fcfc823SAlex Bennée obj->start_hw = qvirtio_gpio_pci_start_hw;
1438fcfc823SAlex Bennée obj->destructor = qvirtio_gpio_pci_destructor;
1448fcfc823SAlex Bennée
1458fcfc823SAlex Bennée return obj;
1468fcfc823SAlex Bennée }
1478fcfc823SAlex Bennée
virtio_gpio_register_nodes(void)1488fcfc823SAlex Bennée static void virtio_gpio_register_nodes(void)
1498fcfc823SAlex Bennée {
1508fcfc823SAlex Bennée QPCIAddress addr = {
1518fcfc823SAlex Bennée .devfn = QPCI_DEVFN(4, 0),
1528fcfc823SAlex Bennée };
1538fcfc823SAlex Bennée
1548fcfc823SAlex Bennée QOSGraphEdgeOptions edge_opts = { };
1558fcfc823SAlex Bennée
1568fcfc823SAlex Bennée /* vhost-user-gpio-device */
157523e4002SAlex Bennée edge_opts.extra_device_opts = "id=gpio0,chardev=chr-vhost-user-test "
158523e4002SAlex Bennée "-global virtio-mmio.force-legacy=false";
1598fcfc823SAlex Bennée qos_node_create_driver("vhost-user-gpio-device",
1608fcfc823SAlex Bennée virtio_gpio_device_create);
1618fcfc823SAlex Bennée qos_node_consumes("vhost-user-gpio-device", "virtio-bus", &edge_opts);
1628fcfc823SAlex Bennée qos_node_produces("vhost-user-gpio-device", "vhost-user-gpio");
1638fcfc823SAlex Bennée
1648fcfc823SAlex Bennée /* virtio-gpio-pci */
1658fcfc823SAlex Bennée edge_opts.extra_device_opts = "id=gpio0,addr=04.0,chardev=chr-vhost-user-test";
1668fcfc823SAlex Bennée add_qpci_address(&edge_opts, &addr);
1678fcfc823SAlex Bennée qos_node_create_driver("vhost-user-gpio-pci", virtio_gpio_pci_create);
1688fcfc823SAlex Bennée qos_node_consumes("vhost-user-gpio-pci", "pci-bus", &edge_opts);
1698fcfc823SAlex Bennée qos_node_produces("vhost-user-gpio-pci", "vhost-user-gpio");
1708fcfc823SAlex Bennée }
1718fcfc823SAlex Bennée
1728fcfc823SAlex Bennée libqos_init(virtio_gpio_register_nodes);
173