OSDev.org

The Place to Start for Operating System Developers
It is currently Sun Apr 23, 2017 9:45 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: (SOLVED) Questions about ATA DMA
PostPosted: Sat Feb 11, 2017 12:12 pm 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 115
Location: At somewhere in universe
Hi, I was implementing ATA DMA over my ATA PIO implementation, because ATA PIO is slow. (Loading a ~16 MB elf takes 14-16 seconds)
I had some questions...

Why there isn't only one PRD? Another form is that question why there are multiple PRDs, a PRDT?

Also I couldn't get what does "64K Boundary" mean. Does it mean its address shouldn't be higher than 64K in memory, 64K aligned PRD physical address of data buffer, 64K aligned PRDT or maximum total size of 64K? Or another else?

And, some documentation says I should enable Busmastering in setting the second bit PCI IDE's Command field. Should I set that bit?

Is one PRD enough for me? May I change the PRD variables after setting PRDT by Busmaster PRDT Register? A pseudo code what do I mean is:

Code:
#define PRDT_SIZE 1

void set_prdt()
{
    prd_t* prdt = (prd_t*) calloc(PRDT_SIZE, sizeof(prd_t));

    // Set Busmaster PRDT register...
}

void read_sectors (uint64_t lba, uint16_t sector_count, uint32_t* address)
{
    prdt[0].physical_address = (uintptr_t) address;
    prdt[0].size = sector_count * 512;
    prdt[0].endbit = 1;

    // Read code... (Send lba bits, set start/stop bit, etc)
}


I use that documentation mainly for ATA DMA: http://www.osdever.net/downloads/docs/idems100.zip

Thanks in advance


Last edited by Agola on Tue Feb 14, 2017 3:14 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Sat Feb 11, 2017 4:36 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7821
Location: At his keyboard!
Hi,

Agola wrote:
Why there isn't only one PRD? Another form is that question why there are multiple PRDs, a PRDT?


Assume you want to read 100 sectors (51200 bytes) from disk to virtual address 0x123456789. Because of paging, there is no guarantee that the physical addresses are contiguous (and the ATA controller doesn't know anything about paging), so you need to split this up into physically contiguous pieces. Worst case is where none of the 4 KiB pages are physically contiguous and you need 13 PRDs (and this worst case would be relatively likely, and isn't a rare worst case that almost never happens).

Agola wrote:
Also I couldn't get what does "64K Boundary" mean. Does it mean its address shouldn't be higher than 64K in memory, 64K aligned PRD physical address of data buffer, 64K aligned PRDT or maximum total size of 64K? Or another else?


A 64 KiB boundary is any (physical) address that has the lowest 16 bits clear (e.g. 0x00010000, 0x00020000, 0x00030000, ..., 0xFFFE0000, 0xFFFF0000). "Can't cross a 64 KiB boundary" means that "address_of_first_byte >> 16 == address_of_last_byte >> 16" must be true. For example, reading 512 bytes into the area from 0x00010000 to 0x000101FF is fine (because 0x0001 == 0x0001), and reading 512 bytes into the area from 0x0001FF00 to 0x000200FF is not fine (because 0x0001 != 0x0002).

Agola wrote:
And, some documentation says I should enable Busmastering in setting the second bit PCI IDE's Command field. Should I set that bit?


You have to set that bit if you want DMA/bus mastering to work.

Agola wrote:
Is one PRD enough for me?


If all your reads/writes use physically contiguous area/s of physical memory that don't cross a 64 KiB boundary, then you only need one PRD. Typically (with paging, and with "zero copy" where you transfer data directly to/from a process and don't have a buffer that you copy data into/out of) you need to figure out how many PRDs are necessary for each read or write.

Agola wrote:
May I change the PRD variables after setting PRDT by Busmaster PRDT Register?


You can change the PRDs when the "start/stop bit" is set; however it's likely that doing so can cause problems (e.g. data corruption caused by controller caching the address and/or various possible race conditions).

Mostly; when you first initialise the controller you should make sure the "start/stop bit" is clear; then you should setup a transfer (the PRDs, etc) and then set the "start/stop" bit (to enable it) and do the read/write, then when the transfer is completed (or terminated due to a disk error or something) you should to clear the "start/stop" bit. After the "start/stop" bit is cleared (one transfer is completed), you can setup the next transfer (the PRDs, etc).


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Sun Feb 12, 2017 6:01 am 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 115
Location: At somewhere in universe
Brendan wrote:
Hi,

