diff options
author | Liav A <liavalb@gmail.com> | 2021-11-13 10:32:49 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-11-13 10:05:22 +0100 |
commit | 1ae76676a56d01fab2ffecbb0c5a5904e457ae84 (patch) | |
tree | 94ef01d24afeae77d5c900735050ebaa59feb3c0 /Kernel/Storage/ATA | |
parent | 4dc3617f3c1e35a8865fb1d26b2779959e6423fc (diff) | |
download | serenity-1ae76676a56d01fab2ffecbb0c5a5904e457ae84.zip |
Kernel/Storage: Don't use interrupts when identifying AHCI devices
Don't use interrupts when trying to identify a device that is connected
to a port on the AHCI controller, and instead poll for changes in status
to end the transaction.
Not only this simplifies the initialization sequence, it ensures that
for whatever reason the controller doesn't send an IRQ, we are never
getting stuck at this point.
Diffstat (limited to 'Kernel/Storage/ATA')
-rw-r--r-- | Kernel/Storage/ATA/AHCIPort.cpp | 62 | ||||
-rw-r--r-- | Kernel/Storage/ATA/AHCIPort.h | 4 |
2 files changed, 40 insertions, 26 deletions
diff --git a/Kernel/Storage/ATA/AHCIPort.cpp b/Kernel/Storage/ATA/AHCIPort.cpp index 9114541d88..ee762254b2 100644 --- a/Kernel/Storage/ATA/AHCIPort.cpp +++ b/Kernel/Storage/ATA/AHCIPort.cpp @@ -253,7 +253,7 @@ bool AHCIPort::reset() if (!initiate_sata_reset(lock)) { return false; } - return initialize(lock); + return initialize(); } bool AHCIPort::initialize_without_reset() @@ -261,10 +261,10 @@ bool AHCIPort::initialize_without_reset() MutexLocker locker(m_lock); SpinlockLocker lock(m_hard_lock); dmesgln("AHCI Port {}: {}", representative_port_index(), try_disambiguate_sata_status()); - return initialize(lock); + return initialize(); } -bool AHCIPort::initialize(SpinlockLocker<Spinlock>& main_lock) +bool AHCIPort::initialize() { VERIFY(m_lock.is_locked()); dbgln_if(AHCI_DEBUG, "AHCI Port {}: Initialization. Signature = {:#08x}", representative_port_index(), static_cast<u32>(m_port_registers.sig)); @@ -293,7 +293,7 @@ bool AHCIPort::initialize(SpinlockLocker<Spinlock>& main_lock) size_t logical_sector_size = 512; size_t physical_sector_size = 512; u64 max_addressable_sector = 0; - if (identify_device(main_lock)) { + if (identify_device()) { auto identify_block = Memory::map_typed<ATAIdentifyBlock>(m_parent_handler->get_identify_metadata_physical_region(m_port_index)); // Check if word 106 is valid before using it! if ((identify_block->physical_sector_size_to_logical_sector_size >> 14) == 1) { @@ -617,7 +617,7 @@ bool AHCIPort::access_device(AsyncBlockDeviceRequest::RequestType direction, u64 return true; } -bool AHCIPort::identify_device(SpinlockLocker<Spinlock>& main_lock) +bool AHCIPort::identify_device() { VERIFY(m_lock.is_locked()); VERIFY(is_operable()); @@ -652,29 +652,43 @@ bool AHCIPort::identify_device(SpinlockLocker<Spinlock>& main_lock) if (!spin_until_ready()) return false; - // FIXME: Find a better way to send IDENTIFY DEVICE and getting an interrupt! - { - main_lock.unlock(); - VERIFY_INTERRUPTS_ENABLED(); - full_memory_barrier(); - m_wait_for_completion = true; - dbgln_if(AHCI_DEBUG, "AHCI Port {}: Marking command header at index {} as ready to identify device", representative_port_index(), unused_command_header.value()); - m_port_registers.ci = 1 << unused_command_header.value(); - full_memory_barrier(); + // Just in case we have a pending interrupt. + m_interrupt_enable.clear(); + m_interrupt_status.clear(); - while (1) { - if (m_port_registers.serr != 0) { - dbgln("AHCI Port {}: Identify failed, SError {:#08x}", representative_port_index(), (u32)m_port_registers.serr); - try_disambiguate_sata_error(); - return false; - } - if (!m_wait_for_completion) - break; + full_memory_barrier(); + dbgln_if(AHCI_DEBUG, "AHCI Port {}: Marking command header at index {} as ready to identify device", representative_port_index(), unused_command_header.value()); + m_port_registers.ci = 1 << unused_command_header.value(); + full_memory_barrier(); + + size_t time_elapsed = 0; + bool success = false; + while (1) { + // Note: We allow it to spin for 256 milliseconds, which should be enough for a device to respond. + if (time_elapsed >= 256) { + break; } - main_lock.lock(); + if (m_port_registers.serr != 0) { + dbgln("AHCI Port {}: Identify failed, SError {:#08x}", representative_port_index(), (u32)m_port_registers.serr); + try_disambiguate_sata_error(); + break; + } + if (!(m_port_registers.ci & (1 << unused_command_header.value()))) { + success = true; + break; + } + IO::delay(1000); // delay with 1 milliseconds + time_elapsed++; } - return true; + // Note: We probably ended up triggering an interrupt but we don't really want to handle it, + // so just get rid of it. + // FIXME: Do that in a better way so we don't need to actually remember this every time + // we need to do this. + m_interrupt_status.clear(); + m_interrupt_enable.set_all(); + + return success; } bool AHCIPort::shutdown() diff --git a/Kernel/Storage/ATA/AHCIPort.h b/Kernel/Storage/ATA/AHCIPort.h index c99eccde29..d360703752 100644 --- a/Kernel/Storage/ATA/AHCIPort.h +++ b/Kernel/Storage/ATA/AHCIPort.h @@ -53,7 +53,7 @@ public: private: bool is_phy_enabled() const { return (m_port_registers.ssts & 0xf) == 3; } - bool initialize(SpinlockLocker<Spinlock>&); + bool initialize(); UNMAP_AFTER_INIT AHCIPort(const AHCIPortHandler&, volatile AHCI::PortRegisters&, u32 port_index); @@ -81,7 +81,7 @@ private: bool spin_until_ready() const; - bool identify_device(SpinlockLocker<Spinlock>&); + bool identify_device(); ALWAYS_INLINE void start_command_list_processing() const; ALWAYS_INLINE void mark_command_header_ready_to_process(u8 command_header_index) const; |