Merge tag 'tty-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are some small tty/vt and serial driver fixes for 7.0-rc5.
  Included in here are:

   - 8250 driver fixes for reported problems

   - serial core lockup fix

   - uartlite driver bugfix

   - vt save/restore bugfix

  All of these have been in linux-next for over a week with no reported
  problems"

* tag 'tty-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  vt: save/restore unicode screen buffer for alternate screen
  serial: 8250_dw: Ensure BUSY is deasserted
  serial: 8250: Add late synchronize_irq() to shutdown to handle DW UART BUSY
  serial: 8250_dw: Rework IIR_NO_INT handling to stop interrupt storm
  serial: 8250_dw: Rework dw8250_handle_irq() locking and IIR handling
  serial: 8250: Add serial8250_handle_irq_locked()
  serial: 8250_dw: Avoid unnecessary LCR writes
  serial: 8250: Protect LCR write in shutdown
  serial: 8250_pci: add support for the AX99100
  serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN
  serial: uartlite: fix PM runtime usage count underflow on probe
  serial: 8250: always disable IRQ during THRE test
  serial: 8250: Fix TX deadlock when using DMA
This commit is contained in:
Linus Torvalds
2026-03-20 11:52:32 -07:00
10 changed files with 356 additions and 96 deletions

View File

@@ -175,7 +175,9 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
return value;
}
void serial8250_clear_fifos(struct uart_8250_port *p);
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
@@ -400,6 +402,26 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
return dma && dma->tx_running;
}
static inline void serial8250_tx_dma_pause(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
if (!dma->tx_running)
return;
dmaengine_pause(dma->txchan);
}
static inline void serial8250_tx_dma_resume(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
if (!dma->tx_running)
return;
dmaengine_resume(dma->txchan);
}
#else
static inline int serial8250_tx_dma(struct uart_8250_port *p)
{
@@ -421,6 +443,9 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
{
return false;
}
static inline void serial8250_tx_dma_pause(struct uart_8250_port *p) { }
static inline void serial8250_tx_dma_resume(struct uart_8250_port *p) { }
#endif
static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)

View File

@@ -162,7 +162,22 @@ void serial8250_tx_dma_flush(struct uart_8250_port *p)
*/
dma->tx_size = 0;
/*
* We can't use `dmaengine_terminate_sync` because `uart_flush_buffer` is
* holding the uart port spinlock.
*/
dmaengine_terminate_async(dma->txchan);
/*
* The callback might or might not run. If it doesn't run, we need to ensure
* that `tx_running` is cleared so that we can schedule new transactions.
* If it does run, then the zombie callback will clear `tx_running` again
* and perform a no-op since `tx_size` was cleared above.
*
* In either case, we ASSUME the DMA transaction will terminate before we
* issue a new `serial8250_tx_dma`.
*/
dma->tx_running = 0;
}
int serial8250_rx_dma(struct uart_8250_port *p)

View File

