mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 02:03:06 -05:00
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.
This commit is contained in:
parent
833a6bd047
commit
8b446fb579
Notes:
sideshowbarker
2024-07-18 21:01:58 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/8b446fb5797 Pull-request: https://github.com/SerenityOS/serenity/pull/5971
5 changed files with 40 additions and 24 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue