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
+60 -1
View File
@@ -5,6 +5,8 @@
#include <zinnia/list.h>
#include <zinnia/percpu.h>
#include <zinnia/print.h>
#include <zinnia/sched.h>
#include <zinnia/utils.h>
#include <arch/cpu.h>
#include <arch/irq.h>
@@ -39,9 +41,43 @@ void irq_unlock() {
void irq_line_program(struct irq_line* line, enum irq_trigger_mode trigger, enum irq_polarity polarity) {
irq_lock();
line->mode = line->set_config(line, trigger, polarity);
line->trigger = trigger;
irq_unlock();
}
static bool holds_mask_while_threaded(struct irq_line* line) {
return line->trigger == IRQ_TRIGGER_LEVEL && (line->mode & IRQ_MODE_MASKABLE) && line->mask && line->unmask;
}
static void wake_thread(struct irq_line* line, struct irq_handler* handler) {
if (holds_mask_while_threaded(line)) {
spin_lock(&line->thread_lock);
if (!handler->holds_mask) {
handler->holds_mask = true;
if (line->threads_pending++ == 0)
line->mask(line);
}
spin_unlock(&line->thread_lock);
}
work_queue(handler->wq, &handler->work);
}
static void irq_thread_work(struct work* work) {
struct irq_handler* handler = containerof(work, struct irq_handler, work);
struct irq_line* line = handler->line;
handler->thread(handler);
spin_lock(&line->thread_lock);
if (handler->holds_mask) {
handler->holds_mask = false;
if (--line->threads_pending == 0)
line->unmask(line);
}
spin_unlock(&line->thread_lock);
}
void irq_line_raise(struct irq_line* line) {
assert(!arch_irq_get_state(), "Raised an IRQ line with interrupts enabled");
@@ -51,8 +87,13 @@ void irq_line_raise(struct irq_line* line) {
bool claimed = false;
struct irq_handler* handler;
list_foreach(handler, &line->handlers, next) {
if (handler->raise(handler) == IRQ_STATUS_HANDLED)
enum irq_status status = handler->raise ? handler->raise(handler) : IRQ_STATUS_WAKE_THREAD;
if (status == IRQ_STATUS_WAKE_THREAD && handler->wq) {
wake_thread(line, handler);
claimed = true;
} else if (status != IRQ_STATUS_IGNORED) {
claimed = true;
}
}
if (!claimed)
@@ -83,3 +124,21 @@ void irq_line_detach(struct irq_line* line, struct irq_handler* handler) {
while (__atomic_load_n(&line->is_busy, __ATOMIC_ACQUIRE))
arch_cpu_pause();
}
errno_t irq_line_attach_threaded(struct irq_line* line, struct irq_handler* handler, const char* name) {
if (!handler->thread)
return EINVAL;
char task_name[TASK_NAME_MAX];
ksnprintf(task_name, sizeof(task_name), "irq/%s", name);
handler->line = line;
work_init(&handler->work, irq_thread_work);
handler->holds_mask = false;
errno_t status = workqueue_create(task_name, SCHED_PRIO_IRQ, &handler->wq);
if (status)
return status;
irq_line_attach(line, handler);
return 0;
}