From: Michael Walle <hidden> Date: 2021-05-11 20:02:05
Give fsl_lpuart some love and add break, loopback and sysrq support. While
at it, some errors were noticed, which are also fixed in this series.
The sysrq support was tested on both interrupt driven and DMA based
transfers on the 32bit LPUART.
Michael Walle (8):
serial: fsl_lpuart: don't modify arbitrary data on lpuart32
serial: fsl_lpuart: use UARTDATA_MASK macro
serial: fsl_lpuart: don't restore interrupt state in ISR
serial: fsl_lpuart: handle break and make sysrq work
serial: fsl_lpuart: remove RTSCTS handling from get_mctrl()
serial: fsl_lpuart: remove manual RTSCTS control from 8-bit LPUART
serial: fsl_lpuart: add loopback support
serial: fsl_lpuart: disable DMA for console and fix sysrq
drivers/tty/serial/fsl_lpuart.c | 126 +++++++++++++++++---------------
1 file changed, 69 insertions(+), 57 deletions(-)
--
2.20.1
From: Michael Walle <hidden> Date: 2021-05-11 20:02:07
lpuart_rx_dma_startup() is used for both the 8 bit and the 32 bit
version of the LPUART. Modify the UARTCR only for the 8 bit version.
Fixes: f4eef224a09f ("serial: fsl_lpuart: add sysrq support when using dma")
Signed-off-by: Michael Walle <redacted>
---
drivers/tty/serial/fsl_lpuart.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Michael Walle <hidden> Date: 2021-05-11 20:02:09
Use the corresponding macro instead of the magic number. While at it,
drop the useless cast to "unsigned char".
Signed-off-by: Michael Walle <redacted>
---
drivers/tty/serial/fsl_lpuart.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Michael Walle <hidden> Date: 2021-05-11 20:02:12
Since commit 81e2073c175b ("genirq: Disable interrupts for force
threaded handlers") interrupt handlers that are not explicitly requested
as threaded are always called with interrupts disabled and there is no
need to save the interrupt state when taking the port lock.
This is a preparation for sysrq handling which uses
uart_unlock_and_check_sysrq();
Signed-off-by: Michael Walle <redacted>
---
drivers/tty/serial/fsl_lpuart.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
From: Michael Walle <hidden> Date: 2021-05-11 20:02:16
Although there is already (broken) sysrq characters handling, a break
condition was never detected. There is also a possible deadlock because
we might call handle_sysrq() while still holding the port lock.
Add support for break detection and use the proper
uart_unlock_and_check_sysrq() to defer calling handle_sysrq().
Signed-off-by: Michael Walle <redacted>
---
drivers/tty/serial/fsl_lpuart.c | 36 ++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 10 deletions(-)
From: Michael Walle <hidden> Date: 2021-05-11 20:02:20
The LPUART doesn't have the ability to control the RTS or CTS line
manually. Instead it will set it automatically when data is send or
handle it when data is received. Thus drop the wrong code in set_mctrl.
For the 32 bit version this was already done in the commit 2b30efe2e88a
("tty: serial: lpuart: Remove unnecessary code from set_mctrl"). Keep
the 8-bit version in sync and remove it there, too.
Signed-off-by: Michael Walle <redacted>
---
drivers/tty/serial/fsl_lpuart.c | 28 +---------------------------
1 file changed, 1 insertion(+), 27 deletions(-)
@@ -1403,17 +1403,7 @@ static int lpuart32_config_rs485(struct uart_port *port,staticunsignedintlpuart_get_mctrl(structuart_port*port){-unsignedinttemp=0;-unsignedcharreg;--reg=readb(port->membase+UARTMODEM);-if(reg&UARTMODEM_TXCTSE)-temp|=TIOCM_CTS;--if(reg&UARTMODEM_RXRTSE)-temp|=TIOCM_RTS;--returntemp;+return0;}staticunsignedintlpuart32_get_mctrl(structuart_port*port)
@@ -1423,23 +1413,7 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)staticvoidlpuart_set_mctrl(structuart_port*port,unsignedintmctrl){-unsignedchartemp;-structlpuart_port*sport=container_of(port,-structlpuart_port,port);--/* Make sure RXRTSE bit is not set when RS485 is enabled */-if(!(sport->port.rs485.flags&SER_RS485_ENABLED)){-temp=readb(sport->port.membase+UARTMODEM)&-~(UARTMODEM_RXRTSE|UARTMODEM_TXCTSE);--if(mctrl&TIOCM_RTS)-temp|=UARTMODEM_RXRTSE;-if(mctrl&TIOCM_CTS)-temp|=UARTMODEM_TXCTSE;--writeb(temp,port->membase+UARTMODEM);-}}staticvoidlpuart32_set_mctrl(structuart_port*port,unsignedintmctrl)
From: Michael Walle <hidden> Date: 2021-05-11 20:02:24
The LPUART can loop the RX and TX signal. Add support for it.
Please note, this was only tested on the 32 bit version of the LPUART.
Signed-off-by: Michael Walle <redacted>
---
drivers/tty/serial/fsl_lpuart.c | 36 +++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
@@ -1403,22 +1403,54 @@ static int lpuart32_config_rs485(struct uart_port *port,staticunsignedintlpuart_get_mctrl(structuart_port*port){-return0;+unsignedintmctrl=0;+u8reg;++reg=readb(port->membase+UARTCR1);+if(reg&UARTCR1_LOOPS)+mctrl|=TIOCM_LOOP;++returnmctrl;}staticunsignedintlpuart32_get_mctrl(structuart_port*port){-return0;+unsignedintmctrl=0;+u32reg;++reg=lpuart32_read(port,UARTCTRL);+if(reg&UARTCTRL_LOOPS)+mctrl|=TIOCM_LOOP;++returnmctrl;}staticvoidlpuart_set_mctrl(structuart_port*port,unsignedintmctrl){+u8reg;++reg=readb(port->membase+UARTCR1);++/* for internal loopback we need LOOPS=1 and RSRC=0 */+reg&=~(UARTCR1_LOOPS|UARTCR1_RSRC);+if(mctrl&TIOCM_LOOP)+reg|=UARTCR1_LOOPS;+writeb(reg,port->membase+UARTCR1);}staticvoidlpuart32_set_mctrl(structuart_port*port,unsignedintmctrl){+u32reg;++reg=lpuart32_read(port,UARTCTRL);++/* for internal loopback we need LOOPS=1 and RSRC=0 */+reg&=~(UARTCTRL_LOOPS|UARTCTRL_RSRC);+if(mctrl&TIOCM_LOOP)+reg|=UARTCTRL_LOOPS;+lpuart32_write(port,reg,UARTCTRL);}staticvoidlpuart_break_ctl(structuart_port*port,intbreak_state)
From: Michael Walle <hidden> Date: 2021-05-11 20:02:26
SYSRQ doesn't work with DMA. This is because there is no error
indication whether a symbol had a framing error or not. Actually,
this is not completely correct, there is a bit in the data register
which is set in this case, but we'd have to read change the DMA access
to 16 bit and we'd need to post process the data, thus make the DMA
pointless in the first place.
Signed-off-by: Michael Walle <redacted>
---
Please note, that there is already sysrq/break support in the 8 bit
version. But I think there is a race between the hardware DMA controller
and the ISR in this driver. I'm not sure though and can't test it.
Angelo, maybe you could test it, I'd presume with this patch you don't need
the special handling in the ISR anymore.
drivers/tty/serial/fsl_lpuart.c | 6 ++++++
1 file changed, 6 insertions(+)
From: Michael Walle <hidden> Date: 2021-05-11 20:02:28
The wrong code in set_mctrl() was already removed in commit 2b30efe2e88a
("tty: serial: lpuart: Remove unnecessary code from set_mctrl"), but the
code in get_mctrl() wasn't removed. It will not return the state of the
RTS or CTS line but whether automatic flow control is enabled, which is
wrong for the get_mctrl(). Thus remove it.
Fixes: 2b30efe2e88a ("tty: serial: lpuart: Remove unnecessary code from set_mctrl")
Signed-off-by: Michael Walle <redacted>
---
drivers/tty/serial/fsl_lpuart.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
From: Johan Hovold <johan@kernel.org> Date: 2021-05-12 09:25:35
On Tue, May 11, 2021 at 10:01:43PM +0200, Michael Walle wrote:
Since commit 81e2073c175b ("genirq: Disable interrupts for force
threaded handlers") interrupt handlers that are not explicitly requested
as threaded are always called with interrupts disabled and there is no
need to save the interrupt state when taking the port lock.
Since you've copied the above words verbatim from commit 75f4e830fa9c
("serial: do not restore interrupt state in sysrq helper") I'd expect
you to use quotes or at least refer to the commit you copied the
rationale from.
This is a preparation for sysrq handling which uses
uart_unlock_and_check_sysrq();
From: Johan Hovold <johan@kernel.org> Date: 2021-05-12 09:31:01
On Tue, May 11, 2021 at 10:01:44PM +0200, Michael Walle wrote:
Although there is already (broken) sysrq characters handling, a break
condition was never detected. There is also a possible deadlock because
we might call handle_sysrq() while still holding the port lock.
Where's the possible deadlock?
First, as you point out above the driver currently doesn't detect breaks
so the sysrq handler is never called and there's no risk for deadlocks
in the console code.
Second, the driver's console implementation explicitly handles being
called recursively so would not deadlock after you start detecting
breaks either.
Add support for break detection and use the proper
uart_unlock_and_check_sysrq() to defer calling handle_sysrq().
From: Michael Walle <hidden> Date: 2021-05-12 09:42:46
Am 2021-05-12 11:25, schrieb Johan Hovold:
On Tue, May 11, 2021 at 10:01:43PM +0200, Michael Walle wrote:
quoted
Since commit 81e2073c175b ("genirq: Disable interrupts for force
threaded handlers") interrupt handlers that are not explicitly
requested
as threaded are always called with interrupts disabled and there is no
need to save the interrupt state when taking the port lock.
Since you've copied the above words verbatim from commit 75f4e830fa9c
("serial: do not restore interrupt state in sysrq helper") I'd expect
you to use quotes or at least refer to the commit you copied the
rationale from.
Sure, sorry.
quoted
This is a preparation for sysrq handling which uses
uart_unlock_and_check_sysrq();
From: Michael Walle <hidden> Date: 2021-05-12 09:46:38
Am 2021-05-12 11:30, schrieb Johan Hovold:
On Tue, May 11, 2021 at 10:01:44PM +0200, Michael Walle wrote:
quoted
Although there is already (broken) sysrq characters handling, a break
condition was never detected. There is also a possible deadlock
because
we might call handle_sysrq() while still holding the port lock.
First, as you point out above the driver currently doesn't detect
breaks
so the sysrq handler is never called and there's no risk for deadlocks
in the console code.
But this commit introduces it? Therefore, I don't get your point.
Second, the driver's console implementation explicitly handles being
called recursively so would not deadlock after you start detecting
breaks either.
See above. Or there is something wrong with the lock debugging.
quoted
Add support for break detection and use the proper
uart_unlock_and_check_sysrq() to defer calling handle_sysrq().
From: Johan Hovold <johan@kernel.org> Date: 2021-05-12 10:07:10
On Wed, May 12, 2021 at 11:46:28AM +0200, Michael Walle wrote:
Am 2021-05-12 11:30, schrieb Johan Hovold:
quoted
On Tue, May 11, 2021 at 10:01:44PM +0200, Michael Walle wrote:
quoted
Although there is already (broken) sysrq characters handling, a break
condition was never detected. There is also a possible deadlock
because
we might call handle_sysrq() while still holding the port lock.
Note that it says "possible" deadlock; the lockdep validator probably
isn't smart enough to understand the trylock hack in the console write
callback.
quoted
First, as you point out above the driver currently doesn't detect
breaks
so the sysrq handler is never called and there's no risk for deadlocks
in the console code.
But this commit introduces it? Therefore, I don't get your point.
My point is that your commit message makes it sound like an actual
deadlock in the current code. Something which, for example, can cause
commits to get backported to stable when it is not needed.
quoted
Second, the driver's console implementation explicitly handles being
called recursively so would not deadlock after you start detecting
breaks either.
See above. Or there is something wrong with the lock debugging.
Seems to work as intended.
quoted
quoted
Add support for break detection and use the proper
uart_unlock_and_check_sysrq() to defer calling handle_sysrq().
But you should get rid of the sysrq trylock hack when switching to
uart_unlock_and_check_sysrq().
Johan
From: Michael Walle <hidden> Date: 2021-05-12 10:31:51
[dropped fugang.duan@nxp.com, mail bounces with 550 5.4.1 Recipient
address rejected: Access denied]
Am 2021-05-12 12:07, schrieb Johan Hovold:
On Wed, May 12, 2021 at 11:46:28AM +0200, Michael Walle wrote:
quoted
Am 2021-05-12 11:30, schrieb Johan Hovold:
quoted
On Tue, May 11, 2021 at 10:01:44PM +0200, Michael Walle wrote:
quoted
Although there is already (broken) sysrq characters handling, a break
condition was never detected. There is also a possible deadlock
because
we might call handle_sysrq() while still holding the port lock.
Note that it says "possible" deadlock; the lockdep validator probably
isn't smart enough to understand the trylock hack in the console write
callback.
quoted
quoted
First, as you point out above the driver currently doesn't detect
breaks
so the sysrq handler is never called and there's no risk for deadlocks
in the console code.
But this commit introduces it? Therefore, I don't get your point.
My point is that your commit message makes it sound like an actual
deadlock in the current code. Something which, for example, can cause
commits to get backported to stable when it is not needed.
I see. I'll rephrase the commit message. FWIW I intentionally didn't
put a Fixes: tag here, because of that.
quoted
quoted
Second, the driver's console implementation explicitly handles being
called recursively so would not deadlock after you start detecting
breaks either.
See above. Or there is something wrong with the lock debugging.
Seems to work as intended.
quoted
quoted
quoted
Add support for break detection and use the proper
uart_unlock_and_check_sysrq() to defer calling handle_sysrq().
But you should get rid of the sysrq trylock hack when switching to
uart_unlock_and_check_sysrq().
Ok. But only for the sport->port.sysrq part right? We'll still
need it for oops_in_progress.
Thanks for reviewing,
-michael