Kernel: Fix timeouts in AHCI code and add more volatile keywords

This commit is contained in:
Bananymous 2024-01-12 19:25:38 +02:00
parent 4be726b130
commit 7adc7e55a5
1 changed files with 19 additions and 16 deletions

View File

@ -8,6 +8,8 @@
namespace Kernel namespace Kernel
{ {
static constexpr uint64_t s_ata_timeout = 1000;
static void start_cmd(volatile HBAPortMemorySpace* port) static void start_cmd(volatile HBAPortMemorySpace* port)
{ {
while (port->cmd & HBA_PxCMD_CR) while (port->cmd & HBA_PxCMD_CR)
@ -100,24 +102,26 @@ namespace Kernel
auto slot = find_free_command_slot(); auto slot = find_free_command_slot();
ASSERT(slot.has_value()); ASSERT(slot.has_value());
auto& command_header = ((HBACommandHeader*)m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()]; volatile auto& command_header = reinterpret_cast<volatile HBACommandHeader*>(m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()];
command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t); command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
command_header.w = 0; command_header.w = 0;
command_header.prdtl = 1; command_header.prdtl = 1;
auto& command_table = *(HBACommandTable*)m_dma_region->paddr_to_vaddr(command_header.ctba); volatile auto& command_table = *reinterpret_cast<volatile HBACommandTable*>(m_dma_region->paddr_to_vaddr(command_header.ctba));
memset(&command_table, 0x00, sizeof(HBACommandTable)); memset(const_cast<HBACommandTable*>(&command_table), 0x00, sizeof(HBACommandTable));
command_table.prdt_entry[0].dba = m_data_dma_region->paddr(); command_table.prdt_entry[0].dba = m_data_dma_region->paddr();
command_table.prdt_entry[0].dbc = 511; command_table.prdt_entry[0].dbc = 511;
command_table.prdt_entry[0].i = 1; command_table.prdt_entry[0].i = 1;
auto& command = *(FISRegisterH2D*)command_table.cfis; volatile auto& command = *reinterpret_cast<volatile FISRegisterH2D*>(command_table.cfis);
command.fis_type = FIS_TYPE_REGISTER_H2D; command.fis_type = FIS_TYPE_REGISTER_H2D;
command.c = 1; command.c = 1;
command.command = ATA_COMMAND_IDENTIFY; command.command = ATA_COMMAND_IDENTIFY;
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ata_timeout;
while (m_port->tfd & (ATA_STATUS_BSY | ATA_STATUS_DRQ)) while (m_port->tfd & (ATA_STATUS_BSY | ATA_STATUS_DRQ))
continue; if (SystemTimer::get().ms_since_boot() >= timeout)
return BAN::Error::from_errno(ETIMEDOUT);
m_port->ci = 1 << slot.value(); m_port->ci = 1 << slot.value();
@ -152,18 +156,17 @@ namespace Kernel
BAN::ErrorOr<void> AHCIDevice::block_until_command_completed(uint32_t command_slot) BAN::ErrorOr<void> AHCIDevice::block_until_command_completed(uint32_t command_slot)
{ {
static constexpr uint64_t total_timeout_ms = 5000;
static constexpr uint64_t poll_timeout_ms = 10; static constexpr uint64_t poll_timeout_ms = 10;
auto start_time = SystemTimer::get().ms_since_boot(); auto start_time = SystemTimer::get().ms_since_boot();
while (start_time + poll_timeout_ms < SystemTimer::get().ns_since_boot()) while (SystemTimer::get().ms_since_boot() < start_time + poll_timeout_ms)
if (!(m_port->ci & (1 << command_slot))) if (!(m_port->ci & (1 << command_slot)))
return {}; return {};
// FIXME: This should actually block once semaphores support blocking with timeout. // FIXME: This should actually block once semaphores support blocking with timeout.
// This doesn't allow scheduler to go properly idle. // This doesn't allow scheduler to go properly idle.
while (start_time + total_timeout_ms < SystemTimer::get().ns_since_boot()) while (SystemTimer::get().ms_since_boot() < start_time + s_ata_timeout)
{ {
Scheduler::get().reschedule(); Scheduler::get().reschedule();
if (!(m_port->ci & (1 << command_slot))) if (!(m_port->ci & (1 << command_slot)))
@ -216,7 +219,7 @@ namespace Kernel
auto slot = find_free_command_slot(); auto slot = find_free_command_slot();
ASSERT(slot.has_value()); ASSERT(slot.has_value());
auto& command_header = ((HBACommandHeader*)m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()]; volatile auto& command_header = reinterpret_cast<volatile HBACommandHeader*>(m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()];
command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t); command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
command_header.prdtl = 1; command_header.prdtl = 1;
switch (command) switch (command)
@ -231,15 +234,15 @@ namespace Kernel
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
auto& command_table = *(HBACommandTable*)m_dma_region->paddr_to_vaddr(command_header.ctba); volatile auto& command_table = *reinterpret_cast<HBACommandTable*>(m_dma_region->paddr_to_vaddr(command_header.ctba));
memset(&command_table, 0x00, sizeof(HBACommandTable)); memset(const_cast<HBACommandTable*>(&command_table), 0x00, sizeof(HBACommandTable));
command_table.prdt_entry[0].dba = m_data_dma_region->paddr() & 0xFFFFFFFF; command_table.prdt_entry[0].dba = m_data_dma_region->paddr() & 0xFFFFFFFF;
command_table.prdt_entry[0].dbau = m_data_dma_region->paddr() >> 32; command_table.prdt_entry[0].dbau = m_data_dma_region->paddr() >> 32;
command_table.prdt_entry[0].dbc = sector_count * sector_size() - 1; command_table.prdt_entry[0].dbc = sector_count * sector_size() - 1;
command_table.prdt_entry[0].i = 1; command_table.prdt_entry[0].i = 1;
auto& fis_command = *(FISRegisterH2D*)command_table.cfis; volatile auto& fis_command = *reinterpret_cast<volatile FISRegisterH2D*>(command_table.cfis);
memset(&fis_command, 0x00, sizeof(FISRegisterH2D)); memset(const_cast<FISRegisterH2D*>(&fis_command), 0x00, sizeof(FISRegisterH2D));
fis_command.fis_type = FIS_TYPE_REGISTER_H2D; fis_command.fis_type = FIS_TYPE_REGISTER_H2D;
fis_command.c = 1; fis_command.c = 1;
@ -283,8 +286,8 @@ namespace Kernel
BAN::Optional<uint32_t> AHCIDevice::find_free_command_slot() BAN::Optional<uint32_t> AHCIDevice::find_free_command_slot()
{ {
uint32_t slots = m_port->sact | m_port->ci; uint32_t slots = m_port->sact | m_port->ci;
for (uint32_t i = 0; i < m_controller->command_slot_count(); i++, slots >>= 1) for (uint32_t i = 0; i < m_controller->command_slot_count(); i++)
if (!(slots & 1)) if (!(slots & (1 << i)))
return i; return i;
return {}; return {};
} }