summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2021-04-15 19:17:49 +1000
committerAndreas Kling <kling@serenityos.org>2021-04-17 10:21:23 +0200
commit42b1eb5af1177800f383960be0932447e4a7cb5e (patch)
tree14e7284e6861d3549db6b3295896be7704b1b51e /Kernel
parent4a467c553a966ca753760bd282534ef5c97a9417 (diff)
downloadserenity-42b1eb5af1177800f383960be0932447e4a7cb5e.zip
Kernel: Activate queues and enable interrutps in VirtIODevices
This patch actually enables virtio queues after configuring them so the device can use them, it also enables interrupt handling in VirtIODevice so they are not ignored. Co-authored-by: Sahan <sahan.h.fernando@gmail.com>
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/VirtIO/VirtIO.cpp29
-rw-r--r--Kernel/VirtIO/VirtIO.h1
-rw-r--r--Kernel/VirtIO/VirtIOQueue.cpp3
-rw-r--r--Kernel/VirtIO/VirtIOQueue.h3
4 files changed, 30 insertions, 6 deletions
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<VirtIOQueueDescriptor> m_descriptors { nullptr };
OwnPtr<VirtIOQueueDriver> m_driver { nullptr };