/* * 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; }
/* * This is mostly serial8250_handle_irq(). We have a slightly different DMA * hoook for RX/TX and need different logic for them in the ISR. Therefore we * use the default routine in the non-DMA case and this one for with DMA. */ static int omap_8250_dma_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned char status; unsigned long flags; u8 iir; int dma_err = 0; serial8250_rpm_get(up); iir = serial_port_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { serial8250_rpm_put(up); return 0; } spin_lock_irqsave(&port->lock, flags); status = serial_port_in(port, UART_LSR); if (status & (UART_LSR_DR | UART_LSR_BI)) { dma_err = omap_8250_rx_dma(up, iir); if (dma_err) { status = serial8250_rx_chars(up, status); omap_8250_rx_dma(up, 0); } } serial8250_modem_status(up); if (status & UART_LSR_THRE && up->dma->tx_err) { if (uart_tx_stopped(&up->port) || uart_circ_empty(&up->port.state->xmit)) { up->dma->tx_err = 0; serial8250_tx_chars(up); } else { /* * try again due to an earlier failer which * might have been resolved by now. */ dma_err = omap_8250_tx_dma(up); if (dma_err) serial8250_tx_chars(up); } } spin_unlock_irqrestore(&port->lock, flags); serial8250_rpm_put(up); return 1; }
int fsl8250_handle_irq(struct uart_port *port) { unsigned char lsr, orig_lsr; unsigned long flags; unsigned int iir; struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); spin_lock_irqsave(&up->port.lock, flags); iir = port->serial_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { spin_unlock_irqrestore(&up->port.lock, flags); return 0; } /* This is the WAR; if last event was BRK, then read and return */ if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) { up->lsr_saved_flags &= ~UART_LSR_BI; port->serial_in(port, UART_RX); spin_unlock_irqrestore(&up->port.lock, flags); return 1; } lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR); if (lsr & (UART_LSR_DR | UART_LSR_BI)) lsr = serial8250_rx_chars(up, lsr); serial8250_modem_status(up); if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); up->lsr_saved_flags = orig_lsr; spin_unlock_irqrestore(&up->port.lock, flags); return 1; }