mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
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:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static void dw8250_force_idle(struct uart_port *p)
|
||||
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);
|
||||
unsigned int lsr;
|
||||
|
||||
/*
|
||||
* 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))
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
int ret;
|
||||
|
||||
ret = dw8250_idle_enter(p);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
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,17 +479,9 @@ 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)
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user