Agola wrote:
Why there isn't only one PRD? Another form is that question why there are multiple PRDs, a PRDT?


Assume you want to read 100 sectors (51200 bytes) from disk to virtual address 0x123456789. Because of paging, there is no guarantee that the physical addresses are contiguous (and the ATA controller doesn't know anything about paging), so you need to split this up into physically contiguous pieces. Worst case is where none of the 4 KiB pages are physically contiguous and you need 13 PRDs (and this worst case would be relatively likely, and isn't a rare worst case that almost never happens).

Agola wrote:
Also I couldn't get what does "64K Boundary" mean. Does it mean its address shouldn't be higher than 64K in memory, 64K aligned PRD physical address of data buffer, 64K aligned PRDT or maximum total size of 64K? Or another else?


A 64 KiB boundary is any (physical) address that has the lowest 16 bits clear (e.g. 0x00010000, 0x00020000, 0x00030000, ..., 0xFFFE0000, 0xFFFF0000). "Can't cross a 64 KiB boundary" means that "address_of_first_byte >> 16 == address_of_last_byte >> 16" must be true. For example, reading 512 bytes into the area from 0x00010000 to 0x000101FF is fine (because 0x0001 == 0x0001), and reading 512 bytes into the area from 0x0001FF00 to 0x000200FF is not fine (because 0x0001 != 0x0002).

Agola wrote:
And, some documentation says I should enable Busmastering in setting the second bit PCI IDE's Command field. Should I set that bit?


You have to set that bit if you want DMA/bus mastering to work.

Agola wrote:
Is one PRD enough for me?


If all your reads/writes use physically contiguous area/s of physical memory that don't cross a 64 KiB boundary, then you only need one PRD. Typically (with paging, and with "zero copy" where you transfer data directly to/from a process and don't have a buffer that you copy data into/out of) you need to figure out how many PRDs are necessary for each read or write.

Agola wrote:
May I change the PRD variables after setting PRDT by Busmaster PRDT Register?


You can change the PRDs when the "start/stop bit" is set; however it's likely that doing so can cause problems (e.g. data corruption caused by controller caching the address and/or various possible race conditions).

Mostly; when you first initialise the controller you should make sure the "start/stop bit" is clear; then you should setup a transfer (the PRDs, etc) and then set the "start/stop" bit (to enable it) and do the read/write, then when the transfer is completed (or terminated due to a disk error or something) you should to clear the "start/stop" bit. After the "start/stop" bit is cleared (one transfer is completed), you can setup the next transfer (the PRDs, etc).


Cheers,

Brendan


Wow, that answers all of my questions. Thanks!

Except, a new one :oops:

In http://wiki.osdev.org/PCI_IDE_Controller and http://wiki.osdev.org/ATA_PIO_Mode, the LBA3, LBA4 and LBA5 has different register values.

In http://wiki.osdev.org/PCI_IDE_Controller:

Code:
#define ATA_REG_LBA0       0x03
#define ATA_REG_LBA1       0x04
#define ATA_REG_LBA2       0x05
#define ATA_REG_LBA3       0x09
#define ATA_REG_LBA4       0x0A
#define ATA_REG_LBA5       0x0B


The LBA register offsets are like above.

In http://wiki.osdev.org/ATA_PIO_Mode; LBA3, LBA4 and LBA5 has the same register offset with LBA0, LBA1 and LBA2.

Which one should I refer?

Also the DMA is not working with no error code, the memory buffer fills with zeroes.
I couldn't find a good ATA datasheet / spec also.

Thanks in advance.


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Sun Feb 12, 2017 8:08 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7821
Location: At his keyboard!
Hi,

Agola wrote:
In http://wiki.osdev.org/PCI_IDE_Controller and http://wiki.osdev.org/ATA_PIO_Mode, the LBA3, LBA4 and LBA5 has different register values.

In http://wiki.osdev.org/PCI_IDE_Controller:

Code:
#define ATA_REG_LBA0       0x03
#define ATA_REG_LBA1       0x04
#define ATA_REG_LBA2       0x05
#define ATA_REG_LBA3       0x09
#define ATA_REG_LBA4       0x0A
#define ATA_REG_LBA5       0x0B


The LBA register offsets are like above.

In http://wiki.osdev.org/ATA_PIO_Mode; LBA3, LBA4 and LBA5 has the same register offset with LBA0, LBA1 and LBA2.

Which one should I refer?


