Skip to content
/ linux Public

Commit a773f01

Browse files
ij-intelgregkh
authored andcommitted
serial: 8250_dw: Ensure BUSY is deasserted
commit a7b9ce3 upstream. DW UART cannot write to LCR, DLL, and DLH while BUSY is asserted. Existance of BUSY depends on uart_16550_compatible, if UART HW is configured with it those registers can always be written. There currently is dw8250_force_idle() which attempts to achieve non-BUSY state by disabling FIFO, however, the solution is unreliable when Rx keeps getting more and more characters. Create a sequence of operations that ensures UART cannot keep BUSY asserted indefinitely. The new sequence relies on enabling loopback mode temporarily to prevent incoming Rx characters keeping UART BUSY. Ensure no Tx in ongoing while the UART is switches into the loopback mode (requires exporting serial8250_fifo_wait_for_lsr_thre() and adding DMA Tx pause/resume functions). According to tests performed by Adriana Nicolae <adriana@arista.com>, simply disabling FIFO or clearing FIFOs only once does not always ensure BUSY is deasserted but up to two tries may be needed. This could be related to ongoing Rx of a character (a guess, not known for sure). Therefore, retry FIFO clearing a few times (retry limit 4 is arbitrary number but using, e.g., p->fifosize seems overly large). Tests performed by others did not exhibit similar challenge but it does not seem harmful to leave the FIFO clearing loop in place for all DW UARTs with BUSY functionality. Use the new dw8250_idle_enter/exit() to do divisor writes and LCR writes. In case of plain LCR writes, opportunistically try to update LCR first and only invoke dw8250_idle_enter() if the write did not succeed (it has been observed that in practice most LCR writes do succeed without complications). This issue was first reported by qianfan Zhao who put lots of debugging effort into understanding the solution space. Fixes: c49436b ("serial: 8250_dw: Improve unwritable LCR workaround") Fixes: 7d4008e ("tty: add a DesignWare 8250 driver") Cc: stable <stable@kernel.org> Reported-by: qianfan Zhao <qianfanguijin@163.com> Link: https://lore.kernel.org/linux-serial/289bb78a-7509-1c5c-2923-a04ed3b6487d@163.com/ Reported-by: Adriana Nicolae <adriana@arista.com> Link: https://lore.kernel.org/linux-serial/20250819182322.3451959-1-adriana@arista.com/ Reported-by: Bandal, Shankar <shankar.bandal@intel.com> Tested-by: Bandal, Shankar <shankar.bandal@intel.com> Tested-by: Murthy, Shanth <shanth.murthy@intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://patch.msgid.link/20260203171049.4353-8-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0e16f46 commit a773f01

File tree

3 files changed

+161
-55
lines changed

3 files changed

+161
-55
lines changed

drivers/tty/serial/8250/8250.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,9 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
184184
return value;
185185
}
186186

187+
void serial8250_clear_fifos(struct uart_8250_port *p);
187188
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
189+
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count);
188190

189191
void serial8250_rpm_get(struct uart_8250_port *p);
190192
void serial8250_rpm_put(struct uart_8250_port *p);
@@ -409,6 +411,26 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
409411

410412
return dma && dma->tx_running;
411413
}
414+
415+
static inline void serial8250_tx_dma_pause(struct uart_8250_port *p)
416+
{
417+
struct uart_8250_dma *dma = p->dma;
418+
419+
if (!dma->tx_running)
420+
return;
421+
422+
dmaengine_pause(dma->txchan);
423+
}
424+
425+
static inline void serial8250_tx_dma_resume(struct uart_8250_port *p)
426+
{
427+
struct uart_8250_dma *dma = p->dma;
428+
429+
if (!dma->tx_running)
430+
return;
431+
432+
dmaengine_resume(dma->txchan);
433+
}
412434
#else
413435
static inline int serial8250_tx_dma(struct uart_8250_port *p)
414436
{
@@ -430,6 +452,9 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
430452
{
431453
return false;
432454
}
455+
456+
static inline void serial8250_tx_dma_pause(struct uart_8250_port *p) { }
457+
static inline void serial8250_tx_dma_resume(struct uart_8250_port *p) { }
433458
#endif
434459

435460
static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)

drivers/tty/serial/8250/8250_dw.c

Lines changed: 121 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/delay.h>
1717
#include <linux/device.h>
1818
#include <linux/io.h>
19+
#include <linux/lockdep.h>
1920
#include <linux/mod_devicetable.h>
2021
#include <linux/module.h>
2122
#include <linux/notifier.h>
@@ -47,6 +48,8 @@
4748

4849
#define DW_UART_MCR_SIRE BIT(6)
4950

51+
#define DW_UART_USR_BUSY BIT(0)
52+
5053
/* Renesas specific register fields */
5154
#define RZN1_UART_xDMACR_DMA_EN BIT(0)
5255
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
@@ -89,6 +92,7 @@ struct dw8250_data {
8992

9093
unsigned int skip_autocfg:1;
9194
unsigned int uart_16550_compatible:1;
95+
unsigned int in_idle:1;
9296

9397
u8 no_int_count;
9498
};
@@ -121,78 +125,151 @@ static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u3
121125
return value;
122126
}
123127

