Add basic xHCI driver and USB devices enumeration
This commit is contained in:
+15
-38
@@ -1,10 +1,10 @@
|
||||
#include "src/kernel/nvme.h"
|
||||
#include "src/kernel/log.h"
|
||||
#include "src/kernel/memory.h"
|
||||
#include "src/kernel/panic.h"
|
||||
#include "src/kernel/pci.h"
|
||||
#include "src/lib/layout.h"
|
||||
#include "src/lib/memory.h"
|
||||
#include "src/lib/util.h"
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
@@ -41,8 +41,8 @@ typedef volatile struct __attribute__((packed)) {
|
||||
#define NVME_REGS_ASQS_R(r) BITS_R(r->aqa, 11, 0)
|
||||
#define NVME_REGS_ASQS_W(r, v) BITS_W(r->aqa, 11, 0, v)
|
||||
|
||||
static nvme_regs_t *regs = (nvme_regs_t *)(KERNEL_VIRTUAL_BASE + MEMORY_SIZE);
|
||||
static volatile uint32_t *db_regs = (uint32_t *)(KERNEL_VIRTUAL_BASE + MEMORY_SIZE + 0x1000); // TODO Get stride from caps.
|
||||
static nvme_regs_t *regs = (nvme_regs_t *)KERNEL_VIRTUAL_NVME;
|
||||
static volatile uint32_t *db_regs = (uint32_t *)(KERNEL_VIRTUAL_NVME + 0x1000); // TODO Get stride from caps.
|
||||
|
||||
#define QUEUE_DEPTH 2
|
||||
|
||||
@@ -140,7 +140,7 @@ static void io_exec_sync(nvme_sqe_t *cmd) {
|
||||
memory_copy(cmd, sizeof(nvme_sqe_t), &io_sq[io_sq_tail]);
|
||||
|
||||
TRACE_LN("Advancing submission doorbell...");
|
||||
db_regs[2] = io_sq_tail = (io_sq_tail + 1) % QUEUE_DEPTH; // TODO Get offset from caps.
|
||||
db_regs[2] = io_sq_tail = (io_sq_tail + 1) % QUEUE_DEPTH;
|
||||
|
||||
TRACE_LN("Waiting for completion...");
|
||||
nvme_cqe_t *cmp = &io_cq[io_cq_head];
|
||||
@@ -165,46 +165,23 @@ static void io_exec_sync(nvme_sqe_t *cmd) {
|
||||
}
|
||||
|
||||
void nvme_init() {
|
||||
LOG_LN("Searching for suitable device...");
|
||||
uint8_t found = 0;
|
||||
for (uint16_t bus = 0; bus < PCI_MAX_BUSES && !found; bus++) {
|
||||
for (uint8_t device = 0; device < PCI_MAX_DEVICES && !found; device++) {
|
||||
for (uint8_t function = 0; function < PCI_MAX_FUNCTIONS && !found; function++) {
|
||||
uint32_t id = pci_read((uint8_t)bus, device, function, PCI_OFFSET_DEVICE_VENDOR);
|
||||
if (PCI_DEVICE(id) == PCI_DEVICE_EMPTY) {
|
||||
continue;
|
||||
}
|
||||
uint32_t class = pci_read((uint8_t)bus, device, function, PCI_OFFSET_CLASS_REVISION);
|
||||
if (PCI_CLASS(class) != NVME_PCI_CLASS || PCI_CLASS_SUB(class) != NVME_PCI_SUBCLASS) {
|
||||
continue;
|
||||
}
|
||||
TRACE_LN("Searching for suitable device...");
|
||||
pci_bdf_t bdf = pci_find_by_class(NVME_PCI_CLASS, NVME_PCI_SUBCLASS, NUL);
|
||||
ASSERT(bdf, "nvme_init: No suitable devices found.");
|
||||
|
||||
LOG_LN("Found device, %hx:%hx.", PCI_VENDOR(id), PCI_DEVICE(id));
|
||||
|
||||
uint64_t bar = pci_bar((uint8_t)bus, device, function);
|
||||
LOG_LN("Mapping device to memory, phys %lx <-> virt %lx...", bar, regs);
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
memory_page_map((void *)KERNEL_VIRTUAL_PML4, (void *)((uint8_t *)regs + i * PAGE_SIZE), (void *)((uint8_t *)bar + i * PAGE_SIZE),
|
||||
PAGE_WRITABLE | PAGE_PCD | PAGE_USER);
|
||||
}
|
||||
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(found, "nvme_init: No suitable devices found.");
|
||||
TRACE_LN("Mapping device to virtual memory...");
|
||||
pci_map(bdf, regs, 4);
|
||||
ASSERT(NVME_REGS_NVME_CS_SUPPORTED(regs), "nvme_init: NVM command set not supported.");
|
||||
ASSERT(QUEUE_DEPTH <= NVME_REGS_MQES(regs), "nvme_init: Command queues are too big.")
|
||||
|
||||
LOG_LN("Disabling device...");
|
||||
TRACE_LN("Disabling device...");
|
||||
regs->cc = 0;
|
||||
TRACE_VAL_F(regs->cc, "%lx");
|
||||
while (NVME_REGS_RDY(regs))
|
||||
;
|
||||
TRACE_VAL_F(regs->cc, "%lx");
|
||||
|
||||
LOG_LN("Configuring device...");
|
||||
TRACE_LN("Configuring device...");
|
||||
NVME_REGS_ASQS_W(regs, QUEUE_DEPTH - 1);
|
||||
regs->asq = (uint64_t)(VIRT_TO_PHYS(admin_sq));
|
||||
NVME_REGS_ACQS_W(regs, QUEUE_DEPTH - 1);
|
||||
@@ -213,7 +190,7 @@ void nvme_init() {
|
||||
TRACE_VAL_F(regs->acq, "%lx");
|
||||
TRACE_VAL_F(regs->aqa, "%lx");
|
||||
|
||||
LOG_LN("Enabling device...");
|
||||
TRACE_LN("Enabling device...");
|
||||
NVME_REGS_IOCQES_W(regs, 4);
|
||||
NVME_REGS_IOSQES_W(regs, 6);
|
||||
NVME_REGS_CSS_W(regs, 0);
|
||||
@@ -223,7 +200,7 @@ void nvme_init() {
|
||||
;
|
||||
TRACE_VAL_F(regs->cc, "%lx");
|
||||
|
||||
LOG_LN("Creating I/O completion queue...");
|
||||
TRACE_LN("Creating I/O completion queue...");
|
||||
nvme_sqe_t create_io_cq = {
|
||||
.opc = 0x05,
|
||||
.prp1 = (uint64_t)VIRT_TO_PHYS(io_cq),
|
||||
@@ -232,7 +209,7 @@ void nvme_init() {
|
||||
};
|
||||
admin_exec_sync(&create_io_cq);
|
||||
|
||||
LOG_LN("Creating I/O submission queue...");
|
||||
TRACE_LN("Creating I/O submission queue...");
|
||||
nvme_sqe_t create_io_sq = {
|
||||
.opc = 0x01,
|
||||
.prp1 = (uint64_t)VIRT_TO_PHYS(io_sq),
|
||||
@@ -241,7 +218,7 @@ void nvme_init() {
|
||||
};
|
||||
admin_exec_sync(&create_io_sq);
|
||||
|
||||
LOG_LN("Done.");
|
||||
TRACE_LN("Done.");
|
||||
}
|
||||
|
||||
void nvme_read_sectors(uint32_t index, uint8_t count, void *to) {
|
||||
|
||||
Reference in New Issue
Block a user