1 /* 2 * VirtioBus 3 * 4 * Copyright (C) 2012 : GreenSocs Ltd 5 * http://www.greensocs.com/ , email: info@greensocs.com 6 * 7 * Developed by : 8 * Frederic Konrad <fred.konrad@greensocs.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation, either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with this program; if not, see <http://www.gnu.org/licenses/>. 22 * 23 */ 24 25 #include "qemu/osdep.h" 26 #include "hw/hw.h" 27 #include "qemu/error-report.h" 28 #include "hw/qdev.h" 29 #include "hw/virtio/virtio-bus.h" 30 #include "hw/virtio/virtio.h" 31 #include "exec/address-spaces.h" 32 33 /* #define DEBUG_VIRTIO_BUS */ 34 35 #ifdef DEBUG_VIRTIO_BUS 36 #define DPRINTF(fmt, ...) \ 37 do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0) 38 #else 39 #define DPRINTF(fmt, ...) do { } while (0) 40 #endif 41 42 /* A VirtIODevice is being plugged */ 43 void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) 44 { 45 DeviceState *qdev = DEVICE(vdev); 46 BusState *qbus = BUS(qdev_get_parent_bus(qdev)); 47 VirtioBusState *bus = VIRTIO_BUS(qbus); 48 VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); 49 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 50 51 DPRINTF("%s: plug device.\n", qbus->name); 52 53 if (klass->pre_plugged != NULL) { 54 klass->pre_plugged(qbus->parent, errp); 55 } 56 57 /* Get the features of the plugged device. */ 58 assert(vdc->get_features != NULL); 59 vdev->host_features = vdc->get_features(vdev, vdev->host_features, 60 errp); 61 62 if (klass->device_plugged != NULL) { 63 klass->device_plugged(qbus->parent, errp); 64 } 65 66 if (klass->get_dma_as != NULL && 67 virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { 68 vdev->dma_as = klass->get_dma_as(qbus->parent); 69 } else { 70 vdev->dma_as = &address_space_memory; 71 } 72 } 73 74 /* Reset the virtio_bus */ 75 void virtio_bus_reset(VirtioBusState *bus) 76 { 77 VirtIODevice *vdev = virtio_bus_get_device(bus); 78 79 DPRINTF("%s: reset device.\n", BUS(bus)->name); 80 if (vdev != NULL) { 81 virtio_reset(vdev); 82 } 83 } 84 85 /* A VirtIODevice is being unplugged */ 86 void virtio_bus_device_unplugged(VirtIODevice *vdev) 87 { 88 DeviceState *qdev = DEVICE(vdev); 89 BusState *qbus = BUS(qdev_get_parent_bus(qdev)); 90 VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus); 91 92 DPRINTF("%s: remove device.\n", qbus->name); 93 94 if (vdev != NULL) { 95 if (klass->device_unplugged != NULL) { 96 klass->device_unplugged(qbus->parent); 97 } 98 } 99 } 100 101 /* Get the device id of the plugged device. */ 102 uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus) 103 { 104 VirtIODevice *vdev = virtio_bus_get_device(bus); 105 assert(vdev != NULL); 106 return vdev->device_id; 107 } 108 109 /* Get the config_len field of the plugged device. */ 110 size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus) 111 { 112 VirtIODevice *vdev = virtio_bus_get_device(bus); 113 assert(vdev != NULL); 114 return vdev->config_len; 115 } 116 117 /* Get bad features of the plugged device. */ 118 uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus) 119 { 120 VirtIODevice *vdev = virtio_bus_get_device(bus); 121 VirtioDeviceClass *k; 122 123 assert(vdev != NULL); 124 k = VIRTIO_DEVICE_GET_CLASS(vdev); 125 if (k->bad_features != NULL) { 126 return k->bad_features(vdev); 127 } else { 128 return 0; 129 } 130 } 131 132 /* Get config of the plugged device. */ 133 void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config) 134 { 135 VirtIODevice *vdev = virtio_bus_get_device(bus); 136 VirtioDeviceClass *k; 137 138 assert(vdev != NULL); 139 k = VIRTIO_DEVICE_GET_CLASS(vdev); 140 if (k->get_config != NULL) { 141 k->get_config(vdev, config); 142 } 143 } 144 145 /* Set config of the plugged device. */ 146 void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config) 147 { 148 VirtIODevice *vdev = virtio_bus_get_device(bus); 149 VirtioDeviceClass *k; 150 151 assert(vdev != NULL); 152 k = VIRTIO_DEVICE_GET_CLASS(vdev); 153 if (k->set_config != NULL) { 154 k->set_config(vdev, config); 155 } 156 } 157 158 /* On success, ioeventfd ownership belongs to the caller. */ 159 int virtio_bus_grab_ioeventfd(VirtioBusState *bus) 160 { 161 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 162 163 /* vhost can be used even if ioeventfd=off in the proxy device, 164 * so do not check k->ioeventfd_enabled. 165 */ 166 if (!k->ioeventfd_assign) { 167 return -ENOSYS; 168 } 169 170 if (bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) { 171 virtio_bus_stop_ioeventfd(bus); 172 /* Remember that we need to restart ioeventfd 173 * when ioeventfd_grabbed becomes zero. 174 */ 175 bus->ioeventfd_started = true; 176 } 177 bus->ioeventfd_grabbed++; 178 return 0; 179 } 180 181 void virtio_bus_release_ioeventfd(VirtioBusState *bus) 182 { 183 assert(bus->ioeventfd_grabbed != 0); 184 if (--bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) { 185 /* Force virtio_bus_start_ioeventfd to act. */ 186 bus->ioeventfd_started = false; 187 virtio_bus_start_ioeventfd(bus); 188 } 189 } 190 191 int virtio_bus_start_ioeventfd(VirtioBusState *bus) 192 { 193 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 194 DeviceState *proxy = DEVICE(BUS(bus)->parent); 195 VirtIODevice *vdev = virtio_bus_get_device(bus); 196 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 197 int r; 198 199 if (!k->ioeventfd_assign || !k->ioeventfd_enabled(proxy)) { 200 return -ENOSYS; 201 } 202 if (bus->ioeventfd_started) { 203 return 0; 204 } 205 206 /* Only set our notifier if we have ownership. */ 207 if (!bus->ioeventfd_grabbed) { 208 r = vdc->start_ioeventfd(vdev); 209 if (r < 0) { 210 error_report("%s: failed. Fallback to userspace (slower).", __func__); 211 return r; 212 } 213 } 214 bus->ioeventfd_started = true; 215 return 0; 216 } 217 218 void virtio_bus_stop_ioeventfd(VirtioBusState *bus) 219 { 220 VirtIODevice *vdev; 221 VirtioDeviceClass *vdc; 222 223 if (!bus->ioeventfd_started) { 224 return; 225 } 226 227 /* Only remove our notifier if we have ownership. */ 228 if (!bus->ioeventfd_grabbed) { 229 vdev = virtio_bus_get_device(bus); 230 vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 231 vdc->stop_ioeventfd(vdev); 232 } 233 bus->ioeventfd_started = false; 234 } 235 236 bool virtio_bus_ioeventfd_enabled(VirtioBusState *bus) 237 { 238 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 239 DeviceState *proxy = DEVICE(BUS(bus)->parent); 240 241 return k->ioeventfd_assign && k->ioeventfd_enabled(proxy); 242 } 243 244 /* 245 * This function switches ioeventfd on/off in the device. 246 * The caller must set or clear the handlers for the EventNotifier. 247 */ 248 int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) 249 { 250 VirtIODevice *vdev = virtio_bus_get_device(bus); 251 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 252 DeviceState *proxy = DEVICE(BUS(bus)->parent); 253 VirtQueue *vq = virtio_get_queue(vdev, n); 254 EventNotifier *notifier = virtio_queue_get_host_notifier(vq); 255 int r = 0; 256 257 if (!k->ioeventfd_assign) { 258 return -ENOSYS; 259 } 260 261 if (assign) { 262 r = event_notifier_init(notifier, 1); 263 if (r < 0) { 264 error_report("%s: unable to init event notifier: %s (%d)", 265 __func__, strerror(-r), r); 266 return r; 267 } 268 r = k->ioeventfd_assign(proxy, notifier, n, true); 269 if (r < 0) { 270 error_report("%s: unable to assign ioeventfd: %d", __func__, r); 271 goto cleanup_event_notifier; 272 } 273 return 0; 274 } else { 275 k->ioeventfd_assign(proxy, notifier, n, false); 276 } 277 278 cleanup_event_notifier: 279 /* Test and clear notifier after disabling event, 280 * in case poll callback didn't have time to run. 281 */ 282 virtio_queue_host_notifier_read(notifier); 283 event_notifier_cleanup(notifier); 284 return r; 285 } 286 287 static char *virtio_bus_get_dev_path(DeviceState *dev) 288 { 289 BusState *bus = qdev_get_parent_bus(dev); 290 DeviceState *proxy = DEVICE(bus->parent); 291 return qdev_get_dev_path(proxy); 292 } 293 294 static char *virtio_bus_get_fw_dev_path(DeviceState *dev) 295 { 296 return NULL; 297 } 298 299 static void virtio_bus_class_init(ObjectClass *klass, void *data) 300 { 301 BusClass *bus_class = BUS_CLASS(klass); 302 bus_class->get_dev_path = virtio_bus_get_dev_path; 303 bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path; 304 } 305 306 static const TypeInfo virtio_bus_info = { 307 .name = TYPE_VIRTIO_BUS, 308 .parent = TYPE_BUS, 309 .instance_size = sizeof(VirtioBusState), 310 .abstract = true, 311 .class_size = sizeof(VirtioBusClass), 312 .class_init = virtio_bus_class_init 313 }; 314 315 static void virtio_register_types(void) 316 { 317 type_register_static(&virtio_bus_info); 318 } 319 320 type_init(virtio_register_types) 321