I think they're both the same; except http://wiki.osdev.org/PCI_IDE_Controller isn't using actual register numbers and is using its own "encoded register enum" with a function to convert that into the actual register. More specifically; for the "void ide_write(unsigned char channel, unsigned char reg, unsigned char data)" example function; if "reg = 0x09 = LBA3" it ends up at:

Code:
    if (reg < 0x0C)
        outb(channels[channel].base  + reg - 0x06, data);


..where the "reg - 0x06" means that if "reg = 0x09 = LBA3", then "0x09-0x06 = 0x03" which is the same as the other wiki page says.

Note that this is confusing (because the "encoded register enum" doesn't match the actual register numbers), but might work out nicer to work with because you wouldn't have to deal with the fact that the same register number is used for 2 different registers everywhere else.

Agola wrote:
Also the DMA is not working with no error code, the memory buffer fills with zeroes.


That sounds like the DMA is working (correctly transferring data from somewhere) and the problem is somewhere else (where the data is coming from).

Agola wrote:
I couldn't find a good ATA datasheet / spec also.


Both of those wiki pages have various links at the bottom (in their "External Links" sections). Sadly, T13 expect you to pay for their standards, but fortunately it's easy to find an "almost identical draft" (by searching the web for the document's title, possibly with "filetype:pdf" to limit the search to PDF files).


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Sun Feb 12, 2017 12:04 pm 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 115
Location: At somewhere in universe
Thanks, finally DMA is working correctly.
I was using outb to write PRDT location instead of outl, a fun mistake.

A problem that I have, it has same/lower speed with PIO. A 1.4 MB file takes ~3 seconds to read.
Is it normal? Why the DMA is as slow as PIO? I hope it is a VM based problem.

