summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-03-27 21:44:25 +0300
committerAndreas Kling <kling@serenityos.org>2021-04-03 11:57:23 +0200
commit2718d7c74cc7a3c5b125fe1ec89ab189547b1dd8 (patch)
treea54189ad2a63e3df708cb34d975245170248d194
parent627cfe017c34ccd08a4a047a5548703b66d447cd (diff)
downloadserenity-2718d7c74cc7a3c5b125fe1ec89ab189547b1dd8.zip
Kernel/Storage: Add support for IDE controllers in PCI native mode
Also handle native and compatibility channel modes together, so if only one IDE channel was set to work on PCI native mode, we need to handle it separately, so the other channel continue to operate with the legacy IO ports and interrupt line.
-rw-r--r--Kernel/Storage/BMIDEChannel.cpp11
-rw-r--r--Kernel/Storage/BMIDEChannel.h2
-rw-r--r--Kernel/Storage/IDEChannel.cpp32
-rw-r--r--Kernel/Storage/IDEChannel.h3
-rw-r--r--Kernel/Storage/IDEController.cpp68
-rw-r--r--Kernel/Storage/IDEController.h3
6 files changed, 95 insertions, 24 deletions
diff --git a/Kernel/Storage/BMIDEChannel.cpp b/Kernel/Storage/BMIDEChannel.cpp
index e6214680c1..0a4c7ddd72 100644
--- a/Kernel/Storage/BMIDEChannel.cpp
+++ b/Kernel/Storage/BMIDEChannel.cpp
@@ -36,12 +36,23 @@ UNMAP_AFTER_INIT NonnullRefPtr<BMIDEChannel> BMIDEChannel::create(const IDEContr
return adopt(*new BMIDEChannel(ide_controller, io_group, type));
}
+UNMAP_AFTER_INIT NonnullRefPtr<BMIDEChannel> BMIDEChannel::create(const IDEController& ide_controller, u8 irq, IDEChannel::IOAddressGroup io_group, IDEChannel::ChannelType type)
+{
+ return adopt(*new BMIDEChannel(ide_controller, irq, io_group, type));
+}
+
UNMAP_AFTER_INIT BMIDEChannel::BMIDEChannel(const IDEController& controller, IDEChannel::IOAddressGroup io_group, IDEChannel::ChannelType type)
: IDEChannel(controller, io_group, type)
{
initialize();
}
+UNMAP_AFTER_INIT BMIDEChannel::BMIDEChannel(const IDEController& controller, u8 irq, IDEChannel::IOAddressGroup io_group, IDEChannel::ChannelType type)
+ : IDEChannel(controller, irq, io_group, type)
+{
+ initialize();
+}
+
UNMAP_AFTER_INIT void BMIDEChannel::initialize()
{
VERIFY(m_io_group.bus_master_base().has_value());
diff --git a/Kernel/Storage/BMIDEChannel.h b/Kernel/Storage/BMIDEChannel.h
index 281048f1a0..855adf17ca 100644
--- a/Kernel/Storage/BMIDEChannel.h
+++ b/Kernel/Storage/BMIDEChannel.h
@@ -46,12 +46,14 @@ class BMIDEChannel final : public IDEChannel {
public:
static NonnullRefPtr<BMIDEChannel> create(const IDEController&, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type);
+ static NonnullRefPtr<BMIDEChannel> create(const IDEController&, u8 irq, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type);
virtual ~BMIDEChannel() override {};
virtual bool is_dma_enabled() const override { return true; };
private:
BMIDEChannel(const IDEController&, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type);
+ BMIDEChannel(const IDEController&, u8 irq, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type);
void initialize();
void complete_current_request(AsyncDeviceRequest::RequestResult);
diff --git a/Kernel/Storage/IDEChannel.cpp b/Kernel/Storage/IDEChannel.cpp
index 52e324a8d3..f8b7418130 100644
--- a/Kernel/Storage/IDEChannel.cpp
+++ b/Kernel/Storage/IDEChannel.cpp
@@ -49,6 +49,11 @@ UNMAP_AFTER_INIT NonnullRefPtr<IDEChannel> IDEChannel::create(const IDEControlle
return adopt(*new IDEChannel(controller, io_group, type));
}
+UNMAP_AFTER_INIT NonnullRefPtr<IDEChannel> IDEChannel::create(const IDEController& controller, u8 irq, IOAddressGroup io_group, ChannelType type)
+{
+ return adopt(*new IDEChannel(controller, irq, io_group, type));
+}
+
RefPtr<StorageDevice> IDEChannel::master_device() const
{
return m_master;
@@ -59,16 +64,9 @@ RefPtr<StorageDevice> IDEChannel::slave_device() const
return m_slave;
}
-UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddressGroup io_group, ChannelType type)
- : IRQHandler(type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ)
- , m_channel_type(type)
- , m_io_group(io_group)
- , m_parent_controller(controller)
+UNMAP_AFTER_INIT void IDEChannel::initialize()
{
disable_irq();
-
- // FIXME: The device may not be capable of DMA.
-
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());
if (m_io_group.bus_master_base().has_value())
@@ -83,6 +81,24 @@ UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddre
clear_pending_interrupts();
}
+UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, u8 irq, IOAddressGroup io_group, ChannelType type)
+ : IRQHandler(irq)
+ , m_channel_type(type)
+ , m_io_group(io_group)
+ , m_parent_controller(controller)
+{
+ initialize();
+}
+
+UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddressGroup io_group, ChannelType type)
+ : IRQHandler(type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ)
+ , m_channel_type(type)
+ , m_io_group(io_group)
+ , m_parent_controller(controller)
+{
+ initialize();
+}
+
void IDEChannel::clear_pending_interrupts() const
{
m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>();
diff --git a/Kernel/Storage/IDEChannel.h b/Kernel/Storage/IDEChannel.h
index c6b3598297..5fc1c2e80f 100644
--- a/Kernel/Storage/IDEChannel.h
+++ b/Kernel/Storage/IDEChannel.h
@@ -106,6 +106,7 @@ public:
public:
static NonnullRefPtr<IDEChannel> create(const IDEController&, IOAddressGroup, ChannelType type);
+ static NonnullRefPtr<IDEChannel> create(const IDEController&, u8 irq, IOAddressGroup, ChannelType type);
virtual ~IDEChannel() override;
RefPtr<StorageDevice> master_device() const;
@@ -117,6 +118,7 @@ public:
private:
void complete_current_request(AsyncDeviceRequest::RequestResult);
+ void initialize();
protected:
enum class LBAMode : u8 {
@@ -131,6 +133,7 @@ protected:
};
IDEChannel(const IDEController&, IOAddressGroup, ChannelType type);
+ IDEChannel(const IDEController&, u8 irq, IOAddressGroup, ChannelType type);
//^ IRQHandler
virtual void handle_irq(const RegisterState&) override;
diff --git a/Kernel/Storage/IDEController.cpp b/Kernel/Storage/IDEController.cpp
index 7d06d634cf..c55adf432c 100644
--- a/Kernel/Storage/IDEController.cpp
+++ b/Kernel/Storage/IDEController.cpp
@@ -80,6 +80,21 @@ UNMAP_AFTER_INIT IDEController::~IDEController()
{
}
+bool IDEController::is_pci_native_mode_enabled() const
+{
+ return (PCI::get_programming_interface(pci_address()) & 0x05) != 0;
+}
+
+bool IDEController::is_pci_native_mode_enabled_on_primary_channel() const
+{
+ return (PCI::get_programming_interface(pci_address()) & 0x1) == 0x1;
+}
+
+bool IDEController::is_pci_native_mode_enabled_on_secondary_channel() const
+{
+ return (PCI::get_programming_interface(pci_address()) & 0x4) == 0x4;
+}
+
bool IDEController::is_bus_master_capable() const
{
return PCI::get_programming_interface(pci_address()) & (1 << 7);
@@ -119,28 +134,49 @@ UNMAP_AFTER_INIT void IDEController::initialize(bool force_pio)
dbgln("IDE controller @ {}: primary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2).in<u8>() >> 5) & 0b11));
dbgln("IDE controller @ {}: secondary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2 + 8).in<u8>() >> 5) & 0b11));
+ if (!is_bus_master_capable())
+ force_pio = true;
+
auto bar0 = PCI::get_BAR0(pci_address());
- auto base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0);
+ auto primary_base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0 & (~1));
auto bar1 = PCI::get_BAR1(pci_address());
- auto control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress(bar1);
+ auto primary_control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress(bar1 & (~1));
+ auto bar2 = PCI::get_BAR2(pci_address());
+ auto secondary_base_io = (bar2 == 0x1 || bar2 == 0) ? IOAddress(0x170) : IOAddress(bar2 & (~1));
+ auto bar3 = PCI::get_BAR3(pci_address());
+ auto secondary_control_io = (bar3 == 0x1 || bar3 == 0) ? IOAddress(0x376) : IOAddress(bar3 & (~1));
- if (!is_bus_master_capable())
- force_pio = true;
+ auto irq_line = PCI::get_interrupt_line(pci_address());
+ if (is_pci_native_mode_enabled()) {
+ VERIFY(irq_line != 0);
+ }
+
+ if (is_pci_native_mode_enabled_on_primary_channel()) {
+ if (force_pio)
+ m_channels.append(IDEChannel::create(*this, irq_line, { primary_base_io, primary_control_io }, IDEChannel::ChannelType::Primary));
+ else
+ m_channels.append(BMIDEChannel::create(*this, irq_line, { primary_control_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary));
+ } else {
+ if (force_pio)
+ m_channels.append(IDEChannel::create(*this, { primary_base_io, primary_control_io }, IDEChannel::ChannelType::Primary));
+ else
+ m_channels.append(BMIDEChannel::create(*this, { primary_base_io, primary_control_io, bus_master_base }, IDEChannel::ChannelType::Primary));
+ }
- if (force_pio)
- 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();
- auto bar2 = PCI::get_BAR2(pci_address());
- base_io = (bar2 == 0x1 || bar2 == 0) ? IOAddress(0x170) : IOAddress(bar2);
- 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 }, IDEChannel::ChannelType::Secondary));
- else
- m_channels.append(BMIDEChannel::create(*this, { base_io, control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary));
+ if (is_pci_native_mode_enabled_on_secondary_channel()) {
+ if (force_pio)
+ m_channels.append(IDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io }, IDEChannel::ChannelType::Secondary));
+ else
+ m_channels.append(BMIDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary));
+ } else {
+ if (force_pio)
+ m_channels.append(IDEChannel::create(*this, { secondary_base_io, secondary_control_io }, IDEChannel::ChannelType::Secondary));
+ else
+ m_channels.append(BMIDEChannel::create(*this, { secondary_base_io, secondary_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 e51aca5201..6cd9ed1a6b 100644
--- a/Kernel/Storage/IDEController.h
+++ b/Kernel/Storage/IDEController.h
@@ -53,8 +53,11 @@ public:
virtual void complete_current_request(AsyncDeviceRequest::RequestResult) override;
bool is_bus_master_capable() const;
+ bool is_pci_native_mode_enabled() const;
private:
+ bool is_pci_native_mode_enabled_on_primary_channel() const;
+ bool is_pci_native_mode_enabled_on_secondary_channel() const;
IDEController(PCI::Address address, bool force_pio);
RefPtr<StorageDevice> device_by_channel_and_position(u32 index) const;