Skip to content

Commit f4eef22

Browse files
adureghello-tsgregkh
authored andcommitted
serial: fsl_lpuart: add sysrq support when using dma
Add handling of magic sysrq keys when using dma/edma. Tested by sending BREAK followed by a sysrq command inside a 5 secs time window, by: echo 1 > /proc/sys/kernel/sysrq BREAK + h, t, e, b, c Tested also sending a command after 5 secs after BREAK, that's properly ignored. Signed-off-by: Angelo Dureghello <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bfeb285 commit f4eef22

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

drivers/tty/serial/fsl_lpuart.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,15 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
976976

977977
sts = readb(sport->port.membase + UARTSR1);
978978

979+
/* SysRq, using dma, check for linebreak by framing err. */
980+
if (sts & UARTSR1_FE && sport->lpuart_dma_rx_use) {
981+
readb(sport->port.membase + UARTDR);
982+
uart_handle_break(&sport->port);
983+
/* linebreak produces some garbage, removing it */
984+
writeb(UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO);
985+
return IRQ_HANDLED;
986+
}
987+
979988
if (sts & UARTSR1_RDRF && !sport->lpuart_dma_rx_use)
980989
lpuart_rxint(sport);
981990

@@ -1004,6 +1013,37 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
10041013
return IRQ_HANDLED;
10051014
}
10061015

1016+
1017+
static inline void lpuart_handle_sysrq_chars(struct uart_port *port,
1018+
unsigned char *p, int count)
1019+
{
1020+
while (count--) {
1021+
if (*p && uart_handle_sysrq_char(port, *p))
1022+
return;
1023+
p++;
1024+
}
1025+
}
1026+
1027+
static void lpuart_handle_sysrq(struct lpuart_port *sport)
1028+
{
1029+
struct circ_buf *ring = &sport->rx_ring;
1030+
int count;
1031+
1032+
if (ring->head < ring->tail) {
1033+
count = sport->rx_sgl.length - ring->tail;
1034+
lpuart_handle_sysrq_chars(&sport->port,
1035+
ring->buf + ring->tail, count);
1036+
ring->tail = 0;
1037+
}
1038+
1039+
if (ring->head > ring->tail) {
1040+
count = ring->head - ring->tail;
1041+
lpuart_handle_sysrq_chars(&sport->port,
1042+
ring->buf + ring->tail, count);
1043+
ring->tail = ring->head;
1044+
}
1045+
}
1046+
10071047
static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
10081048
{
10091049
struct tty_port *port = &sport->port.state->port;
@@ -1090,6 +1130,15 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
10901130
*/
10911131
ring->head = sport->rx_sgl.length - state.residue;
10921132
BUG_ON(ring->head > sport->rx_sgl.length);
1133+
1134+
/*
1135+
* Silent handling of keys pressed in the sysrq timeframe
1136+
*/
1137+
if (sport->port.sysrq) {
1138+
lpuart_handle_sysrq(sport);
1139+
goto exit;
1140+
}
1141+
10931142
/*
10941143
* At this point ring->head may point to the first byte right after the
10951144
* last byte of the dma buffer:
@@ -1121,6 +1170,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
11211170
sport->port.icount.rx += count;
11221171
}
11231172

1173+
exit:
11241174
dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1,
11251175
DMA_FROM_DEVICE);
11261176

@@ -1557,6 +1607,7 @@ static void lpuart_tx_dma_startup(struct lpuart_port *sport)
15571607
static void lpuart_rx_dma_startup(struct lpuart_port *sport)
15581608
{
15591609
int ret;
1610+
unsigned char cr3;
15601611

15611612
if (!sport->dma_rx_chan)
15621613
goto err;
@@ -1573,6 +1624,12 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport)
15731624
sport->lpuart_dma_rx_use = true;
15741625
rx_dma_timer_init(sport);
15751626

1627+
if (sport->port.has_sysrq) {
1628+
cr3 = readb(sport->port.membase + UARTCR3);
1629+
cr3 |= UARTCR3_FEIE;
1630+
writeb(cr3, sport->port.membase + UARTCR3);
1631+
}
1632+
15761633
return;
15771634

15781635
err:

0 commit comments

Comments
 (0)