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