/* * 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->port = up; mod_timer(&vuart->unthrottle_timer, jiffies + 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 void aspeed_vuart_unthrottle_exp(struct timer_list *timer) { struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer); struct uart_8250_port *up = vuart->port; if (!tty_buffer_space_avail(&up->port.state->port)) { mod_timer(&vuart->unthrottle_timer, jiffies + unthrottle_timeout); return; } aspeed_vuart_unthrottle(&up->port); }
static int pty_space(struct tty_struct *to) { int n = tty_buffer_space_avail(to->port); return min(n, 8192); }
static int pty_write_room(struct tty_struct *tty) { if (tty->stopped) return 0; return tty_buffer_space_avail(tty->link->port); }