Kernel: Fix timeouts in AHCI code and add more volatile keywords
This commit is contained in:
parent
4be726b130
commit
7adc7e55a5
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue