dev/block: Add NVMe driver
This commit is contained in:
@@ -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);
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user