summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-03-27 09:22:25 +0300
committerAndreas Kling <kling@serenityos.org>2021-03-27 16:40:16 +0100
commit8b446fb57979f4d184f50c6b6813801d354a974b (patch)
treeca7f7f7a04fdd058f37e00a1fda68beffd8e8f7d
parent833a6bd047e91b648c4d7c24ae518163df10b9f6 (diff)
downloadserenity-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.cpp27
-rw-r--r--Kernel/Storage/IDEChannel.cpp12
-rw-r--r--Kernel/Storage/IDEChannel.h11
-rw-r--r--Kernel/Storage/IDEController.cpp12
-rw-r--r--Kernel/Storage/IDEController.h2
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);