diff options
author | Liav A <liavalb@gmail.com> | 2021-03-27 09:22:25 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-03-27 16:40:16 +0100 |
commit | 8b446fb57979f4d184f50c6b6813801d354a974b (patch) | |
tree | ca7f7f7a04fdd058f37e00a1fda68beffd8e8f7d | |
parent | 833a6bd047e91b648c4d7c24ae518163df10b9f6 (diff) | |
download | serenity-8b446fb57979f4d184f50c6b6813801d354a974b.zip |
Kernel/Storage: Add support for non-bus mastering IDE controllers
Although unlikely to happen, a user can have an IDE controller that
doesn't support bus master capability. If that's the case, we need to
check for this, and create an IDEChannel (not BMIDEChannel) to allow
IO operations with the controller.
-rw-r--r-- | Kernel/Storage/BMIDEChannel.cpp | 27 | ||||
-rw-r--r-- | Kernel/Storage/IDEChannel.cpp | 12 | ||||
-rw-r--r-- | Kernel/Storage/IDEChannel.h | 11 | ||||
-rw-r--r-- | Kernel/Storage/IDEController.cpp | 12 | ||||
-rw-r--r-- | Kernel/Storage/IDEController.h | 2 |
5 files changed, 40 insertions, 24 deletions
diff --git a/Kernel/Storage/BMIDEChannel.cpp b/Kernel/Storage/BMIDEChannel.cpp index 0ee8c0d80e..0a74041e98 100644 --- a/Kernel/Storage/BMIDEChannel.cpp +++ b/Kernel/Storage/BMIDEChannel.cpp @@ -74,7 +74,8 @@ void BMIDEChannel::handle_irq(const RegisterState&) m_entropy_source.add_random_event(status); - u8 bstatus = m_io_group.bus_master_base().offset(2).in<u8>(); + VERIFY(m_io_group.bus_master_base().has_value()); + u8 bstatus = m_io_group.bus_master_base().value().offset(2).in<u8>(); if (!(bstatus & 0x4)) { // interrupt not from this device, ignore dbgln_if(PATA_DEBUG, "BMIDEChannel: ignore interrupt"); @@ -131,7 +132,8 @@ void BMIDEChannel::complete_current_request(AsyncDeviceRequest::RequestResult re } // I read somewhere that this may trigger a cache flush so let's do it. - m_io_group.bus_master_base().offset(2).out<u8>(m_io_group.bus_master_base().offset(2).in<u8>() | 0x6); + VERIFY(m_io_group.bus_master_base().has_value()); + m_io_group.bus_master_base().value().offset(2).out<u8>(m_io_group.bus_master_base().value().offset(2).in<u8>() | 0x6); } lock.unlock(); @@ -155,20 +157,20 @@ void BMIDEChannel::ata_write_sectors(bool slave_request, u16 capabilities) } VERIFY(prdt().size <= PAGE_SIZE); - + VERIFY(m_io_group.bus_master_base().has_value()); // Stop bus master - m_io_group.bus_master_base().out<u8>(0); + m_io_group.bus_master_base().value().out<u8>(0); // Write the PRDT location - m_io_group.bus_master_base().offset(4).out<u32>(m_prdt_page->paddr().get()); + m_io_group.bus_master_base().value().offset(4).out<u32>(m_prdt_page->paddr().get()); // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. - m_io_group.bus_master_base().offset(2).out<u8>(m_io_group.bus_master_base().offset(2).in<u8>() | 0x6); + m_io_group.bus_master_base().value().offset(2).out<u8>(m_io_group.bus_master_base().value().offset(2).in<u8>() | 0x6); ata_access(Direction::Write, slave_request, lba, request.block_count(), capabilities); // Start bus master - m_io_group.bus_master_base().out<u8>(0x1); + m_io_group.bus_master_base().value().out<u8>(0x1); } void BMIDEChannel::send_ata_io_command(LBAMode lba_mode, Direction direction) const @@ -192,22 +194,23 @@ void BMIDEChannel::ata_read_sectors(bool slave_request, u16 capabilities) VERIFY(prdt().size <= PAGE_SIZE); + VERIFY(m_io_group.bus_master_base().has_value()); // Stop bus master - m_io_group.bus_master_base().out<u8>(0); + m_io_group.bus_master_base().value().out<u8>(0); // Write the PRDT location - m_io_group.bus_master_base().offset(4).out(m_prdt_page->paddr().get()); + m_io_group.bus_master_base().value().offset(4).out(m_prdt_page->paddr().get()); // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. - m_io_group.bus_master_base().offset(2).out<u8>(m_io_group.bus_master_base().offset(2).in<u8>() | 0x6); + m_io_group.bus_master_base().value().offset(2).out<u8>(m_io_group.bus_master_base().value().offset(2).in<u8>() | 0x6); // Set transfer direction - m_io_group.bus_master_base().out<u8>(0x8); + m_io_group.bus_master_base().value().out<u8>(0x8); ata_access(Direction::Read, slave_request, lba, request.block_count(), capabilities); // Start bus master - m_io_group.bus_master_base().out<u8>(0x9); + m_io_group.bus_master_base().value().out<u8>(0x9); } } diff --git a/Kernel/Storage/IDEChannel.cpp b/Kernel/Storage/IDEChannel.cpp index 1fc4b9e36c..0ddbb787ea 100644 --- a/Kernel/Storage/IDEChannel.cpp +++ b/Kernel/Storage/IDEChannel.cpp @@ -71,7 +71,10 @@ UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddre dbgln_if(PATA_DEBUG, "IDEChannel: {} IO base: {}", channel_type_string(), m_io_group.io_base()); dbgln_if(PATA_DEBUG, "IDEChannel: {} control base: {}", channel_type_string(), m_io_group.control_base()); - dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base: {}", channel_type_string(), m_io_group.bus_master_base()); + if (m_io_group.bus_master_base().has_value()) + dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base: {}", channel_type_string(), m_io_group.bus_master_base().value()); + else + dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base disabled", channel_type_string()); m_parent_controller->enable_pin_based_interrupts(); detect_disks(); @@ -181,13 +184,6 @@ void IDEChannel::handle_irq(const RegisterState&) m_entropy_source.add_random_event(status); - u8 bstatus = m_io_group.bus_master_base().offset(2).in<u8>(); - if (!(bstatus & 0x4)) { - // interrupt not from this device, ignore - dbgln_if(PATA_DEBUG, "IDEChannel: ignore interrupt"); - return; - } - ScopedSpinLock lock(m_request_lock); dbgln_if(PATA_DEBUG, "IDEChannel: interrupt: DRQ={}, BSY={}, DRDY={}", (status & ATA_SR_DRQ) != 0, diff --git a/Kernel/Storage/IDEChannel.h b/Kernel/Storage/IDEChannel.h index 192c149a80..7651df4bba 100644 --- a/Kernel/Storage/IDEChannel.h +++ b/Kernel/Storage/IDEChannel.h @@ -72,6 +72,13 @@ public: { } + IOAddressGroup(IOAddress io_base, IOAddress control_base) + : m_io_base(io_base) + , m_control_base(control_base) + , m_bus_master_base() + { + } + // Disable default implementations that would use surprising integer promotion. bool operator==(const IOAddressGroup&) const = delete; bool operator<=(const IOAddressGroup&) const = delete; @@ -81,7 +88,7 @@ public: IOAddress io_base() const { return m_io_base; }; IOAddress control_base() const { return m_control_base; } - IOAddress bus_master_base() const { return m_bus_master_base; } + Optional<IOAddress> bus_master_base() const { return m_bus_master_base; } const IOAddressGroup& operator=(const IOAddressGroup& group) { @@ -94,7 +101,7 @@ public: private: IOAddress m_io_base; IOAddress m_control_base; - IOAddress m_bus_master_base; + Optional<IOAddress> m_bus_master_base; }; public: diff --git a/Kernel/Storage/IDEController.cpp b/Kernel/Storage/IDEController.cpp index 56a83b2f5c..ad81ae144b 100644 --- a/Kernel/Storage/IDEController.cpp +++ b/Kernel/Storage/IDEController.cpp @@ -80,6 +80,11 @@ UNMAP_AFTER_INIT IDEController::~IDEController() { } +bool IDEController::is_bus_master_capable() const +{ + return PCI::get_programming_interface(pci_address()) & (1 << 7); +} + UNMAP_AFTER_INIT void IDEController::initialize(bool force_pio) { auto bus_master_base = IOAddress(PCI::get_BAR4(pci_address()) & (~1)); @@ -89,8 +94,11 @@ UNMAP_AFTER_INIT void IDEController::initialize(bool force_pio) auto bar1 = PCI::get_BAR1(pci_address()); auto control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress(bar1); + if (!is_bus_master_capable()) + force_pio = true; + if (force_pio) - m_channels.append(IDEChannel::create(*this, { base_io, control_io, bus_master_base }, IDEChannel::ChannelType::Primary)); + m_channels.append(IDEChannel::create(*this, { base_io, control_io }, IDEChannel::ChannelType::Primary)); else m_channels.append(BMIDEChannel::create(*this, { base_io, control_io, bus_master_base }, IDEChannel::ChannelType::Primary)); m_channels[0].enable_irq(); @@ -100,7 +108,7 @@ UNMAP_AFTER_INIT void IDEController::initialize(bool force_pio) auto bar3 = PCI::get_BAR3(pci_address()); control_io = (bar3 == 0x1 || bar3 == 0) ? IOAddress(0x376) : IOAddress(bar3); if (force_pio) - m_channels.append(IDEChannel::create(*this, { base_io, control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary)); + m_channels.append(IDEChannel::create(*this, { base_io, control_io }, IDEChannel::ChannelType::Secondary)); else m_channels.append(BMIDEChannel::create(*this, { base_io, control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary)); m_channels[1].enable_irq(); diff --git a/Kernel/Storage/IDEController.h b/Kernel/Storage/IDEController.h index aff37f1bd9..3a2ac39bac 100644 --- a/Kernel/Storage/IDEController.h +++ b/Kernel/Storage/IDEController.h @@ -53,6 +53,8 @@ public: virtual void start_request(const StorageDevice&, AsyncBlockDeviceRequest&) override; virtual void complete_current_request(AsyncDeviceRequest::RequestResult) override; + bool is_bus_master_capable() const; + private: IDEController(PCI::Address address, bool force_pio); |