aboutsummaryrefslogtreecommitdiff
path: root/drivers/tty/serial/8250/8250_exar.c
diff options
context:
space:
mode:
authorGravatar Robert Middleton <robert.middleton@rm5248.com> 2019-08-01 10:56:40 -0400
committerGravatar Greg Kroah-Hartman <gregkh@linuxfoundation.org> 2019-09-04 12:43:50 +0200
commit47b1747f705e90d8197b77207e19c0ec67c16958 (patch)
tree7fd337e9500be261097c95317af73f898432e552 /drivers/tty/serial/8250/8250_exar.c
parentserial: 8250_exar: Move custom divisor support out from 8250_port (diff)
downloadlinux-47b1747f705e90d8197b77207e19c0ec67c16958.tar.gz
linux-47b1747f705e90d8197b77207e19c0ec67c16958.tar.bz2
linux-47b1747f705e90d8197b77207e19c0ec67c16958.zip
serial: 8250_exar: Clear buffer before shutdown
When closing and shutting down the exar serial port, if the chip has not finished sending all of the data in its buffer, the remaining bytes will be lost. Hold off on the shutdown until the bytes have all been sent. Signed-off-by: Robert Middleton <robert.middleton@rm5248.com> Link: https://lore.kernel.org/r/20190801145640.26080-1-robert.middleton@rm5248.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/8250/8250_exar.c')
-rw-r--r--drivers/tty/serial/8250/8250_exar.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 3a39368e6e47..357e20a6566f 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -19,6 +19,7 @@
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/8250_pci.h>
+#include <linux/delay.h>
#include <asm/byteorder.h>
@@ -515,6 +516,27 @@ static irqreturn_t exar_misc_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static void
+exar_shutdown(struct uart_port *port)
+{
+ unsigned char lsr;
+ bool tx_complete = 0;
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct circ_buf *xmit = &port->state->xmit;
+ int i = 0;
+
+ do {
+ lsr = serial_in(up, UART_LSR);
+ if (lsr & (UART_LSR_TEMT | UART_LSR_THRE))
+ tx_complete = 1;
+ else
+ tx_complete = 0;
+ msleep(1);
+ } while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000);
+
+ serial8250_do_shutdown(port);
+}
+
static int
exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
@@ -555,6 +577,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
uart.port.flags = UPF_SHARE_IRQ | UPF_EXAR_EFR | UPF_FIXED_TYPE | UPF_FIXED_PORT;
uart.port.irq = pci_irq_vector(pcidev, 0);
uart.port.dev = &pcidev->dev;
+ uart.port.shutdown = exar_shutdown;
rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler,
IRQF_SHARED, "exar_uart", priv);