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/machine/PciVirtualFunctions.h"
9#include "pedigree/kernel/panic.h"
10#include "pedigree/kernel/process/Scheduler.h"
11#include "pedigree/kernel/process/TerminationDeferral.h"
12#include "pedigree/kernel/processor/IoBase.h"
13#include "pedigree/kernel/processor/Processor.h"
14#include "pedigree/kernel/time/Time.h"
15#include "pedigree/kernel/utilities/new"
16#include "pedigree/kernel/utilities/utility.h"
19#include "modules/drivers/common/InterruptProbe.h"
23uint16_t readLe16(
const uint8_t* data) {
24 return data[0] | (uint16_t{data[1]} << 8);
26uint32_t readLe32(
const uint8_t* data) {
27 return readLe16(data) | (uint32_t{readLe16(data + 2)} << 16);
31NvmeController::NvmeController(
Device* pci)
37 m_ReadyMilliseconds(500),
38 m_MaxTransfer(MaxTransfer),
43 m_VirtualizationSupported(false),
44 m_NamespaceManagementSupported(false),
46 m_HardwareOwned(false),
47 m_DmaInstalled(false),
50 m_BatchInitialising(false),
55 setSpecificType(
String(
"nvme-controller"));
57NvmeController::~NvmeController() {
61bool NvmeController::waitReady(
bool ready) {
62 const auto deadline = Time::getTicks() + m_ReadyMilliseconds * Time::Multiplier::Millisecond;
64 const uint32_t status = m_Registers->
read32(Status);
65 if (status == 0xffffffffU || (ready && (status & 2U)))
67 if (
bool(status & 1U) == ready)
69 Time::delay(Time::Multiplier::Millisecond);
70 }
while (Time::getTicks() < deadline);
73bool NvmeController::disable() {
74 m_Registers->
write32(0xffffffffU, InterruptMaskSet);
75 m_Registers->
write32(m_Registers->
read32(Configuration) & ~(1U | (3U << 14)), Configuration);
76 (void)m_Registers->
read32(Configuration);
77 return waitReady(
false);
79void NvmeController::failController() {
85 m_Registers->
write32(0xffffffffU, InterruptMaskSet);
86 (void)m_Registers->
read32(InterruptMaskSet);
91 for (
auto* queue : m_Io) {
99 panic(
"NVMe: controller cannot stop DMA; refusing to release memory");
100 m_DmaInstalled =
false;
103bool NvmeController::command(
NvmeQueue& queue,
Command request,
void* buffer,
size_t bytes,
104 bool writing, uint32_t* result,
bool interruptProbe,
bool cacheFill,
105 physical_uintptr_t directWritePhysical) {
111 interrupts = m_Interrupts;
113 const size_t timeout = (&queue != &m_Admin && (request.opcode & 255U) == 0) ? 120 : 30;
115 queue.execute(request, buffer, bytes, writing, interrupts, timeout, result, interruptProbe,
116 cacheFill, directWritePhysical, &directReadMapping);
117 if (status == NvmeQueue::Result::TransportError)
119 return status == NvmeQueue::Result::Success;
121bool NvmeController::identify(uint32_t nsid, uint8_t kind,
void* buffer,
bool interruptProbe) {
128 request.cdw10 = kind;
129 return command(m_Admin, request, buffer, PageSize,
false,
nullptr, interruptProbe);
135 if (!m_Commands.
tryAcquire(lease) || !m_VirtualizationSupported) {
139 return primaryControllerCapabilitiesLocked(capabilities);
142bool NvmeController::primaryControllerCapabilitiesLocked(
144 uint8_t data[PageSize]{};
147 request.cdw10 = 0x14U | (uint32_t{m_ControllerId} << 16);
148 if (!command(m_Admin, request, data,
sizeof(data)) || readLe16(data) != m_ControllerId) {
151 capabilities.controllerId = readLe16(data);
152 capabilities.portId = readLe16(data + 2);
153 capabilities.resourceTypes = data[4] & 3U;
155 for (
size_t i = 0; i < 2; ++i) {
156 const uint8_t* resource = data + 32 + (32 * i);
157 *resources[i] = {readLe32(resource), readLe32(resource + 4), readLe16(resource + 8),
158 readLe16(resource + 10), readLe16(resource + 12), readLe16(resource + 14)};
163bool NvmeController::secondaryControllers(uint16_t firstControllerId,
167 if (!m_Commands.
tryAcquire(lease) || !m_VirtualizationSupported) {
171 return secondaryControllersLocked(firstControllerId, controllers);
174bool NvmeController::secondaryControllersLocked(uint16_t firstControllerId,
176 uint8_t data[PageSize]{};
179 request.cdw10 = 0x15U | (uint32_t{firstControllerId} << 16);
180 if (!command(m_Admin, request, data,
sizeof(data)) || data[0] > 127) {
183 for (
size_t i = 0; i < data[0]; ++i) {
184 const uint8_t* entry = data + 32 + (32 * i);
185 const uint16_t
id = readLe16(entry);
186 if (
id < firstControllerId ||
id == m_ControllerId || readLe16(entry + 2) != m_ControllerId) {
190 controllers.entries[i] = {id,
194 readLe16(entry + 10),
195 readLe16(entry + 12)};
197 controllers.count = data[0];
201bool NvmeController::virtualizationManagement(uint16_t controllerId, VirtualResource resource,
202 VirtualizationAction action, uint16_t count,
203 uint16_t* modified) {
207 if ((resource != VirtualResource::Queue && resource != VirtualResource::Interrupt) ||
208 (action != VirtualizationAction::AllocatePrimary && action != VirtualizationAction::Offline &&
209 action != VirtualizationAction::Assign && action != VirtualizationAction::Online) ||
210 ((action == VirtualizationAction::Offline || action == VirtualizationAction::Online) &&
215 if (!m_Commands.
tryAcquire(lease) || !m_VirtualizationSupported) {
219 if (action == VirtualizationAction::AllocatePrimary) {
220 if (controllerId != m_ControllerId) {
225 if (controllerId == m_ControllerId || !secondaryControllersLocked(controllerId, controllers)) {
229 for (
size_t i = 0; i < controllers.count; ++i) {
230 if (controllers.entries[i].controllerId == controllerId) {
231 target = &controllers.entries[i];
235 if (!target || (action == VirtualizationAction::Assign && target->online)) {
239 if (action == VirtualizationAction::AllocatePrimary || action == VirtualizationAction::Assign) {
241 if (!primaryControllerCapabilitiesLocked(capabilities) ||
242 !(capabilities.resourceTypes & (1U <<
static_cast<unsigned>(resource)))) {
246 resource == VirtualResource::Queue ? capabilities.queues : capabilities.interrupts;
247 if (count > limits.flexibleTotal ||
248 (action == VirtualizationAction::Assign && count > limits.secondaryMaximum)) {
253 request.opcode = 0x1c;
254 request.cdw10 = (uint32_t{controllerId} << 16) | (
static_cast<uint32_t
>(resource) << 8) |
255 static_cast<uint32_t
>(action);
256 request.cdw11 = count;
258 if (!command(m_Admin, request,
nullptr, 0,
false, &result)) {
262 (action == VirtualizationAction::AllocatePrimary || action == VirtualizationAction::Assign)) {
263 *modified = result & 0xffffU;
268bool NvmeController::setNamespaceAttachment(uint32_t nsid, uint16_t controllerId,
bool attached) {
269 if (!nsid || nsid == 0xffffffffU) {
273 if (!m_Commands.
tryAcquire(lease) || !m_NamespaceManagementSupported) {
277 if (controllerId == m_ControllerId && findNamespace(nsid)) {
280 uint8_t controllers[PageSize]{};
282 controllers[2] = controllerId;
283 controllers[3] = controllerId >> 8;
285 request.opcode = 0x15;
287 request.cdw10 = attached ? 0 : 1;
288 return command(m_Admin, request, controllers,
sizeof(controllers),
true);
291bool NvmeController::initialiseController() {
295 auto& pci = PciBus::instance();
297 if (!pci.inspectFunction(m_Pci, inherited,
false)) {
298 ERROR(
"NVMe: unsupported PCI state (D0 and valid capabilities required)");
301 m_OriginalCommand = inherited.command;
302 const bool virtualFunction = m_Pci->getPhysicalFunction() !=
nullptr;
303 uint64_t base = 0, assignedBytes = 0;
304 if (virtualFunction) {
305 if (!PciVirtualFunctions::bar(m_Pci, 0, base, assignedBytes)) {
309 const uint32_t bar = pci.readConfigSpace(m_Pci, 4);
310 if ((bar & 1U) || ((bar & 6U) != 0 && (bar & 6U) != 4)) {
314 if ((bar & 6U) == 4) {
315 base |=
static_cast<uint64_t
>(pci.readConfigSpace(m_Pci, 5)) << 32;
319 for (
auto* address : m_Pci->
addresses()) {
320 if (address->m_Name !=
"bar0" || !base || !address->m_Address || address->m_IsIoSpace ||
321 (virtualFunction && address->m_Size != assignedBytes)) {
324 uint64_t cpuPhysical = 0;
325 if (!pci.translateAddress(base, address->m_Size,
false, cpuPhysical) ||
326 address->m_Address != cpuPhysical) {
331 if (!mapping || mapping->
m_Size < Doorbells + 16)
334 if (!pci.updateCommand(m_Pci, 0, 2U | 0x400U))
337 m_Registers = mapping->
m_Io;
338 if (!m_Registers || m_Registers->
size() < mapping->
m_Size)
340 const uint32_t version = m_Registers->
read32(Version);
342 m_Registers->
read32(Cap) | (
static_cast<uint64_t
>(m_Registers->
read32(Cap + 4)) << 32);
345 if (version < 0x00010100 || version == 0xffffffffU || !(cap & (1ULL << 37)) ||
348 const size_t stride =
size_t{4} << ((cap >> 32) & 15U);
349 if (mapping->
m_Size < Doorbells + 3 * stride + 4)
351 m_ReadyMilliseconds = (((cap >> 24) & 255U) + 1) * 500;
352 m_HardwareOwned =
true;
357 if (!pci.updateCommand(m_Pci, 4U, 2U | 0x400U) ||
358 !pci.disableMessageInterrupts(m_Pci, inherited) ||
359 !pci.resourcesUnchanged(m_Pci, inherited)) {
362 if (pci.attachIsolatedDma(m_Pci)) {
364 m_DmaIsolated = !virtualFunction;
365 NOTICE(
"NVMe: using isolated DMA domain");
366 }
else if (virtualFunction) {
367 ERROR(
"NVMe: virtual function requires isolated DMA");
370 (void)pci.attachDmaRemapping(m_Pci);
372 const uint16_t depth = (cap & 0xffffU) >= QueueDepth - 1 ? QueueDepth : (cap & 0xffffU) + 1;
373 if (!m_Admin.initialise(m_Registers, 0, depth, stride, PageSize, m_Pci))
375 m_Registers->
write32((depth - 1U) | ((depth - 1U) << 16), AdminAttributes);
376 m_Registers->
write32(m_Admin.submissionAddress(), AdminSubmission);
377 m_Registers->
write32(m_Admin.submissionAddress() >> 32, AdminSubmission + 4);
378 m_Registers->
write32(m_Admin.completionAddress(), AdminCompletion);
379 m_Registers->
write32(m_Admin.completionAddress() >> 32, AdminCompletion + 4);
381 m_DmaInstalled =
true;
382 if (!pci.updateCommand(m_Pci, 0, 6U | 0x400U))
384 m_Registers->
write32(1U | (6U << 16) | (4U << 20), Configuration);
385 if (!waitReady(
true))
387 uint8_t controller[PageSize]{};
388 if (!identify(0, 1, controller))
390 m_ControllerId = readLe16(controller + 78);
391 m_VirtualizationSupported = (readLe16(controller + 256) & (1U << 7)) != 0;
392 m_NamespaceManagementSupported = (readLe16(controller + 256) & (1U << 3)) != 0;
393 if ((controller[512] & 15U) > 6 || (controller[512] >> 4) < 6 || (controller[513] & 15U) > 4 ||
394 (controller[513] >> 4) < 4)
396 const uint8_t mdts = controller[77];
397 if (mdts && mdts < 4)
398 m_MaxTransfer = PageSize << mdts;
399 for (
size_t i = 0; i < 40; ++i) {
400 const uint8_t ch = controller[24 + i];
401 m_Model[i] = ch >= 32 && ch <= 126 ? ch :
' ';
404 while (length && m_Model[length - 1] ==
' ')
407 const uint32_t maximumId = controller[516] | (uint32_t{controller[517]} << 8) |
408 (uint32_t{controller[518]} << 16) | (uint32_t{controller[519]} << 24);
409 bool activeNamespaces =
false;
410 if (maximumId && !discoverNamespaces(maximumId, activeNamespaces)) {
413 if (!
getNumChildren() && (activeNamespaces || virtualFunction || !m_VirtualizationSupported)) {
416 size_t requestedQueues = 0;
418 for (
size_t cpu = 0; cpu <
Processor::getCount() && requestedQueues < MaxIoQueues; ++cpu) {
419 if (online.contains(cpu)) {
420 m_IoProcessor[requestedQueues++] = cpu;
423 if (!requestedQueues) {
425 m_IoProcessor[0] = 0;
427 uint16_t msixControl = 0;
428 const size_t messageCount =
429 inherited.msix && pci.readConfig16(m_Pci, inherited.msix + 2, msixControl)
430 ? (msixControl & 0x7ffU) + 1U
432 if (requestedQueues > (messageCount > 1 ? messageCount - 1 : 1)) {
433 requestedQueues = messageCount > 1 ? messageCount - 1 : 1;
436 const size_t doorbellQueues = ((mapping->
m_Size - Doorbells - 4) / stride - 1) / 2;
437 if (requestedQueues > doorbellQueues) {
438 requestedQueues = doorbellQueues;
444 request.cdw11 = (requestedQueues - 1) | ((requestedQueues - 1) << 16);
445 uint32_t granted = 0;
446 if (!command(m_Admin, request,
nullptr, 0,
false, &granted)) {
449 m_IoCount = requestedQueues;
450 const size_t submissionQueues = (granted & 0xffffU) + 1U;
451 const size_t completionQueues = (granted >> 16) + 1U;
452 if (m_IoCount > submissionQueues) {
453 m_IoCount = submissionQueues;
455 if (m_IoCount > completionQueues) {
456 m_IoCount = completionQueues;
459 IrqManager* irqManager = Machine::instance().getIrqManager();
461 size_t processors[MaxIoQueues + 1] = {};
462 for (
size_t i = 0; i < MaxIoQueues + 1; ++i) {
465 processors[i] = m_IoProcessor[i - 1];
468 size_t vectorCount = m_IoCount && messageCount > 1 ? m_IoCount + 1 : 1;
471 m_BatchInitialising =
true;
474 irq_id_t vectors[MaxIoQueues + 1] = {};
475 bool fallbackSafe =
true;
480 for (
size_t i = 1; i < vectorCount; ++i) {
481 m_IoIrq[i - 1] = vectors[i];
483 NOTICE(
"NVMe: MSI-X vectors=" <<
Dec << vectorCount <<
", I/O queues=" << m_IoCount <<
Hex);
487 ERROR(
"NVMe: MSI-X setup failed without a safe fallback");
490 if (vectorCount == 1) {
492 m_BatchInitialising =
false;
497 vectorCount = m_IoCount + 1;
502 uint16_t ioDepth = depth;
503 if (m_IoCount && ioDepth > MaxIoSlots / m_IoCount + 1) {
504 ioDepth = MaxIoSlots / m_IoCount + 1;
506 for (
size_t i = 0; i < m_IoCount; ++i) {
508 if (!queue->initialise(m_Registers, i + 1, ioDepth, stride, m_MaxTransfer, m_Pci)) {
522 if (!createIoQueue(i, m_IoIrq[i] ? i + 1 : 0)) {
530 ERROR(
"NVMe: could not register PCI interrupt");
536 m_BatchInitialising =
false;
537 if (!pci.updateCommand(m_Pci, 0x400U, 6U))
539 m_Registers->
write32(1, InterruptMaskClear);
540 (void)m_Registers->
read32(Status);
542 if (!InterruptProbe::run([&] {
return identify(0, 1, controller,
true); },
543 [&] {
return m_Admin.interruptCompletions(); })) {
544 ERROR(
"NVMe: interrupt delivery probe failed");
547 for (
size_t i = 0; i < m_IoCount; ++i) {
550 if (!InterruptProbe::run(
551 [&] {
return command(*m_Io[i], flush,
nullptr, 0,
false,
nullptr,
true); },
552 [&] {
return m_Io[i]->interruptCompletions(); })) {
553 ERROR(
"NVMe: I/O vector delivery probe failed for queue " <<
Dec << i + 1 <<
Hex);
559 NOTICE(
"NVMe: '" << m_Model <<
"' ready, " <<
Dec <<
getNumChildren() <<
" namespaces, "
560 << m_IoCount <<
" I/O queues, " << ioDepth - 1U <<
" slots per queue" <<
Hex);
563bool NvmeController::createIoQueue(
size_t index, uint16_t interruptVector) {
565 const uint16_t
id = index + 1;
568 request.prp1 = queue.completionAddress();
569 request.cdw10 =
id | ((queue.depth() - 1U) << 16);
570 request.cdw11 = 3U | (uint32_t(interruptVector) << 16);
571 if (!command(m_Admin, request)) {
576 request.prp1 = queue.submissionAddress();
577 request.cdw10 =
id | ((queue.depth() - 1U) << 16);
578 request.cdw11 = 1U | (uint32_t(
id) << 16);
579 return command(m_Admin, request);
583 for (
size_t i = 0; i < m_IoCount; ++i) {
584 if (m_IoProcessor[i] == cpu) {
588 return *m_Io[cpu % m_IoCount];
590bool NvmeController::discoverNamespaces(uint32_t maximumId,
bool& activeNamespaces) {
591 activeNamespaces =
false;
592 uint32_t previous = 0;
595 for (
size_t page = 0; page < 1024; ++page) {
596 uint32_t ids[1024]{};
597 if (!identify(previous, 2, ids))
599 for (uint32_t nsid : ids) {
602 if (nsid <= previous || nsid > maximumId || nsid == 0xffffffffU)
604 activeNamespaces =
true;
606 auto* disk =
new NvmeDisk(
this, nsid);
607 if (disk->initialise())
613 ERROR(
"NVMe: active namespace list exceeds enumeration limit");
616NvmeDisk* NvmeController::findNamespace(uint32_t nsid) {
619 if (disk->namespaceId() == nsid)
624bool NvmeController::readWrite(uint32_t nsid, uint64_t lba, uint32_t blocks,
void* buffer,
625 size_t bytes,
bool writing) {
626 return readWrite(nsid, lba, blocks, buffer, bytes, writing,
false);
628bool NvmeController::readWrite(uint32_t nsid, uint64_t lba, uint32_t blocks,
void* buffer,
629 size_t bytes,
bool writing,
bool cacheFill,
630 physical_uintptr_t directWritePhysical) {
634 const NvmeDisk* disk = findNamespace(nsid);
635 if (!disk || !blocks || blocks > 65536 || bytes > m_MaxTransfer ||
638 blocks > disk->getBlockCount() - lba)
642 request.opcode = writing ? 1 : 2;
645 request.cdw11 = lba >> 32;
646 request.cdw12 = blocks - 1;
647 return command(ioQueue(), request, buffer, bytes, writing,
nullptr,
false, cacheFill,
648 directWritePhysical);
650bool NvmeController::flush(uint32_t nsid) {
652 if (!m_Commands.
tryAcquire(lease) || !findNamespace(nsid))
658 return command(ioQueue(), request);
668 if (!m_Interrupts && !m_BatchInitialising) {
669 return IrqDisposition::NotHandled;
671 if (m_BatchInitialising || !m_IoIrq[0]) {
672 queues[count++] = &m_Admin;
673 for (
auto* queue : m_Io) {
675 queues[count++] = queue;
678 }
else if (
id == m_Irq) {
679 queues[count++] = &m_Admin;
681 for (
size_t i = 0; i < MaxIoQueues; ++i) {
682 if (
id == m_IoIrq[i] && m_Io[i]) {
683 queues[count++] = m_Io[i];
691 bool handled =
false;
692 for (
size_t i = 0; i < count; ++i) {
693 handled |= queues[i]->complete(
true);
695 return handled ? IrqDisposition::Handled : IrqDisposition::NotHandled;
697size_t NvmeController::interruptCompletions()
const {
698 size_t completions = m_Admin.interruptCompletions();
699 for (
size_t i = 0; i < m_IoCount; ++i) {
700 completions += m_Io[i]->interruptCompletions();
704size_t NvmeController::ioQueueInterruptCompletions(
size_t queue)
const {
705 return queue < m_IoCount ? m_Io[queue]->interruptCompletions() : 0;
707void NvmeController::shutdown() {
716 m_Interrupts =
false;
718 m_Registers->
write32(0xffffffffU, InterruptMaskSet);
720 if (m_Irq && !Machine::instance().getIrqManager()->unregisterHandler(m_Irq,
this))
721 panic(
"NVMe: synchronous interrupt retirement failed");
723 for (
auto&
irq : m_IoIrq) {
724 if (
irq && !Machine::instance().getIrqManager()->unregisterHandler(
irq,
this)) {
725 panic(
"NVMe: synchronous I/O vector retirement failed");
730 for (
auto* queue : m_Io) {
735 if (m_DmaInstalled && !m_Failed && (m_Registers->
read32(Status) & 1U)) {
736 m_Registers->
write32((m_Registers->
read32(Configuration) & ~(3U << 14)) | (1U << 14),
738 const auto deadline = Time::getTicks() + 30 * Time::Multiplier::Second;
739 while ((m_Registers->
read32(Status) & 12U) != 8U && Time::getTicks() < deadline)
740 Time::delay(Time::Multiplier::Millisecond);
741 if ((m_Registers->
read32(Status) & 12U) != 8U)
742 panic(
"NVMe: orderly shutdown notification timed out");
744 if (m_DmaInstalled && !disable())
745 panic(
"NVMe: cannot stop DMA during shutdown");
746 m_DmaInstalled =
false;
748 const uint16_t command =
749 m_HardwareOwned ? (m_OriginalCommand & ~4U) | 0x400U : m_OriginalCommand;
750 if (!PciBus::instance().updateCommand(m_Pci, 0x407U, command & 0x407U))
751 panic(
"NVMe: failed to verify PCI state during shutdown");
754 for (
auto*& queue : m_Io) {
763 if (!PciBus::instance().detachIsolatedDma(m_Pci)) {
764 panic(
"NVMe: failed to retire isolated DMA domain");
766 m_DmaIsolated =
false;
771size_t NvmeController::maximumOutstanding()
const {
773 for (
size_t i = 0; i < m_IoCount; ++i) {
774 const size_t outstanding = m_Io[i]->maximumOutstanding();
775 if (outstanding > maximum) {
776 maximum = outstanding;
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 registerPciMessageIrqHandler(IrqHandler *handler, Device *pDevice, const IrqPolicy &intxFallbackPolicy)
virtual bool registerPciMsixIrqHandlers(Device *device, IrqHandler *const *handlers, size_t count, irq_id_t *ids, bool &fallbackSafe, const size_t *processors=nullptr)
IrqDisposition irq(irq_id_t number) override
size_t getNativeBlockSize() const override
MUST_USE_RESULT bool tryAcquire(Lease &lease)
void shutdownDiskCaches(bool deviceAvailable=true)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN