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();
|
BAN::Optional<uint32_t> find_free_command_slot();
|
||||||
|
|
||||||
void handle_irq();
|
void handle_irq();
|
||||||
void block_until_irq();
|
|
||||||
|
BAN::ErrorOr<void> block_until_command_completed(uint32_t command_slot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::RefPtr<AHCIController> m_controller;
|
BAN::RefPtr<AHCIController> m_controller;
|
||||||
|
@ -41,8 +42,6 @@ namespace Kernel
|
||||||
// TODO: can we read straight to user buffer?
|
// TODO: can we read straight to user buffer?
|
||||||
BAN::UniqPtr<DMARegion> m_data_dma_region;
|
BAN::UniqPtr<DMARegion> m_data_dma_region;
|
||||||
|
|
||||||
volatile bool m_has_got_irq { false };
|
|
||||||
|
|
||||||
friend class AHCIController;
|
friend class AHCIController;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <kernel/Scheduler.h>
|
||||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
#include <kernel/Storage/ATA/AHCI/Controller.h>
|
||||||
#include <kernel/Storage/ATA/AHCI/Device.h>
|
#include <kernel/Storage/ATA/AHCI/Device.h>
|
||||||
#include <kernel/Storage/ATA/ATADefinitions.h>
|
#include <kernel/Storage/ATA/ATADefinitions.h>
|
||||||
|
@ -40,7 +41,7 @@ namespace Kernel
|
||||||
m_port->ie = 0xFFFFFFFF;
|
m_port->ie = 0xFFFFFFFF;
|
||||||
|
|
||||||
TRY(read_identify_data());
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -120,8 +121,7 @@ namespace Kernel
|
||||||
|
|
||||||
m_port->ci = 1 << slot.value();
|
m_port->ci = 1 << slot.value();
|
||||||
|
|
||||||
// FIXME: timeout
|
TRY(block_until_command_completed(slot.value()));
|
||||||
do { block_until_irq(); } while (m_port->ci & (1 << slot.value()));
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -145,17 +145,32 @@ namespace Kernel
|
||||||
|
|
||||||
void AHCIDevice::handle_irq()
|
void AHCIDevice::handle_irq()
|
||||||
{
|
{
|
||||||
ASSERT(!m_has_got_irq);
|
|
||||||
uint16_t err = m_port->serr & 0xFFFF;
|
uint16_t err = m_port->serr & 0xFFFF;
|
||||||
if (err)
|
if (err)
|
||||||
print_error(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))
|
static constexpr uint64_t total_timeout_ms = 5000;
|
||||||
__builtin_ia32_pause();
|
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)
|
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();
|
m_port->ci = 1 << slot.value();
|
||||||
|
|
||||||
// FIXME: timeout
|
TRY(block_until_command_completed(slot.value()));
|
||||||
do { block_until_irq(); } while (m_port->ci & (1 << slot.value()));
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue