Tegra HSUART DMA Configuration Failure and PIO Mode Data Corruption

Platform: Jetson AGX Orin (T234, p3737+p3701), L4T R36.4.3, Kernel 5.15.148-tegra

  1. BACKGROUND - Original PIO Mode Issue (Before Any Modifications)

In stock L4T R36.4.3 with PIO mode (default configuration, no DMA enabled in device tree for serial@3110000):

Observed behavior:

  • Transmit 18 bytes, expect 46-byte response
  • Kernel logs show icount.rx=46 (kernel received 46 bytes)
  • User space only receives 44 bytes (2 bytes lost in tty_flip_buffer_push timing)
  • Success rate: ~99.5%, but 0.5% frame loss is unacceptable for industrial communication

Root cause identified: serial-tegra.c calls tty_insert_flip_string() but only calls tty_flip_buffer_push() at end of RX ISR. The 2-byte loss occurs when push() flushes partial data while more data is still being processed.


  1. ATTEMPTED FIX - Device Tree DMA Configuration

To solve PIO timing issues, we attempted to enable DMA mode by modifying device tree:

Changes made:

File 1: tegra234-p3737-0000+p3701-xxxx-nv-common.dtsi - board-level enable

            serial@3110000 {                                                                                                                                                                                                                                
                    compatible = "nvidia,tegra194-hsuart";                                                                                                                                                                                                  
                    reset-names = "serial";                                                                                                                                                                                                                 
                    status = "okay";                                                                                                                                                                                                                        
  •                 dmas = <&gpcdma 26>, <&gpcdma 27>;                                                                                                                                                                                                      
    
  •                 dma-names = "rx", "tx";                                                                                                                                                                                                                 
            };                                                                                                                                                                                                                                              
    

File 2: tegra234-soc-overlay.dtsi - serial@3110000 base definition

            serial@3110000 {                                                                                                                                                                                                                                
                    compatible = "nvidia,tegra234-uart", "nvidia,tegra20-uart";                                                                                                                                                                             
                    reg = <0x0 0x03110000 0x0 0x10000>;                                                                                                                                                                                                     
                    ...                                                                                                                                                                                                                                     
  •                 iommus = <&smmu_niso0 TEGRA234_SID_GPCDMA>;                                                                                                                                                                                             
    
  •                 dma-coherent;                                                                                                                                                                                                                           
                    status = "disabled";                                                                                                                                                                                                                    
            };   
    

  1. CURRENT FAILURE - Both DMA and PIO Paths Broken

After above DT changes and kernel rebuild:

Issue A: RX DMA - No Data Transfer
DMA DEBUG: channel rx allocated successfully
DMA DEBUG: RX slave config: src=0x3110000, dst=0xffffffd0, width=1
// No “RX COMPLETE” callbacks - DMA never fires

  • DMA channels allocate without error
  • But no actual data transfer occurs
  • kernel_rx_delta=0 during tests

Issue B: TX Data Corruption (Critical)
When DMA partially works, TX shows systematic 4-byte data shift:

Test sequence:

  1. Write 18 bytes: DB 10 04 00 BB 14 35 02 00 00 01 01 00 00 00 00 24 00
  2. First TX: 16 bytes sent correctly (db 10 04 00 bb 14 35 02…)
  3. Complete, tail=16, remaining 2 bytes in buffer
  4. Second write 18 bytes to buffer at tail=18
  5. Bug: Driver sees tail=18 (not 4-byte aligned) → triggers “alignment PIO”
  6. PIO sends 2 “alignment” bytes (which are actually valid frame data)
  7. tail advances to 20 (consumed 2 valid data bytes as “padding”)
  8. Subsequent DMA sends from offset 20: 04 00 bb 14 35 02… (shifted garbage)

Log evidence:
[ 290.065433] start_next_tx: tail_idx=0, count=18, align=0 → choosing DMA
[ 290.065438] TX: sending 16 bytes: db 10 04 00 bb 14 35 02… (OK)
[ 290.065469] TX COMPLETE: tail_after=16, head=18, pending=2
[ 290.566163] start_next_tx: tail_idx=18, align_needed=2 → choosing PIO for alignment
[ 290.566181] start_next_tx: tail_idx=20, count=16, align=0 → choosing DMA
[ 290.566187] TX: sending 16 bytes: 04 00 bb 14 35 02 00 00… (WRONG! Shifted by 4)

The 4-byte shift: tail jumps 18→20 (consumed 2 valid bytes) + next frame starts 4 bytes later than expected, causing the “04 00 bb 14” garbage data.

Hi xuqiang0521,

Are you using the devkit or custom board for AGX Orin?

Do you enable the HW flow control to prevent the data loss?

