Kernel: Add timeout to ACHI commands
ACHI commands can now fail from timeouts.
This commit is contained in:
parent
fb801044ec
commit
2d0da93ac4
|
@ -30,7 +30,8 @@ namespace Kernel
|
|||
BAN::Optional<uint32_t> find_free_command_slot();
|
||||
|
||||
void handle_irq();
|
||||
void block_until_irq();
|
||||
|
||||
BAN::ErrorOr<void> block_until_command_completed(uint32_t command_slot);
|
||||
|
||||
private:
|
||||
BAN::RefPtr<AHCIController> m_controller;
|
||||
|
@ -41,8 +42,6 @@ namespace Kernel
|
|||
// TODO: can we read straight to user buffer?
|
||||
BAN::UniqPtr<DMARegion> m_data_dma_region;
|
||||
|
||||
volatile bool m_has_got_irq { false };
|
||||
|
||||
friend class AHCIController;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
||||
#include <kernel/Storage/ATA/AHCI/Device.h>
|
||||
#include <kernel/Storage/ATA/ATADefinitions.h>
|
||||
|
@ -40,7 +41,7 @@ namespace Kernel
|
|||
m_port->ie = 0xFFFFFFFF;
|
||||
|
||||
TRY(read_identify_data());
|
||||
TRY(detail::ATABaseDevice::initialize({ (const uint16_t*)m_data_dma_region->vaddr(), m_data_dma_region->size() }));
|
||||
TRY(detail::ATABaseDevice::initialize({ (const uint16_t*)m_data_dma_region->vaddr(), m_data_dma_region->size() / sizeof(uint16_t) }));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -120,8 +121,7 @@ namespace Kernel
|
|||
|
||||
m_port->ci = 1 << slot.value();
|
||||
|
||||
// FIXME: timeout
|
||||
do { block_until_irq(); } while (m_port->ci & (1 << slot.value()));
|
||||
TRY(block_until_command_completed(slot.value()));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -145,17 +145,32 @@ namespace Kernel
|
|||
|
||||
void AHCIDevice::handle_irq()
|
||||
{
|
||||
ASSERT(!m_has_got_irq);
|
||||
uint16_t err = m_port->serr & 0xFFFF;
|
||||
if (err)
|
||||
print_error(err);
|
||||
m_has_got_irq = true;
|
||||
}
|
||||
|
||||
void AHCIDevice::block_until_irq()
|
||||
BAN::ErrorOr<void> AHCIDevice::block_until_command_completed(uint32_t command_slot)
|
||||
{
|
||||
while (!__sync_bool_compare_and_swap(&m_has_got_irq, true, false))
|
||||
__builtin_ia32_pause();
|
||||
static constexpr uint64_t total_timeout_ms = 5000;
|
||||
static constexpr uint64_t poll_timeout_ms = 10;
|
||||
|
||||
auto start_time = SystemTimer::get().ms_since_boot();
|
||||
|
||||
while (start_time + poll_timeout_ms < SystemTimer::get().ns_since_boot())
|
||||
if (!(m_port->ci & (1 << command_slot)))
|
||||
return {};
|
||||
|
||||
// FIXME: This should actually block once semaphores support blocking with timeout.
|
||||
// This doesn't allow scheduler to go properly idle.
|
||||
while (start_time + total_timeout_ms < SystemTimer::get().ns_since_boot())
|
||||
{
|
||||
Scheduler::get().reschedule();
|
||||
if (!(m_port->ci & (1 << command_slot)))
|
||||
return {};
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(ETIMEDOUT);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> AHCIDevice::read_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ByteSpan buffer)
|
||||
|
@ -260,8 +275,7 @@ namespace Kernel
|
|||
|
||||
m_port->ci = 1 << slot.value();
|
||||
|
||||
// FIXME: timeout
|
||||
do { block_until_irq(); } while (m_port->ci & (1 << slot.value()));
|
||||
TRY(block_until_command_completed(slot.value()));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue