mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 02:12:09 -05:00
IDEDiskDevice: Support reading multiple sectors at a time with DMA.
This is another sizable improvement to GCC compile times.
This commit is contained in:
parent
ed79116e94
commit
c7d8aa6969
4 changed files with 27 additions and 14 deletions
|
@ -15,12 +15,8 @@ bool DiskDevice::read(DiskOffset offset, unsigned length, byte* out) const
|
|||
dword first_block = offset / block_size();
|
||||
dword end_block = (offset + length) / block_size();
|
||||
byte* outptr = out;
|
||||
for (unsigned bi = first_block; bi < end_block; ++bi) {
|
||||
if (!read_block(bi, outptr))
|
||||
return false;
|
||||
outptr += block_size();
|
||||
}
|
||||
return true;
|
||||
|
||||
return const_cast<DiskDevice*>(this)->read_blocks(first_block, end_block - first_block, outptr);
|
||||
}
|
||||
|
||||
bool DiskDevice::write(DiskOffset offset, unsigned length, const byte* in)
|
||||
|
|
|
@ -17,6 +17,8 @@ public:
|
|||
bool read(DiskOffset, unsigned length, byte*) const;
|
||||
bool write(DiskOffset, unsigned length, const byte*);
|
||||
|
||||
virtual bool read_blocks(unsigned index, word count, byte*) = 0;
|
||||
|
||||
protected:
|
||||
DiskDevice();
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Scheduler.h"
|
||||
#include "PIC.h"
|
||||
#include <Kernel/Lock.h>
|
||||
#include <Kernel/VM/MemoryManager.h>
|
||||
|
||||
//#define DISK_DEBUG
|
||||
|
||||
|
@ -126,10 +127,17 @@ unsigned IDEDiskDevice::block_size() const
|
|||
return 512;
|
||||
}
|
||||
|
||||
bool IDEDiskDevice::read_blocks(unsigned index, word count, byte* out)
|
||||
{
|
||||
if (m_bus_master_base)
|
||||
return read_sectors_with_dma(index, count, out);
|
||||
return read_sectors(index, count, out);
|
||||
}
|
||||
|
||||
bool IDEDiskDevice::read_block(unsigned index, byte* out) const
|
||||
{
|
||||
if (m_bus_master_base)
|
||||
return const_cast<IDEDiskDevice&>(*this).read_sector_with_dma(index, out);
|
||||
return const_cast<IDEDiskDevice&>(*this).read_sectors_with_dma(index, 1, out);
|
||||
return const_cast<IDEDiskDevice&>(*this).read_sectors(index, 1, out);
|
||||
}
|
||||
|
||||
|
@ -248,6 +256,7 @@ void IDEDiskDevice::initialize()
|
|||
m_prdt.end_of_table = 0x8000;
|
||||
PCI::enable_bus_mastering(m_pci_address);
|
||||
m_bus_master_base = PCI::get_BAR4(m_pci_address) & 0xfffc;
|
||||
m_dma_buffer_page = MM.allocate_supervisor_physical_page();
|
||||
dbgprintf("PIIX Bus master IDE: I/O @ %x\n", m_bus_master_base);
|
||||
}
|
||||
}
|
||||
|
@ -258,19 +267,21 @@ static void wait_400ns(word io_base)
|
|||
IO::in8(io_base + ATA_REG_ALTSTATUS);
|
||||
}
|
||||
|
||||
bool IDEDiskDevice::read_sector_with_dma(dword lba, byte* outbuf)
|
||||
bool IDEDiskDevice::read_sectors_with_dma(dword lba, word count, byte* outbuf)
|
||||
{
|
||||
LOCKER(m_lock);
|
||||
#ifdef DISK_DEBUG
|
||||
dbgprintf("%s(%u): IDEDiskDevice::read_sector_with_dma (%u) -> %p\n",
|
||||
dbgprintf("%s(%u): IDEDiskDevice::read_sectors_with_dma (%u x%u) -> %p\n",
|
||||
current->process().name().characters(),
|
||||
current->pid(), lba, outbuf);
|
||||
current->pid(), lba, count, outbuf);
|
||||
#endif
|
||||
|
||||
disable_irq();
|
||||
|
||||
m_prdt.offset = PhysicalAddress((dword)outbuf);
|
||||
m_prdt.size = 512;
|
||||
m_prdt.offset = m_dma_buffer_page->paddr();
|
||||
m_prdt.size = 512 * count;
|
||||
|
||||
ASSERT(m_prdt.size <= PAGE_SIZE);
|
||||
|
||||
// Stop bus master
|
||||
IO::out8(m_bus_master_base, 0);
|
||||
|
@ -303,7 +314,7 @@ bool IDEDiskDevice::read_sector_with_dma(dword lba, byte* outbuf)
|
|||
IO::out8(io_base + ATA_REG_LBA1, 0);
|
||||
IO::out8(io_base + ATA_REG_LBA2, 0);
|
||||
|
||||
IO::out8(io_base + ATA_REG_SECCOUNT0, 1);
|
||||
IO::out8(io_base + ATA_REG_SECCOUNT0, count);
|
||||
IO::out8(io_base + ATA_REG_LBA0, (lba & 0x000000ff) >> 0);
|
||||
IO::out8(io_base + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8);
|
||||
IO::out8(io_base + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16);
|
||||
|
@ -326,6 +337,8 @@ bool IDEDiskDevice::read_sector_with_dma(dword lba, byte* outbuf)
|
|||
if (m_device_error)
|
||||
return false;
|
||||
|
||||
memcpy(outbuf, m_dma_buffer_page->paddr().as_ptr(), 512 * count);
|
||||
|
||||
// I read somewhere that this may trigger a cache flush so let's do it.
|
||||
IO::out8(m_bus_master_base + 2, IO::in8(m_bus_master_base + 2) | 0x6);
|
||||
return true;
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
virtual unsigned block_size() const override;
|
||||
virtual bool read_block(unsigned index, byte*) const override;
|
||||
virtual bool write_block(unsigned index, const byte*) override;
|
||||
virtual bool read_blocks(unsigned index, word count, byte*) override;
|
||||
|
||||
protected:
|
||||
IDEDiskDevice();
|
||||
|
@ -37,7 +38,7 @@ private:
|
|||
|
||||
void initialize();
|
||||
bool wait_for_irq();
|
||||
bool read_sector_with_dma(dword sector, byte*);
|
||||
bool read_sectors_with_dma(dword sector, word count, byte*);
|
||||
bool read_sectors(dword start_sector, word count, byte* buffer);
|
||||
bool write_sectors(dword start_sector, word count, const byte* data);
|
||||
|
||||
|
@ -50,6 +51,7 @@ private:
|
|||
|
||||
PCI::Address m_pci_address;
|
||||
PhysicalRegionDescriptor m_prdt;
|
||||
RetainPtr<PhysicalPage> m_dma_buffer_page;
|
||||
word m_bus_master_base { 0 };
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue