Hi Uwe, On Mon, Sep 04, 2017 at 08:47:08AM +0200, Uwe Kleine-König wrote: > Hello Clemens, > > first of all thanks for your research and feed back to the list. > > On Mon, Sep 04, 2017 at 02:24:45AM +0200, Clemens Gruber wrote: > > I finished my analysis of the imx RS-485 DMA problem, we discussed on > > the list before and which was fixed upstream with commit 514ab34dbad6 > > ("serial: imx: Prevent TX buffer PIO write when a DMA has been started") > > from Ian. > > > > Open questions were: > > 1) Why did this only appear on SMP machines? > > 2) Why did this only affect RS-485? > > > > Thanks to ftrace, I can now answer both: > > > > 1) When starting a new transmission, the following happens in > > imx_start_tx: > > After imx_port_rts_active to enable the external RS-485 transceiver, > > the transmit-complete-interrupt is enabled (TCEN). > > Then, imx_dma_tx is called and the DMA request is handed off. > > Now, while sdma_prep_slave_sg and sdma_load_context are executing on one > > CPU core, imx_int is called on another, because the previously enabled > > interrupt asserted immediately (TXDC was active because both the TxFIFO > > and the Shifter were empty) after enabling it. (50us on i.MX6Q SMP) > > This leads to the transmit_buffer function (called from imx_int/imx_txint) > > writing to UTXD which corrupts the ongoing DMA transmission and also leads to > > xmit->tail getting double-incremented and jumping over xmit->head, so the whole > > UART_XMIT_SIZE xmit buffer is sent out. > > On non-SMP machines, the interrupt is handled later when > > uart_circ_empty(xmit) is already true and transmit_buffer returns before > > doing PIO. With a non-SMP kernel on an i.MX6Q, I measured 35ms until > > imx_int/imx_txint and the function_graph trace showed > > imx_txint() > > imx_stop_tx() > > (Instead of a trace_printk I added to the PIO loop in transmit_buffer) > > I see that imx_start_tx only enables irqs but doesn't send data. So I > wonder if this could be done better by already writing to TXDATA (in the > !dma case) or preparing the DMA transfer (otherwise). Up to now the > driver waits for an irq which introduces a needless delay first > including a context switch first. If DMA is enabled, imx_start_tx already calls imx_dma_tx. But we could begin sending data in the !DMA case (and the X-char both in DMA and !DMA cases) from within imx_start_tx and set TCEN at the end. I'd also like to separate the handling of TRDY and TXDC in imx_int. The latter is only relevant for RS-485 and should result in an imx_stop_tx if uart_circ_empty || uart_tx_stopped. No need to jump into imx_txint/imx_transmit_buffer with its x_char and wakeup handling. Cheers, Clemens -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html