summaryrefslogtreecommitdiff
path: root/Kernel/Storage
diff options
context:
space:
mode:
authorPankaj Raghav <pankydev8@gmail.com>2022-01-27 16:44:58 +0530
committerAndreas Kling <kling@serenityos.org>2022-02-02 18:26:59 +0100
commitd234e6b801992875c892222c5c1725f151eb3f12 (patch)
tree8fffe92254c300015de3b4e976a7f5486b24720d /Kernel/Storage
parentaa832ee2511693114db417714183a4ac37272e9b (diff)
downloadserenity-d234e6b801992875c892222c5c1725f151eb3f12.zip
Kernel: Add polling support to NVMe
Add polling support to NVMe so that it does not use interrupt to complete a IO but instead actively polls for completion. This probably is not very efficient in terms of CPU usage but it does not use interrupts to complete a IO which is beneficial at the moment as there is no MSI(X) support and it can reduce the latency of an IO in a very fast NVMe device. The NVMeQueue class has been made the base class for NVMeInterruptQueue and NVMePollQueue. The factory function `NVMeQueue::try_create` will return the appropriate queue to the controller based on the polling boot parameter. The polling mode can be enabled by adding an extra boot parameter: `nvme_poll`.
Diffstat (limited to 'Kernel/Storage')
-rw-r--r--Kernel/Storage/NVMe/NVMeController.cpp26
-rw-r--r--Kernel/Storage/NVMe/NVMeController.h8
-rw-r--r--Kernel/Storage/NVMe/NVMeDefinitions.h1
-rw-r--r--Kernel/Storage/NVMe/NVMeInterruptQueue.cpp57
-rw-r--r--Kernel/Storage/NVMe/NVMeInterruptQueue.h24
-rw-r--r--Kernel/Storage/NVMe/NVMePollQueue.cpp44
-rw-r--r--Kernel/Storage/NVMe/NVMePollQueue.h22
-rw-r--r--Kernel/Storage/NVMe/NVMeQueue.cpp53
-rw-r--r--Kernel/Storage/NVMe/NVMeQueue.h39
-rw-r--r--Kernel/Storage/StorageManagement.cpp12
-rw-r--r--Kernel/Storage/StorageManagement.h4
11 files changed, 208 insertions, 82 deletions
diff --git a/Kernel/Storage/NVMe/NVMeController.cpp b/Kernel/Storage/NVMe/NVMeController.cpp
index 0397273eea..aab71dece3 100644
--- a/Kernel/Storage/NVMe/NVMeController.cpp
+++ b/Kernel/Storage/NVMe/NVMeController.cpp
@@ -12,6 +12,7 @@
#include <Kernel/Arch/x86/Processor.h>
#include <Kernel/Arch/x86/SafeMem.h>
#include <Kernel/Bus/PCI/API.h>
+#include <Kernel/CommandLine.h>
#include <Kernel/Devices/Device.h>
#include <Kernel/FileSystem/ProcFS.h>
#include <Kernel/Sections.h>
@@ -19,10 +20,10 @@
namespace Kernel {
Atomic<u8> NVMeController::controller_id {};
-UNMAP_AFTER_INIT ErrorOr<NonnullRefPtr<NVMeController>> NVMeController::try_initialize(const Kernel::PCI::DeviceIdentifier& device_identifier)
+UNMAP_AFTER_INIT ErrorOr<NonnullRefPtr<NVMeController>> NVMeController::try_initialize(const Kernel::PCI::DeviceIdentifier& device_identifier, bool is_queue_polled)
{
auto controller = TRY(adopt_nonnull_ref_or_enomem(new NVMeController(device_identifier)));
- TRY(controller->initialize());
+ TRY(controller->initialize(is_queue_polled));
NVMeController::controller_id++;
return controller;
}
@@ -33,11 +34,11 @@ UNMAP_AFTER_INIT NVMeController::NVMeController(const PCI::DeviceIdentifier& dev
{
}
-UNMAP_AFTER_INIT ErrorOr<void> NVMeController::initialize()
+UNMAP_AFTER_INIT ErrorOr<void> NVMeController::initialize(bool is_queue_polled)
{
// Nr of queues = one queue per core
auto nr_of_queues = Processor::count();
- auto irq = m_pci_device_id.interrupt_line().value();
+ auto irq = is_queue_polled ? Optional<u8> {} : m_pci_device_id.interrupt_line().value();
PCI::enable_memory_space(m_pci_device_id.address());
PCI::enable_bus_mastering(m_pci_device_id.address());
@@ -62,7 +63,7 @@ UNMAP_AFTER_INIT ErrorOr<void> NVMeController::initialize()
// Create an IO queue per core
for (u32 cpuid = 0; cpuid < nr_of_queues; ++cpuid) {
// qid is zero is used for admin queue
- TRY(create_io_queue(irq, cpuid + 1));
+ TRY(create_io_queue(cpuid + 1, irq));
}
TRY(identify_and_init_namespaces());
return {};
@@ -253,7 +254,7 @@ void NVMeController::complete_current_request([[maybe_unused]] AsyncDeviceReques
VERIFY_NOT_REACHED();
}
-UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_admin_queue(u8 irq)
+UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_admin_queue(Optional<u8> irq)
{
auto qdepth = get_admin_q_dept();
OwnPtr<Memory::Region> cq_dma_region;
@@ -281,8 +282,6 @@ UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_admin_queue(u8 irq)
}
auto doorbell_regs = TRY(Memory::map_typed_writable<volatile DoorbellRegister>(PhysicalAddress(m_bar + REG_SQ0TDBL_START)));
- m_admin_queue = TRY(NVMeQueue::try_create(0, irq, qdepth, move(cq_dma_region), cq_dma_pages, move(sq_dma_region), sq_dma_pages, move(doorbell_regs)));
-
m_controller_regs->acq = reinterpret_cast<u64>(AK::convert_between_host_and_little_endian(cq_dma_pages.first().paddr().as_ptr()));
m_controller_regs->asq = reinterpret_cast<u64>(AK::convert_between_host_and_little_endian(sq_dma_pages.first().paddr().as_ptr()));
@@ -291,12 +290,13 @@ UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_admin_queue(u8 irq)
return EFAULT;
}
set_admin_queue_ready_flag();
- m_admin_queue->enable_interrupts();
+ m_admin_queue = TRY(NVMeQueue::try_create(0, irq, qdepth, move(cq_dma_region), cq_dma_pages, move(sq_dma_region), sq_dma_pages, move(doorbell_regs)));
+
dbgln_if(NVME_DEBUG, "NVMe: Admin queue created");
return {};
}
-UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_io_queue(u8 irq, u8 qid)
+UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_io_queue(u8 qid, Optional<u8> irq)
{
OwnPtr<Memory::Region> cq_dma_region;
NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_pages;
@@ -326,7 +326,8 @@ UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_io_queue(u8 irq, u8 qid)
sub.create_cq.cqid = qid;
// The queue size is 0 based
sub.create_cq.qsize = AK::convert_between_host_and_little_endian(IO_QUEUE_SIZE - 1);
- auto flags = QUEUE_IRQ_ENABLED | QUEUE_PHY_CONTIGUOUS;
+ auto flags = irq.has_value() ? QUEUE_IRQ_ENABLED : QUEUE_IRQ_DISABLED;
+ flags |= QUEUE_PHY_CONTIGUOUS;
// TODO: Eventually move to MSI.
// For now using pin based interrupts. Clear the first 16 bits
// to use pin-based interrupts.
@@ -340,7 +341,7 @@ UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_io_queue(u8 irq, u8 qid)
sub.create_sq.sqid = qid;
// The queue size is 0 based
sub.create_sq.qsize = AK::convert_between_host_and_little_endian(IO_QUEUE_SIZE - 1);
- auto flags = QUEUE_IRQ_ENABLED | QUEUE_PHY_CONTIGUOUS;
+ auto flags = QUEUE_PHY_CONTIGUOUS;
sub.create_sq.cqid = qid;
sub.create_sq.sq_flags = AK::convert_between_host_and_little_endian(flags);
submit_admin_command(sub, true);
@@ -350,7 +351,6 @@ UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_io_queue(u8 irq, u8 qid)
auto doorbell_regs = TRY(Memory::map_typed_writable<volatile DoorbellRegister>(PhysicalAddress(m_bar + queue_doorbell_offset)));
m_queues.append(TRY(NVMeQueue::try_create(qid, irq, IO_QUEUE_SIZE, move(cq_dma_region), cq_dma_pages, move(sq_dma_region), sq_dma_pages, move(doorbell_regs))));
- m_queues.last().enable_interrupts();
dbgln_if(NVME_DEBUG, "NVMe: Created IO Queue with QID{}", m_queues.size());
return {};
}
diff --git a/Kernel/Storage/NVMe/NVMeController.h b/Kernel/Storage/NVMe/NVMeController.h
index bc85786c10..d881e48f52 100644
--- a/Kernel/Storage/NVMe/NVMeController.h
+++ b/Kernel/Storage/NVMe/NVMeController.h
@@ -26,8 +26,8 @@ namespace Kernel {
class NVMeController : public PCI::Device
, public StorageController {
public:
- static ErrorOr<NonnullRefPtr<NVMeController>> try_initialize(PCI::DeviceIdentifier const&);
- ErrorOr<void> initialize();
+ static ErrorOr<NonnullRefPtr<NVMeController>> try_initialize(PCI::DeviceIdentifier const&, bool is_queue_polled);
+ ErrorOr<void> initialize(bool is_queue_polled);
explicit NVMeController(PCI::DeviceIdentifier const&);
RefPtr<StorageDevice> device(u32 index) const override;
size_t devices_count() const override;
@@ -58,8 +58,8 @@ public:
private:
ErrorOr<void> identify_and_init_namespaces();
Tuple<u64, u8> get_ns_features(IdentifyNamespace& identify_data_struct);
- ErrorOr<void> create_admin_queue(u8 irq);
- ErrorOr<void> create_io_queue(u8 irq, u8 qid);
+ ErrorOr<void> create_admin_queue(Optional<u8> irq);
+ ErrorOr<void> create_io_queue(u8 qid, Optional<u8> irq);
void calculate_doorbell_stride()
{
m_dbl_stride = (m_controller_regs->cap >> CAP_DBL_SHIFT) & CAP_DBL_MASK;
diff --git a/Kernel/Storage/NVMe/NVMeDefinitions.h b/Kernel/Storage/NVMe/NVMeDefinitions.h
index 5ba4911e46..b7ce1416ce 100644
--- a/Kernel/Storage/NVMe/NVMeDefinitions.h
+++ b/Kernel/Storage/NVMe/NVMeDefinitions.h
@@ -125,6 +125,7 @@ enum IOCommandOpcode {
// FLAGS
static constexpr u8 QUEUE_PHY_CONTIGUOUS = (1 << 0);
static constexpr u8 QUEUE_IRQ_ENABLED = (1 << 1);
+static constexpr u8 QUEUE_IRQ_DISABLED = (0 << 1);
struct [[gnu::packed]] NVMeCompletion {
LittleEndian<u32> cmd_spec;
diff --git a/Kernel/Storage/NVMe/NVMeInterruptQueue.cpp b/Kernel/Storage/NVMe/NVMeInterruptQueue.cpp
new file mode 100644
index 0000000000..f3e5752c66
--- /dev/null
+++ b/Kernel/Storage/NVMe/NVMeInterruptQueue.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2022, Pankaj R <pankydev8@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "NVMeInterruptQueue.h"
+#include "Kernel/Devices/BlockDevice.h"
+#include "NVMeDefinitions.h"
+#include <Kernel/WorkQueue.h>
+
+namespace Kernel {
+
+UNMAP_AFTER_INIT NVMeInterruptQueue::NVMeInterruptQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u8 irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs)
+ : NVMeQueue(move(rw_dma_region), rw_dma_page, qid, q_depth, move(cq_dma_region), cq_dma_page, move(sq_dma_region), sq_dma_page, move(db_regs))
+ , IRQHandler(irq)
+{
+ enable_irq();
+}
+
+bool NVMeInterruptQueue::handle_irq(const RegisterState&)
+{
+ SpinlockLocker lock(m_request_lock);
+ return process_cq() ? true : false;
+}
+
+void NVMeInterruptQueue::submit_sqe(NVMeSubmission& sub)
+{
+ NVMeQueue::submit_sqe(sub);
+}
+
+void NVMeInterruptQueue::complete_current_request(u16 status)
+{
+ VERIFY(m_request_lock.is_locked());
+
+ g_io_work->queue([this, status]() {
+ SpinlockLocker lock(m_request_lock);
+ auto current_request = m_current_request;
+ m_current_request.clear();
+ if (status) {
+ lock.unlock();
+ current_request->complete(AsyncBlockDeviceRequest::Failure);
+ return;
+ }
+ if (current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Read) {
+ if (auto result = current_request->write_to_buffer(current_request->buffer(), m_rw_dma_region->vaddr().as_ptr(), 512 * current_request->block_count()); result.is_error()) {
+ lock.unlock();
+ current_request->complete(AsyncDeviceRequest::MemoryFault);
+ return;
+ }
+ }
+ lock.unlock();
+ current_request->complete(AsyncDeviceRequest::Success);
+ return;
+ });
+}
+}
diff --git a/Kernel/Storage/NVMe/NVMeInterruptQueue.h b/Kernel/Storage/NVMe/NVMeInterruptQueue.h
new file mode 100644
index 0000000000..9b562efb58
--- /dev/null
+++ b/Kernel/Storage/NVMe/NVMeInterruptQueue.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022, Pankaj R <pankydev8@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/Storage/NVMe/NVMeQueue.h>
+
+namespace Kernel {
+
+class NVMeInterruptQueue : public NVMeQueue
+ , public IRQHandler {
+public:
+ NVMeInterruptQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u8 irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs);
+ void submit_sqe(NVMeSubmission& submission) override;
+ virtual ~NVMeInterruptQueue() override {};
+
+private:
+ virtual void complete_current_request(u16 status) override;
+ bool handle_irq(RegisterState const&) override;
+};
+}
diff --git a/Kernel/Storage/NVMe/NVMePollQueue.cpp b/Kernel/Storage/NVMe/NVMePollQueue.cpp
new file mode 100644
index 0000000000..8b1340a9b4
--- /dev/null
+++ b/Kernel/Storage/NVMe/NVMePollQueue.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022, Pankaj R <pankydev8@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "NVMePollQueue.h"
+#include "Kernel/Arch/x86/IO.h"
+#include "Kernel/Devices/BlockDevice.h"
+#include "NVMeDefinitions.h"
+
+namespace Kernel {
+UNMAP_AFTER_INIT NVMePollQueue::NVMePollQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs)
+ : NVMeQueue(move(rw_dma_region), rw_dma_page, qid, q_depth, move(cq_dma_region), cq_dma_page, move(sq_dma_region), sq_dma_page, move(db_regs))
+{
+}
+
+void NVMePollQueue::submit_sqe(NVMeSubmission& sub)
+{
+ NVMeQueue::submit_sqe(sub);
+ SpinlockLocker lock_cq(m_cq_lock);
+ while (!process_cq()) {
+ IO::delay(1);
+ }
+}
+
+void NVMePollQueue::complete_current_request(u16 status)
+{
+ auto current_request = m_current_request;
+ m_current_request.clear();
+ if (status) {
+ current_request->complete(AsyncBlockDeviceRequest::Failure);
+ return;
+ }
+ if (current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Read) {
+ if (auto result = current_request->write_to_buffer(current_request->buffer(), m_rw_dma_region->vaddr().as_ptr(), 512 * current_request->block_count()); result.is_error()) {
+ current_request->complete(AsyncDeviceRequest::MemoryFault);
+ return;
+ }
+ }
+ current_request->complete(AsyncDeviceRequest::Success);
+ return;
+}
+}
diff --git a/Kernel/Storage/NVMe/NVMePollQueue.h b/Kernel/Storage/NVMe/NVMePollQueue.h
new file mode 100644
index 0000000000..458f11c14f
--- /dev/null
+++ b/Kernel/Storage/NVMe/NVMePollQueue.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022, Pankaj R <pankydev8@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/Storage/NVMe/NVMeQueue.h>
+
+namespace Kernel {
+
+class NVMePollQueue : public NVMeQueue {
+public:
+ NVMePollQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs);
+ void submit_sqe(NVMeSubmission& submission) override;
+ virtual ~NVMePollQueue() override {};
+
+private:
+ virtual void complete_current_request(u16 status) override;
+};
+}
diff --git a/Kernel/Storage/NVMe/NVMeQueue.cpp b/Kernel/Storage/NVMe/NVMeQueue.cpp
index 5289f6446d..bf531f9224 100644
--- a/Kernel/Storage/NVMe/NVMeQueue.cpp
+++ b/Kernel/Storage/NVMe/NVMeQueue.cpp
@@ -6,36 +6,38 @@
#include "NVMeQueue.h"
#include "Kernel/StdLib.h"
+#include "NVMeQueue.h"
#include <Kernel/Arch/x86/IO.h>
-#include <Kernel/Scheduler.h>
#include <Kernel/Storage/NVMe/NVMeController.h>
-#include <Kernel/WorkQueue.h>
+#include <Kernel/Storage/NVMe/NVMeInterruptQueue.h>
+#include <Kernel/Storage/NVMe/NVMePollQueue.h>
namespace Kernel {
-
-ErrorOr<NonnullRefPtr<NVMeQueue>> NVMeQueue::try_create(u16 qid, u8 irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs)
+ErrorOr<NonnullRefPtr<NVMeQueue>> NVMeQueue::try_create(u16 qid, Optional<u8> irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs)
{
// Note: Allocate DMA region for RW operation. For now the requests don't exceed more than 4096 bytes (Storage device takes care of it)
RefPtr<Memory::PhysicalPage> rw_dma_page;
auto rw_dma_region = TRY(MM.allocate_dma_buffer_page("NVMe Queue Read/Write DMA"sv, Memory::Region::Access::ReadWrite, rw_dma_page));
- auto queue = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) NVMeQueue(move(rw_dma_region), *rw_dma_page, qid, irq, q_depth, move(cq_dma_region), cq_dma_page, move(sq_dma_region), sq_dma_page, move(db_regs))));
+ if (!irq.has_value()) {
+ auto queue = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) NVMePollQueue(move(rw_dma_region), *rw_dma_page, qid, q_depth, move(cq_dma_region), cq_dma_page, move(sq_dma_region), sq_dma_page, move(db_regs))));
+ return queue;
+ }
+ auto queue = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) NVMeInterruptQueue(move(rw_dma_region), *rw_dma_page, qid, irq.value(), q_depth, move(cq_dma_region), cq_dma_page, move(sq_dma_region), sq_dma_page, move(db_regs))));
return queue;
}
-UNMAP_AFTER_INIT NVMeQueue::NVMeQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u8 irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs)
- : IRQHandler(irq)
+UNMAP_AFTER_INIT NVMeQueue::NVMeQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs)
+ : m_current_request(nullptr)
+ , m_rw_dma_region(move(rw_dma_region))
, m_qid(qid)
, m_admin_queue(qid == 0)
- , m_irq(irq)
, m_qdepth(q_depth)
, m_cq_dma_region(move(cq_dma_region))
, m_cq_dma_page(cq_dma_page)
, m_sq_dma_region(move(sq_dma_region))
, m_sq_dma_page(sq_dma_page)
- , m_rw_dma_region(move(rw_dma_region))
, m_db_regs(move(db_regs))
, m_rw_dma_page(rw_dma_page)
- , m_current_request(nullptr)
{
m_sqe_array = { reinterpret_cast<NVMeSubmission*>(m_sq_dma_region->vaddr().as_ptr()), m_qdepth };
@@ -59,7 +61,7 @@ void NVMeQueue::update_cqe_head()
}
}
-bool NVMeQueue::handle_irq(const RegisterState&)
+u32 NVMeQueue::process_cq()
{
u32 nr_of_processed_cqes = 0;
while (cqe_available()) {
@@ -76,7 +78,6 @@ bool NVMeQueue::handle_irq(const RegisterState&)
// everything is operated on a single request similar to BMIDE driver.
// TODO: Remove this constraint eventually.
VERIFY(cmdid == m_prev_sq_tail);
- SpinlockLocker lock(m_request_lock);
if (m_current_request) {
complete_current_request(status);
}
@@ -86,7 +87,7 @@ bool NVMeQueue::handle_irq(const RegisterState&)
if (nr_of_processed_cqes) {
update_cq_doorbell();
}
- return nr_of_processed_cqes ? true : false;
+ return nr_of_processed_cqes;
}
void NVMeQueue::submit_sqe(NVMeSubmission& sub)
@@ -126,7 +127,7 @@ u16 NVMeQueue::submit_sync_sqe(NVMeSubmission& sub)
index = m_qdepth - 1;
}
cqe_cid = m_cqe_array[index].command_id;
- Scheduler::yield();
+ IO::delay(1);
} while (cid != cqe_cid);
auto status = CQ_STATUS_FIELD(m_cqe_array[m_cq_head].status);
@@ -171,29 +172,7 @@ void NVMeQueue::write(AsyncBlockDeviceRequest& request, u16 nsid, u64 index, u32
submit_sqe(sub);
}
-void NVMeQueue::complete_current_request(u16 status)
+UNMAP_AFTER_INIT NVMeQueue::~NVMeQueue()
{
- VERIFY(m_request_lock.is_locked());
-
- g_io_work->queue([this, status]() {
- SpinlockLocker lock(m_request_lock);
- auto current_request = m_current_request;
- m_current_request.clear();
- if (status) {
- lock.unlock();
- current_request->complete(AsyncBlockDeviceRequest::Failure);
- return;
- }
- if (current_request->request_type() == AsyncBlockDeviceRequest::RequestType::Read) {
- if (auto result = current_request->write_to_buffer(current_request->buffer(), m_rw_dma_region->vaddr().as_ptr(), 512 * current_request->block_count()); result.is_error()) {
- lock.unlock();
- current_request->complete(AsyncDeviceRequest::MemoryFault);
- return;
- }
- }
- lock.unlock();
- current_request->complete(AsyncDeviceRequest::Success);
- return;
- });
}
}
diff --git a/Kernel/Storage/NVMe/NVMeQueue.h b/Kernel/Storage/NVMe/NVMeQueue.h
index 85dbd7ddc3..66ca555da7 100644
--- a/Kernel/Storage/NVMe/NVMeQueue.h
+++ b/Kernel/Storage/NVMe/NVMeQueue.h
@@ -27,45 +27,47 @@ struct DoorbellRegister {
};
class AsyncBlockDeviceRequest;
-class NVMeQueue : public IRQHandler
- , public RefCounted<NVMeQueue> {
+class NVMeQueue : public RefCounted<NVMeQueue> {
public:
- static ErrorOr<NonnullRefPtr<NVMeQueue>> try_create(u16 qid, u8 irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs);
+ static ErrorOr<NonnullRefPtr<NVMeQueue>> try_create(u16 qid, Optional<u8> irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs);
bool is_admin_queue() { return m_admin_queue; };
- void submit_sqe(NVMeSubmission&);
u16 submit_sync_sqe(NVMeSubmission&);
void read(AsyncBlockDeviceRequest& request, u16 nsid, u64 index, u32 count);
void write(AsyncBlockDeviceRequest& request, u16 nsid, u64 index, u32 count);
- void enable_interrupts() { enable_irq(); };
- void disable_interrupts() { disable_irq(); };
+ virtual void submit_sqe(NVMeSubmission&);
+ virtual ~NVMeQueue();
-private:
- NVMeQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u8 irq, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs);
-
- virtual bool handle_irq(const RegisterState&) override;
+protected:
+ u32 process_cq();
+ void update_sq_doorbell()
+ {
+ m_db_regs->sq_tail = m_sq_tail;
+ }
+ NVMeQueue(NonnullOwnPtr<Memory::Region> rw_dma_region, Memory::PhysicalPage const& rw_dma_page, u16 qid, u32 q_depth, OwnPtr<Memory::Region> cq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> cq_dma_page, OwnPtr<Memory::Region> sq_dma_region, NonnullRefPtrVector<Memory::PhysicalPage> sq_dma_page, Memory::TypedMapping<volatile DoorbellRegister> db_regs);
+private:
bool cqe_available();
void update_cqe_head();
- void complete_current_request(u16 status);
+ virtual void complete_current_request(u16 status) = 0;
void update_cq_doorbell()
{
m_db_regs->cq_head = m_cq_head;
}
- void update_sq_doorbell()
- {
- m_db_regs->sq_tail = m_sq_tail;
- }
+protected:
+ Spinlock m_cq_lock { LockRank::Interrupts };
+ RefPtr<AsyncBlockDeviceRequest> m_current_request;
+ NonnullOwnPtr<Memory::Region> m_rw_dma_region;
+ Spinlock m_request_lock;
+private:
u16 m_qid {};
u8 m_cq_valid_phase { 1 };
u16 m_sq_tail {};
u16 m_prev_sq_tail {};
u16 m_cq_head {};
bool m_admin_queue { false };
- u8 m_irq {};
u32 m_qdepth {};
- Spinlock m_cq_lock { LockRank::Interrupts };
Spinlock m_sq_lock { LockRank::Interrupts };
OwnPtr<Memory::Region> m_cq_dma_region;
NonnullRefPtrVector<Memory::PhysicalPage> m_cq_dma_page;
@@ -73,10 +75,7 @@ private:
OwnPtr<Memory::Region> m_sq_dma_region;
NonnullRefPtrVector<Memory::PhysicalPage> m_sq_dma_page;
Span<NVMeCompletion> m_cqe_array;
- NonnullOwnPtr<Memory::Region> m_rw_dma_region;
Memory::TypedMapping<volatile DoorbellRegister> m_db_regs;
NonnullRefPtr<Memory::PhysicalPage> m_rw_dma_page;
- Spinlock m_request_lock;
- RefPtr<AsyncBlockDeviceRequest> m_current_request;
};
}
diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp
index cfcdc5b274..1b67a2febd 100644
--- a/Kernel/Storage/StorageManagement.cpp
+++ b/Kernel/Storage/StorageManagement.cpp
@@ -44,7 +44,7 @@ bool StorageManagement::boot_argument_contains_partition_uuid()
return m_boot_argument.starts_with(partition_uuid_prefix);
}
-UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio)
+UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio, bool nvme_poll)
{
VERIFY(m_controllers.is_empty());
@@ -60,10 +60,10 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio)
static constexpr PCI::HardwareID vmd_device = { 0x8086, 0x9a0b };
if (device_identifier.hardware_id() == vmd_device) {
auto controller = PCI::VolumeManagementDevice::must_create(device_identifier);
- PCI::Access::the().add_host_controller_and_enumerate_attached_devices(move(controller), [this](PCI::DeviceIdentifier const& device_identifier) -> void {
+ PCI::Access::the().add_host_controller_and_enumerate_attached_devices(move(controller), [this, nvme_poll](PCI::DeviceIdentifier const& device_identifier) -> void {
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
if (subclass_code == SubclassID::NVMeController) {
- auto controller = NVMeController::try_initialize(device_identifier);
+ auto controller = NVMeController::try_initialize(device_identifier, nvme_poll);
if (controller.is_error()) {
dmesgln("Unable to initialize NVMe controller: {}", controller.error());
} else {
@@ -84,7 +84,7 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio)
m_controllers.append(AHCIController::initialize(device_identifier));
}
if (subclass_code == SubclassID::NVMeController) {
- auto controller = NVMeController::try_initialize(device_identifier);
+ auto controller = NVMeController::try_initialize(device_identifier, nvme_poll);
if (controller.is_error()) {
dmesgln("Unable to initialize NVMe controller: {}", controller.error());
} else {
@@ -274,11 +274,11 @@ NonnullRefPtr<FileSystem> StorageManagement::root_filesystem() const
return file_system;
}
-UNMAP_AFTER_INIT void StorageManagement::initialize(StringView root_device, bool force_pio)
+UNMAP_AFTER_INIT void StorageManagement::initialize(StringView root_device, bool force_pio, bool poll)
{
VERIFY(s_device_minor_number == 0);
m_boot_argument = root_device;
- enumerate_controllers(force_pio);
+ enumerate_controllers(force_pio, poll);
enumerate_storage_devices();
enumerate_disk_partitions();
if (!boot_argument_contains_partition_uuid()) {
diff --git a/Kernel/Storage/StorageManagement.h b/Kernel/Storage/StorageManagement.h
index 29c7e6be19..32c1678dc2 100644
--- a/Kernel/Storage/StorageManagement.h
+++ b/Kernel/Storage/StorageManagement.h
@@ -23,7 +23,7 @@ class StorageManagement {
public:
StorageManagement();
static bool initialized();
- void initialize(StringView boot_argument, bool force_pio);
+ void initialize(StringView boot_argument, bool force_pio, bool nvme_poll);
static StorageManagement& the();
NonnullRefPtr<FileSystem> root_filesystem() const;
@@ -36,7 +36,7 @@ public:
private:
bool boot_argument_contains_partition_uuid();
- void enumerate_controllers(bool force_pio);
+ void enumerate_controllers(bool force_pio, bool nvme_poll);
void enumerate_storage_devices();
void enumerate_disk_partitions();