nvme_disk: Add a polling fallback mode.
Before implementing interrupts, all I/O was polled. Now we only use polling as fallback if interrupts mode does not work for some reason. Should fix #17484.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2020, Haiku, Inc. All rights reserved.
|
* Copyright 2019-2022, Haiku, Inc. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -96,6 +96,7 @@ typedef struct {
|
|||||||
rw_lock rounded_write_lock;
|
rw_lock rounded_write_lock;
|
||||||
|
|
||||||
ConditionVariable interrupt;
|
ConditionVariable interrupt;
|
||||||
|
int32 polling;
|
||||||
|
|
||||||
struct qpair_info {
|
struct qpair_info {
|
||||||
struct nvme_qpair* qpair;
|
struct nvme_qpair* qpair;
|
||||||
@@ -264,7 +265,9 @@ nvme_disk_init_device(void* _info, void** _cookie)
|
|||||||
if (irq == 0 || irq == 0xFF) {
|
if (irq == 0 || irq == 0xFF) {
|
||||||
TRACE_ERROR("device PCI:%d:%d:%d was assigned an invalid IRQ\n",
|
TRACE_ERROR("device PCI:%d:%d:%d was assigned an invalid IRQ\n",
|
||||||
info->info.bus, info->info.device, info->info.function);
|
info->info.bus, info->info.device, info->info.function);
|
||||||
return B_ERROR;
|
info->polling = 1;
|
||||||
|
} else {
|
||||||
|
info->polling = 0;
|
||||||
}
|
}
|
||||||
info->interrupt.Init(NULL, NULL);
|
info->interrupt.Init(NULL, NULL);
|
||||||
install_io_interrupt_handler(irq, nvme_interrupt_handler, (void*)info, B_NO_HANDLED_INFO);
|
install_io_interrupt_handler(irq, nvme_interrupt_handler, (void*)info, B_NO_HANDLED_INFO);
|
||||||
@@ -403,6 +406,7 @@ nvme_interrupt_handler(void* _info)
|
|||||||
{
|
{
|
||||||
nvme_disk_driver_info* info = (nvme_disk_driver_info*)_info;
|
nvme_disk_driver_info* info = (nvme_disk_driver_info*)_info;
|
||||||
info->interrupt.NotifyAll();
|
info->interrupt.NotifyAll();
|
||||||
|
info->polling = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,10 +440,15 @@ await_status(nvme_disk_driver_info* info, struct nvme_qpair* qpair, status_t& st
|
|||||||
if (status != EINPROGRESS)
|
if (status != EINPROGRESS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (entry.Wait(B_RELATIVE_TIMEOUT, 5 * 1000 * 1000) != B_OK) {
|
if (info->polling > 0) {
|
||||||
|
entry.Wait(B_RELATIVE_TIMEOUT, min_c(5 * 1000 * 1000,
|
||||||
|
(1 << timeouts) * 1000));
|
||||||
|
timeouts++;
|
||||||
|
} else if (entry.Wait(B_RELATIVE_TIMEOUT, 5 * 1000 * 1000) != B_OK) {
|
||||||
// This should never happen, as we are woken up on every interrupt
|
// This should never happen, as we are woken up on every interrupt
|
||||||
// no matter the qpair or transfer within; so if it does occur,
|
// no matter the qpair or transfer within; so if it does occur,
|
||||||
// that probably means the controller stalled or something.
|
// that probably means the controller stalled, or maybe cannot
|
||||||
|
// generate interrupts at all.
|
||||||
|
|
||||||
TRACE_ERROR("timed out waiting for interrupt!\n");
|
TRACE_ERROR("timed out waiting for interrupt!\n");
|
||||||
if (timeouts++ >= 3) {
|
if (timeouts++ >= 3) {
|
||||||
@@ -447,6 +456,11 @@ await_status(nvme_disk_driver_info* info, struct nvme_qpair* qpair, status_t& st
|
|||||||
status = B_TIMED_OUT;
|
status = B_TIMED_OUT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info->polling++;
|
||||||
|
if (info->polling > 0) {
|
||||||
|
TRACE_ALWAYS("switching to polling mode, performance will be affected!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nvme_qpair_poll(qpair, 0);
|
nvme_qpair_poll(qpair, 0);
|
||||||
@@ -470,7 +484,8 @@ struct nvme_io_request {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void ior_reset_sgl(nvme_io_request* request, uint32_t offset)
|
static void
|
||||||
|
ior_reset_sgl(nvme_io_request* request, uint32_t offset)
|
||||||
{
|
{
|
||||||
TRACE("IOR Reset: %" B_PRIu32 "\n", offset);
|
TRACE("IOR Reset: %" B_PRIu32 "\n", offset);
|
||||||
|
|
||||||
@@ -484,7 +499,8 @@ void ior_reset_sgl(nvme_io_request* request, uint32_t offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ior_next_sge(nvme_io_request* request, uint64_t* address, uint32_t* length)
|
static int
|
||||||
|
ior_next_sge(nvme_io_request* request, uint64_t* address, uint32_t* length)
|
||||||
{
|
{
|
||||||
int32 index = request->iovec_i;
|
int32 index = request->iovec_i;
|
||||||
if (index < 0 || index > request->iovec_count)
|
if (index < 0 || index > request->iovec_count)
|
||||||
|
|||||||
Reference in New Issue
Block a user