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:
parent
627cfe017c
commit
2718d7c74c
6 changed files with 96 additions and 25 deletions
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue