diff --git a/Kernel/VirtIO/VirtIO.cpp b/Kernel/VirtIO/VirtIO.cpp index b2283496fb..ee2f01833f 100644 --- a/Kernel/VirtIO/VirtIO.cpp +++ b/Kernel/VirtIO/VirtIO.cpp @@ -37,10 +37,14 @@ void VirtIO::detect() if (id.vendor_id != VIRTIO_PCI_VENDOR_ID) return; switch (id.device_id) { - case VIRTIO_CONSOLE_PCI_DEVICE_ID: + case VIRTIO_CONSOLE_PCI_DEVICE_ID: { [[maybe_unused]] auto& unused = adopt(*new VirtIOConsole(address)).leak_ref(); break; } + default: + dbgln_if(VIRTIO_DEBUG, "VirtIO: Unknown VirtIO device with ID: {}", id.device_id); + break; + } }); } @@ -52,6 +56,8 @@ VirtIODevice::VirtIODevice(PCI::Address address, String class_name) dbgln("{}: Found @ {}", m_class_name, pci_address()); enable_bus_mastering(pci_address()); + PCI::enable_interrupt_line(pci_address()); + enable_irq(); reset_device(); set_status_bit(DEVICE_STATUS_ACKNOWLEDGE); @@ -249,7 +255,6 @@ void VirtIODevice::reset_device() while (config_read8(*m_common_cfg, COMMON_CFG_DEVICE_STATUS) != 0) { // TODO: delay a bit? } - return; } bool VirtIODevice::setup_queue(u16 queue_index) @@ -274,12 +279,24 @@ bool VirtIODevice::setup_queue(u16 queue_index) config_write64(*m_common_cfg, COMMON_CFG_QUEUE_DRIVER, queue->driver_area().get()); config_write64(*m_common_cfg, COMMON_CFG_QUEUE_DEVICE, queue->device_area().get()); - dbgln_if(VIRTIO_DEBUG, "{}: Queue[{}] size: {}", m_class_name, queue_index, queue_size); + dbgln_if(VIRTIO_DEBUG, "{}: Queue[{}] configured with size: {}", m_class_name, queue_index, queue_size); m_queues.append(move(queue)); return true; } +bool VirtIODevice::activate_queue(u16 queue_index) +{ + if (!m_common_cfg) + return false; + + config_write16(*m_common_cfg, COMMON_CFG_QUEUE_SELECT, queue_index); + config_write16(*m_common_cfg, COMMON_CFG_QUEUE_ENABLE, true); + + dbgln_if(VIRTIO_DEBUG, "{}: Queue[{}] activated", m_class_name, queue_index); + return true; +} + void VirtIODevice::set_requested_queue_count(u16 count) { m_queue_count = count; @@ -302,6 +319,10 @@ bool VirtIODevice::setup_queues() if (!setup_queue(i)) return false; } + for (u16 i = 0; i < m_queue_count; i++) { // Queues can only be activated *after* all others queues were also configured + if (!activate_queue(i)) + return false; + } return true; } @@ -335,7 +356,7 @@ u8 VirtIODevice::isr_status() void VirtIODevice::handle_irq(const RegisterState&) { u8 isr_type = isr_status(); - dbgln_if(VIRTIO_DEBUG, "VirtIODevice: Handling interrupt with status: {}", isr_type); + dbgln_if(VIRTIO_DEBUG, "{}: Handling interrupt with status: {}", m_class_name, isr_type); if (isr_type & DEVICE_CONFIG_INTERRUPT) { if (!handle_device_config_change()) { set_status_bit(DEVICE_STATUS_FAILED); diff --git a/Kernel/VirtIO/VirtIO.h b/Kernel/VirtIO/VirtIO.h index ac20a7735e..e5c98db1f1 100644 --- a/Kernel/VirtIO/VirtIO.h +++ b/Kernel/VirtIO/VirtIO.h @@ -231,6 +231,7 @@ private: bool setup_queues(); bool setup_queue(u16 queue_index); + bool activate_queue(u16 queue_index); void notify_queue(u16 queue_index); void reset_device(); diff --git a/Kernel/VirtIO/VirtIOQueue.cpp b/Kernel/VirtIO/VirtIOQueue.cpp index 19c9c76053..1afbbca066 100644 --- a/Kernel/VirtIO/VirtIOQueue.cpp +++ b/Kernel/VirtIO/VirtIOQueue.cpp @@ -77,10 +77,11 @@ bool VirtIOQueue::supply_buffer(const u8* buffer, u32 len, BufferType buffer_typ m_free_buffers--; m_free_head = (m_free_head + 1) % m_queue_size; - m_driver->rings[m_driver->index % m_queue_size] = descriptor_index; + m_driver->rings[m_driver_index_shadow % m_queue_size] = descriptor_index; // m_driver_index_shadow is used to prevent accesses to index before the rings are updated full_memory_barrier(); + m_driver_index_shadow++; m_driver->index++; full_memory_barrier(); diff --git a/Kernel/VirtIO/VirtIOQueue.h b/Kernel/VirtIO/VirtIOQueue.h index 9c3034870b..003d0a807f 100644 --- a/Kernel/VirtIO/VirtIOQueue.h +++ b/Kernel/VirtIO/VirtIOQueue.h @@ -33,7 +33,7 @@ namespace Kernel { enum class BufferType { DeviceReadable = 0, - DeviceWritable = 1 + DeviceWritable = 2 }; class VirtIOQueue { @@ -92,6 +92,7 @@ private: u16 m_free_buffers; u16 m_free_head { 0 }; u16 m_used_tail { 0 }; + u16 m_driver_index_shadow { 0 }; OwnPtr m_descriptors { nullptr }; OwnPtr m_driver { nullptr };