1*8fcfc823SAlex Bennée /* 2*8fcfc823SAlex Bennée * virtio-gpio nodes for testing 3*8fcfc823SAlex Bennée * 4*8fcfc823SAlex Bennée * Copyright (c) 2022 Linaro Ltd 5*8fcfc823SAlex Bennée * 6*8fcfc823SAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later 7*8fcfc823SAlex Bennée */ 8*8fcfc823SAlex Bennée 9*8fcfc823SAlex Bennée #include "qemu/osdep.h" 10*8fcfc823SAlex Bennée #include "standard-headers/linux/virtio_config.h" 11*8fcfc823SAlex Bennée #include "../libqtest.h" 12*8fcfc823SAlex Bennée #include "qemu/module.h" 13*8fcfc823SAlex Bennée #include "qgraph.h" 14*8fcfc823SAlex Bennée #include "virtio-gpio.h" 15*8fcfc823SAlex Bennée 16*8fcfc823SAlex Bennée static QGuestAllocator *alloc; 17*8fcfc823SAlex Bennée 18*8fcfc823SAlex Bennée static void virtio_gpio_cleanup(QVhostUserGPIO *gpio) 19*8fcfc823SAlex Bennée { 20*8fcfc823SAlex Bennée QVirtioDevice *vdev = gpio->vdev; 21*8fcfc823SAlex Bennée int i; 22*8fcfc823SAlex Bennée 23*8fcfc823SAlex Bennée for (i = 0; i < 2; i++) { 24*8fcfc823SAlex Bennée qvirtqueue_cleanup(vdev->bus, gpio->queues[i], alloc); 25*8fcfc823SAlex Bennée } 26*8fcfc823SAlex Bennée g_free(gpio->queues); 27*8fcfc823SAlex Bennée } 28*8fcfc823SAlex Bennée 29*8fcfc823SAlex Bennée /* 30*8fcfc823SAlex Bennée * This handles the VirtIO setup from the point of view of the driver 31*8fcfc823SAlex Bennée * frontend and therefor doesn't present any vhost specific features 32*8fcfc823SAlex Bennée * and in fact masks of the re-used bit. 33*8fcfc823SAlex Bennée */ 34*8fcfc823SAlex Bennée static void virtio_gpio_setup(QVhostUserGPIO *gpio) 35*8fcfc823SAlex Bennée { 36*8fcfc823SAlex Bennée QVirtioDevice *vdev = gpio->vdev; 37*8fcfc823SAlex Bennée uint64_t features; 38*8fcfc823SAlex Bennée int i; 39*8fcfc823SAlex Bennée 40*8fcfc823SAlex Bennée features = qvirtio_get_features(vdev); 41*8fcfc823SAlex Bennée features &= ~QVIRTIO_F_BAD_FEATURE; 42*8fcfc823SAlex Bennée qvirtio_set_features(vdev, features); 43*8fcfc823SAlex Bennée 44*8fcfc823SAlex Bennée gpio->queues = g_new(QVirtQueue *, 2); 45*8fcfc823SAlex Bennée for (i = 0; i < 2; i++) { 46*8fcfc823SAlex Bennée gpio->queues[i] = qvirtqueue_setup(vdev, alloc, i); 47*8fcfc823SAlex Bennée } 48*8fcfc823SAlex Bennée qvirtio_set_driver_ok(vdev); 49*8fcfc823SAlex Bennée } 50*8fcfc823SAlex Bennée 51*8fcfc823SAlex Bennée static void *qvirtio_gpio_get_driver(QVhostUserGPIO *v_gpio, 52*8fcfc823SAlex Bennée const char *interface) 53*8fcfc823SAlex Bennée { 54*8fcfc823SAlex Bennée if (!g_strcmp0(interface, "vhost-user-gpio")) { 55*8fcfc823SAlex Bennée return v_gpio; 56*8fcfc823SAlex Bennée } 57*8fcfc823SAlex Bennée if (!g_strcmp0(interface, "virtio")) { 58*8fcfc823SAlex Bennée return v_gpio->vdev; 59*8fcfc823SAlex Bennée } 60*8fcfc823SAlex Bennée 61*8fcfc823SAlex Bennée g_assert_not_reached(); 62*8fcfc823SAlex Bennée } 63*8fcfc823SAlex Bennée 64*8fcfc823SAlex Bennée static void *qvirtio_gpio_device_get_driver(void *object, 65*8fcfc823SAlex Bennée const char *interface) 66*8fcfc823SAlex Bennée { 67*8fcfc823SAlex Bennée QVhostUserGPIODevice *v_gpio = object; 68*8fcfc823SAlex Bennée return qvirtio_gpio_get_driver(&v_gpio->gpio, interface); 69*8fcfc823SAlex Bennée } 70*8fcfc823SAlex Bennée 71*8fcfc823SAlex Bennée /* virtio-gpio (mmio) */ 72*8fcfc823SAlex Bennée static void qvirtio_gpio_device_destructor(QOSGraphObject *obj) 73*8fcfc823SAlex Bennée { 74*8fcfc823SAlex Bennée QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj; 75*8fcfc823SAlex Bennée virtio_gpio_cleanup(&gpio_dev->gpio); 76*8fcfc823SAlex Bennée } 77*8fcfc823SAlex Bennée 78*8fcfc823SAlex Bennée static void qvirtio_gpio_device_start_hw(QOSGraphObject *obj) 79*8fcfc823SAlex Bennée { 80*8fcfc823SAlex Bennée QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj; 81*8fcfc823SAlex Bennée virtio_gpio_setup(&gpio_dev->gpio); 82*8fcfc823SAlex Bennée } 83*8fcfc823SAlex Bennée 84*8fcfc823SAlex Bennée static void *virtio_gpio_device_create(void *virtio_dev, 85*8fcfc823SAlex Bennée QGuestAllocator *t_alloc, 86*8fcfc823SAlex Bennée void *addr) 87*8fcfc823SAlex Bennée { 88*8fcfc823SAlex Bennée QVhostUserGPIODevice *virtio_device = g_new0(QVhostUserGPIODevice, 1); 89*8fcfc823SAlex Bennée QVhostUserGPIO *interface = &virtio_device->gpio; 90*8fcfc823SAlex Bennée 91*8fcfc823SAlex Bennée interface->vdev = virtio_dev; 92*8fcfc823SAlex Bennée alloc = t_alloc; 93*8fcfc823SAlex Bennée 94*8fcfc823SAlex Bennée virtio_device->obj.get_driver = qvirtio_gpio_device_get_driver; 95*8fcfc823SAlex Bennée virtio_device->obj.start_hw = qvirtio_gpio_device_start_hw; 96*8fcfc823SAlex Bennée virtio_device->obj.destructor = qvirtio_gpio_device_destructor; 97*8fcfc823SAlex Bennée 98*8fcfc823SAlex Bennée return &virtio_device->obj; 99*8fcfc823SAlex Bennée } 100*8fcfc823SAlex Bennée 101*8fcfc823SAlex Bennée /* virtio-gpio-pci */ 102*8fcfc823SAlex Bennée static void qvirtio_gpio_pci_destructor(QOSGraphObject *obj) 103*8fcfc823SAlex Bennée { 104*8fcfc823SAlex Bennée QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj; 105*8fcfc823SAlex Bennée QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj; 106*8fcfc823SAlex Bennée 107*8fcfc823SAlex Bennée virtio_gpio_cleanup(&gpio_pci->gpio); 108*8fcfc823SAlex Bennée qvirtio_pci_destructor(pci_vobj); 109*8fcfc823SAlex Bennée } 110*8fcfc823SAlex Bennée 111*8fcfc823SAlex Bennée static void qvirtio_gpio_pci_start_hw(QOSGraphObject *obj) 112*8fcfc823SAlex Bennée { 113*8fcfc823SAlex Bennée QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj; 114*8fcfc823SAlex Bennée QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj; 115*8fcfc823SAlex Bennée 116*8fcfc823SAlex Bennée qvirtio_pci_start_hw(pci_vobj); 117*8fcfc823SAlex Bennée virtio_gpio_setup(&gpio_pci->gpio); 118*8fcfc823SAlex Bennée } 119*8fcfc823SAlex Bennée 120*8fcfc823SAlex Bennée static void *qvirtio_gpio_pci_get_driver(void *object, const char *interface) 121*8fcfc823SAlex Bennée { 122*8fcfc823SAlex Bennée QVhostUserGPIOPCI *v_gpio = object; 123*8fcfc823SAlex Bennée 124*8fcfc823SAlex Bennée if (!g_strcmp0(interface, "pci-device")) { 125*8fcfc823SAlex Bennée return v_gpio->pci_vdev.pdev; 126*8fcfc823SAlex Bennée } 127*8fcfc823SAlex Bennée return qvirtio_gpio_get_driver(&v_gpio->gpio, interface); 128*8fcfc823SAlex Bennée } 129*8fcfc823SAlex Bennée 130*8fcfc823SAlex Bennée static void *virtio_gpio_pci_create(void *pci_bus, QGuestAllocator *t_alloc, 131*8fcfc823SAlex Bennée void *addr) 132*8fcfc823SAlex Bennée { 133*8fcfc823SAlex Bennée QVhostUserGPIOPCI *virtio_spci = g_new0(QVhostUserGPIOPCI, 1); 134*8fcfc823SAlex Bennée QVhostUserGPIO *interface = &virtio_spci->gpio; 135*8fcfc823SAlex Bennée QOSGraphObject *obj = &virtio_spci->pci_vdev.obj; 136*8fcfc823SAlex Bennée 137*8fcfc823SAlex Bennée virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr); 138*8fcfc823SAlex Bennée interface->vdev = &virtio_spci->pci_vdev.vdev; 139*8fcfc823SAlex Bennée alloc = t_alloc; 140*8fcfc823SAlex Bennée 141*8fcfc823SAlex Bennée obj->get_driver = qvirtio_gpio_pci_get_driver; 142*8fcfc823SAlex Bennée obj->start_hw = qvirtio_gpio_pci_start_hw; 143*8fcfc823SAlex Bennée obj->destructor = qvirtio_gpio_pci_destructor; 144*8fcfc823SAlex Bennée 145*8fcfc823SAlex Bennée return obj; 146*8fcfc823SAlex Bennée } 147*8fcfc823SAlex Bennée 148*8fcfc823SAlex Bennée static void virtio_gpio_register_nodes(void) 149*8fcfc823SAlex Bennée { 150*8fcfc823SAlex Bennée QPCIAddress addr = { 151*8fcfc823SAlex Bennée .devfn = QPCI_DEVFN(4, 0), 152*8fcfc823SAlex Bennée }; 153*8fcfc823SAlex Bennée 154*8fcfc823SAlex Bennée QOSGraphEdgeOptions edge_opts = { }; 155*8fcfc823SAlex Bennée 156*8fcfc823SAlex Bennée /* vhost-user-gpio-device */ 157*8fcfc823SAlex Bennée edge_opts.extra_device_opts = "id=gpio0,chardev=chr-vhost-user-test"; 158*8fcfc823SAlex Bennée qos_node_create_driver("vhost-user-gpio-device", 159*8fcfc823SAlex Bennée virtio_gpio_device_create); 160*8fcfc823SAlex Bennée qos_node_consumes("vhost-user-gpio-device", "virtio-bus", &edge_opts); 161*8fcfc823SAlex Bennée qos_node_produces("vhost-user-gpio-device", "vhost-user-gpio"); 162*8fcfc823SAlex Bennée 163*8fcfc823SAlex Bennée /* virtio-gpio-pci */ 164*8fcfc823SAlex Bennée edge_opts.extra_device_opts = "id=gpio0,addr=04.0,chardev=chr-vhost-user-test"; 165*8fcfc823SAlex Bennée add_qpci_address(&edge_opts, &addr); 166*8fcfc823SAlex Bennée qos_node_create_driver("vhost-user-gpio-pci", virtio_gpio_pci_create); 167*8fcfc823SAlex Bennée qos_node_consumes("vhost-user-gpio-pci", "pci-bus", &edge_opts); 168*8fcfc823SAlex Bennée qos_node_produces("vhost-user-gpio-pci", "vhost-user-gpio"); 169*8fcfc823SAlex Bennée } 170*8fcfc823SAlex Bennée 171*8fcfc823SAlex Bennée libqos_init(virtio_gpio_register_nodes); 172