128+
static void dw8250_idle_exit(struct uart_port *p)
129+
{
130+
struct dw8250_data *d = to_dw8250_data(p->private_data);
131+
struct uart_8250_port *up = up_to_u8250p(p);
132+
133+
if (d->uart_16550_compatible)
134+
return;
135+
136+
if (up->capabilities & UART_CAP_FIFO)
137+
serial_port_out(p, UART_FCR, up->fcr);
138+
serial_port_out(p, UART_MCR, up->mcr);
139+
serial_port_out(p, UART_IER, up->ier);
140+
141+
/* DMA Rx is restarted by IRQ handler as needed. */
142+
if (up->dma)
143+
serial8250_tx_dma_resume(up);
144+
145+
d->in_idle = 0;
146+
}
147+
124148
/*
125-
* This function is being called as part of the uart_port::serial_out()
126-
* routine. Hence, it must not call serial_port_out() or serial_out()
127-
* against the modified registers here, i.e. LCR.
149+
* Ensure BUSY is not asserted. If DW UART is configured with
150+
* !uart_16550_compatible, the writes to LCR, DLL, and DLH fail while
151+
* BUSY is asserted.
152+
*
153+
* Context: port's lock must be held
128154
*/
129-
static void dw8250_force_idle(struct uart_port *p)
155+
static int dw8250_idle_enter(struct uart_port *p)
130156
{
157+
struct dw8250_data *d = to_dw8250_data(p->private_data);
158+
unsigned int usr_reg = d->pdata ? d->pdata->usr_reg : DW_UART_USR;
131159
struct uart_8250_port *up = up_to_u8250p(p);
132-
unsigned int lsr;
160+
int retries;
161+
u32 lsr;
133162

134-
/*
135-
* The following call currently performs serial_out()
136-
* against the FCR register. Because it differs to LCR
137-
* there will be no infinite loop, but if it ever gets
138-
* modified, we might need a new custom version of it
139-
* that avoids infinite recursion.
140-
*/
141-
serial8250_clear_and_reinit_fifos(up);
163+
lockdep_assert_held_once(&p->lock);
164+
165+
if (d->uart_16550_compatible)
166+
return 0;
167+
168+
d->in_idle = 1;
169+
170+
/* Prevent triggering interrupt from RBR filling */
171+
serial_port_out(p, UART_IER, 0);
172+
173+
if (up->dma) {
174+
serial8250_rx_dma_flush(up);
175+
if (serial8250_tx_dma_running(up))
176+
serial8250_tx_dma_pause(up);
177+
}
142178

143179
/*
144-
* With PSLVERR_RESP_EN parameter set to 1, the device generates an
145-
* error response when an attempt to read an empty RBR with FIFO
146-
* enabled.
180+
* Wait until Tx becomes empty + one extra frame time to ensure all bits
181+
* have been sent on the wire.
182+
*
183+
* FIXME: frame_time delay is too long with very low baudrates.
147184
*/
148-
if (up->fcr & UART_FCR_ENABLE_FIFO) {
149-
lsr = serial_port_in(p, UART_LSR);
150-
if (!(lsr & UART_LSR_DR))
151-
return;
185+
serial8250_fifo_wait_for_lsr_thre(up, p->fifosize);
186+
ndelay(p->frame_time);
187+
188+
serial_port_out(p, UART_MCR, up->mcr | UART_MCR_LOOP);
189+
190+
retries = 4; /* Arbitrary limit, 2 was always enough in tests */
191+
do {
192+
serial8250_clear_fifos(up);
193+
if (!(serial_port_in(p, usr_reg) & DW_UART_USR_BUSY))
194+
break;
195+
/* FIXME: frame_time delay is too long with very low baudrates. */
196+
ndelay(p->frame_time);
197+
} while (--retries);
198+
199+
lsr = serial_lsr_in(up);
200+
if (lsr & UART_LSR_DR) {
201+
serial_port_in(p, UART_RX);
202+
up->lsr_saved_flags = 0;
152203
}
153204

154-
serial_port_in(p, UART_RX);
205+
/* Now guaranteed to have BUSY deasserted? Just sanity check */
206+
if (serial_port_in(p, usr_reg) & DW_UART_USR_BUSY) {
207+
dw8250_idle_exit(p);
208+
return -EBUSY;
209+
}
210+
211+
return 0;
212+
}
213+
214+
static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
215+
unsigned int quot, unsigned int quot_frac)
216+
{
217+
struct uart_8250_port *up = up_to_u8250p(p);
218+
int ret;
219+
220+
ret = dw8250_idle_enter(p);
221+
if (ret < 0)
222+
return;
223+
224+
serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB);
225+
if (!(serial_port_in(p, UART_LCR) & UART_LCR_DLAB))
226+
goto idle_failed;
227+
228+
serial_dl_write(up, quot);
229+
serial_port_out(p, UART_LCR, up->lcr);
230+
231+
idle_failed:
232+
dw8250_idle_exit(p);
155233
}
156234

