meta-ox64-bsp/recipes-kernel/linux/linux-yocto/0020-tty-serial-bflb_uart-fix-leaked-ISR-registration.patch
Grzegorz Kowalski 3e13a0fa03 add initial bootable image
based on openbouffalo/meta-bl808
2024-08-31 17:45:25 +02:00

248 lines
7.2 KiB
Diff

From 21dd2b6821d171463407a77536ea8044dc64bbeb Mon Sep 17 00:00:00 2001
From: Allen Martin <armartin@gmail.com>
Date: Fri, 20 Jan 2023 19:42:33 -0800
Subject: [PATCH 20/21] tty: serial: bflb_uart: fix leaked ISR registration
-call devm_free_irq() in shutdown to release ISR registered in
startup.
-change many functions to take driver private bflb_uart_port *
instead of serial_core uart_port *
-add to_bflb_uart_port() to assist with above
-switch to using uart_port_tx_limited() serial_core helper
which is the preferred way to do transmission instead of
accessing serial_core xmit buffer directly
---
drivers/tty/serial/bflb_uart.c | 133 ++++++++++++++++++++-------------
1 file changed, 79 insertions(+), 54 deletions(-)
diff --git a/drivers/tty/serial/bflb_uart.c b/drivers/tty/serial/bflb_uart.c
index b091ad7a891a..5911f489959c 100644
--- a/drivers/tty/serial/bflb_uart.c
+++ b/drivers/tty/serial/bflb_uart.c
@@ -82,12 +82,17 @@
#define BFLB_UART_MAXPORTS 8
#define BFLB_UART_BAUD 2000000
#define BFLB_UART_RX_FIFO_TH 7
+#define BFLB_UART_TX_FIFO_DEPTH 32
struct bflb_uart_port {
struct uart_port port;
struct clk *clk;
};
+#define to_bflb_uart_port(p) (container_of((p), \
+ struct bflb_uart_port, \
+ port))
+
static struct bflb_uart_port *bflb_uart_ports[BFLB_UART_MAXPORTS];
static inline u32 rdl(struct uart_port *port, u32 reg)
@@ -227,91 +232,104 @@ static void bflb_uart_set_termios(struct uart_port *port,
spin_unlock_irqrestore(&port->lock, flags);
}
-static void bflb_uart_rx_chars(struct uart_port *port)
+static void bflb_uart_rx_chars(struct bflb_uart_port *bp)
{
unsigned char ch, flag;
unsigned long status;
- while ((status = rdl(port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) {
- ch = rdl(port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK;
+ while ((status = rdl(&bp->port, UART_FIFO_CONFIG_1)) & UART_RX_FIFO_CNT_MSK) {
+ ch = rdl(&bp->port, UART_FIFO_RDATA) & UART_FIFO_RDATA_MSK;
flag = TTY_NORMAL;
- port->icount.rx++;
+ bp->port.icount.rx++;
- if (uart_handle_sysrq_char(port, ch))
+ if (uart_handle_sysrq_char(&bp->port, ch))
continue;
- uart_insert_char(port, 0, 0, ch, flag);
+ uart_insert_char(&bp->port, 0, 0, ch, flag);
}
- spin_unlock(&port->lock);
- tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
+ spin_unlock(&bp->port.lock);
+ tty_flip_buffer_push(&bp->port.state->port);
+ spin_lock(&bp->port.lock);
}
-static void bflb_uart_tx_chars(struct uart_port *port)
+/**
+ * bflb_uart_txfifo_space() - How much space is left int the TX FIFO?
+ * @bp: pointer to a struct bflb_uart_port
+ *
+ * Read the transmit FIFO count to find out how much space is left
+ *
+ * Returns: UART_TX_FIFO_CNT - count of space left in the TX FIFO
+ */
+static int bflb_uart_txfifo_space(struct bflb_uart_port *bp)
{
- struct circ_buf *xmit = &port->state->xmit;
- unsigned int pending, count;
+ return (rdl(&bp->port, UART_FIFO_CONFIG_1)
+ & UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT;
+}
- if (port->x_char) {
- /* Send special char - probably flow control */
- wrl(port, UART_FIFO_WDATA, port->x_char);
- port->x_char = 0;
- port->icount.tx++;
- return;
- }
+/**
+ * bflb_uart_tx_char() - enqueue a byte to transmit onto the TX FIFO
+ * @bp: pointer to a struct bflb_uart_port
+ * @ch: character to transmit
+ *
+ * Enqueue a byte @ch onto the transmit FIFO, given a pointer @bp to the
+ * struct bflb_uart_port * to transmit on.
+ *
+ * Context: Any context.
+ */
+static void bflb_uart_tx_char(struct bflb_uart_port *bp, int ch)
+{
+ wrl(&bp->port, UART_FIFO_WDATA, ch);
+}
- pending = uart_circ_chars_pending(xmit);
- if (pending > 0) {
- count = (rdl(port, UART_FIFO_CONFIG_1) &
- UART_TX_FIFO_CNT_MSK) >> UART_TX_FIFO_CNT_SFT;
- if (count > pending)
- count = pending;
- if (count > 0) {
- pending -= count;
- while (count--) {
- wrl(port, UART_FIFO_WDATA, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- }
- if (pending < WAKEUP_CHARS)
- uart_write_wakeup(port);
- }
- }
+/**
+ * bflb_uart_tx_chars() - enqueue multiple bytes onto the TX FIFO
+ * @bp: pointer to a struct bflb_uart_port
+ *
+ * Transfer up to a TX FIFO size's worth of characters from the Linux serial
+ * transmit buffer to the BFLB UART TX FIFO.
+ *
+ * Context: Any context. Expects @bp->port.lock to be held by caller.
+ */
+static void bflb_uart_tx_chars(struct bflb_uart_port *bp)
+{
+ u8 ch;
- if (pending == 0)
- bflb_uart_stop_tx(port);
+ uart_port_tx_limited(&bp->port, ch, BFLB_UART_TX_FIFO_DEPTH,
+ bflb_uart_txfifo_space(bp),
+ bflb_uart_tx_char(bp, ch),
+ ({}));
}
static irqreturn_t bflb_uart_interrupt(int irq, void *data)
{
- struct uart_port *port = data;
+ struct bflb_uart_port *bp = data;
u32 isr, val;
- isr = rdl(port, UART_INT_STS);
- wrl(port, UART_INT_CLEAR, isr);
+ isr = rdl(&bp->port, UART_INT_STS);
+ wrl(&bp->port, UART_INT_CLEAR, isr);
- isr &= ~rdl(port, UART_INT_MASK);
+ isr &= ~rdl(&bp->port, UART_INT_MASK);
- spin_lock(&port->lock);
+ spin_lock(&bp->port.lock);
if (isr & UART_URX_FER_INT) {
/* RX FIFO error interrupt */
- val = rdl(port, UART_FIFO_CONFIG_0);
+ val = rdl(&bp->port, UART_FIFO_CONFIG_0);
if (val & UART_RX_FIFO_OVERFLOW)
- port->icount.overrun++;
+ bp->port.icount.overrun++;
val |= UART_RX_FIFO_CLR;
- wrl(port, UART_FIFO_CONFIG_0, val);
+ wrl(&bp->port, UART_FIFO_CONFIG_0, val);
}
if (isr & (UART_URX_FIFO_INT | UART_URX_RTO_INT)) {
- bflb_uart_rx_chars(port);
+ bflb_uart_rx_chars(bp);
}
if (isr & (UART_UTX_FIFO_INT | UART_UTX_END_INT)) {
- bflb_uart_tx_chars(port);
+ bflb_uart_tx_chars(bp);
}
- spin_unlock(&port->lock);
+ spin_unlock(&bp->port.lock);
return IRQ_RETVAL(isr);
}
@@ -335,19 +353,22 @@ static void bflb_uart_config_port(struct uart_port *port, int flags)
static int bflb_uart_startup(struct uart_port *port)
{
unsigned long flags;
- int ret;
u32 val;
+ struct bflb_uart_port *bp = to_bflb_uart_port(port);
+ int ret;
+
+ dev_dbg(port->dev, "startup %s\n", port->name);
+
+ spin_lock_irqsave(&port->lock, flags);
ret = devm_request_irq(port->dev, port->irq, bflb_uart_interrupt,
- IRQF_SHARED, port->name, port);
+ IRQF_SHARED, port->name, bp);
if (ret) {
dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
port->irq, ret);
return ret;
}
- spin_lock_irqsave(&port->lock, flags);
-
val = rdl(port, UART_INT_MASK);
val |= 0xfff;
wrl(port, UART_INT_MASK, val);
@@ -383,10 +404,14 @@ static int bflb_uart_startup(struct uart_port *port)
static void bflb_uart_shutdown(struct uart_port *port)
{
unsigned long flags;
+ struct bflb_uart_port *bp = to_bflb_uart_port(port);
+
+ dev_dbg(port->dev, "shutdown %s\n", port->name);
spin_lock_irqsave(&port->lock, flags);
/* mask all interrupts now */
wrl(port, UART_INT_MASK, UART_UTX_END_INT | UART_URX_END_INT);
+ devm_free_irq(port->dev, port->irq, bp);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -589,7 +614,7 @@ static int bflb_uart_probe(struct platform_device *pdev)
port->line = index;
port->type = PORT_BFLB;
port->iotype = UPIO_MEM;
- port->fifosize = 32;
+ port->fifosize = BFLB_UART_TX_FIFO_DEPTH;
port->ops = &bflb_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
port->dev = &pdev->dev;
--
2.25.1