1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 23:17:45 +00:00

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.
This commit is contained in:
Liav A 2021-03-27 21:44:25 +03:00 committed by Andreas Kling
parent 627cfe017c
commit 2718d7c74c
6 changed files with 96 additions and 25 deletions

View file

@ -36,12 +36,23 @@ UNMAP_AFTER_INIT NonnullRefPtr<BMIDEChannel> BMIDEChannel::create(const IDEContr
return adopt(*new BMIDEChannel(ide_controller, io_group, type)); 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) UNMAP_AFTER_INIT BMIDEChannel::BMIDEChannel(const IDEController& controller, IDEChannel::IOAddressGroup io_group, IDEChannel::ChannelType type)
: IDEChannel(controller, io_group, type) : IDEChannel(controller, io_group, type)
{ {
initialize(); 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() UNMAP_AFTER_INIT void BMIDEChannel::initialize()
{ {
VERIFY(m_io_group.bus_master_base().has_value()); VERIFY(m_io_group.bus_master_base().has_value());

View file

@ -46,12 +46,14 @@ class BMIDEChannel final : public IDEChannel {
public: public:
static NonnullRefPtr<BMIDEChannel> create(const IDEController&, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type); 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 ~BMIDEChannel() override {};
virtual bool is_dma_enabled() const override { return true; }; virtual bool is_dma_enabled() const override { return true; };
private: private:
BMIDEChannel(const IDEController&, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type); BMIDEChannel(const IDEController&, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type);
BMIDEChannel(const IDEController&, u8 irq, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type);
void initialize(); void initialize();
void complete_current_request(AsyncDeviceRequest::RequestResult); void complete_current_request(AsyncDeviceRequest::RequestResult);

View file

@ -49,6 +49,11 @@ UNMAP_AFTER_INIT NonnullRefPtr<IDEChannel> IDEChannel::create(const IDEControlle
return adopt(*new IDEChannel(controller, io_group, type)); 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 RefPtr<StorageDevice> IDEChannel::master_device() const
{ {
return m_master; return m_master;
@ -59,16 +64,9 @@ RefPtr<StorageDevice> IDEChannel::slave_device() const
return m_slave; return m_slave;
} }
UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddressGroup io_group, ChannelType type) UNMAP_AFTER_INIT void IDEChannel::initialize()
: IRQHandler(type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ)
, m_channel_type(type)
, m_io_group(io_group)
, m_parent_controller(controller)
{ {
disable_irq(); 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: {} 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: {} control base: {}", channel_type_string(), m_io_group.control_base());
if (m_io_group.bus_master_base().has_value()) 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(); 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 void IDEChannel::clear_pending_interrupts() const
{ {
m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>(); m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>();

View file

@ -106,6 +106,7 @@ public:
public: public:
static NonnullRefPtr<IDEChannel> create(const IDEController&, IOAddressGroup, ChannelType type); static NonnullRefPtr<IDEChannel> create(const IDEController&, IOAddressGroup, ChannelType type);
static NonnullRefPtr<IDEChannel> create(const IDEController&, u8 irq, IOAddressGroup, ChannelType type);
virtual ~IDEChannel() override; virtual ~IDEChannel() override;
RefPtr<StorageDevice> master_device() const; RefPtr<StorageDevice> master_device() const;
@ -117,6 +118,7 @@ public:
private: private:
void complete_current_request(AsyncDeviceRequest::RequestResult); void complete_current_request(AsyncDeviceRequest::RequestResult);
void initialize();
protected: protected:
enum class LBAMode : u8 { enum class LBAMode : u8 {
@ -131,6 +133,7 @@ protected:
}; };
IDEChannel(const IDEController&, IOAddressGroup, ChannelType type); IDEChannel(const IDEController&, IOAddressGroup, ChannelType type);
IDEChannel(const IDEController&, u8 irq, IOAddressGroup, ChannelType type);
//^ IRQHandler //^ IRQHandler
virtual void handle_irq(const RegisterState&) override; virtual void handle_irq(const RegisterState&) override;

View file

@ -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 bool IDEController::is_bus_master_capable() const
{ {
return PCI::get_programming_interface(pci_address()) & (1 << 7); 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 @ {}: 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)); dbgln("IDE controller @ {}: secondary channel DMA capable? {}", pci_address(), ((bus_master_base.offset(2 + 8).in<u8>() >> 5) & 0b11));
auto bar0 = PCI::get_BAR0(pci_address());
auto base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0);
auto bar1 = PCI::get_BAR1(pci_address());
auto control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress(bar1);
if (!is_bus_master_capable()) if (!is_bus_master_capable())
force_pio = true; force_pio = true;
if (force_pio) auto bar0 = PCI::get_BAR0(pci_address());
m_channels.append(IDEChannel::create(*this, { base_io, control_io }, IDEChannel::ChannelType::Primary)); auto primary_base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0 & (~1));
else auto bar1 = PCI::get_BAR1(pci_address());
m_channels.append(BMIDEChannel::create(*this, { base_io, control_io, bus_master_base }, IDEChannel::ChannelType::Primary)); 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));
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));
}
m_channels[0].enable_irq(); m_channels[0].enable_irq();
auto bar2 = PCI::get_BAR2(pci_address()); if (is_pci_native_mode_enabled_on_secondary_channel()) {
base_io = (bar2 == 0x1 || bar2 == 0) ? IOAddress(0x170) : IOAddress(bar2); if (force_pio)
auto bar3 = PCI::get_BAR3(pci_address()); m_channels.append(IDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io }, IDEChannel::ChannelType::Secondary));
control_io = (bar3 == 0x1 || bar3 == 0) ? IOAddress(0x376) : IOAddress(bar3); else
if (force_pio) m_channels.append(BMIDEChannel::create(*this, irq_line, { secondary_base_io, secondary_control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary));
m_channels.append(IDEChannel::create(*this, { base_io, control_io }, IDEChannel::ChannelType::Secondary)); } else {
else if (force_pio)
m_channels.append(BMIDEChannel::create(*this, { base_io, control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary)); 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(); m_channels[1].enable_irq();
} }

View file

@ -53,8 +53,11 @@ public:
virtual void complete_current_request(AsyncDeviceRequest::RequestResult) override; virtual void complete_current_request(AsyncDeviceRequest::RequestResult) override;
bool is_bus_master_capable() const; bool is_bus_master_capable() const;
bool is_pci_native_mode_enabled() const;
private: 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); IDEController(PCI::Address address, bool force_pio);
RefPtr<StorageDevice> device_by_channel_and_position(u32 index) const; RefPtr<StorageDevice> device_by_channel_and_position(u32 index) const;