mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-28 13:43:45 +03:00
Kernel: Use a WaitQueue in PATAChannel
Instead of waking up repeatedly to check if a disk operation has finished, use a WaitQueue and wake it up in the IRQ handler. This simplifies the device driver a bit, and makes it more responsive as well :^)
This commit is contained in:
parent
9ed272ce98
commit
8b129476b1
Notes:
sideshowbarker
2024-07-19 11:00:36 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/8b129476b13
@ -97,6 +97,8 @@ PATAChannel::PATAChannel(ChannelType type, bool force_pio)
|
||||
, m_io_base((type == ChannelType::Primary ? 0x1F0 : 0x170))
|
||||
, m_control_base((type == ChannelType::Primary ? 0x3f6 : 0x376))
|
||||
{
|
||||
disable_irq();
|
||||
|
||||
m_dma_enabled.resource() = true;
|
||||
ProcFS::add_sys_bool("ide_dma", m_dma_enabled);
|
||||
|
||||
@ -144,20 +146,12 @@ static void print_ide_status(u8 status)
|
||||
(status & ATA_SR_ERR) != 0);
|
||||
}
|
||||
|
||||
bool PATAChannel::wait_for_irq()
|
||||
void PATAChannel::wait_for_irq()
|
||||
{
|
||||
#ifdef PATA_DEBUG
|
||||
kprintf("PATAChannel: waiting for IRQ %d...\n", irq_number());
|
||||
#endif
|
||||
while (!m_interrupted) {
|
||||
// FIXME: Put this process into a Blocked state instead, it's stupid to wake up just to check a flag.
|
||||
Scheduler::yield();
|
||||
}
|
||||
#ifdef PATA_DEBUG
|
||||
kprintf("PATAChannel: received IRQ %d!\n", irq_number());
|
||||
#endif
|
||||
|
||||
return true;
|
||||
cli();
|
||||
enable_irq();
|
||||
current->wait_on(m_irq_queue);
|
||||
disable_irq();
|
||||
}
|
||||
|
||||
void PATAChannel::handle_irq()
|
||||
@ -173,7 +167,7 @@ void PATAChannel::handle_irq()
|
||||
#ifdef PATA_DEBUG
|
||||
kprintf("PATAChannel: interrupt: DRQ=%u BSY=%u DRDY=%u\n", (status & ATA_SR_DRQ) != 0, (status & ATA_SR_BSY) != 0, (status & ATA_SR_DRDY) != 0);
|
||||
#endif
|
||||
m_interrupted = true;
|
||||
m_irq_queue.wake_all();
|
||||
}
|
||||
|
||||
static void io_delay()
|
||||
@ -186,8 +180,6 @@ void PATAChannel::detect_disks()
|
||||
{
|
||||
// There are only two possible disks connected to a channel
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
enable_irq();
|
||||
|
||||
IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xA0 | (i << 4)); // First, we need to select the drive itself
|
||||
|
||||
// Apparently these need to be 0 before sending IDENTIFY?!
|
||||
@ -257,8 +249,6 @@ bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, u8* outbuf, bool
|
||||
current->pid(), lba, count, outbuf);
|
||||
#endif
|
||||
|
||||
disable_irq();
|
||||
|
||||
m_prdt.offset = m_dma_buffer_page->paddr();
|
||||
m_prdt.size = 512 * count;
|
||||
|
||||
@ -276,9 +266,6 @@ bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, u8* outbuf, bool
|
||||
// Set transfer direction
|
||||
IO::out8(m_bus_master_base, 0x8);
|
||||
|
||||
m_interrupted = false;
|
||||
enable_irq();
|
||||
|
||||
while (IO::in8(m_io_base + ATA_REG_STATUS) & ATA_SR_BSY)
|
||||
;
|
||||
|
||||
@ -315,7 +302,6 @@ bool PATAChannel::ata_read_sectors_with_dma(u32 lba, u16 count, u8* outbuf, bool
|
||||
IO::out8(m_bus_master_base, 0x9);
|
||||
|
||||
wait_for_irq();
|
||||
disable_irq();
|
||||
|
||||
if (m_device_error)
|
||||
return false;
|
||||
@ -336,8 +322,6 @@ bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf
|
||||
current->pid(), lba, count, inbuf);
|
||||
#endif
|
||||
|
||||
disable_irq();
|
||||
|
||||
m_prdt.offset = m_dma_buffer_page->paddr();
|
||||
m_prdt.size = 512 * count;
|
||||
|
||||
@ -354,9 +338,6 @@ bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf
|
||||
// Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware.
|
||||
IO::out8(m_bus_master_base + 2, IO::in8(m_bus_master_base + 2) | 0x6);
|
||||
|
||||
m_interrupted = false;
|
||||
enable_irq();
|
||||
|
||||
while (IO::in8(m_io_base + ATA_REG_STATUS) & ATA_SR_BSY)
|
||||
;
|
||||
|
||||
@ -393,7 +374,6 @@ bool PATAChannel::ata_write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf
|
||||
IO::out8(m_bus_master_base, 0x1);
|
||||
|
||||
wait_for_irq();
|
||||
disable_irq();
|
||||
|
||||
if (m_device_error)
|
||||
return false;
|
||||
@ -415,7 +395,6 @@ bool PATAChannel::ata_read_sectors(u32 start_sector, u16 count, u8* outbuf, bool
|
||||
start_sector,
|
||||
outbuf);
|
||||
#endif
|
||||
disable_irq();
|
||||
|
||||
while (IO::in8(m_io_base + ATA_REG_STATUS) & ATA_SR_BSY)
|
||||
;
|
||||
@ -439,8 +418,6 @@ bool PATAChannel::ata_read_sectors(u32 start_sector, u16 count, u8* outbuf, bool
|
||||
;
|
||||
|
||||
IO::out8(m_io_base + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
|
||||
m_interrupted = false;
|
||||
enable_irq();
|
||||
wait_for_irq();
|
||||
|
||||
if (m_device_error)
|
||||
@ -475,7 +452,6 @@ bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf
|
||||
count,
|
||||
start_sector);
|
||||
#endif
|
||||
disable_irq();
|
||||
|
||||
while (IO::in8(m_io_base + ATA_REG_STATUS) & ATA_SR_BSY)
|
||||
;
|
||||
@ -512,19 +488,13 @@ bool PATAChannel::ata_write_sectors(u32 start_sector, u16 count, const u8* inbuf
|
||||
kprintf("PATAChannel: Writing 512 bytes (part %d) (status=%b), inbuf=%p...\n", i, status, inbuf + (512 * i));
|
||||
#endif
|
||||
|
||||
disable_irq();
|
||||
IO::repeated_out16(m_io_base + ATA_REG_DATA, inbuf + (512 * i), 256);
|
||||
m_interrupted = false;
|
||||
enable_irq();
|
||||
wait_for_irq();
|
||||
status = IO::in8(m_io_base + ATA_REG_STATUS);
|
||||
ASSERT(!(status & ATA_SR_BSY));
|
||||
}
|
||||
|
||||
disable_irq();
|
||||
IO::out8(m_io_base + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
|
||||
m_interrupted = false;
|
||||
enable_irq();
|
||||
wait_for_irq();
|
||||
u8 status = IO::in8(m_io_base + ATA_REG_STATUS);
|
||||
ASSERT(!(status & ATA_SR_BSY));
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <Kernel/PCI.h>
|
||||
#include <Kernel/VM/PhysicalAddress.h>
|
||||
#include <Kernel/VM/PhysicalPage.h>
|
||||
#include <Kernel/WaitQueue.h>
|
||||
|
||||
struct PhysicalRegionDescriptor {
|
||||
PhysicalAddress offset;
|
||||
@ -49,7 +50,7 @@ private:
|
||||
void initialize(bool force_pio);
|
||||
void detect_disks();
|
||||
|
||||
bool wait_for_irq();
|
||||
void wait_for_irq();
|
||||
bool ata_read_sectors_with_dma(u32, u16, u8*, bool);
|
||||
bool ata_write_sectors_with_dma(u32, u16, const u8*, bool);
|
||||
bool ata_read_sectors(u32, u16, u8*, bool);
|
||||
@ -60,7 +61,8 @@ private:
|
||||
u16 m_io_base { 0x1F0 };
|
||||
u16 m_control_base { 0 };
|
||||
volatile u8 m_device_error { 0 };
|
||||
volatile bool m_interrupted { false };
|
||||
|
||||
WaitQueue m_irq_queue;
|
||||
|
||||
PCI::Address m_pci_address;
|
||||
PhysicalRegionDescriptor m_prdt;
|
||||
|
@ -322,6 +322,11 @@ public:
|
||||
return block<ConditionBlocker>(state_string, move(condition));
|
||||
}
|
||||
|
||||
void wait_on(WaitQueue& queue)
|
||||
{
|
||||
(void)block<WaitQueueBlocker>(queue);
|
||||
}
|
||||
|
||||
void unblock();
|
||||
|
||||
// Tell this thread to unblock if needed,
|
||||
|
Loading…
Reference in New Issue
Block a user