Please share the full dmesg and device tree for further check.

Could you reproduce the similar issue in the UART loopback test through shorting TX/RX?

1 Does uartb (serial@3110000) hardware support GPC DMA RX transfer on custom carrier boards?

2 If supported, what is the correct DMA channel number (not an arbitrary free channel, but the hardware-fixed one) for uartb RX/TX?

3 If supported, are there any other special configurations required in the device tree besides the dmas property (e.g., specific iommus StreamID for uartb, or should we use AHBDMA instead of GPCDMA)?

1 custom board for AGX Orin

2 We have not enabled hardware flow control(RTS/CTS),current b=115200.

In PIO mode, the kernel receives the data (icount.rx increments correctly), but userspace loses 2 bytes when reading. This is caused by the tty_flip_buffer_push timing window between interrupt handler and TTY layer

The device tree serial port configuration is the original/unmodified version from the Jetson Linux R36.4.3 package

Yes, it should be supported while we don’t verify it locally.
You can try adding the following lines for serial@3110000 to enable it working with DMA mode.

                        dmas = <&gpcdma 12>, <&gpcdma 12>;
                        dma-names = "rx", "tx";
                        iommus = <&smmu_niso0 TEGRA234_SID_GPCDMA>;

Please enable HW flow control with RTS/CTS to prevent the data loss.

I would suggest verifying with the latest JP6.2.2(R36.5).

Testing GPCDMA RX/TX with channel 12 for UARTB (serial@3110000, ttyTHS2) - DMA allocation succeeds but transfer does not work.

Device Tree Configuration:
serial@3110000 {
compatible = “nvidia,tegra194-hsuart”;
status = “okay”;
dmas = <&gpcdma 12>, <&gpcdma 12>;
dma-names = “rx”, “tx”;
};

dmesg Log:
[ 913.181550] serial-tegra 3110000.serial: DMA DEBUG: attempting TX DMA allocation
[ 913.181553] serial-tegra 3110000.serial: DMA DEBUG: attempting RX DMA allocation
[ 913.181575] serial-tegra 3110000.serial: DMA DEBUG: channel rx allocated successfully
[ 913.181590] serial-tegra 3110000.serial: DMA DEBUG: RX DMA allocated successfully
[ 913.182689] serial-tegra 3110000.serial: DMA DEBUG RX START: submitting 4096 bytes DMA
[ 914.963745] tegra-gpcdma 2600000.dma-controller: DMA pause timed out

Test Result:

  • TX: Falls back to PIO immediately (“choosing PIO”), DMA not working
  • RX: residue=4096, count=0, DMA controller times out
  • Kernel RX counter: 0 bytes (expected 46)
  1. Is channel 12 the correct GPCDMA channel for UARTB (0x3110000)?
  2. If not, what is the correct RX and TX channel number?

GPCDMA automatically assigns channels 20 (TX) and 21 (RX) to UARTB. However, RX DMA does not work at all, while TX DMA works correctly.

Evidence:
[TX] DMA DEBUG TX COMPLETE: requested=16, residue=0, actual_count=16 ✅ Working
[RX] DMA DEBUG RX PUSH: residue=4096, count=0 ❌ No data
[RX] tegra-gpcdma: DMA pause timed out ❌ Controller stuck

Key Findings:

  1. PIO mode works fine - Can receive 37-46 bytes, proving physical layer is OK
  2. Manual channel assignment fails - Tried channels 8, 12, 24 in DT, all return -19 (ENODEV)
  3. GPCDMA auto-assigns 20/21 and ignores DT specified channels
  4. RX buffer remains full (4096 residue) - DMA controller never writes to memory
  5. FCR DMA_SELECT bit is set, dma-coherent property present in DT

Configuration:
serial@3110000 {
compatible = “nvidia,tegra194-hsuart”;
dmas = <&gpcdma 0>, <&gpcdma 0>; /* Auto-assigns ch20/21 */
dma-names = “rx”, “tx”;
iommus = <&smmu_niso0 TEGRA234_SID_GPCDMA>;
status = “okay”;
};

Questions:

  1. Does UARTB (0x3110000) require a specific GPCDMA channel or Stream ID (SID) for RX?
  2. Is there hardware limitation preventing GPCDMA RX on UARTB?

Please try specifying 9 for dmas property as following.

                        dmas = <&gpcdma 9>, <&gpcdma 9>;
                        dma-names = "rx", "tx";
                        iommus = <&smmu_niso0 TEGRA234_SID_GPCDMA>;

If you still hit the issue, please share the full dmesg and the extracted device tree in runtime for further check.

$ sudo dtc -I fs -O dts -o extracted_proc.dts /proc/device-tree