2#include "NvmeController.h"
3#include "pedigree/kernel/LockGuard.h"
4#include "pedigree/kernel/Log.h"
5#include "pedigree/kernel/machine/IrqManager.h"
6#include "pedigree/kernel/machine/Machine.h"
7#include "pedigree/kernel/machine/Pci.h"
8#include "pedigree/kernel/panic.h"
9#include "pedigree/kernel/processor/IoBase.h"
10#include "pedigree/kernel/time/Time.h"
11#include "pedigree/kernel/utilities/new"
12#include "pedigree/kernel/utilities/utility.h"
15#include "modules/drivers/common/InterruptProbe.h"
18NvmeController::NvmeController(
Device* pci)
21 m_ReadyMilliseconds(500),
22 m_MaxTransfer(MaxTransfer),
26 m_HardwareOwned(false),
27 m_DmaInstalled(false),
33 setSpecificType(
String(
"nvme-controller"));
35NvmeController::~NvmeController() {
39bool NvmeController::waitReady(
bool ready) {
40 const auto deadline = Time::getTicks() + m_ReadyMilliseconds * Time::Multiplier::Millisecond;
42 const uint32_t status = m_Registers->
read32(Status);
43 if (status == 0xffffffffU || (ready && (status & 2U)))
45 if (
bool(status & 1U) == ready)
47 Time::delay(Time::Multiplier::Millisecond);
48 }
while (Time::getTicks() < deadline);
51bool NvmeController::disable() {
52 m_Registers->
write32(0xffffffffU, InterruptMaskSet);
53 m_Registers->
write32(m_Registers->
read32(Configuration) & ~(1U | (3U << 14)), Configuration);
54 (void)m_Registers->
read32(Configuration);
55 return waitReady(
false);
57void NvmeController::failController() {
63 m_Registers->
write32(0xffffffffU, InterruptMaskSet);
64 (void)m_Registers->
read32(InterruptMaskSet);
73 panic(
"NVMe: controller cannot stop DMA; refusing to release memory");
74 m_DmaInstalled =
false;
77bool NvmeController::command(
NvmeQueue& queue,
Command request,
void* buffer,
size_t bytes,
78 bool writing, uint32_t* result,
bool interruptProbe) {
82 interrupts = m_Interrupts;
84 const size_t timeout = (&queue == &m_Io && (request.opcode & 255U) == 0) ? 120 : 30;
86 queue.execute(request, buffer, bytes, writing, interrupts, timeout, result, interruptProbe);
87 if (status == NvmeQueue::Result::TransportError)
89 return status == NvmeQueue::Result::Success;
91bool NvmeController::identify(uint32_t nsid, uint8_t kind,
void* buffer,
bool interruptProbe) {
99 return command(m_Admin, request, buffer, PageSize,
false,
nullptr, interruptProbe);
102bool NvmeController::initialiseController() {
106 auto& pci = PciBus::instance();
108 if (!pci.inspectFunction(m_Pci, inherited)) {
109 ERROR(
"NVMe: unsupported PCI state (D0, valid capabilities and PIC INTx required)");
112 m_OriginalCommand = inherited.command;
113 const uint32_t bar = pci.readConfigSpace(m_Pci, 4);
114 if ((bar & 1U) || ((bar & 6U) != 0 && (bar & 6U) != 4))
116 uint64_t base = bar & ~15U;
118 base |=
static_cast<uint64_t
>(pci.readConfigSpace(m_Pci, 5)) << 32;
120 for (
auto* address : m_Pci->
addresses()) {
121 if (address->m_Name ==
"bar0" && base && !address->m_IsIoSpace && address->m_Address == base)
124 if (!mapping || mapping->
m_Size < Doorbells + 16)
127 if (!pci.updateCommand(m_Pci, 0, 2U | 0x400U))
130 m_Registers = mapping->
m_Io;
131 if (!m_Registers || m_Registers->
size() < mapping->
m_Size)
133 const uint32_t version = m_Registers->
read32(Version);
135 m_Registers->
read32(Cap) | (
static_cast<uint64_t
>(m_Registers->
read32(Cap + 4)) << 32);
138 if (version < 0x00010100 || version == 0xffffffffU || !(cap & (1ULL << 37)) ||
141 const size_t stride =
size_t{4} << ((cap >> 32) & 15U);
142 if (mapping->
m_Size < Doorbells + 3 * stride + 4)
144 m_ReadyMilliseconds = (((cap >> 24) & 255U) + 1) * 500;
145 m_HardwareOwned =
true;
150 if (!pci.updateCommand(m_Pci, 4U, 2U | 0x400U) ||
151 !pci.disableMessageInterrupts(m_Pci, inherited) || !pci.resourcesUnchanged(m_Pci, inherited))
153 const uint16_t depth = (cap & 0xffffU) >= QueueDepth - 1 ? QueueDepth : (cap & 0xffffU) + 1;
154 if (!m_Admin.initialise(m_Registers, 0, depth, stride, PageSize) ||
155 !m_Io.initialise(m_Registers, 1, depth, stride, MaxTransfer))
157 m_Registers->
write32((depth - 1U) | ((depth - 1U) << 16), AdminAttributes);
158 m_Registers->
write32(m_Admin.submissionAddress(), AdminSubmission);
159 m_Registers->
write32(m_Admin.submissionAddress() >> 32, AdminSubmission + 4);
160 m_Registers->
write32(m_Admin.completionAddress(), AdminCompletion);
161 m_Registers->
write32(m_Admin.completionAddress() >> 32, AdminCompletion + 4);
163 m_DmaInstalled =
true;
164 if (!pci.updateCommand(m_Pci, 0, 6U | 0x400U))
166 m_Registers->
write32(1U | (6U << 16) | (4U << 20), Configuration);
167 if (!waitReady(
true))
169 uint8_t controller[PageSize]{};
170 if (!identify(0, 1, controller))
172 if ((controller[512] & 15U) > 6 || (controller[512] >> 4) < 6 || (controller[513] & 15U) > 4 ||
173 (controller[513] >> 4) < 4)
175 const uint8_t mdts = controller[77];
176 if (mdts && mdts < 4)
177 m_MaxTransfer = PageSize << mdts;
178 for (
size_t i = 0; i < 40; ++i) {
179 const uint8_t ch = controller[24 + i];
180 m_Model[i] = ch >= 32 && ch <= 126 ? ch :
' ';
183 while (length && m_Model[length - 1] ==
' ')
186 if (!createIoQueue())
188 const uint32_t maximumId = controller[516] | (uint32_t{controller[517]} << 8) |
189 (uint32_t{controller[518]} << 16) | (uint32_t{controller[519]} << 24);
190 if (!maximumId || !discoverNamespaces(maximumId) || !
getNumChildren())
193 IrqPolicy::pciIntxThreaded());
195 ERROR(
"NVMe: could not register PCI INTx");
201 if (!pci.updateCommand(m_Pci, 0x400U, 6U))
203 m_Registers->
write32(1, InterruptMaskClear);
204 (void)m_Registers->
read32(Status);
206 if (!InterruptProbe::run([&] {
return identify(0, 1, controller,
true); },
207 [&] {
return m_Admin.interruptCompletions(); })) {
208 ERROR(
"NVMe: interrupt delivery probe failed");
213 NOTICE(
"NVMe: '" << m_Model <<
"' ready, " <<
Dec <<
getNumChildren() <<
" namespaces, "
214 << depth - 1U <<
" command slots, shared INTx" <<
Hex);
217bool NvmeController::createIoQueue() {
221 if (!command(m_Admin, request))
225 request.prp1 = m_Io.completionAddress();
226 request.cdw10 = 1U | ((m_Io.depth() - 1U) << 16);
228 if (!command(m_Admin, request))
232 request.prp1 = m_Io.submissionAddress();
233 request.cdw10 = 1U | ((m_Io.depth() - 1U) << 16);
234 request.cdw11 = 1U | (1U << 16);
235 return command(m_Admin, request);
237bool NvmeController::discoverNamespaces(uint32_t maximumId) {
238 uint32_t previous = 0;
241 for (
size_t page = 0; page < 1024; ++page) {
242 uint32_t ids[1024]{};
243 if (!identify(previous, 2, ids))
245 for (uint32_t nsid : ids) {
248 if (nsid <= previous || nsid > maximumId || nsid == 0xffffffffU)
251 auto* disk =
new NvmeDisk(
this, nsid);
252 if (disk->initialise())
258 ERROR(
"NVMe: active namespace list exceeds enumeration limit");
261NvmeDisk* NvmeController::findNamespace(uint32_t nsid) {
264 if (disk->namespaceId() == nsid)
269bool NvmeController::readWrite(uint32_t nsid, uint64_t lba, uint32_t blocks,
void* buffer,
270 size_t bytes,
bool writing) {
274 const NvmeDisk* disk = findNamespace(nsid);
275 if (!disk || !blocks || blocks > 65536 || bytes > m_MaxTransfer ||
276 blocks > (~
size_t{0} / disk->getNativeBlockSize()) ||
277 bytes != blocks * disk->getNativeBlockSize() || lba >= disk->getBlockCount() ||
278 blocks > disk->getBlockCount() - lba)
282 request.opcode = writing ? 1 : 2;
285 request.cdw11 = lba >> 32;
286 request.cdw12 = blocks - 1;
287 return command(m_Io, request, buffer, bytes, writing);
289bool NvmeController::flush(uint32_t nsid) {
291 if (!m_Commands.
tryAcquire(lease) || !findNamespace(nsid))
297 return command(m_Io, request);
304 return IrqDisposition::NotHandled;
305 const bool admin = m_Admin.complete(
true);
306 const bool io = m_Io.complete(
true);
307 return admin || io ? IrqDisposition::Handled : IrqDisposition::NotHandled;
309size_t NvmeController::interruptCompletions()
const {
310 return m_Admin.interruptCompletions() + m_Io.interruptCompletions();
312void NvmeController::shutdown() {
321 m_Interrupts =
false;
323 m_Registers->
write32(0xffffffffU, InterruptMaskSet);
325 if (m_Irq && !Machine::instance().getIrqManager()->unregisterHandler(m_Irq,
this))
326 panic(
"NVMe: synchronous interrupt retirement failed");
330 if (m_DmaInstalled && !m_Failed && (m_Registers->
read32(Status) & 1U)) {
331 m_Registers->
write32((m_Registers->
read32(Configuration) & ~(3U << 14)) | (1U << 14),
333 const auto deadline = Time::getTicks() + 30 * Time::Multiplier::Second;
334 while ((m_Registers->
read32(Status) & 12U) != 8U && Time::getTicks() < deadline)
335 Time::delay(Time::Multiplier::Millisecond);
336 if ((m_Registers->
read32(Status) & 12U) != 8U)
337 panic(
"NVMe: orderly shutdown notification timed out");
339 if (m_DmaInstalled && !disable())
340 panic(
"NVMe: cannot stop DMA during shutdown");
341 m_DmaInstalled =
false;
343 const uint16_t command =
344 m_HardwareOwned ? (m_OriginalCommand & ~4U) | 0x400U : m_OriginalCommand;
345 if (!PciBus::instance().updateCommand(m_Pci, 0x407U, command & 0x407U))
346 panic(
"NVMe: failed to verify PCI state during shutdown");
351size_t NvmeController::maximumOutstanding()
const {
352 return m_Io.maximumOutstanding();
void map(size_t forcedSize=0, bool bUser=false, bool bWriteCombine=false, bool bWriteThrough=false)
Device * getChild(size_t n)
virtual Vector< Address * > & addresses()
uint8_t getPciClassCode()
void addChild(Device *pDevice)
uint8_t getPciSubclassCode()
uint8_t getPciProgInterface()
virtual void write32(uint32_t value, size_t offset=0)=0
virtual uint32_t read32(size_t offset=0)=0
virtual size_t size() const =0
virtual irq_id_t registerPciIrqHandler(IrqHandler *handler, Device *pDevice, const IrqPolicy &policy)=0
IrqDisposition irq(irq_id_t number) override
MUST_USE_RESULT bool tryAcquire(Lease &lease)
void shutdownDiskCaches()
void EXPORTED_PUBLIC panic(const char *msg) NORETURN