mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-11 01:06:01 +03:00
d234e6b801
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`.
219 lines
5.1 KiB
C
219 lines
5.1 KiB
C
/*
|
||
* Copyright (c) 2021, Pankaj R <pankydev8@gmail.com>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#pragma once
|
||
|
||
#include <AK/Endian.h>
|
||
#include <AK/Types.h>
|
||
|
||
struct ControllerRegister {
|
||
u64 cap;
|
||
u32 vs;
|
||
u32 intms;
|
||
u32 intmc;
|
||
u32 cc;
|
||
u32 rsvd1;
|
||
u32 csts;
|
||
u32 nssr;
|
||
u32 aqa;
|
||
u64 asq;
|
||
u64 acq;
|
||
u64 rsvd2[505];
|
||
};
|
||
|
||
struct IdentifyNamespace {
|
||
u64 nsze;
|
||
u64 ncap;
|
||
u8 rsdv1[10];
|
||
u8 flbas;
|
||
u8 rsvd2[100];
|
||
u32 lbaf[16];
|
||
u64 rsvd3[488];
|
||
};
|
||
|
||
// BAR
|
||
static constexpr u32 BAR_ADDR_MASK = 0xFFFFFFF0;
|
||
// DOORBELL
|
||
static constexpr u32 REG_SQ0TDBL_START = 0x1000;
|
||
static constexpr u32 REG_SQ0TDBL_END = 0x1003;
|
||
static constexpr u8 DBL_REG_SIZE = 8;
|
||
// CAP
|
||
static constexpr u8 CAP_DBL_SHIFT = 32;
|
||
static constexpr u8 CAP_DBL_MASK = 0xf;
|
||
static constexpr u8 CAP_TO_SHIFT = 24;
|
||
static constexpr u64 CAP_TO_MASK = 0xff << CAP_TO_SHIFT;
|
||
static constexpr u16 MQES(u64 cap)
|
||
{
|
||
return (cap & 0xffff) + 1;
|
||
}
|
||
|
||
static constexpr u32 CAP_TO(u64 cap)
|
||
{
|
||
return (cap & CAP_TO_MASK) >> CAP_TO_SHIFT;
|
||
}
|
||
|
||
// CC – Controller Configuration
|
||
static constexpr u8 CC_EN_BIT = 0x0;
|
||
static constexpr u8 CSTS_RDY_BIT = 0x0;
|
||
static constexpr u8 CSTS_SHST_SHIFT = 2;
|
||
static constexpr u32 CSTS_SHST_MASK = 0x3 << CSTS_SHST_SHIFT;
|
||
static constexpr u8 CC_IOSQES_BIT = 16;
|
||
static constexpr u8 CC_IOCQES_BIT = 20;
|
||
|
||
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 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)
|
||
{
|
||
return q_depth << CQ_WIDTH;
|
||
}
|
||
static constexpr u16 SQ_SIZE(u16 q_depth)
|
||
{
|
||
return q_depth << SQ_WIDTH;
|
||
}
|
||
static constexpr u8 PHASE_TAG(u16 x)
|
||
{
|
||
return x & 0x1;
|
||
}
|
||
static constexpr u16 CQ_STATUS_FIELD_MASK = 0xfffe;
|
||
static constexpr u16 CQ_STATUS_FIELD(u16 x)
|
||
{
|
||
return (x & CQ_STATUS_FIELD_MASK) >> 1;
|
||
}
|
||
|
||
static constexpr u16 IO_QUEUE_SIZE = 64; // TODO:Need to be configurable
|
||
|
||
// IDENTIFY
|
||
static constexpr u16 NVMe_IDENTIFY_SIZE = 4096;
|
||
static constexpr u8 NVMe_CNS_ID_ACTIVE_NS = 0x2;
|
||
static constexpr u8 NVMe_CNS_ID_NS = 0x0;
|
||
static constexpr u8 FLBA_SIZE_INDEX = 26;
|
||
static constexpr u8 FLBA_SIZE_MASK = 0xf;
|
||
static constexpr u8 LBA_FORMAT_SUPPORT_INDEX = 128;
|
||
static constexpr u32 LBA_SIZE_MASK = 0x00ff0000;
|
||
|
||
// OPCODES
|
||
// ADMIN COMMAND SET
|
||
enum AdminCommandOpCode {
|
||
OP_ADMIN_CREATE_COMPLETION_QUEUE = 0x5,
|
||
OP_ADMIN_CREATE_SUBMISSION_QUEUE = 0x1,
|
||
OP_ADMIN_IDENTIFY = 0x6,
|
||
};
|
||
|
||
// IO opcodes
|
||
enum IOCommandOpcode {
|
||
OP_NVME_WRITE = 0x1,
|
||
OP_NVME_READ = 0x2
|
||
};
|
||
|
||
// 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;
|
||
LittleEndian<u32> res;
|
||
|
||
LittleEndian<u16> sq_head; /* how much of this queue may be reclaimed */
|
||
LittleEndian<u16> sq_id; /* submission queue that generated this entry */
|
||
|
||
u16 command_id; /* of the command which completed */
|
||
LittleEndian<u16> status; /* did the command fail, and if so, why? */
|
||
};
|
||
|
||
struct [[gnu::packed]] DataPtr {
|
||
LittleEndian<u64> prp1;
|
||
LittleEndian<u64> prp2;
|
||
};
|
||
|
||
struct [[gnu::packed]] NVMeGenericCmd {
|
||
LittleEndian<u32> nsid;
|
||
LittleEndian<u64> rsvd;
|
||
LittleEndian<u64> metadata;
|
||
struct DataPtr data_ptr;
|
||
LittleEndian<u32> cdw10;
|
||
LittleEndian<u32> cdw11;
|
||
LittleEndian<u32> cdw12;
|
||
LittleEndian<u32> cdw13;
|
||
LittleEndian<u32> cdw14;
|
||
LittleEndian<u32> cdw15;
|
||
};
|
||
|
||
struct [[gnu::packed]] NVMeRWCmd {
|
||
LittleEndian<u32> nsid;
|
||
LittleEndian<u64> rsvd;
|
||
LittleEndian<u64> metadata;
|
||
struct DataPtr data_ptr;
|
||
LittleEndian<u64> slba;
|
||
LittleEndian<u16> length;
|
||
LittleEndian<u16> control;
|
||
LittleEndian<u32> dsmgmt;
|
||
LittleEndian<u32> reftag;
|
||
LittleEndian<u16> apptag;
|
||
LittleEndian<u16> appmask;
|
||
};
|
||
|
||
struct [[gnu::packed]] NVMeIdentifyCmd {
|
||
LittleEndian<u32> nsid;
|
||
LittleEndian<u64> rsvd1[2];
|
||
struct DataPtr data_ptr;
|
||
u8 cns;
|
||
u8 rsvd2;
|
||
LittleEndian<u16> ctrlid;
|
||
u8 rsvd3[3];
|
||
u8 csi;
|
||
u64 rsvd4[2];
|
||
};
|
||
|
||
struct [[gnu::packed]] NVMeCreateCQCmd {
|
||
u32 rsvd1[5];
|
||
LittleEndian<u64> prp1;
|
||
u64 rsvd2;
|
||
LittleEndian<u16> cqid;
|
||
LittleEndian<u16> qsize;
|
||
LittleEndian<u16> cq_flags;
|
||
LittleEndian<u16> irq_vector;
|
||
u64 rsvd12[2];
|
||
};
|
||
|
||
struct [[gnu::packed]] NVMeCreateSQCmd {
|
||
u32 rsvd1[5];
|
||
LittleEndian<u64> prp1;
|
||
u64 rsvd2;
|
||
LittleEndian<u16> sqid;
|
||
LittleEndian<u16> qsize;
|
||
LittleEndian<u16> sq_flags;
|
||
LittleEndian<u16> cqid;
|
||
u64 rsvd12[2];
|
||
};
|
||
|
||
struct [[gnu::packed]] NVMeSubmission {
|
||
u8 op;
|
||
u8 flags;
|
||
LittleEndian<u16> cmdid;
|
||
union [[gnu::packed]] {
|
||
NVMeGenericCmd generic;
|
||
NVMeIdentifyCmd identify;
|
||
NVMeRWCmd rw;
|
||
NVMeCreateCQCmd create_cq;
|
||
NVMeCreateSQCmd create_sq;
|
||
};
|
||
};
|