Wind River Support Network

HomeDefectsLIN1019-9350
Fixed

LIN1019-9350 : nxp-ls1046: i2c-imx.c driver, DMA not working

Created: Jan 26, 2023    Updated: Apr 4, 2023
Resolved Date: Feb 9, 2023
Found In Version: 10.19.45.25
Fix Version: 10.19.45.27
Severity: Severe
Applicable for: Wind River Linux LTS 19
Component/s: BSP

Description

Everything works fine for small data transfers (< DMA_THRESHOLD=16 bytes) as the CPU handles the i2c transactions, i.e. transmit/receives every single byte programming the i2c module. For bigger data transfers, the DMA comes into play, and we found:
 * the eDMA is not coherent with the CPU cache -> this can be fixed by declaring the i2c adapter as non "dma-coherent", in the device-tree node;

 * the eDMA has only 32bit field of destination address, in the TCD (transfer control descriptor);

In particular, the last bullet implies that if the buffer, that will be pointed by the DMA transaction, lives in a physical DRAM address higher than 1GB (generally speaking it has a 64-bit physical address), it is impossible for the DMA to reach that zone, without having an IOMMU that translates the 32-bit bus address into a more general 64-bit one. All mapping and synch are expected to be performed in dma_map_single/unmap().

With the DMA involved, reading more than 16 bytes, lead to all zeros, which is totally wrong. Please note that the last 2 bytes are always good, as they are managed by the CPU, not by the DMA. With an oscilloscope, the customer verified that the hardware transaction is happening on the wires and that the DMA operation is stored in DRAM. But the DMA writes apparently the wrong physical address.
Said otherwise the physical address behind the ioctl buffer msgs[1]{-}>buff (see i2c_imx_xfer() func) is different from the physical address pointed by dma{-}>dma_buf, as it lives outside of the 32-bit addressable space – I am assuming a 1-1 mapping among bus addresses and physical addresses, equivalently no translation is performed by a hypothetical IOMMU responsible of translating the bus addresses into physical ones.

Steps to Reproduce

1.  Create an LTS19 RCPL25 project 
$ git clone --branch WRLINUX_10_19_LTS_RCPL0025 https://gateway.delivers.windriver.com/git/linux-lts/release/wrlinux-lts.19/WRLinux-lts-19-Core/wrlinux-x
$ ./wrlinux-x/setup.sh --machines nxp-ls1046 --dl-layers
$ . ./environment-setup-x86_64-wrlinuxsdk-linux
$ . ./oe-init-build-env
add IMAGE_INSTALL_append +=  " i2c-tools" to conf/local.conf
$ bitbake wrlinux-image-std
$ bitbake -c menuconfig linux-yocto
Device drivers -> I2C support -> enable I2C Device Interface

2. On the board, first, fill up EEPROM with a counter value:
root@nxp-ls1046:~# i2ctransfer -f -y 0 w8@0x52 0x00 0x01+
root@nxp-ls1046:~# i2ctransfer -f -y 0 w8@0x52 0x07 0x08+
root@nxp-ls1046:~# i2ctransfer -f -y 0 w8@0x52 0x0e 0x0f+

3. I2C transfer without DMA involved

Everything is okay if the read transfer is less than 16 bytes (DMA_THRESHOLD).

root@nxp-ls1046:~# i2ctransfer -f -y 0 w1@0x52 0x00 r8
0x11 0x12 0x13 0x14 0x15 0x06 0x07 0x08

root@nxp-ls1046:~# i2ctransfer -f -y 0 w1@0x52 0x00 r15
0x11 0x12 0x13 0x14 0x15 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f

root@nxp-ls1046:~# i2ctransfer -f -y 0 w1@0x52 0x0e r15
0x0f 0x10 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff

4. I2C transfer with DMA involved:

root@nxp-ls1046:~# i2ctransfer -f -y 0 w1@0x52 0x00 r16
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0f 0x10

root@nxp-ls1046:~# i2ctransfer -f -y 0 w1@0x52 0x00 r20
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xff 0xff
Live chat
Online