UDMA for Compact Flash over PC Card?
Iain Barker
ibarker at aastra.com
Tue Feb 5 11:46:38 EST 2008
FYI, we've been looking at this recently, and the DMA-related PXA patch from this email thread:
http://lists.infradead.org/pipermail/linux-pcmcia/2007-April/004473.html
On Wed Apr 4 06:36:35 EDT 2007, Steve Newbury wrote:
>
> The only way of getting CF devices to run in (U)DMA mode is to physically
> attach them to an IDE controller. CF devices can electrically operate as
> either PCMCIA-like or IDE devices. If operating as a PCMCIA device it can only
> be accessed with IO or MMIO. If you want more performance than the 300ns cycle
> IO access time you need to use MMIO **and set the access speed to the correct
> value for that CF device**, you'll then get much higher performace (upto
> 20MB/s). Using a variation on Thomas Kleffel's patch I've tried before, not
> completely managed to get it working, see this lists archives. I couldn't get
> the interrupt working for some reason.
>
> Steve
The compact flash spec has a feature that allows DMA host controllers to move data to and from the CF data buffer WHEN USING PIO MODE, more efficiently and quicker than simply doing individual reads and writes to and from the single 16-bit ata data register.
i.e. for architectures which have a DMA controller (for example, PCI bridges) when used with PCMCIA controllers which DO NOT support DMA (for example, TI PCI1510), this can reduce CPU overhead for PIO transfers considerably.
This feature is simply a pseudo buffer, that resides at ata offset 0x0400-0x0800, that allows incrementing dmas sequential access to the same ata data register, which in reality is just a fifo, but the feature is only available when the cf is configured for MEMORY mode.
There was an earlier attempt to support MMIO by Thomas Kleffel, but his patch was reverted in 2.6.19 by Andrew Morton due to various problems.
Although it's not in the mainline Linux code, I know readers on this list who use Thomas' patch, so this is an attempt at summarising the problems and possible fixes.
1/ It has a problem with still using the default PCI IO access functions to communicate with the cf's ATA registers during probe, rather than using MMIO for all operations.
Fix: Adding specific code to ide_register_hw_with_fixup function to load the PCI MEM functions into the hwif struct when that struct is being initialized and the is_mmio flag is set.
In drivers/ide/legacy/ide-cs.c
Within the CIS parser, set the memory mode per Thomas' is_mmio patch:
> link->conf.IntType = INT_MEMORY;
Then pass is_mmio from Thomas' patch as the last parameter when calling the fixup function:
> int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif), int is_mmio)
807a808,821
> if (is_mmio)
> {
> default_hwif_mmiops(hwif);
> hwif->io_ports[IDE_DATA_OFFSET] += 0x0400;
> hwif->mmio = 2;
> }
>
2/ Once the ide driver was able to communicate successfully with the cf ATA registers in MEM mode we could see that the interrupts didn't work.
Fix: Changing the desired interrupt mode from INT_MEMORY_AND_IO to INT_MEMORY when configuring the pcmcia socket controller. The lowest-level yenta socket code could handle this functionality but the higher-level pcmcia code could not handle it.
i.e. fix this by adding 2 lines of of INT_MEMORY support code to the pcmcia_request_configuration function.
In drivers/pcmcia/pcmcia_resource.c
628a629,633
> if (req->IntType & INT_MEMORY)
> {
> s->socket.flags &= ~SS_IOCARD; // this is not an IO card
> s->socket.csc_mask |= SS_READY; // enable the READY interrupt
> }
3/ Extend the base register so that it looks at the MMIO buffer at +400 instead of the base data register.
In drivers/ide/legacy/ide-cs.c
> int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif), int is_mmio)
807a808,821
> /* if the mmio flag is set we populate the hwif structure with
> * the functions used to access PCI memory space (as opposed to
> * the default functions which access PCI io space). we also
> * change the 'data' offset to the address of the data buffer
> * that exists at offset 0x0400 so that we can use pci dmas
> * to move data faster.
> */
> if (is_mmio)
> {
> default_hwif_mmiops(hwif);
> hwif->io_ports[IDE_DATA_OFFSET] += 0x0400;
> hwif->mmio = 2;
> }
>
Note: This isn't a complete solution, as with the ide driver now working in MEMORY mode it still needs architecture-specific code to implement the DMA transfer
to the MMIO FIFO buffer. That's relatively trivial using the arch native PCI driver functions to move 16-bit data to and from the PCI bus using block
transfers instead of single-access transfers, for example the PXA driver from Steven.
Thanks to the following for ideas and guidance:
Steven Newbury
Thomas Kelffel
Piotr Krysiuk
Fabrice Aeschbacher
and especially Gui Viviers for the above solution.
More information about the linux-pcmcia
mailing list