@@ -9,10 +9,14 @@
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/lockdep.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
@@ -40,8 +44,12 @@
#define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */
/* DesignWare specific register fields */
#define DW_UART_IIR_IID GENMASK(3, 0)
#define DW_UART_MCR_SIRE BIT(6)
#define DW_UART_USR_BUSY BIT(0)
/* Renesas specific register fields */
#define RZN1_UART_xDMACR_DMA_EN BIT(0)
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
@@ -56,6 +64,13 @@
#define DW_UART_QUIRK_IS_DMA_FC BIT(3)
#define DW_UART_QUIRK_APMC0D08 BIT(4)
#define DW_UART_QUIRK_CPR_VALUE BIT(5)
#define DW_UART_QUIRK_IER_KICK BIT(6)
/*
* Number of consecutive IIR_NO_INT interrupts required to trigger interrupt
* storm prevention code.
*/
#define DW_UART_QUIRK_IER_KICK_THRES 4
struct dw8250_platform_data {
u8 usr_reg;
@@ -77,6 +92,9 @@ struct dw8250_data {
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
unsigned int in_idle:1;
u8 no_int_count;
};
static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
@@ -107,78 +125,167 @@ static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u3
return value;
}
static void dw8250_idle_exit(struct uart_port *p)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
struct uart_8250_port *up = up_to_u8250p(p);
if (d->uart_16550_compatible)
return;
if (up->capabilities & UART_CAP_FIFO)
serial_port_out(p, UART_FCR, up->fcr);
serial_port_out(p, UART_MCR, up->mcr);
serial_port_out(p, UART_IER, up->ier);
/* DMA Rx is restarted by IRQ handler as needed. */
if (up->dma)
serial8250_tx_dma_resume(up);
d->in_idle = 0;
}
/*
* This function is being called as part of the uart_port::serial_out()
* routine. Hence, it must not call serial_port_out() or serial_out()
* against the modified registers here, i.e. LCR.
* Ensure BUSY is not asserted. If DW UART is configured with
* !uart_16550_compatible, the writes to LCR, DLL, and DLH fail while
* BUSY is asserted.
*
* Context: port's lock must be held
*/
static void dw8250_force_idle(struct uart_port *p)
static int dw8250_idle_enter(struct uart_port *p)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
unsigned int usr_reg = d->pdata ? d->pdata->usr_reg : DW_UART_USR;
struct uart_8250_port *up = up_to_u8250p(p);
int retries;
u32 lsr;
lockdep_assert_held_once(&p->lock);
if (d->uart_16550_compatible)
return 0;
d->in_idle = 1;
/* Prevent triggering interrupt from RBR filling */
serial_port_out(p, UART_IER, 0);
if (up->dma) {
serial8250_rx_dma_flush(up);
if (serial8250_tx_dma_running(up))
serial8250_tx_dma_pause(up);
}
/*
* Wait until Tx becomes empty + one extra frame time to ensure all bits
* have been sent on the wire.
*
* FIXME: frame_time delay is too long with very low baudrates.
*/
serial8250_fifo_wait_for_lsr_thre(up, p->fifosize);
ndelay(p->frame_time);
serial_port_out(p, UART_MCR, up->mcr | UART_MCR_LOOP);
retries = 4; /* Arbitrary limit, 2 was always enough in tests */
do {
serial8250_clear_fifos(up);
if (!(serial_port_in(p, usr_reg) & DW_UART_USR_BUSY))
break;
/* FIXME: frame_time delay is too long with very low baudrates. */
ndelay(p->frame_time);
} while (--retries);
lsr = serial_lsr_in(up);
if (lsr & UART_LSR_DR) {
serial_port_in(p, UART_RX);
up->lsr_saved_flags = 0;
}
/* Now guaranteed to have BUSY deasserted? Just sanity check */
if (serial_port_in(p, usr_reg) & DW_UART_USR_BUSY) {
dw8250_idle_exit(p);
return -EBUSY;
}
return 0;
}
static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
struct uart_8250_port *up = up_to_u8250p(p);
unsigned int lsr;
int ret;
/*
* The following call currently performs serial_out()
* against the FCR register. Because it differs to LCR
* there will be no infinite loop, but if it ever gets
* modified, we might need a new custom version of it
* that avoids infinite recursion.
*/
serial8250_clear_and_reinit_fifos(up);
/*
* With PSLVERR_RESP_EN parameter set to 1, the device generates an
* error response when an attempt to read an empty RBR with FIFO
* enabled.
*/
if (up->fcr & UART_FCR_ENABLE_FIFO) {
lsr = serial_port_in(p, UART_LSR);
if (!(lsr & UART_LSR_DR))
ret = dw8250_idle_enter(p);
if (ret < 0)
return;
}
serial_port_in(p, UART_RX);
serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB);
if (!(serial_port_in(p, UART_LCR) & UART_LCR_DLAB))
goto idle_failed;
serial_dl_write(up, quot);
serial_port_out(p, UART_LCR, up->lcr);
idle_failed:
dw8250_idle_exit(p);
}
/*
* This function is being called as part of the uart_port::serial_out()
* routine. Hence, it must not call serial_port_out() or serial_out()
* against the modified registers here, i.e. LCR.
* routine. Hence, special care must be taken when serial_port_out() or
* serial_out() against the modified registers here, i.e. LCR (d->in_idle is
* used to break recursion loop).
*/
static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
void __iomem *addr = p->membase + (offset << p->regshift);
int tries = 1000;
u32 lcr;
int ret;
if (offset != UART_LCR || d->uart_16550_compatible)
return;
/* Make sure LCR write wasn't ignored */
while (tries--) {
u32 lcr = serial_port_in(p, offset);
lcr = serial_port_in(p, UART_LCR);
/* Make sure LCR write wasn't ignored */
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return;
dw8250_force_idle(p);
if (d->in_idle)
goto write_err;
#ifdef CONFIG_64BIT
if (p->type == PORT_OCTEON)
__raw_writeq(value & 0xff, addr);
else
#endif
if (p->iotype == UPIO_MEM32)
writel(value, addr);
else if (p->iotype == UPIO_MEM32BE)
iowrite32be(value, addr);
else
writeb(value, addr);
}
ret = dw8250_idle_enter(p);
if (ret < 0)
goto write_err;
serial_port_out(p, UART_LCR, value);
dw8250_idle_exit(p);
return;
write_err:
/*
* FIXME: this deadlocks if port->lock is already held
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
*/
return; /* Silences "label at the end of compound statement" */
}
/*
* With BUSY, LCR writes can be very expensive (IRQ + complex retry logic).
* If the write does not change the value of the LCR register, skip it entirely.
*/
static bool dw8250_can_skip_reg_write(struct uart_port *p, unsigned int offset, u32 value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
u32 lcr;
if (offset != UART_LCR || d->uart_16550_compatible)
return false;
lcr = serial_port_in(p, offset);
return lcr == value;
}
/* Returns once the transmitter is empty or we run out of retries */
@@ -207,12 +314,18 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
if (dw8250_can_skip_reg_write(p, offset, value))
return;
writeb(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
static void dw8250_serial_out38x(struct uart_port *p, unsigned int offset, u32 value)
{
if (dw8250_can_skip_reg_write(p, offset, value))
return;
/* Allow the TX to drain before we reconfigure */
if (offset == UART_LCR)
dw8250_tx_wait_empty(p);
@@ -237,6 +350,9 @@ static u32 dw8250_serial_inq(struct uart_port *p, unsigned int offset)
static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 value)
{
if (dw8250_can_skip_reg_write(p, offset, value))
return;
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
@@ -248,6 +364,9 @@ static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 val
static void dw8250_serial_out32(struct uart_port *p, unsigned int offset, u32 value)
{
if (dw8250_can_skip_reg_write(p, offset, value))
return;
writel(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
@@ -261,6 +380,9 @@ static u32 dw8250_serial_in32(struct uart_port *p, unsigned int offset)
static void dw8250_serial_out32be(struct uart_port *p, unsigned int offset, u32 value)
{
if (dw8250_can_skip_reg_write(p, offset, value))
return;
iowrite32be(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
@@ -272,6 +394,29 @@ static u32 dw8250_serial_in32be(struct uart_port *p, unsigned int offset)
return dw8250_modify_msr(p, offset, value);
}
/*
* INTC10EE UART can IRQ storm while reporting IIR_NO_INT. Inducing IIR value
* change has been observed to break the storm.
*
* If Tx is empty (THRE asserted), we use here IER_THRI to cause IIR_NO_INT ->
* IIR_THRI transition.
*/
static void dw8250_quirk_ier_kick(struct uart_port *p)
{
struct uart_8250_port *up = up_to_u8250p(p);
u32 lsr;
if (up->ier & UART_IER_THRI)
return;
lsr = serial_lsr_in(up);
if (!(lsr & UART_LSR_THRE))
return;
serial_port_out(p, UART_IER, up->ier | UART_IER_THRI);
serial_port_in(p, UART_LCR); /* safe, no side-effects */
serial_port_out(p, UART_IER, up->ier);
}
static int dw8250_handle_irq(struct uart_port *p)
{
@@ -281,7 +426,31 @@ static int dw8250_handle_irq(struct uart_port *p)
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = d->pdata->quirks;
unsigned int status;
unsigned long flags;
guard(uart_port_lock_irqsave)(p);
switch (FIELD_GET(DW_UART_IIR_IID, iir)) {
case UART_IIR_NO_INT:
if (d->uart_16550_compatible || up->dma)
return 0;
if (quirks & DW_UART_QUIRK_IER_KICK &&
d->no_int_count == (DW_UART_QUIRK_IER_KICK_THRES - 1))
dw8250_quirk_ier_kick(p);
d->no_int_count = (d->no_int_count + 1) % DW_UART_QUIRK_IER_KICK_THRES;
return 0;
case UART_IIR_BUSY:
/* Clear the USR */
serial_port_in(p, d->pdata->usr_reg);
d->no_int_count = 0;
return 1;
}
d->no_int_count = 0;
/*
* There are ways to get Designware-based UARTs into a state where
@@ -294,20 +463,15 @@ static int dw8250_handle_irq(struct uart_port *p)
* so we limit the workaround only to non-DMA mode.
*/
if (!up->dma && rx_timeout) {
uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
serial_port_in(p, UART_RX);
uart_port_unlock_irqrestore(p, flags);
}
/* Manually stop the Rx DMA transfer when acting as flow controller */
if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) {
uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
uart_port_unlock_irqrestore(p, flags);
if (status & (UART_LSR_DR | UART_LSR_BI)) {
dw8250_writel_ext(p, RZN1_UART_RDMACR, 0);
@@ -315,19 +479,11 @@ static int dw8250_handle_irq(struct uart_port *p)
}
}
if (serial8250_handle_irq(p, iir))
return 1;
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
serial_port_in(p, d->pdata->usr_reg);
serial8250_handle_irq_locked(p, iir);
return 1;
}
return 0;
}
static void dw8250_clk_work_cb(struct work_struct *work)
{
struct dw8250_data *d = work_to_dw8250_data(work);
@@ -527,6 +683,14 @@ static void dw8250_reset_control_assert(void *data)
reset_control_assert(data);
}
static void dw8250_shutdown(struct uart_port *port)
{
struct dw8250_data *d = to_dw8250_data(port->private_data);
serial8250_do_shutdown(port);
d->no_int_count = 0;
}
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {}, *up = &uart;
@@ -545,8 +709,10 @@ static int dw8250_probe(struct platform_device *pdev)
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
p->dev = dev;
p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios;
p->set_divisor = dw8250_set_divisor;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -654,10 +820,12 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
if (data->uart_16550_compatible)
if (data->uart_16550_compatible) {
p->handle_irq = NULL;
else if (data->pdata)
} else if (data->pdata) {
p->handle_irq = dw8250_handle_irq;
p->shutdown = dw8250_shutdown;
}
dw8250_setup_dma_filter(p, data);
@@ -789,6 +957,11 @@ static const struct dw8250_platform_data dw8250_skip_set_rate_data = {
.quirks = DW_UART_QUIRK_SKIP_SET_RATE,
};
static const struct dw8250_platform_data dw8250_intc10ee = {
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_IER_KICK,
};
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
@@ -818,7 +991,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
{ "INTC10EE", (kernel_ulong_t)&dw8250_dw_apb },
{ "INTC10EE", (kernel_ulong_t)&dw8250_intc10ee },
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
@@ -836,6 +1009,7 @@ static struct platform_driver dw8250_platform_driver = {
module_platform_driver(dw8250_platform_driver);
MODULE_IMPORT_NS("SERIAL_8250");
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");

View File

@@ -137,6 +137,8 @@ struct serial_private {
};
#define PCI_DEVICE_ID_HPE_PCI_SERIAL 0x37e
#define PCIE_VENDOR_ID_ASIX 0x125B
#define PCIE_DEVICE_ID_AX99100 0x9100
static const struct pci_device_id pci_use_msi[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
@@ -149,6 +151,8 @@ static const struct pci_device_id pci_use_msi[] = {
0xA000, 0x1000) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL,
PCI_ANY_ID, PCI_ANY_ID) },
{ PCI_DEVICE_SUB(PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
0xA000, 0x1000) },
{ }
};
@@ -920,6 +924,7 @@ static int pci_netmos_init(struct pci_dev *dev)
case PCI_DEVICE_ID_NETMOS_9912:
case PCI_DEVICE_ID_NETMOS_9922:
case PCI_DEVICE_ID_NETMOS_9900:
case PCIE_DEVICE_ID_AX99100:
num_serial = pci_netmos_9900_numports(dev);
break;
@@ -2544,6 +2549,14 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.init = pci_netmos_init,
.setup = pci_netmos_9900_setup,
},
{
.vendor = PCIE_VENDOR_ID_ASIX,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_netmos_init,
.setup = pci_netmos_9900_setup,
},
/*
* EndRun Technologies
*/
@@ -6065,6 +6078,10 @@ static const struct pci_device_id serial_pci_tbl[] = {
0xA000, 0x3002,
0, 0, pbn_NETMOS9900_2s_115200 },
{ PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
0xA000, 0x1000,
0, 0, pbn_b0_1_115200 },
/*
* Best Connectivity and Rosewill PCI Multi I/O cards
*/

View File

@@ -18,6 +18,7 @@
#include <linux/irq.h>
#include <linux/console.h>
#include <linux/gpio/consumer.h>
#include <linux/lockdep.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -488,7 +489,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
/*
* FIFO support.
*/
static void serial8250_clear_fifos(struct uart_8250_port *p)
void serial8250_clear_fifos(struct uart_8250_port *p)
{
if (p->capabilities & UART_CAP_FIFO) {
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -497,6 +498,7 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
serial_out(p, UART_FCR, 0);
}
}
EXPORT_SYMBOL_NS_GPL(serial8250_clear_fifos, "SERIAL_8250");
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
@@ -1782,20 +1784,16 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
}
/*
* This handles the interrupt from one port.
* Context: port's lock must be held by the caller.
*/
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
bool skip_rx = false;
unsigned long flags;
u16 status;
if (iir & UART_IIR_NO_INT)
return 0;
uart_port_lock_irqsave(port, &flags);
lockdep_assert_held_once(&port->lock);
status = serial_lsr_in(up);
@@ -1828,8 +1826,19 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
else if (!up->dma->tx_running)
__stop_tx(up);
}
}
EXPORT_SYMBOL_NS_GPL(serial8250_handle_irq_locked, "SERIAL_8250");
uart_unlock_and_check_sysrq_irqrestore(port, flags);
/*
* This handles the interrupt from one port.
*/
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{
if (iir & UART_IIR_NO_INT)
return 0;
guard(uart_port_lock_irqsave)(port);
serial8250_handle_irq_locked(port, iir);
return 1;
}
@@ -2147,8 +2156,7 @@ static void serial8250_THRE_test(struct uart_port *port)
if (up->port.flags & UPF_NO_THRE_TEST)
return;
if (port->irqflags & IRQF_SHARED)
disable_irq_nosync(port->irq);
disable_irq(port->irq);
/*
* Test for UARTs that do not reassert THRE when the transmitter is idle and the interrupt
@@ -2170,7 +2178,6 @@ static void serial8250_THRE_test(struct uart_port *port)
serial_port_out(port, UART_IER, 0);
}
if (port->irqflags & IRQF_SHARED)
enable_irq(port->irq);
/*
@@ -2350,6 +2357,7 @@ static int serial8250_startup(struct uart_port *port)
void serial8250_do_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
u32 lcr;
serial8250_rpm_get(up);
/*
@@ -2376,13 +2384,13 @@ void serial8250_do_shutdown(struct uart_port *port)
port->mctrl &= ~TIOCM_OUT2;
serial8250_set_mctrl(port, port->mctrl);
/* Disable break condition */
lcr = serial_port_in(port, UART_LCR);
lcr &= ~UART_LCR_SBC;
serial_port_out(port, UART_LCR, lcr);
}
/*
* Disable break condition and FIFOs
*/
serial_port_out(port, UART_LCR,
serial_port_in(port, UART_LCR) & ~UART_LCR_SBC);
serial8250_clear_fifos(up);
rsa_disable(up);
@@ -2392,6 +2400,12 @@ void serial8250_do_shutdown(struct uart_port *port)
* the IRQ chain.
*/
serial_port_in(port, UART_RX);
/*
* LCR writes on DW UART can trigger late (unmaskable) IRQs.
* Handle them before releasing the handler.
*/
synchronize_irq(port->irq);
serial8250_rpm_put(up);
up->ops->release_irq(up);
@@ -3185,6 +3199,17 @@ void serial8250_set_defaults(struct uart_8250_port *up)
}
EXPORT_SYMBOL_GPL(serial8250_set_defaults);
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count)
{
unsigned int i;
for (i = 0; i < count; i++) {
if (wait_for_lsr(up, UART_LSR_THRE))
return;
}
}
EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, "SERIAL_8250");
#ifdef CONFIG_SERIAL_8250_CONSOLE
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3226,16 +3251,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
{
unsigned int i;
for (i = 0; i < count; i++) {
if (wait_for_lsr(up, UART_LSR_THRE))
return;
}
}
/*
* Print a string to the serial port using the device FIFO
*
@@ -3254,7 +3269,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
while (s != end) {
/* Allow timeout for each byte of a possibly full FIFO */
fifo_wait_for_lsr(up, fifosize);
serial8250_fifo_wait_for_lsr_thre(up, fifosize);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
@@ -3272,7 +3287,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
* Allow timeout for each byte written since the caller will only wait
* for UART_LSR_BOTH_EMPTY using the timeout of a single character
*/
fifo_wait_for_lsr(up, tx_count);
serial8250_fifo_wait_for_lsr_thre(up, tx_count);
}
/*

View File

@@ -643,6 +643,9 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned int ret;
port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf)
ret = 0;
else
ret = kfifo_avail(&state->port.xmit_fifo);
uart_port_unlock_deref(port, flags);
return ret;

View File

@@ -878,6 +878,7 @@ of_err:
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);

View File

@@ -1339,6 +1339,8 @@ struct vc_data *vc_deallocate(unsigned int currcons)
kfree(vc->vc_saved_screen);
vc->vc_saved_screen = NULL;
}
vc_uniscr_free(vc->vc_saved_uni_lines);
vc->vc_saved_uni_lines = NULL;
}
return vc;
}
@@ -1884,6 +1886,8 @@ static void enter_alt_screen(struct vc_data *vc)
vc->vc_saved_screen = kmemdup((u16 *)vc->vc_origin, size, GFP_KERNEL);
if (vc->vc_saved_screen == NULL)
return;
vc->vc_saved_uni_lines = vc->vc_uni_lines;
vc->vc_uni_lines = NULL;
vc->vc_saved_rows = vc->vc_rows;
vc->vc_saved_cols = vc->vc_cols;
save_cur(vc);
@@ -1905,6 +1909,8 @@ static void leave_alt_screen(struct vc_data *vc)
dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
memcpy(dest, src, 2 * cols);
}
vc_uniscr_set(vc, vc->vc_saved_uni_lines);
vc->vc_saved_uni_lines = NULL;
restore_cur(vc);
/* Update the entire screen */
if (con_should_update(vc))
@@ -2227,6 +2233,8 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
if (vc->vc_saved_screen != NULL) {
kfree(vc->vc_saved_screen);
vc->vc_saved_screen = NULL;
vc_uniscr_free(vc->vc_saved_uni_lines);
vc->vc_saved_uni_lines = NULL;
vc->vc_saved_rows = 0;
vc->vc_saved_cols = 0;
}

View File

@@ -160,6 +160,7 @@ struct vc_data {
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
u32 **vc_uni_lines; /* unicode screen content */
u16 *vc_saved_screen;
u32 **vc_saved_uni_lines;
unsigned int vc_saved_cols;
unsigned int vc_saved_rows;
/* additional information is in vt_kern.h */

View File

@@ -195,6 +195,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot);
int fsl8250_handle_irq(struct uart_port *port);
void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir);
int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr);
void serial8250_read_char(struct uart_8250_port *up, u16 lsr);