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 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 318fcfc823SAlex Bennée * frontend and therefor doesn't present any vhost specific features 328fcfc823SAlex Bennée * and in fact masks of the re-used bit. 338fcfc823SAlex Bennée */ 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 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 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) */ 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 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 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 */ 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 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 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 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 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 */ 157*523e4002SAlex Bennée edge_opts.extra_device_opts = "id=gpio0,chardev=chr-vhost-user-test " 158*523e4002SAlex 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