From: Eddie James <eajames@linux.vnet.ibm.com>
To: linux-aspeed@lists.ozlabs.org
Subject: [PATCH 5/5] serial/aspeed-vuart: Implement quick throttle mechanism
Date: Fri, 23 Mar 2018 10:51:55 -0500 [thread overview]
Message-ID: <473dcfc9-9462-6b67-6d40-3f9d5ecaf492@linux.vnet.ibm.com> (raw)
In-Reply-To: <20180321025241.19785-6-jk@ozlabs.org>
On 03/20/2018 09:52 PM, Jeremy Kerr wrote:
> Although we populate the ->throttle and ->unthrottle UART operations,
> these may not be called until the ldisc has had a chance to schedule and
> check buffer space. This means that we may overflow the flip buffers
> without ever hitting the ldisc's throttle threshold.
>
> This change implements an interrupt-based throttle, where we check for
> space in the flip buffers before reading characters from the UART's
> FIFO. If there's no space available, we disable the RX interrupt and
> schedule a timer to check for space later.
>
> This prevents a case where we drop characters under heavy RX load.
Tested-by: Eddie James <eajames@linux.vnet.ibm.com>
>
> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
> ---
> drivers/tty/serial/8250/8250_aspeed_vuart.c | 103 ++++++++++++++++++++++++++--
> 1 file changed, 99 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
> index 50c082b4a1ac..bc2b63578e58 100644
> --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
> +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
> @@ -14,6 +14,8 @@
> #include <linux/of_address.h>
> #include <linux/of_irq.h>
> #include <linux/of_platform.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> #include <linux/clk.h>
>
> #include "8250.h"
> @@ -32,8 +34,16 @@ struct aspeed_vuart {
> void __iomem *regs;
> struct clk *clk;
> int line;
> + struct timer_list unthrottle_timer;
> };
>
> +/*
> + * If we fill the tty flip buffers, we throttle the data ready interrupt
> + * to prevent dropped characters. This timeout defines how long we wait
> + * to (conditionally, depending on buffer state) unthrottle.
> + */
> +static const int unthrottle_timeout = HZ/10;
> +
> /*
> * The VUART is basically two UART 'front ends' connected by their FIFO
> * (no actual serial line in between). One is on the BMC side (management
> @@ -183,17 +193,23 @@ static void aspeed_vuart_shutdown(struct uart_port *uart_port)
> serial8250_do_shutdown(uart_port);
> }
>
> -static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
> +static void __aspeed_vuart_set_throttle(struct uart_8250_port *up,
> + bool throttle)
> {
> unsigned char irqs = UART_IER_RLSI | UART_IER_RDI;
> - struct uart_8250_port *up = up_to_u8250p(port);
> - unsigned long flags;
>
> - spin_lock_irqsave(&port->lock, flags);
> up->ier &= ~irqs;
> if (!throttle)
> up->ier |= irqs;
> serial_out(up, UART_IER, up->ier);
> +}
> +static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
> +{
> + struct uart_8250_port *up = up_to_u8250p(port);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&port->lock, flags);
> + __aspeed_vuart_set_throttle(up, throttle);
> spin_unlock_irqrestore(&port->lock, flags);
> }
>
> @@ -207,6 +223,81 @@ static void aspeed_vuart_unthrottle(struct uart_port *port)
> aspeed_vuart_set_throttle(port, false);
> }
>
> +static void aspeed_vuart_unthrottle_exp(unsigned long data)
> +{
> + struct uart_8250_port *up = (void *)data;
> + struct aspeed_vuart *vuart = up->port.private_data;
> +
> + if (!tty_buffer_space_avail(&up->port.state->port)) {
> + mod_timer(&vuart->unthrottle_timer, unthrottle_timeout);
> + return;
> + }
> +
> + aspeed_vuart_unthrottle(&up->port);
> +}
> +
> +/*
> + * Custom interrupt handler to manage finer-grained flow control. Although we
> + * have throttle/unthrottle callbacks, we've seen that the VUART device can
> + * deliver characters faster than the ldisc has a chance to check buffer space
> + * against the throttle threshold. This results in dropped characters before
> + * the throttle.
> + *
> + * We do this by checking for flip buffer space before RX. If we have no space,
> + * throttle now and schedule an unthrottle for later, once the ldisc has had
> + * a chance to drain the buffers.
> + */
> +static int aspeed_vuart_handle_irq(struct uart_port *port) { struct
> + uart_8250_port *up = up_to_u8250p(port); unsigned int iir, lsr;
> + unsigned long flags; int space, count;
> +
> + iir = serial_port_in(port, UART_IIR);
> +
> + if (iir & UART_IIR_NO_INT)
> + return 0;
> +
> + spin_lock_irqsave(&port->lock, flags);
> +
> + lsr = serial_port_in(port, UART_LSR);
> +
> + if (lsr & (UART_LSR_DR | UART_LSR_BI)) {
> + space = tty_buffer_space_avail(&port->state->port);
> +
> + if (!space) {
> + /* throttle and schedule an unthrottle later */
> + struct aspeed_vuart *vuart = port->private_data;
> + __aspeed_vuart_set_throttle(up, true);
> +
> + if (!timer_pending(&vuart->unthrottle_timer)) {
> + vuart->unthrottle_timer.data =
> + (unsigned long)up;
> + mod_timer(&vuart->unthrottle_timer,
> + unthrottle_timeout);
> + }
> +
> + } else {
> + count = min(space, 256);
> +
> + do {
> + serial8250_read_char(up, lsr);
> + lsr = serial_in(up, UART_LSR);
> + if (--count == 0)
> + break;
> + } while (lsr & (UART_LSR_DR | UART_LSR_BI));
> +
> + tty_flip_buffer_push(&port->state->port);
> + }
> + }
> +
> + serial8250_modem_status(up);
> + if (lsr & UART_LSR_THRE)
> + serial8250_tx_chars(up);
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +
> + return 1;
> +}
> +
> static int aspeed_vuart_probe(struct platform_device *pdev)
> {
> struct uart_8250_port port;
> @@ -223,6 +314,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
> return -ENOMEM;
>
> vuart->dev = &pdev->dev;
> + setup_timer(&vuart->unthrottle_timer,
> + aspeed_vuart_unthrottle_exp, (unsigned long)vuart);
>
> res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> vuart->regs = devm_ioremap_resource(&pdev->dev, res);
> @@ -284,6 +377,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
>
> port.port.irq = irq_of_parse_and_map(np, 0);
> port.port.irqflags = IRQF_SHARED;
> + port.port.handle_irq = aspeed_vuart_handle_irq;
> port.port.iotype = UPIO_MEM;
> port.port.type = PORT_16550A;
> port.port.uartclk = clk;
> @@ -323,6 +417,7 @@ static int aspeed_vuart_remove(struct platform_device *pdev)
> {
> struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
>
> + del_timer_sync(&vuart->unthrottle_timer);
> aspeed_vuart_set_enabled(vuart, false);
> serial8250_unregister_port(vuart->line);
> sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
next prev parent reply other threads:[~2018-03-23 15:51 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-21 2:52 [PATCH 0/5] serial: implement flow control for ASPEED VUART driver Jeremy Kerr
2018-03-21 2:52 ` [PATCH 1/5] serial: Introduce UPSTAT_SYNC_FIFO for synchronised FIFOs Jeremy Kerr
2018-03-23 15:33 ` Greg Kroah-Hartman
2018-03-27 1:38 ` Jeremy Kerr
2018-03-23 15:50 ` Eddie James
2018-03-21 2:52 ` [PATCH 2/5] serial: expose buf_overrun count through proc interface Jeremy Kerr
2018-03-23 15:29 ` Greg Kroah-Hartman
2018-03-27 1:44 ` Jeremy Kerr
2018-03-23 15:50 ` Eddie James
2018-03-21 2:52 ` [PATCH 3/5] serial/8250: export serial8250_read_char Jeremy Kerr
2018-03-23 15:51 ` Eddie James
2018-03-21 2:52 ` [PATCH 4/5] serial/aspeed-vuart: Implement rx throttling Jeremy Kerr
2018-03-23 15:51 ` Eddie James
2018-03-21 2:52 ` [PATCH 5/5] serial/aspeed-vuart: Implement quick throttle mechanism Jeremy Kerr
2018-03-21 3:26 ` Joel Stanley
2018-03-21 3:32 ` Jeremy Kerr
2018-03-21 3:57 ` Jeremy Kerr
2018-03-21 4:36 ` [PATCH v2 " Jeremy Kerr
2018-03-23 15:51 ` Eddie James [this message]
2018-03-23 15:51 ` [PATCH 0/5] serial: implement flow control for ASPEED VUART driver Greg Kroah-Hartman
2018-03-27 3:38 ` Jeremy Kerr
2018-03-27 3:48 ` [PATCH v2 0/4] " Jeremy Kerr
2018-03-27 3:48 ` [PATCH v2 1/4] serial: Introduce UPSTAT_SYNC_FIFO for synchronised FIFOs Jeremy Kerr
2018-03-27 3:48 ` [PATCH v2 2/4] serial/8250: export serial8250_read_char Jeremy Kerr
2018-03-27 3:48 ` [PATCH v2 3/4] serial/aspeed-vuart: Implement rx throttling Jeremy Kerr
2018-03-27 3:48 ` [PATCH v2 4/4] serial/aspeed-vuart: Implement quick throttle mechanism Jeremy Kerr
2018-03-27 6:52 ` [PATCH v2 0/4] serial: implement flow control for ASPEED VUART driver Joel Stanley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=473dcfc9-9462-6b67-6d40-3f9d5ecaf492@linux.vnet.ibm.com \
--to=eajames@linux.vnet.ibm.com \
--cc=linux-aspeed@lists.ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).