Kernel: Properly initialize NVMe admin queue depth

We were reading the value instead of setting it (as required by the
specification). This worked only when we booted with a bootloader which
initialized NVMe before us.
This commit is contained in:
Idan Horowitz 2024-04-22 17:30:12 +03:00 committed by Andreas Kling
commit 7339409575
Notes: sideshowbarker 2024-07-17 14:36:19 +09:00
3 changed files with 10 additions and 19 deletions

View file

@ -145,13 +145,11 @@ ErrorOr<void> NVMeController::start_controller()
return {};
}
UNMAP_AFTER_INIT u32 NVMeController::get_admin_q_dept()
UNMAP_AFTER_INIT void NVMeController::set_admin_q_depth()
{
u32 aqa = m_controller_regs->aqa;
// Queue depth is 0 based
u32 q_depth = min(ACQ_SIZE(aqa), ASQ_SIZE(aqa)) + 1;
dbgln_if(NVME_DEBUG, "NVMe: Admin queue depth is {}", q_depth);
return q_depth;
u16 queue_depth = ADMIN_QUEUE_SIZE - 1;
m_controller_regs->aqa = queue_depth | (queue_depth << AQA_ACQ_SHIFT);
}
UNMAP_AFTER_INIT ErrorOr<void> NVMeController::identify_and_init_namespaces()
@ -317,13 +315,13 @@ void NVMeController::complete_current_request([[maybe_unused]] AsyncDeviceReques
UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_admin_queue(QueueType queue_type)
{
auto qdepth = get_admin_q_dept();
OwnPtr<Memory::Region> cq_dma_region;
Vector<NonnullRefPtr<Memory::PhysicalPage>> cq_dma_pages;
OwnPtr<Memory::Region> sq_dma_region;
Vector<NonnullRefPtr<Memory::PhysicalPage>> sq_dma_pages;
auto cq_size = round_up_to_power_of_two(CQ_SIZE(qdepth), 4096);
auto sq_size = round_up_to_power_of_two(SQ_SIZE(qdepth), 4096);
set_admin_q_depth();
auto cq_size = round_up_to_power_of_two(CQ_SIZE(ADMIN_QUEUE_SIZE), 4096);
auto sq_size = round_up_to_power_of_two(SQ_SIZE(ADMIN_QUEUE_SIZE), 4096);
auto maybe_error = reset_controller();
if (maybe_error.is_error()) {
dmesgln_pci(*this, "Failed to reset the NVMe controller");
@ -362,7 +360,7 @@ UNMAP_AFTER_INIT ErrorOr<void> NVMeController::create_admin_queue(QueueType queu
return maybe_error;
}
set_admin_queue_ready_flag();
m_admin_queue = TRY(NVMeQueue::try_create(*this, 0, irq, qdepth, move(cq_dma_region), move(sq_dma_region), move(doorbell), queue_type));
m_admin_queue = TRY(NVMeQueue::try_create(*this, 0, irq, ADMIN_QUEUE_SIZE, move(cq_dma_region), move(sq_dma_region), move(doorbell), queue_type));
dbgln_if(NVME_DEBUG, "NVMe: Admin queue created");
return {};

View file

@ -38,7 +38,6 @@ protected:
public:
ErrorOr<void> reset_controller();
ErrorOr<void> start_controller();
u32 get_admin_q_dept();
u16 submit_admin_command(NVMeSubmission& sub, bool sync = false)
{
@ -61,6 +60,7 @@ private:
NVMeController(PCI::DeviceIdentifier const&, u32 hardware_relative_controller_id);
void set_admin_q_depth();
ErrorOr<void> identify_and_init_namespaces();
ErrorOr<void> identify_and_init_controller();
NSFeatures get_ns_features(IdentifyNamespace& identify_data_struct);

View file

@ -77,15 +77,7 @@ static constexpr u32 CSTS_SHST(u32 x)
return (x & CSTS_SHST_MASK) >> CSTS_SHST_SHIFT;
}
static constexpr u16 CC_AQA_MASK = (0xfff);
static constexpr u16 ACQ_SIZE(u32 x)
{
return (x >> 16) & CC_AQA_MASK;
}
static constexpr u16 ASQ_SIZE(u32 x)
{
return x & CC_AQA_MASK;
}
static constexpr u16 AQA_ACQ_SHIFT = 16;
static constexpr u8 CQ_WIDTH = 4; // CQ is 16 bytes(2^4) in size.
static constexpr u8 SQ_WIDTH = 6; // SQ size is 64 bytes(2^6) in size.
static constexpr u16 CQ_SIZE(u16 q_depth)
@ -106,6 +98,7 @@ static constexpr u16 CQ_STATUS_FIELD(u16 x)
return (x & CQ_STATUS_FIELD_MASK) >> 1;
}
static constexpr u16 ADMIN_QUEUE_SIZE = 2;
static constexpr u16 IO_QUEUE_SIZE = 64; // TODO:Need to be configurable
// IDENTIFY