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 "qemu/error-report.h" 27 #include "qemu/module.h" 28 #include "qapi/error.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 bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); 51 bool vdev_has_iommu; 52 Error *local_err = NULL; 53 54 DPRINTF("%s: plug device.\n", qbus->name); 55 56 if (klass->pre_plugged != NULL) { 57 klass->pre_plugged(qbus->parent, &local_err); 58 if (local_err) { 59 error_propagate(errp, local_err); 60 return; 61 } 62 } 63 64 /* Get the features of the plugged device. */ 65 assert(vdc->get_features != NULL); 66 vdev->host_features = vdc->get_features(vdev, vdev->host_features, 67 &local_err); 68 if (local_err) { 69 error_propagate(errp, local_err); 70 return; 71 } 72 73 if (klass->device_plugged != NULL) { 74 klass->device_plugged(qbus->parent, &local_err); 75 } 76 if (local_err) { 77 error_propagate(errp, local_err); 78 return; 79 } 80 81 vdev->dma_as = &address_space_memory; 82 if (has_iommu) { 83 vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); 84 /* 85 * Present IOMMU_PLATFORM to the driver iff iommu_plattform=on and 86 * device operational. If the driver does not accept IOMMU_PLATFORM 87 * we fail the device. 88 */ 89 virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM); 90 if (klass->get_dma_as) { 91 vdev->dma_as = klass->get_dma_as(qbus->parent); 92 if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) { 93 error_setg(errp, 94 "iommu_platform=true is not supported by the device"); 95 return; 96 } 97 } 98 } 99 } 100 101 /* Reset the virtio_bus */ 102 void virtio_bus_reset(VirtioBusState *bus) 103 { 104 VirtIODevice *vdev = virtio_bus_get_device(bus); 105 106 DPRINTF("%s: reset device.\n", BUS(bus)->name); 107 if (vdev != NULL) { 108 virtio_reset(vdev); 109 } 110 } 111 112 /* A VirtIODevice is being unplugged */ 113 void virtio_bus_device_unplugged(VirtIODevice *vdev) 114 { 115 DeviceState *qdev = DEVICE(vdev); 116 BusState *qbus = BUS(qdev_get_parent_bus(qdev)); 117 VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus); 118 119 DPRINTF("%s: remove device.\n", qbus->name); 120 121 if (vdev != NULL) { 122 if (klass->device_unplugged != NULL) { 123 klass->device_unplugged(qbus->parent); 124 } 125 } 126 } 127 128 /* Get the device id of the plugged device. */ 129 uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus) 130 { 131 VirtIODevice *vdev = virtio_bus_get_device(bus); 132 assert(vdev != NULL); 133 return vdev->device_id; 134 } 135 136 /* Get the config_len field of the plugged device. */ 137 size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus) 138 { 139 VirtIODevice *vdev = virtio_bus_get_device(bus); 140 assert(vdev != NULL); 141 return vdev->config_len; 142 } 143 144 /* Get bad features of the plugged device. */ 145 uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus) 146 { 147 VirtIODevice *vdev = virtio_bus_get_device(bus); 148 VirtioDeviceClass *k; 149 150 assert(vdev != NULL); 151 k = VIRTIO_DEVICE_GET_CLASS(vdev); 152 if (k->bad_features != NULL) { 153 return k->bad_features(vdev); 154 } else { 155 return 0; 156 } 157 } 158 159 /* Get config of the plugged device. */ 160 void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config) 161 { 162 VirtIODevice *vdev = virtio_bus_get_device(bus); 163 VirtioDeviceClass *k; 164 165 assert(vdev != NULL); 166 k = VIRTIO_DEVICE_GET_CLASS(vdev); 167 if (k->get_config != NULL) { 168 k->get_config(vdev, config); 169 } 170 } 171 172 /* Set config of the plugged device. */ 173 void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config) 174 { 175 VirtIODevice *vdev = virtio_bus_get_device(bus); 176 VirtioDeviceClass *k; 177 178 assert(vdev != NULL); 179 k = VIRTIO_DEVICE_GET_CLASS(vdev); 180 if (k->set_config != NULL) { 181 k->set_config(vdev, config); 182 } 183 } 184 185 /* On success, ioeventfd ownership belongs to the caller. */ 186 int virtio_bus_grab_ioeventfd(VirtioBusState *bus) 187 { 188 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 189 190 /* vhost can be used even if ioeventfd=off in the proxy device, 191 * so do not check k->ioeventfd_enabled. 192 */ 193 if (!k->ioeventfd_assign) { 194 return -ENOSYS; 195 } 196 197 if (bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) { 198 virtio_bus_stop_ioeventfd(bus); 199 /* Remember that we need to restart ioeventfd 200 * when ioeventfd_grabbed becomes zero. 201 */ 202 bus->ioeventfd_started = true; 203 } 204 bus->ioeventfd_grabbed++; 205 return 0; 206 } 207 208 void virtio_bus_release_ioeventfd(VirtioBusState *bus) 209 { 210 assert(bus->ioeventfd_grabbed != 0); 211 if (--bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) { 212 /* Force virtio_bus_start_ioeventfd to act. */ 213 bus->ioeventfd_started = false; 214 virtio_bus_start_ioeventfd(bus); 215 } 216 } 217 218 int virtio_bus_start_ioeventfd(VirtioBusState *bus) 219 { 220 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 221 DeviceState *proxy = DEVICE(BUS(bus)->parent); 222 VirtIODevice *vdev = virtio_bus_get_device(bus); 223 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 224 int r; 225 226 if (!k->ioeventfd_assign || !k->ioeventfd_enabled(proxy)) { 227 return -ENOSYS; 228 } 229 if (bus->ioeventfd_started) { 230 return 0; 231 } 232 233 /* Only set our notifier if we have ownership. */ 234 if (!bus->ioeventfd_grabbed) { 235 r = vdc->start_ioeventfd(vdev); 236 if (r < 0) { 237 error_report("%s: failed. Fallback to userspace (slower).", __func__); 238 return r; 239 } 240 } 241 bus->ioeventfd_started = true; 242 return 0; 243 } 244 245 void virtio_bus_stop_ioeventfd(VirtioBusState *bus) 246 { 247 VirtIODevice *vdev; 248 VirtioDeviceClass *vdc; 249 250 if (!bus->ioeventfd_started) { 251 return; 252 } 253 254 /* Only remove our notifier if we have ownership. */ 255 if (!bus->ioeventfd_grabbed) { 256 vdev = virtio_bus_get_device(bus); 257 vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 258 vdc->stop_ioeventfd(vdev); 259 } 260 bus->ioeventfd_started = false; 261 } 262 263 bool virtio_bus_ioeventfd_enabled(VirtioBusState *bus) 264 { 265 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 266 DeviceState *proxy = DEVICE(BUS(bus)->parent); 267 268 return k->ioeventfd_assign && k->ioeventfd_enabled(proxy); 269 } 270 271 /* 272 * This function switches ioeventfd on/off in the device. 273 * The caller must set or clear the handlers for the EventNotifier. 274 */ 275 int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) 276 { 277 VirtIODevice *vdev = virtio_bus_get_device(bus); 278 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); 279 DeviceState *proxy = DEVICE(BUS(bus)->parent); 280 VirtQueue *vq = virtio_get_queue(vdev, n); 281 EventNotifier *notifier = virtio_queue_get_host_notifier(vq); 282 int r = 0; 283 284 if (!k->ioeventfd_assign) { 285 return -ENOSYS; 286 } 287 288 if (assign) { 289 r = event_notifier_init(notifier, 1); 290 if (r < 0) { 291 error_report("%s: unable to init event notifier: %s (%d)", 292 __func__, strerror(-r), r); 293 return r; 294 } 295 r = k->ioeventfd_assign(proxy, notifier, n, true); 296 if (r < 0) { 297 error_report("%s: unable to assign ioeventfd: %d", __func__, r); 298 virtio_bus_cleanup_host_notifier(bus, n); 299 } 300 } else { 301 k->ioeventfd_assign(proxy, notifier, n, false); 302 } 303 304 if (r == 0) { 305 virtio_queue_set_host_notifier_enabled(vq, assign); 306 } 307 308 return r; 309 } 310 311 void virtio_bus_cleanup_host_notifier(VirtioBusState *bus, int n) 312 { 313 VirtIODevice *vdev = virtio_bus_get_device(bus); 314 VirtQueue *vq = virtio_get_queue(vdev, n); 315 EventNotifier *notifier = virtio_queue_get_host_notifier(vq); 316 317 /* Test and clear notifier after disabling event, 318 * in case poll callback didn't have time to run. 319 */ 320 virtio_queue_host_notifier_read(notifier); 321 event_notifier_cleanup(notifier); 322 } 323 324 static char *virtio_bus_get_dev_path(DeviceState *dev) 325 { 326 BusState *bus = qdev_get_parent_bus(dev); 327 DeviceState *proxy = DEVICE(bus->parent); 328 return qdev_get_dev_path(proxy); 329 } 330 331 static char *virtio_bus_get_fw_dev_path(DeviceState *dev) 332 { 333 return NULL; 334 } 335 336 bool virtio_bus_device_iommu_enabled(VirtIODevice *vdev) 337 { 338 DeviceState *qdev = DEVICE(vdev); 339 BusState *qbus = BUS(qdev_get_parent_bus(qdev)); 340 VirtioBusState *bus = VIRTIO_BUS(qbus); 341 VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); 342 343 if (!klass->iommu_enabled) { 344 return false; 345 } 346 347 return klass->iommu_enabled(qbus->parent); 348 } 349 350 static void virtio_bus_class_init(ObjectClass *klass, void *data) 351 { 352 BusClass *bus_class = BUS_CLASS(klass); 353 bus_class->get_dev_path = virtio_bus_get_dev_path; 354 bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path; 355 } 356 357 static const TypeInfo virtio_bus_info = { 358 .name = TYPE_VIRTIO_BUS, 359 .parent = TYPE_BUS, 360 .instance_size = sizeof(VirtioBusState), 361 .abstract = true, 362 .class_size = sizeof(VirtioBusClass), 363 .class_init = virtio_bus_class_init 364 }; 365 366 static void virtio_register_types(void) 367 { 368 type_register_static(&virtio_bus_info); 369 } 370 371 type_init(virtio_register_types) 372