idedrv Full asynchronous reading/writing, process suspension
This commit is contained in:
@@ -106,6 +106,19 @@ static void ide_delay(uint16_t ctrl) {
|
||||
}
|
||||
#pragma clang optimize on
|
||||
|
||||
static int ide_flush(struct idedrv* idedrv) {
|
||||
uint8_t ctrl = inb(idedrv->ctrl);
|
||||
ctrl |= 0x02;
|
||||
outb(idedrv->ctrl, ctrl);
|
||||
|
||||
if (idedrv->lba48)
|
||||
outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH48);
|
||||
else
|
||||
outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH28);
|
||||
|
||||
return ST_OK;
|
||||
}
|
||||
|
||||
static void ide_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rctx) {
|
||||
(void)user, (void)regs, (void)rctx;
|
||||
|
||||
@@ -123,6 +136,18 @@ static void ide_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rct
|
||||
if ((status & (IDE_ERR | IDE_DF))) {
|
||||
atomic_store(&req->done, 1);
|
||||
idedrv->current_req = NULL;
|
||||
|
||||
struct list_node_link* node = idedrv->sq.proc_list;
|
||||
|
||||
if (node != NULL) {
|
||||
struct proc_sq_entry* sq_entry = list_entry(node, struct proc_sq_entry, sq_link);
|
||||
struct proc* proc = sq_entry->proc;
|
||||
|
||||
free(req);
|
||||
|
||||
int status = req->type == IDE_READ ? -ST_XDRV_READ_ERROR : -ST_XDRV_WRITE_ERROR;
|
||||
proc_sq_resume(proc, sq_entry, rctx, (uintptr_t)status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,6 +165,20 @@ static void ide_irq(void* arg, void* regs, bool user, struct reschedule_ctx* rct
|
||||
if ((req->sector_done_count >= req->sector_count)) {
|
||||
atomic_store(&req->done, 1);
|
||||
idedrv->current_req = NULL;
|
||||
|
||||
if (req->type == IDE_WRITE)
|
||||
ide_flush(idedrv);
|
||||
|
||||
struct list_node_link* node = idedrv->sq.proc_list;
|
||||
|
||||
if (node != NULL) {
|
||||
struct proc_sq_entry* sq_entry = list_entry(node, struct proc_sq_entry, sq_link);
|
||||
struct proc* proc = sq_entry->proc;
|
||||
|
||||
free(req);
|
||||
|
||||
proc_sq_resume(proc, sq_entry, rctx, (uintptr_t)ST_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +358,8 @@ DEFINE_DEVICE_FINI(idedrv_fini) {
|
||||
free(idedrv);
|
||||
}
|
||||
|
||||
static int idedrv_do_read_irqs(struct idedrv* idedrv, size_t sector, size_t sector_count,
|
||||
static int idedrv_do_read_irqs(struct idedrv* idedrv, struct proc* proc,
|
||||
struct reschedule_ctx* rctx, size_t sector, size_t sector_count,
|
||||
void* buffer) {
|
||||
struct idedrv_request* req = malloc(sizeof(*req));
|
||||
|
||||
@@ -339,14 +379,18 @@ static int idedrv_do_read_irqs(struct idedrv* idedrv, size_t sector, size_t sect
|
||||
uint8_t cmd = idedrv->lba48 ? IDE_CMD_READ48 : IDE_CMD_READ28;
|
||||
outb(idedrv->io + IDE_REG_CMD, cmd);
|
||||
|
||||
biglock_unlock();
|
||||
if ((proc->flags & PROC_KPROC)) {
|
||||
biglock_unlock();
|
||||
|
||||
while (!atomic_load(&req->done))
|
||||
spin_lock_relax();
|
||||
while (!atomic_load(&req->done))
|
||||
spin_lock_relax();
|
||||
|
||||
biglock_lock();
|
||||
biglock_lock();
|
||||
|
||||
free(req);
|
||||
free(req);
|
||||
} else {
|
||||
proc_sq_suspend(proc, &idedrv->sq, rctx, NULL, NULL);
|
||||
}
|
||||
|
||||
return ST_OK;
|
||||
}
|
||||
@@ -448,12 +492,13 @@ DEFINE_DEVICE_OP(idedrv_read) {
|
||||
return -ST_XDRV_READ_ERROR;
|
||||
|
||||
if (idedrv->irqs_support)
|
||||
return idedrv_do_read_irqs(idedrv, sector, sector_count, buffer);
|
||||
return idedrv_do_read_irqs(idedrv, proc, rctx, sector, sector_count, buffer);
|
||||
else
|
||||
return idedrv_do_read_no_irqs(idedrv, sector, sector_count, buffer);
|
||||
}
|
||||
|
||||
static int idedrv_do_write_irqs(struct idedrv* idedrv, size_t sector, size_t sector_count,
|
||||
static int idedrv_do_write_irqs(struct idedrv* idedrv, struct proc* proc,
|
||||
struct reschedule_ctx* rctx, size_t sector, size_t sector_count,
|
||||
void* buffer) {
|
||||
struct idedrv_request* req = malloc(sizeof(*req));
|
||||
|
||||
@@ -479,18 +524,24 @@ static int idedrv_do_write_irqs(struct idedrv* idedrv, size_t sector, size_t sec
|
||||
return -ST_XDRV_WRITE_ERROR;
|
||||
}
|
||||
|
||||
outsw(idedrv->io + IDE_REG_DATA, buffer, idedrv->sector_size / 2);
|
||||
|
||||
req->sector_done_count = 1;
|
||||
|
||||
biglock_unlock();
|
||||
if (!(proc->flags & PROC_KPROC)) {
|
||||
proc_sq_suspend(proc, &idedrv->sq, rctx, NULL, NULL);
|
||||
}
|
||||
|
||||
while (!atomic_load(&req->done))
|
||||
spin_lock_relax();
|
||||
outsw(idedrv->io + IDE_REG_DATA, buffer, idedrv->sector_size / 2);
|
||||
|
||||
biglock_lock();
|
||||
if ((proc->flags & PROC_KPROC)) {
|
||||
biglock_unlock();
|
||||
|
||||
free(req);
|
||||
while (!atomic_load(&req->done))
|
||||
spin_lock_relax();
|
||||
|
||||
biglock_lock();
|
||||
|
||||
free(req);
|
||||
}
|
||||
|
||||
return ST_OK;
|
||||
}
|
||||
@@ -561,6 +612,8 @@ static int idedrv_do_write_no_irqs(struct idedrv* idedrv, size_t sector, size_t
|
||||
}
|
||||
}
|
||||
|
||||
ide_flush(idedrv);
|
||||
|
||||
return ST_OK;
|
||||
}
|
||||
|
||||
@@ -589,30 +642,13 @@ DEFINE_DEVICE_OP(idedrv_write) {
|
||||
return -ST_XDRV_WRITE_ERROR;
|
||||
|
||||
if (idedrv->irqs_support)
|
||||
ret = idedrv_do_write_irqs(idedrv, sector, sector_count, buffer);
|
||||
ret = idedrv_do_write_irqs(idedrv, proc, rctx, sector, sector_count, buffer);
|
||||
else
|
||||
ret = idedrv_do_write_no_irqs(idedrv, sector, sector_count, buffer);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
uint8_t ctrl = inb(idedrv->ctrl);
|
||||
ctrl |= 0x02;
|
||||
outb(idedrv->ctrl, ctrl);
|
||||
|
||||
if (idedrv->lba48)
|
||||
outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH48);
|
||||
else
|
||||
outb(idedrv->io + IDE_REG_CMD, IDE_CMD_FLUSH28);
|
||||
|
||||
uint8_t status;
|
||||
do {
|
||||
status = inb(idedrv->io + IDE_REG_STATUS);
|
||||
} while (status & IDE_BSY);
|
||||
|
||||
if (status & (IDE_ERR | IDE_DF))
|
||||
return -ST_XDRV_WRITE_ERROR;
|
||||
|
||||
return ST_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ struct idedrv {
|
||||
size_t prdt_entry_count;
|
||||
uintptr_t bounce_buffer_phys;
|
||||
void* bounce_buffer;
|
||||
struct proc_suspension_q sq;
|
||||
};
|
||||
|
||||
struct ide_probe {
|
||||
|
||||
Reference in New Issue
Block a user