Quantcast
Viewing all articles
Browse latest Browse all 17527

Linux spi-davinci driver: SPI Tx sends all zeros instead of actual data, possible DMA issue

Processor is OMAP-L138, running Linux 3.10.0 on the ARM.  Linux has SPIDEV enabled and spi-davinci providing the low-level SPI support.  SPI0 and SPI1 are both used, but SPI0 is only used on startup to send some configuration settings.  SPI1 is used during normal for the application to communicate with other devices.  Only SCS2 on SPI1 is used.  SPI links are set up to use DMA for transfers.

With no other application processing running, SPI0 can send large data packets (up to 511 byte limit) using SPIDEV driver and IOCTL command for simultaneous read/write.  Data is sent with no problems.

SPI1 can send small data packets (7 bytes) using SPIDEV driver and IOCTL command with no apparent problems.

However during normal running with multiple application threads running, if SPI1 tries to send larger data packets then the SPI often sends zero instead of the actual Tx data.  It may lose the entire packet, or it may only zero out some of the packet.  The more heavily loaded the ARM is, the more likely this is to happen.  If I add printk reporting of the packet in spi_davinci.c function davinci_spi_bufs() before Tx, it reports the data correctly and data corruption stops.  If I just take a checksum of the Tx data and printk that, it still confirms that the Tx data is correct but the data corruption comes back.  So a delay before running the SPI transfer fixes it.

To me, this looks like a problem with DMA and caching.  The extra delay allows the processor time to write cached data back, but when running normally the DMA reads data from the buffer before the cache has been flushed back.  I would expect transfers to do a cache flush/clean before starting.  I can't see it in the spi-davinci.c code, but it should be part of the DMA engine calls to run this.

I do have a relatively old version of spi-davinci.c, but I've checked against the latest Linux branch and there have been no changes which would affect this.

I have found one bug in the driver, where

 		t->tx_dma = dma_map_single(&spi->dev, buf,
				t->len, DMA_FROM_DEVICE);

should be DMA_TO_DEVICE, since the Tx is DMA'ing from memory to the SPI device.  I tried changing this, but it did not fix the problem.


Viewing all articles
Browse latest Browse all 17527

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>