All-
We're currently seeing an issue with inbound EDMA transfers via PCIe, and are wondering if anyone has seen similar results. Details are as follows:
- DM814x on custom PCI expansion card.
- DM814x sits behind PEX8112 PCIe bridge (in reverse-bridging mode), and acts as a PCIe endpoint.
- Custom driver for PCIe endpoint operations on DM814x, based on TI sample code and making use of TI's EDMA infrastructure.
- Transfers (inbound to DM814x and outbound from DM814x) are handled via EDMA, and are sent to/from host memory via an 8 MiB PCIe outbound mapping + offset @ 0x20000000. All transfers are page (4 KiB) aligned and 1 page in size on both the DM814x and x86 host.
- Outbound transfers (from DM814x SDRAM to x86 WinXP host SDRAM) are 100% reliable - we've validated multi-GiB transfers of both test data and encoded bitstreams.
- Inbound transfers (from host x86 WinXP host SDRAM to DM814x SDRAM) are occasionally corrupt; we see 64 bytes of (aligned) zeros somewhere in the middle of the page on the DM814x once the DMA operation completes.
- No EDMA error is reported.
- Re-trying the EDMA does not result in a successful transfer.
- Re-trying the transfer as a simple PIO (i.e. *dest++ = *src++) through the existing mapping is 100% successful.
- A full flush of the cache via flush_cache_all() both before and after the EDMA does not help.
I've included a small snippet of the relevant code below. mdl->pa_buf is the physical address of the buffer on the host system, and ti81xx_edma_dma_rx() is as per the PCIe Express EP Driver User's Guide.
Any tips would be appreciated.
Thanks.
-Cory
/* Map the host memory into PCIe outbound region 0. */
write_application_register(OB_OFFSET_INDEX(0), ((mdl->pa_buf & 0xFF800000) | 1));
write_application_register(OB_OFFSET_HI(0), 0);
/* EDMA transactions _must_ be 16-byte aligned, and on 16-byte
* boundaries.
*
* TMS320DM814x DaVinci(TM) Digital Media Processors
* Silicon Revision 2.1 Errata (SPRZ343A.pdf)
*
* Advisory 2.1.6
*/
dma_addr_src = (dma_addr_t)(0x20000000 | (mdl->pa_buf & 0x007FFFFF));
BUG_ON(dma_addr_src & 0xF);
dma_addr_dest = dma_map_single(c->device, dma_buffer, HDUAC_PAGE_SIZE, DMA_FROM_DEVICE);
BUG_ON(dma_addr_dest & 0xF);
//flush_cache_all();
err_dma = ti81xx_edma_dma_rx(dma_addr_src, dma_addr_dest, 1, 4096, 1, ABSYNC);
if (err_dma)
pr_err(KBUILD_MODNAME ": ti81xx_edma_dma_rx() failed!\n");
dma_unmap_single(c->device, dma_addr_dest, HDUAC_PAGE_SIZE, DMA_FROM_DEVICE);
//flush_cache_all();