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