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@xxxxxxxxxx> --- Changes in v3: - Added a counter(up to 1000) to terminate the loop if the hardware goes away/has a problem, as per Greg K-H drivers/tty/serial/8250/8250_exar.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index edd6dfe055bf..f0eb49113b6a 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> @@ -457,6 +458,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) { @@ -500,6 +522,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) | UPF_EXAR_EFR; 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); -- 2.11.0