Unusual serial flow control regression on SAMA5D35

This forum is for users of Microchip MPUs and who are interested in using Linux OS.

Moderator: nferre

jbyrne
Posts: 5
Joined: Fri Dec 05, 2014 5:18 pm

Unusual serial flow control regression on SAMA5D35

Fri Jul 20, 2018 8:34 pm

Hi,

We have come across an unexpected issue with the Linux serial driver on the SAMA5D35. I suspect this is an exceptional case due to our specific hardware design, but am raising it here because it could affect other people, and I would like to know whether anyone can suggest an alternative solution.

We have a product that uses a Ronetix SAMA5D3x-CM CPU module on a custom designed motherboard. I am in the process of upgrading our kernel from 3.18 to 4.14, and discovered an unexpected regression in serial port communications when hardware flow control was enabled. With the new kernel I would get a spurious zero byte transmitted by the system each time the CTS line was toggled to suspend/resume transmission.

After a prolonged debugging exercise we eventually discovered that the reason is the change made in commit 89d8232411a85b9a6b12fd5da4d07d8a138a8e0c of the upstream linux kernel ("tty/serial: atmel_serial: BUG: stop DMA from transmitting in stop_tx") that disables and re-enables the serial transmitter when the CTS line state changes. The reason this affects our motherboard, but may not have affected anyone else, is that on our design the serial port is connected via opto-isolators. When the serial transmitter is disabled the USART stops driving the line, leaving the chip's internal pull-up to pull it high. This is OK if the line is connected directly to a line-driver, but it does not provide enough current to drive an opto-isolator, so instead of outputting a high signal when the transmitter is disabled it turns off, which gets interpreted by the receiving end as a zero byte once transmission resumes.

In the end, I applied the following fix to the serial driver, which resolves the issue as long as you are using PIO mode. There is no way to use DMA transmission because, as the comments say, the reason this was added is as a workaround for a bug in the silicon where hardware flow control does not work properly with DMA.

Code: Select all

--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -479,12 +479,14 @@ static void atmel_stop_tx(struct uart_port *port)
                atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
        }
 
-       /*
-        * Disable the transmitter.
-        * This is mandatory when DMA is used, otherwise the DMA buffer
-        * is fully transmitted.
-        */
-       atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
+       if (atmel_use_dma_tx(port)) {
+               /*
+                * Disable the transmitter.
+                * This is mandatory when DMA is used, otherwise the DMA buffer
+                * is fully transmitted.
+                */
+               atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
+       }
 
        /* Disable interrupts */
        atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
@@ -519,8 +521,10 @@ static void atmel_start_tx(struct uart_port *port)
        /* Enable interrupts */
        atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
 
-       /* re-enable the transmitter */
-       atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
+       if (atmel_use_dma_tx(port)) {
+               /* re-enable the transmitter */
+               atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
+       }
 }
 
 /*
Can anyone comment on whether this patch would be suitable to submit upstream?

Are there are any alternative software solutions to this problem? It's too late to change the hardware for the systems we have already made.

Thanks,

James
blue_z
Location: USA
Posts: 1703
Joined: Thu Apr 19, 2007 10:15 pm

Re: Unusual serial flow control regression on SAMA5D35

Sat Jul 21, 2018 12:14 am

jbyrne wrote:With the new kernel I would get a spurious zero byte transmitted by the system ...
Have you been able to actually capture any of these "transmitted" spurious bytes on the wire with an oscilloscope or logic analyzer?

jbyrne wrote:... it turns off, which gets interpreted by the receiving end as a zero byte once transmission resumes.
Your explanation transitions from being descriptive to contradictory and ambiguous.

The required framing for a valid asynchronous serial character (i.e. a start bit and stop bit) is highly unlikely to be generated by randomly disabling and enabling the line driver (or opto-isolator).
I would expect the "receiving end" UART to detect such an event as a break condition if the duration is long enough, else it's a framing error.


jbyrne wrote:Are there are any alternative software solutions to this problem?
You neglect to mention what this "receiving end" is.
If this "receiving end" happens to be another Linux host, then this alleged "zero byte" is most likely explained as a termios configuration that inserted a null byte to indicate a break condition (or framing error) on the line.
Such a termios configuration can be modified so that no "zero byte" is inserted into the data.

Regardless, the real (and apparently only) problem seems to be unexpected (or improper) handling of break and/or framing errors by your "receiving end".

Regards
jbyrne
Posts: 5
Joined: Fri Dec 05, 2014 5:18 pm

Re: Unusual serial flow control regression on SAMA5D35

Mon Jul 23, 2018 8:21 pm

blue_z wrote: The required framing for a valid asynchronous serial character (i.e. a start bit and stop bit) is highly unlikely to be generated by randomly disabling and enabling the line driver (or opto-isolator).
I would expect the "receiving end" UART to detect such an event as a break condition if the duration is long enough, else it's a framing error.
blue_z wrote: You neglect to mention what this "receiving end" is.
If this "receiving end" happens to be another Linux host, then this alleged "zero byte" is most likely explained as a termios configuration that inserted a null byte to indicate a break condition (or framing error) on the line.
Such a termios configuration can be modified so that no "zero byte" is inserted into the data.

Yes, you are quite correct, the zero bytes I was seeing were in fact inserted by the Linux host on the receiving end seeing a break condition, as that is the default termios setting. Sorry for the incorrect explanation in my previous post.

blue_z wrote: Regardless, the real (and apparently only) problem seems to be unexpected (or improper) handling of break and/or framing errors by your "receiving end".

I'm not sure I agree with that. The problem is that due to the change in the serial driver (to fix DMA), an incorrect break condition was being signalled when it should not be (even when not using DMA). This is somewhat specific to our hardware design, but I thought it might be useful to post this observation here in case anyone else encounters a similar problem.

I am still tending to think that my patch might be worth considering submitting upstream, as there is no need for the transmitter to be disabled when DMA is not being used, and the fact that it causes the chip to stop actively driving the TX line has an unexpected effect on hardware such as ours. However, I thought it might be worth running it past the people on this forum first to see if anyone disagreed or had a better solution.

James

Return to “LINUX”

Who is online

Users browsing this forum: Google [Bot] and 3 guests