dev/block: Add NVMe driver

This commit is contained in:
2026-10-29 01:50:52 +01:00
parent b52a3949a5
commit 49c454dd97
21 changed files with 2132 additions and 74 deletions
+84
View File
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: ISC
#pragma once
#include <zinnia/errno.h>
#include <zinnia/iovec.h>
#include <zinnia/types.h>
#include <stddef.h>
#include <stdint.h>
typedef uint64_t dma_addr_t;
constexpr dma_addr_t DMA_ADDR_MAX = UINT64_MAX;
struct bio;
struct dma_tag;
struct dma_ops {
errno_t (*map)(struct dma_tag* tag, phys_t phys, size_t len, dma_addr_t* out);
void (*unmap)(struct dma_tag* tag, dma_addr_t addr, size_t len);
};
struct dma_tag {
const struct dma_ops* ops;
void* priv;
dma_addr_t max_addr;
};
extern struct dma_tag dma_default_tag;
void dma_tag_subregion(struct dma_tag* parent, dma_addr_t max_addr, struct dma_tag* out);
struct dma_seg {
dma_addr_t addr;
size_t len;
};
struct dma_buffer {
struct dma_tag* tag;
phys_t phys;
dma_addr_t addr;
void* virt;
size_t len;
};
errno_t dma_buffer_alloc(struct dma_tag* tag, size_t len, struct dma_buffer* out);
void dma_buffer_free(struct dma_buffer* buf);
struct dma_map {
struct dma_tag* tag;
size_t size;
size_t max_segs;
size_t max_seg_size;
size_t boundary;
size_t mapped_len;
size_t num_segs;
struct dma_seg segs[];
};
enum dma_sync {
DMA_SYNC_PREREAD = 1 << 0,
DMA_SYNC_POSTREAD = 1 << 1,
DMA_SYNC_PREWRITE = 1 << 2,
DMA_SYNC_POSTWRITE = 1 << 3,
};
errno_t dma_map_create(
struct dma_tag* tag,
size_t size,
size_t max_segs,
size_t max_seg_size,
size_t boundary,
struct dma_map** out
);
void dma_map_destroy(struct dma_map* map);
errno_t dma_map_load(struct dma_map* map, void* buf, size_t len);
errno_t dma_map_load_bio(struct dma_map* map, struct bio* bio);
errno_t dma_map_load_iter(struct dma_map* map, const iovec_iter_t* iter);
void dma_map_unload(struct dma_map* map);
void dma_map_sync(struct dma_map* map, size_t offset, size_t len, enum dma_sync ops);
void dma_buffer_sync(struct dma_buffer* buf, size_t offset, size_t len, enum dma_sync ops);
+15
View File
@@ -5,13 +5,16 @@
#include <zinnia/compiler.h>
#include <zinnia/errno.h>
#include <zinnia/list.h>
#include <zinnia/spin.h>
#include <zinnia/types.h>
#include <zinnia/workqueue.h>
#include <stddef.h>
#include <stdint.h>
enum irq_status : uint8_t {
IRQ_STATUS_IGNORED,
IRQ_STATUS_HANDLED,
IRQ_STATUS_WAKE_THREAD,
};
enum irq_polarity : uint8_t {
@@ -29,9 +32,17 @@ enum irq_mode : uint8_t {
IRQ_MODE_MASKABLE = 1 << 1,
};
struct irq_line;
struct irq_handler {
enum irq_status (*raise)(struct irq_handler* self);
void (*thread)(struct irq_handler* self);
list_link(struct irq_handler*) next;
struct irq_line* line;
struct workqueue* wq;
struct work work;
bool holds_mask;
};
struct irq_line {
@@ -43,6 +54,9 @@ struct irq_line {
bool is_busy;
list_head(struct irq_handler*) handlers;
enum irq_mode mode;
enum irq_trigger_mode trigger;
struct spinlock thread_lock;
size_t threads_pending;
};
struct msi_line {
@@ -62,6 +76,7 @@ void irq_line_program(struct irq_line* line, enum irq_trigger_mode trigger, enum
void irq_line_raise(struct irq_line* line);
void irq_line_attach(struct irq_line* line, struct irq_handler* handler);
void irq_line_detach(struct irq_line* line, struct irq_handler* handler);
errno_t irq_line_attach_threaded(struct irq_line* line, struct irq_handler* handler, const char* name);
void irq_lock();
void irq_unlock();
+8
View File
@@ -4,6 +4,7 @@
#include <zinnia/alloc.h>
#include <zinnia/compiler.h>
#include <zinnia/dma.h>
#include <zinnia/errno.h>
#include <zinnia/initgraph.h>
#include <zinnia/print.h>
@@ -106,6 +107,7 @@ struct pci_device {
struct pci_access* access;
uint8_t header_type;
struct pci_driver* driver;
struct dma_tag* dma_tag;
};
uint8_t pci_read8(struct pci_device* dev, uint16_t offset);
@@ -137,6 +139,12 @@ uint8_t pci_cap_find(struct pci_device* dev, uint8_t id);
constexpr uint16_t PCI_ANY_ID = 0xffff;
constexpr uint8_t PCI_ANY_CLASS = 0xff;
struct irq_line;
errno_t pci_setup_msix(struct pci_device* dev, struct irq_line** out);
errno_t pci_setup_msi(struct pci_device* dev, struct irq_line** out);
errno_t pci_setup_irq(struct pci_device* dev, struct irq_line** out);
// Matches a device by ID and class.
struct pci_match {
uint16_t vendor_id;