// SPDX-License-Identifier: GPL-2.0 /* * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker. * Copyright 2020 NXP * Copyright 2020 Puresoftware Ltd. * * This isn't a full driver; it just provides an alternate IRQ * handler to deal with an errata and provide ACPI wrapper. * Everything else is just using the bog standard 8250 support. * * We follow code flow of serial8250_default_handle_irq() but add * a check for a break and insert a dummy read on the Rx for the * immediately following IRQ event. * * We re-use the already existing "bug handling" lsr_saved_flags * field to carry the "what we just did" information from the one * IRQ event to the next one.
*/
/* * For a single break the hardware reports LSR.BI for each character * time. This is described in the MPC8313E chip errata as "General17". * A typical break has a duration of 0.3s, with a 115200n8 configuration * that (theoretically) corresponds to ~3500 interrupts in these 0.3s. * In practise it's less (around 500) because of hardware * and software latencies. The workaround recommended by the vendor is * to read the RX register (to clear LSR.DR and thus prevent a FIFO * aging interrupt). To prevent the irq from retriggering LSR must not be * read. (This would clear LSR.BI, hardware would reassert the BI event * immediately and interrupt the CPU again. The hardware clears LSR.BI * when the next valid char is read.)
*/ if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI &&
(up->lsr_saved_flags & UART_LSR_BI))) {
up->lsr_saved_flags &= ~UART_LSR_BI;
serial_port_in(port, UART_RX);
uart_port_unlock_irqrestore(&up->port, flags); return 1;
}
lsr = orig_lsr = serial_port_in(port, UART_LSR);
/* Process incoming characters first */ if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
(up->ier & (UART_IER_RLSI | UART_IER_RDI))) {
lsr = serial8250_rx_chars(up, lsr);
}
/* Stop processing interrupts on input overrun */ if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) { unsignedlong delay;
up->ier = serial_port_in(port, UART_IER); if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
port->ops->stop_rx(port);
} else { /* Keep restarting the timer until * the input overrun subsides.
*/
cancel_delayed_work(&up->overrun_backoff);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.