157235
/*
158236
* This function is being called as part of the uart_port::serial_out()
159-
* routine. Hence, it must not call serial_port_out() or serial_out()
160-
* against the modified registers here, i.e. LCR.
237+
* routine. Hence, special care must be taken when serial_port_out() or
238+
* serial_out() against the modified registers here, i.e. LCR (d->in_idle is
239+
* used to break recursion loop).
161240
*/
162241
static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value)
163242
{
164243
struct dw8250_data *d = to_dw8250_data(p->private_data);
165-
void __iomem *addr = p->membase + (offset << p->regshift);
166-
int tries = 1000;
244+
u32 lcr;
245+
int ret;
167246

168247
if (offset != UART_LCR || d->uart_16550_compatible)
169248
return;
170249

250+
lcr = serial_port_in(p, UART_LCR);
251+
171252
/* Make sure LCR write wasn't ignored */
172-
while (tries--) {
173-
u32 lcr = serial_port_in(p, offset);
253+
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
254+
return;
174255

175-
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
176-
return;
256+
if (d->in_idle)
257+
goto write_err;
177258

178-
dw8250_force_idle(p);
259+
ret = dw8250_idle_enter(p);
260+
if (ret < 0)
261+
goto write_err;
179262

180-
#ifdef CONFIG_64BIT
181-
if (p->type == PORT_OCTEON)
182-
__raw_writeq(value & 0xff, addr);
183-
else
184-
#endif
185-
if (p->iotype == UPIO_MEM32)
186-
writel(value, addr);
187-
else if (p->iotype == UPIO_MEM32BE)
188-
iowrite32be(value, addr);
189-
else
190-
writeb(value, addr);
191-
}
263+
serial_port_out(p, UART_LCR, value);
264+
dw8250_idle_exit(p);
265+
return;
266+
267+
write_err:
192268
/*
193269
* FIXME: this deadlocks if port->lock is already held
194270
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
195271
*/
272+
return; /* Silences "label at the end of compound statement" */
196273
}
197274

198275
/*
@@ -632,8 +709,10 @@ static int dw8250_probe(struct platform_device *pdev)
632709
p->type = PORT_8250;
633710
p->flags = UPF_FIXED_PORT;
634711
p->dev = dev;
712+
635713
p->set_ldisc = dw8250_set_ldisc;
636714
p->set_termios = dw8250_set_termios;
715+
p->set_divisor = dw8250_set_divisor;
637716

638717
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
639718
if (!data)

drivers/tty/serial/8250/8250_port.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
489489
/*
490490
* FIFO support.
491491
*/
492-
static void serial8250_clear_fifos(struct uart_8250_port *p)
492+
void serial8250_clear_fifos(struct uart_8250_port *p)
493493
{
494494
if (p->capabilities & UART_CAP_FIFO) {
495495
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -498,6 +498,7 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
498498
serial_out(p, UART_FCR, 0);
499499
}
500500
}
501+
EXPORT_SYMBOL_NS_GPL(serial8250_clear_fifos, "SERIAL_8250");
501502

502503
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
503504
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
@@ -3198,6 +3199,17 @@ void serial8250_set_defaults(struct uart_8250_port *up)
31983199
}
31993200
EXPORT_SYMBOL_GPL(serial8250_set_defaults);
32003201

3202+
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count)
3203+
{
3204+
unsigned int i;
3205+
3206+
for (i = 0; i < count; i++) {
3207+
if (wait_for_lsr(up, UART_LSR_THRE))
3208+
return;
3209+
}
3210+
}
3211+
EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, "SERIAL_8250");
3212+
32013213
#ifdef CONFIG_SERIAL_8250_CONSOLE
32023214

32033215
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3239,16 +3251,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
32393251
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
32403252
}
32413253

3242-
static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
3243-
{
3244-
unsigned int i;
3245-
3246-
for (i = 0; i < count; i++) {
3247-
if (wait_for_lsr(up, UART_LSR_THRE))
3248-
return;
3249-
}
3250-
}
3251-
32523254
/*
32533255
* Print a string to the serial port using the device FIFO
32543256
*
@@ -3267,7 +3269,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
32673269

32683270
while (s != end) {
32693271
/* Allow timeout for each byte of a possibly full FIFO */
3270-
fifo_wait_for_lsr(up, fifosize);
3272+
serial8250_fifo_wait_for_lsr_thre(up, fifosize);
32713273

32723274
for (i = 0; i < fifosize && s != end; ++i) {
32733275
if (*s == '\n' && !cr_sent) {
@@ -3285,7 +3287,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
32853287
* Allow timeout for each byte written since the caller will only wait
32863288
* for UART_LSR_BOTH_EMPTY using the timeout of a single character
32873289
*/
3288-
fifo_wait_for_lsr(up, tx_count);
3290+
serial8250_fifo_wait_for_lsr_thre(up, tx_count);
32893291
}
32903292

32913293
/*

0 commit comments

Comments
 (0)