Edit: Looks that is because of huge IRQ burst / spam. After doing a cli before 1.4 MB file takes ~0.7 seconds to read. But still far slower than ATA DMA speeds. :(

Thanks


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Sun Feb 12, 2017 7:04 pm 
Offline
Member
Member
User avatar

Joined: Sun Sep 19, 2010 10:05 pm
Posts: 959
PIO mode is probably going to be slightly faster than DMA, unless the CPU is busy doing other things. The whole point of DMA is to allow the CPU to do other things while DMA copies data from the drive to system memory.

You probably either need to disable IRQs from the controller side and use PIO mode, or make sure your interrupt handler for that particular IRQ is working properly and use DMA mode. Using the CLI instruction disables interrupts from the CPU side, but the controller is still going to send interrupt requests, and it is still going to expect the CPU to notify it when the interrupt has been handled.

What hardware is your OS running on?

_________________
Project: OZone
Source: GitHub
Current Task: EHCI Controller

"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Sun Feb 12, 2017 8:07 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7821
Location: At his keyboard!
Hi,

Agola wrote:
A problem that I have, it has same/lower speed with PIO. A 1.4 MB file takes ~3 seconds to read.
Is it normal? Why the DMA is as slow as PIO? I hope it is a VM based problem.


That seems odd to me. For PIO (assuming the disk image is in host OS's caches, which is quite likely given a typical OS developer's "edit, build, test" cycle); a VM has to emulate/execute all the instructions and that should/would be the performance bottleneck. For DMA, the VM can cheat and move all the data at once and (assuming disk image is in host OS's caches) the bottleneck could be host OS's RAM bandwidth.

In other words; I'd be tempted to expect DMA inside a VM to be significantly faster than both PIO and DMA on real hardware.

Agola wrote:
Edit: Looks that is because of huge IRQ burst / spam. After doing a cli before 1.4 MB file takes ~0.7 seconds to read. But still far slower than ATA DMA speeds. :(


Where are these IRQs coming from? Are you only doing "single sector reads" (e.g. reading 2867 individual sectors and getting 2867 IRQs), or are you reading the largest amount possible (e.g. a single 1.4 MiB read that only causes one IRQ when it's finished)?

Note that the device driver probably should have a queue of pending operations; where the device driver's IRQ handler handles the end of the previous operation (checks if it succeeded or failed and notifies something - e.g. the rest of the device driver) and then immediately starts the next operation in the queue of pending operations (if there is one). The only case where an operation isn't started from within the IRQ handler would be if the is no operation in progress (the queue of pending operations is empty).

More specifically, imagine a sequence like this:
  • TaskA asks to read something from disk, the request finds its way to storage device driver and gets added to the driver's queue of pending operations and started (because the queue was empty), and the scheduler blocks the task so it gets no CPU time and switches to a different task
  • TaskB gets CPU time and does some stuff; then it also asks to read something from disk. The request finds its way to storage device driver and gets added to the driver's queue of pending operations (but not started because the disk controller is busy still), and the scheduler blocks the task so it gets no CPU time and switches to a different task.
  • The disk controller's IRQ occurs indicating that the first operation completed. The IRQ handler notifies "something" which causes TaskA to be unblocked, then notices that there's a pending operation and starts that. The scheduler may or may not switch to TaskA immediately, and when TaskA does get CPU time it sees the data it was waiting for has arrived.
  • The disk controller's IRQ occurs indicating that the second operation completed. The IRQ handler notifies "something" which causes TaskB to be unblocked, then notices that there's aren't any more pending operations. The scheduler may or may not switch to TaskB immediately, and when TaskB does get CPU time it sees the data it was waiting for has arrived.

The point here is that the disk controller is kept doing as much work as possible as soon as possible; while the CPU is also kept doing as much work as possible (executing tasks that aren't blocked waiting for IO).


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Mon Feb 13, 2017 1:53 pm 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 115
Location: At somewhere in universe
SpyderTL wrote:
PIO mode is probably going to be slightly faster than DMA, unless the CPU is busy doing other things. The whole point of DMA is to allow the CPU to do other things while DMA copies data from the drive to system memory.

You probably either need to disable IRQs from the controller side and use PIO mode, or make sure your interrupt handler for that particular IRQ is working properly and use DMA mode. Using the CLI instruction disables interrupts from the CPU side, but the controller is still going to send interrupt requests, and it is still going to expect the CPU to notify it when the interrupt has been handled.

What hardware is your OS running on?


I disable the interrupts by setting nIEN bit in master control port 0x3F6, but it simply didn't have effect on speed or interrupts.
How can I disable interrupts fully in DMA mode?

I'm running on Bochs, QEMU and VMWare, I don't have computer for testing.

Brendan wrote:
Hi,

Agola wrote:
A problem that I have, it has same/lower speed with PIO. A 1.4 MB file takes ~3 seconds to read.
Is it normal? Why the DMA is as slow as PIO? I hope it is a VM based problem.


That seems odd to me. For PIO (assuming the disk image is in host OS's caches, which is quite likely given a typical OS developer's "edit, build, test" cycle); a VM has to emulate/execute all the instructions and that should/would be the performance bottleneck. For DMA, the VM can cheat and move all the data at once and (assuming disk image is in host OS's caches) the bottleneck could be host OS's RAM bandwidth.

In other words; I'd be tempted to expect DMA inside a VM to be significantly faster than both PIO and DMA on real hardware.

Agola wrote:
Edit: Looks that is because of huge IRQ burst / spam. After doing a cli before 1.4 MB file takes ~0.7 seconds to read. But still far slower than ATA DMA speeds. :(


Where are these IRQs coming from? Are you only doing "single sector reads" (e.g. reading 2867 individual sectors and getting 2867 IRQs), or are you reading the largest amount possible (e.g. a single 1.4 MiB read that only causes one IRQ when it's finished)?

Note that the device driver probably should have a queue of pending operations; where the device driver's IRQ handler handles the end of the previous operation (checks if it succeeded or failed and notifies something - e.g. the rest of the device driver) and then immediately starts the next operation in the queue of pending operations (if there is one). The only case where an operation isn't started from within the IRQ handler would be if the is no operation in progress (the queue of pending operations is empty).

More specifically, imagine a sequence like this:
  • TaskA asks to read something from disk, the request finds its way to storage device driver and gets added to the driver's queue of pending operations and started (because the queue was empty), and the scheduler blocks the task so it gets no CPU time and switches to a different task
  • TaskB gets CPU time and does some stuff; then it also asks to read something from disk. The request finds its way to storage device driver and gets added to the driver's queue of pending operations (but not started because the disk controller is busy still), and the scheduler blocks the task so it gets no CPU time and switches to a different task.
  • The disk controller's IRQ occurs indicating that the first operation completed. The IRQ handler notifies "something" which causes TaskA to be unblocked, then notices that there's a pending operation and starts that. The scheduler may or may not switch to TaskA immediately, and when TaskA does get CPU time it sees the data it was waiting for has arrived.
  • The disk controller's IRQ occurs indicating that the second operation completed. The IRQ handler notifies "something" which causes TaskB to be unblocked, then notices that there's aren't any more pending operations. The scheduler may or may not switch to TaskB immediately, and when TaskB does get CPU time it sees the data it was waiting for has arrived.

The point here is that the disk controller is kept doing as much work as possible as soon as possible; while the CPU is also kept doing as much work as possible (executing tasks that aren't blocked waiting for IO).


Cheers,

Brendan


I'm doing multiple sector reads, size of ext2 block size, generally 2 sectors.
Even with all interrupts are disabled, an processing in single tasking mode, the read / write speeds are far far away from the expected speed, about 16.6 MB/s. The fastest I got about 2.4 MB/s.

And... What should I output to count port, the sector count or just 1?
Quote:
outb(ATA_BASE + ATA_REG_SECTOR_COUNT0, 1);
or
Quote:
outb(ATA_BASE + ATA_REG_SECTOR_COUNT0, sector_count);


This is how I initialize PRDT...

Code:
uint32_t read_size = sector_count << sector_size; // sector_size is 9, to get fast multiplication with 512 bytes
prdt->size = read_size;
prdt->address = (uintptr_t) memalign(0xFFFF, read_size);


And that is the full code of read:

Code:
uint32_t read_size = sector_count << sector_size; // sector_size is 9, to get fast multiplication with 512 bytes
prdt->size = read_size;
prdt->address = (uintptr_t) memalign(0xFFFF, read_size); //Memory is 64 KB aligned, can use max size without

outb(BUSMASTER_BASE + BUSMASTER_COMMAND, inb(BUSMASTER_BASE + BUSMASTER_COMMAND) & ~1); // Clear start/stop bit
outl(BUSMASTER_BASE + BUSMASTER_PRDT, (uintptr_t) prdt);
outb(BUSMASTER_BASE + BUSMASTER_COMMAND, inb(BUSMASTER_BASE + BUSMASTER_COMMAND) | 8); // Set read bit
outb(BUSMASTER_BASE + BUSMASTER_STATUS, inb(BUSMASTER_BASE + BUSMASTER_STATUS) & ~(0x04 | 0x02)); // Clear interrupt and error flags according to http://wiki.osdev.org/ATA/ATAPI_using_DMA#Standard_Order_of_Sending_Commands

outb(ATA_BASE + ATA_REG_DEV_SELECT, 0xE0 | (lba & 0x0f000000) >> 24);
outb(ATA_BASE + ATA_REG_SECTOR_COUNT0, sector_count);
outb(ATA_BASE + ATA_REG_LBA0, (lba & 0xFF));
outb(ATA_BASE + ATA_REG_LBA1, (lba & 0xFF00) >> 8);
outb(ATA_BASE + ATA_REG_LBA2, (lba & 0xFF0000) >> 16);

ata_wait_bsy();

outb(ATA_BASE + ATA_REG_COMMAND, ATA_CMD_READ_DMA);
outb(BUSMASTER_BASE + BUSMASTER_COMMAND, inb(BUSMASTER_BASE + BUSMASTER_COMMAND) | 1); // Set start/stop bit

busmaster_wait(); // Poll for interrupt bit to clear.

memcpy(buffer, prdt->address, read_size);

outb(BUSMASTER_BASE + BUSMASTER_COMMAND, inb(BUSMASTER_BASE + BUSMASTER_COMMAND) & ~0x1); // Clear start/stop bit


Thanks in advance :oops:

...

Another interesting thing is using BIOS (int 13h) with Virtual 8086 mode has nearly same speeds with my ATA DMA driver. I heard BIOS sets the fastest read mode and reads with it.
I started to suspect VM, because I'm running QEMU on Linux-guest VM on Windows :|


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Mon Feb 13, 2017 9:23 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7821
Location: At his keyboard!
Hi,

Agola wrote:
I'm doing multiple sector reads, size of ext2 block size, generally 2 sectors.


This is the main reason why you get poor performance. For 1 MiB; you pay for the overhead of setting up and sending over a thousand commands, and pay for the overhead of disk controller figuring out where the sectors you wanted are over a thousand times, and pay for the overhead of over a thousand IRQs.

If you read 1 MiB in a single read (1024 blocks or 2048 sectors) you'd only pay for the overheads once.

Basically; your file system code needs to figure out how many contiguous ext2 blocks it wants and ask storage device driver for all of them at once. Note: "how many contiguous ext2 blocks it wants" can be more than it currently needs - e.g. when an application is reading a file sequentially, most OSs will detect that and prefetch by reading more than necessary (into file data cache).

The other reason you get poor performance is that you have no "queue of pending operations". More specifically, while the disk controller is transferring data you waste the entire CPU for nothing (and your file system code isn't using CPU to find the next operation for the disk controller to do), then when the transfer completes there's no pending operation to do so the disk controller is wasted for nothing while it waits for CPU and file system code to figure out the next operation.

At any point in time something that is critical to achieve good performance (either CPU or disk controller) is being wasted for nothing.

Essentially, your performance is bad because the design of your code is extremely bad (and not because there's anything wrong with the implementation of that extremely bad design).


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Mon Feb 13, 2017 9:57 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7821
Location: At his keyboard!
Hi,

Brendan wrote:
Essentially, your performance is bad because the design of your code is extremely bad (and not because there's anything wrong with the implementation of that extremely bad design).


Just to add to this...

If you fix both of these things, then performance will be good, but still won't be excellent. To get excellent performance you need IO priorities (and possible multiple queues of pending operations, one for each priority) so that important disk IO can be done sooner (without being delayed by less important disk IO). You also need to examine the queues of pending operations and determine the best order to do the operations (while taking priority into account) to reduce time wasted by seeks.

You also want to do prefetching, and you want to do it as "very low IO priority" so that it doesn't effect performance of more important reads/writes. Prefetching (when disk controller has nothing better to do) means that data is in RAM before anyone asks for it and (assuming effective file data caching) means that more file IO can be "almost instant".

For this case; if you can't cancel an "already in progress" operation then for very low priority IO (e.g. the prefetching) you do want to split it into many small reads/writes; so that if a higher priority IO request arrives it doesn't have to wait long before an "already in progress" low priority operation completes.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Tue Feb 14, 2017 3:12 pm 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 115
Location: At somewhere in universe
Wow! Such a great idea, reading contiguous sectors together. Why I never thought that before? #-o Thanks!
My design is really bad.

That really increased the read speed of ext2.

Also I noticed running VM in VM affects the read speeds also. I copied the disk image to Windows, and ran with the VMWare and Bochs, read was nearly instant.
I'm getting speeds about ~8 MiB/s currently enough for me.

I'm marking the thread 'Solved'... Though, I have a last two questions;

Code:
outb(ATA_BASE + ATA_REG_SECTOR_COUNT0, sector_count);


Is that really correct? Read size is already handled with PRD, why I need that also? Should I put it sector_count or just one?

And, a PRDT entry addresses 64 KiB max, what should I do if I want to read more than 64 KiB at once?
If I use multiple PRDT entries, can I read more than 64 KiB?

Thanks...


Top
 Profile  
 
 Post subject: Re: Questions about ATA DMA
PostPosted: Tue Feb 14, 2017 9:19 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 7821
Location: At his keyboard!
Hi,

Agola wrote:
I'm marking the thread 'Solved'... Though, I have a last two questions;

Code:
outb(ATA_BASE + ATA_REG_SECTOR_COUNT0, sector_count);


Is that really correct?


Looks correct to me. :)

Agola wrote:
Read size is already handled with PRD, why I need that also? Should I put it sector_count or just one?


It's probably best to think of it as 3 separate pieces of hardware - the disk drive, the ATA/ATAPI controller, and the controller's DMA engine. Note that originally these were literally and physically separate (in ancient times the chipset's ISA DMA chip was used), then they added better DMA (possibly starting with a separate/additional chip on the same card as the IDE/ATA controller chip). Over time more functionality got merged into fewer chips (including shifting things from "add on card" to "built into chipset"); but (partly due to backward compatibility and standards) the same old "logically separate pieces" remains.

Agola wrote:
And, a PRDT entry addresses 64 KiB max, what should I do if I want to read more than 64 KiB at once?
If I use multiple PRDT entries, can I read more than 64 KiB?


Yes. This is the reason there's a table of PRDTs and not just one PRD.

For "largest case"; with a 64 KiB PRDT you'd have up to 8192 PRDs, and each PRD describes what to do with up to 64 KiB of data. This gives a theoretical maximum of 512 MiB for a single read or write. Of course (in practice) it's probably easier to just copy information from page tables into PRDs, and (due to "4 KiB per page") that'd give you a maximum of 32 MiB in a single read or write.

Also note that (if you wanted to be "excessively clever"); you could probably use PRDs to support arbitrary accesses. For example, if you want to read 10 bytes in the middle of a sector, you could arrange one PRD to send the unwanted first half of the sector to a "garbage page", then have another PRD to send the next 10 bytes to where ever they're wanted and make that the last PRD so that the remaining data in the sector doesn't go anywhere (and would probably cause an expected "DMA overrun error" in the controller that you'd have to be prepared to ignore).


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group