1 /* 2 * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <new> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <bus/PCI.h> 12 #include <virtio.h> 13 14 #include "virtio_pci.h" 15 16 17 //#define TRACE_VIRTIO 18 #ifdef TRACE_VIRTIO 19 # define TRACE(x...) dprintf("\33[33mvirtio_pci:\33[0m " x) 20 #else 21 # define TRACE(x...) ; 22 #endif 23 #define TRACE_ALWAYS(x...) dprintf("\33[33mvirtio_pci:\33[0m " x) 24 #define ERROR(x...) dprintf("\33[33mvirtio_pci:\33[0m " x) 25 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 26 27 28 #define VIRTIO_PCI_DEVICE_MODULE_NAME "busses/virtio/virtio_pci/driver_v1" 29 #define VIRTIO_PCI_SIM_MODULE_NAME "busses/virtio/virtio_pci/device/v1" 30 31 #define VIRTIO_PCI_CONTROLLER_TYPE_NAME "virtio pci controller" 32 33 typedef enum { 34 VIRTIO_IRQ_LEGACY, 35 VIRTIO_IRQ_MSI, 36 VIRTIO_IRQ_MSI_X_SHARED, 37 VIRTIO_IRQ_MSI_X, 38 } virtio_irq_type; 39 40 typedef struct { 41 virtio_sim sim; 42 uint16 queue; 43 } virtio_pci_queue_cookie; 44 45 typedef struct { 46 pci_device_module_info* pci; 47 pci_device* device; 48 addr_t base_addr; 49 uint8 irq; 50 virtio_irq_type irq_type; 51 virtio_sim sim; 52 uint16 queue_count; 53 54 device_node* node; 55 pci_info info; 56 57 virtio_pci_queue_cookie *cookies; 58 } virtio_pci_sim_info; 59 60 61 device_manager_info* gDeviceManager; 62 virtio_for_controller_interface* gVirtio; 63 64 65 int32 66 virtio_pci_interrupt(void *data) 67 { 68 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data; 69 uint8 isr = bus->pci->read_io_8(bus->device, 70 bus->base_addr + VIRTIO_PCI_ISR); 71 if (isr == 0) 72 return B_UNHANDLED_INTERRUPT; 73 74 if (isr & VIRTIO_PCI_ISR_CONFIG) 75 gVirtio->config_interrupt_handler(bus->sim); 76 77 if (isr & VIRTIO_PCI_ISR_INTR) 78 gVirtio->queue_interrupt_handler(bus->sim, INT16_MAX); 79 80 return B_HANDLED_INTERRUPT; 81 } 82 83 84 int32 85 virtio_pci_config_interrupt(void *data) 86 { 87 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data; 88 gVirtio->config_interrupt_handler(bus->sim); 89 90 return B_HANDLED_INTERRUPT; 91 } 92 93 94 int32 95 virtio_pci_queue_interrupt(void *data) 96 { 97 virtio_pci_queue_cookie* cookie = (virtio_pci_queue_cookie*)data; 98 gVirtio->queue_interrupt_handler(cookie->sim, cookie->queue); 99 100 return B_HANDLED_INTERRUPT; 101 } 102 103 104 status_t 105 virtio_pci_setup_msix_interrupts(virtio_pci_sim_info* bus) 106 { 107 CALLED(); 108 uint8 irq = 0; // first irq slot 109 bus->pci->write_io_16(bus->device, bus->base_addr 110 + VIRTIO_MSI_CONFIG_VECTOR, irq); 111 if (bus->pci->read_io_16(bus->device, bus->base_addr 112 + VIRTIO_MSI_CONFIG_VECTOR) == VIRTIO_MSI_NO_VECTOR) { 113 ERROR("msix config vector incorrect\n"); 114 return B_BAD_VALUE; 115 } 116 if (bus->irq_type == VIRTIO_IRQ_MSI_X) 117 irq++; 118 119 for (uint16 queue = 0; queue < bus->queue_count; queue++) { 120 bus->pci->write_io_16(bus->device, bus->base_addr 121 + VIRTIO_PCI_QUEUE_SEL, queue); 122 bus->pci->write_io_16(bus->device, bus->base_addr 123 + VIRTIO_MSI_QUEUE_VECTOR, irq); 124 125 if (bus->pci->read_io_16(bus->device, bus->base_addr 126 + VIRTIO_MSI_QUEUE_VECTOR) == VIRTIO_MSI_NO_VECTOR) { 127 ERROR("msix queue vector incorrect\n"); 128 return B_BAD_VALUE; 129 } 130 131 if (bus->irq_type == VIRTIO_IRQ_MSI_X) 132 irq++; 133 } 134 135 return B_OK; 136 } 137 138 139 static void 140 set_sim(void* cookie, virtio_sim sim) 141 { 142 CALLED(); 143 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 144 bus->sim = sim; 145 } 146 147 148 static status_t 149 read_host_features(void* cookie, uint32 *features) 150 { 151 CALLED(); 152 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 153 154 TRACE("read_host_features() %p node %p pci %p device %p\n", bus, 155 bus->node, bus->pci, bus->device); 156 157 *features = bus->pci->read_io_32(bus->device, 158 bus->base_addr + VIRTIO_PCI_HOST_FEATURES); 159 return B_OK; 160 } 161 162 163 static status_t 164 write_guest_features(void* cookie, uint32 features) 165 { 166 CALLED(); 167 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 168 bus->pci->write_io_32(bus->device, bus->base_addr 169 + VIRTIO_PCI_GUEST_FEATURES, features); 170 return B_OK; 171 } 172 173 174 uint8 175 get_status(void* cookie) 176 { 177 CALLED(); 178 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 179 return bus->pci->read_io_8(bus->device, bus->base_addr 180 + VIRTIO_PCI_STATUS); 181 } 182 183 184 void 185 set_status(void* cookie, uint8 status) 186 { 187 CALLED(); 188 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 189 bus->pci->write_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS, 190 status); 191 } 192 193 194 status_t 195 read_device_config(void* cookie, uint8 _offset, void* _buffer, 196 size_t bufferSize) 197 { 198 CALLED(); 199 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 200 201 addr_t offset = bus->base_addr + VIRTIO_PCI_CONFIG(bus) + _offset; 202 uint8* buffer = (uint8*)_buffer; 203 while (bufferSize > 0) { 204 uint8 size = 4; 205 if (bufferSize == 1) { 206 size = 1; 207 *buffer = bus->pci->read_io_8(bus->device, 208 offset); 209 } else if (bufferSize <= 3) { 210 size = 2; 211 *(uint16*)buffer = bus->pci->read_io_16(bus->device, 212 offset); 213 } else { 214 *(uint32*)buffer = bus->pci->read_io_32(bus->device, 215 offset); 216 } 217 buffer += size; 218 bufferSize -= size; 219 offset += size; 220 } 221 222 return B_OK; 223 } 224 225 226 status_t 227 write_device_config(void* cookie, uint8 _offset, const void* _buffer, 228 size_t bufferSize) 229 { 230 CALLED(); 231 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 232 233 addr_t offset = bus->base_addr + VIRTIO_PCI_CONFIG(bus) + _offset; 234 const uint8* buffer = (const uint8*)_buffer; 235 while (bufferSize > 0) { 236 uint8 size = 4; 237 if (bufferSize == 1) { 238 size = 1; 239 bus->pci->write_io_8(bus->device, 240 offset, *buffer); 241 } else if (bufferSize <= 3) { 242 size = 2; 243 bus->pci->write_io_16(bus->device, 244 offset, *(const uint16*)buffer); 245 } else { 246 bus->pci->write_io_32(bus->device, 247 offset, *(const uint32*)buffer); 248 } 249 buffer += size; 250 bufferSize -= size; 251 offset += size; 252 } 253 return B_OK; 254 } 255 256 257 uint16 258 get_queue_ring_size(void* cookie, uint16 queue) 259 { 260 CALLED(); 261 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 262 bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL, 263 queue); 264 return bus->pci->read_io_16(bus->device, bus->base_addr 265 + VIRTIO_PCI_QUEUE_NUM); 266 } 267 268 269 status_t 270 setup_queue(void* cookie, uint16 queue, phys_addr_t phy) 271 { 272 CALLED(); 273 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 274 bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL, 275 queue); 276 bus->pci->write_io_32(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_PFN, 277 (uint32)phy >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); 278 return B_OK; 279 } 280 281 282 status_t 283 setup_interrupt(void* cookie, uint16 queueCount) 284 { 285 CALLED(); 286 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 287 pci_info *pciInfo = &bus->info; 288 289 bus->queue_count = queueCount; 290 291 // try MSI-X 292 uint8 msixCount = bus->pci->get_msix_count(bus->device); 293 if (msixCount >= 1) { 294 if (msixCount >= (queueCount + 1)) { 295 uint8 vector; 296 bus->cookies = new(std::nothrow) 297 virtio_pci_queue_cookie[queueCount]; 298 if (bus->cookies != NULL 299 && bus->pci->configure_msix(bus->device, queueCount + 1, 300 &vector) == B_OK 301 && bus->pci->enable_msix(bus->device) == B_OK) { 302 TRACE_ALWAYS("using MSI-X count %u starting at %d\n", 303 queueCount + 1, vector); 304 bus->irq = vector; 305 bus->irq_type = VIRTIO_IRQ_MSI_X; 306 } else { 307 ERROR("couldn't use MSI-X\n"); 308 } 309 } else { 310 uint8 vector; 311 if (bus->pci->configure_msix(bus->device, queueCount + 1, &vector) == B_OK 312 && bus->pci->enable_msix(bus->device) == B_OK) { 313 TRACE_ALWAYS("using MSI-X vector shared %u\n", 1); 314 bus->irq = vector; 315 bus->irq_type = VIRTIO_IRQ_MSI_X_SHARED; 316 } else { 317 ERROR("couldn't use MSI-X SHARED\n"); 318 } 319 } 320 } else if (bus->pci->get_msi_count(bus->device) >= 1) { 321 // try MSI 322 uint8 vector; 323 if (bus->pci->configure_msi(bus->device, 1, &vector) == B_OK 324 && bus->pci->enable_msi(bus->device) == B_OK) { 325 TRACE_ALWAYS("using MSI vector %u\n", vector); 326 bus->irq = vector; 327 bus->irq_type = VIRTIO_IRQ_MSI; 328 } else { 329 ERROR("couldn't use MSI\n"); 330 } 331 } 332 333 if (bus->irq_type == VIRTIO_IRQ_LEGACY) { 334 bus->irq = pciInfo->u.h0.interrupt_line; 335 TRACE_ALWAYS("using legacy interrupt %u\n", bus->irq); 336 } 337 if (bus->irq == 0 || bus->irq == 0xff) { 338 ERROR("PCI IRQ not assigned\n"); 339 delete bus; 340 return B_ERROR; 341 } 342 343 if (bus->irq_type == VIRTIO_IRQ_MSI_X) { 344 status_t status = install_io_interrupt_handler(bus->irq, 345 virtio_pci_config_interrupt, bus, 0); 346 if (status != B_OK) { 347 ERROR("can't install interrupt handler\n"); 348 return status; 349 } 350 int32 irq = bus->irq + 1; 351 for (int32 queue = 0; queue < queueCount; queue++, irq++) { 352 bus->cookies[queue].sim = bus->sim; 353 bus->cookies[queue].queue = queue; 354 status_t status = install_io_interrupt_handler(irq, 355 virtio_pci_queue_interrupt, &bus->cookies[queue], 0); 356 if (status != B_OK) { 357 ERROR("can't install interrupt handler\n"); 358 return status; 359 } 360 } 361 TRACE("setup_interrupt() installed MSI-X interrupt handlers\n"); 362 virtio_pci_setup_msix_interrupts(bus); 363 } else { 364 // setup interrupt handler 365 status_t status = install_io_interrupt_handler(bus->irq, 366 virtio_pci_interrupt, bus, 0); 367 if (status != B_OK) { 368 ERROR("can't install interrupt handler\n"); 369 return status; 370 } 371 TRACE("setup_interrupt() installed legacy interrupt handler\n"); 372 } 373 374 return B_OK; 375 } 376 377 378 status_t 379 free_interrupt(void* cookie) 380 { 381 CALLED(); 382 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 383 384 if (bus->irq_type == VIRTIO_IRQ_MSI_X) { 385 remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt, 386 bus); 387 int32 irq = bus->irq + 1; 388 for (int32 queue = 0; queue < bus->queue_count; queue++, irq++) { 389 remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt, 390 &bus->cookies[queue]); 391 } 392 delete[] bus->cookies; 393 394 } else 395 remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus); 396 397 if (bus->irq_type != VIRTIO_IRQ_LEGACY) { 398 bus->pci->disable_msi(bus->device); 399 bus->pci->unconfigure_msi(bus->device); 400 } 401 return B_OK; 402 } 403 404 405 void 406 notify_queue(void* cookie, uint16 queue) 407 { 408 CALLED(); 409 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie; 410 bus->pci->write_io_16(bus->device, bus->base_addr 411 + VIRTIO_PCI_QUEUE_NOTIFY, queue); 412 } 413 414 415 // #pragma mark - 416 417 418 static status_t 419 init_bus(device_node* node, void** bus_cookie) 420 { 421 CALLED(); 422 status_t status = B_OK; 423 424 virtio_pci_sim_info* bus = new(std::nothrow) virtio_pci_sim_info; 425 if (bus == NULL) { 426 return B_NO_MEMORY; 427 } 428 429 pci_device_module_info* pci; 430 pci_device* device; 431 { 432 device_node* parent = gDeviceManager->get_parent_node(node); 433 device_node* pciParent = gDeviceManager->get_parent_node(parent); 434 gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci, 435 (void**)&device); 436 gDeviceManager->put_node(pciParent); 437 gDeviceManager->put_node(parent); 438 } 439 440 bus->node = node; 441 bus->pci = pci; 442 bus->device = device; 443 bus->cookies = NULL; 444 bus->irq_type = VIRTIO_IRQ_LEGACY; 445 446 pci_info *pciInfo = &bus->info; 447 pci->get_pci_info(device, pciInfo); 448 449 // legacy interrupt 450 bus->base_addr = pciInfo->u.h0.base_registers[0]; 451 452 // enable bus master and io 453 uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2); 454 pcicmd &= ~(PCI_command_memory | PCI_command_int_disable); 455 pcicmd |= PCI_command_master | PCI_command_io; 456 pci->write_pci_config(device, PCI_command, 2, pcicmd); 457 458 set_status(bus, VIRTIO_CONFIG_STATUS_RESET); 459 set_status(bus, VIRTIO_CONFIG_STATUS_ACK); 460 461 TRACE("init_bus() %p node %p pci %p device %p\n", bus, node, 462 bus->pci, bus->device); 463 464 *bus_cookie = bus; 465 return status; 466 } 467 468 469 static void 470 uninit_bus(void* bus_cookie) 471 { 472 virtio_pci_sim_info* bus = (virtio_pci_sim_info*)bus_cookie; 473 if (bus->irq_type != VIRTIO_IRQ_LEGACY) { 474 if (bus->irq_type == VIRTIO_IRQ_MSI) { 475 remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus); 476 } else { 477 int32 irq = bus->irq + 1; 478 for (uint16 queue = 0; queue < bus->queue_count; queue++, irq++) { 479 remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt, 480 &bus->cookies[queue]); 481 } 482 remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt, 483 bus); 484 } 485 486 bus->pci->disable_msi(bus->device); 487 bus->pci->unconfigure_msi(bus->device); 488 } else 489 remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus); 490 491 delete[] bus->cookies; 492 delete bus; 493 } 494 495 496 static void 497 bus_removed(void* bus_cookie) 498 { 499 return; 500 } 501 502 503 // #pragma mark - 504 505 506 static status_t 507 register_child_devices(void* cookie) 508 { 509 CALLED(); 510 device_node* node = (device_node*)cookie; 511 device_node* parent = gDeviceManager->get_parent_node(node); 512 pci_device_module_info* pci; 513 pci_device* device; 514 gDeviceManager->get_driver(parent, (driver_module_info**)&pci, 515 (void**)&device); 516 517 uint16 pciSubDeviceId = pci->read_pci_config(device, PCI_subsystem_id, 518 2); 519 520 char prettyName[25]; 521 sprintf(prettyName, "Virtio Device %" B_PRIu16, pciSubDeviceId); 522 523 device_attr attrs[] = { 524 // properties of this controller for virtio bus manager 525 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 526 { .string = prettyName }}, 527 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, 528 { .string = VIRTIO_FOR_CONTROLLER_MODULE_NAME }}, 529 530 // private data to identify the device 531 { VIRTIO_DEVICE_TYPE_ITEM, B_UINT16_TYPE, 532 { .ui16 = pciSubDeviceId }}, 533 { VIRTIO_VRING_ALIGNMENT_ITEM, B_UINT16_TYPE, 534 { .ui16 = VIRTIO_PCI_VRING_ALIGN }}, 535 { NULL } 536 }; 537 538 return gDeviceManager->register_node(node, VIRTIO_PCI_SIM_MODULE_NAME, 539 attrs, NULL, &node); 540 } 541 542 543 static status_t 544 init_device(device_node* node, void** device_cookie) 545 { 546 CALLED(); 547 *device_cookie = node; 548 return B_OK; 549 } 550 551 552 static status_t 553 register_device(device_node* parent) 554 { 555 device_attr attrs[] = { 556 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Virtio PCI"}}, 557 {} 558 }; 559 560 return gDeviceManager->register_node(parent, VIRTIO_PCI_DEVICE_MODULE_NAME, 561 attrs, NULL, NULL); 562 } 563 564 565 static float 566 supports_device(device_node* parent) 567 { 568 CALLED(); 569 const char* bus; 570 uint16 vendorID, deviceID; 571 572 // make sure parent is a PCI Virtio device node 573 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK 574 || gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, 575 &vendorID, false) < B_OK 576 || gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID, 577 false) < B_OK) { 578 return -1; 579 } 580 581 if (strcmp(bus, "pci") != 0) 582 return 0.0f; 583 584 if (vendorID == VIRTIO_PCI_VENDORID) { 585 if (deviceID < VIRTIO_PCI_DEVICEID_MIN 586 || deviceID > VIRTIO_PCI_DEVICEID_MAX) { 587 return 0.0f; 588 } 589 590 pci_device_module_info* pci; 591 pci_device* device; 592 gDeviceManager->get_driver(parent, (driver_module_info**)&pci, 593 (void**)&device); 594 uint8 pciSubDeviceId = pci->read_pci_config(device, PCI_revision, 595 1); 596 if (pciSubDeviceId != VIRTIO_PCI_ABI_VERSION) 597 return 0.0f; 598 599 TRACE("Virtio device found! vendor 0x%04x, device 0x%04x\n", vendorID, 600 deviceID); 601 return 0.8f; 602 } 603 604 return 0.0f; 605 } 606 607 608 // #pragma mark - 609 610 611 module_dependency module_dependencies[] = { 612 { VIRTIO_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gVirtio }, 613 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 614 {} 615 }; 616 617 618 static virtio_sim_interface gVirtioPCIDeviceModule = { 619 { 620 { 621 VIRTIO_PCI_SIM_MODULE_NAME, 622 0, 623 NULL 624 }, 625 626 NULL, // supports device 627 NULL, // register device 628 init_bus, 629 uninit_bus, 630 NULL, // register child devices 631 NULL, // rescan 632 bus_removed, 633 }, 634 635 set_sim, 636 read_host_features, 637 write_guest_features, 638 get_status, 639 set_status, 640 read_device_config, 641 write_device_config, 642 get_queue_ring_size, 643 setup_queue, 644 setup_interrupt, 645 free_interrupt, 646 notify_queue 647 }; 648 649 650 static driver_module_info sVirtioDevice = { 651 { 652 VIRTIO_PCI_DEVICE_MODULE_NAME, 653 0, 654 NULL 655 }, 656 657 supports_device, 658 register_device, 659 init_device, 660 NULL, // uninit 661 register_child_devices, 662 NULL, // rescan 663 NULL, // device removed 664 }; 665 666 module_info* modules[] = { 667 (module_info* )&sVirtioDevice, 668 (module_info* )&gVirtioPCIDeviceModule, 669 NULL 670 }; 671