Skip to content

Commit b63e6f6

Browse files
jognessgregkh
authored andcommitted
serial: 8250: Switch to nbcon console
Implement the necessary callbacks to switch the 8250 console driver to perform as an nbcon console. Add implementations for the nbcon console callbacks: ->write_atomic() ->write_thread() ->device_lock() ->device_unlock() and add CON_NBCON to the initial @flags. All register access in the callbacks are within unsafe sections. The ->write_atomic() and ->write_thread() callbacks allow safe handover/takeover per byte and add a preceding newline if they take over from another context mid-line. For the ->write_atomic() callback, a new irq_work is used to defer modem control since it may be called from a context that does not allow waking up tasks. Note: A new __serial8250_clear_IER() is introduced for direct clearing of UART_IER. This will allow to restore the lockdep check to serial8250_clear_IER() in a follow-up commit. Signed-off-by: John Ogness <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Tested-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 910ef43 commit b63e6f6

File tree

3 files changed

+187
-41
lines changed

3 files changed

+187
-41
lines changed

drivers/tty/serial/8250/8250_core.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,34 @@ void __init serial8250_register_ports(struct uart_driver *drv, struct device *de
388388

389389
#ifdef CONFIG_SERIAL_8250_CONSOLE
390390

391-
static void univ8250_console_write(struct console *co, const char *s,
392-
unsigned int count)
391+
static void univ8250_console_write_atomic(struct console *co,
392+
struct nbcon_write_context *wctxt)
393393
{
394394
struct uart_8250_port *up = &serial8250_ports[co->index];
395395

396-
serial8250_console_write(up, s, count);
396+
serial8250_console_write(up, wctxt, true);
397+
}
398+
399+
static void univ8250_console_write_thread(struct console *co,
400+
struct nbcon_write_context *wctxt)
401+
{
402+
struct uart_8250_port *up = &serial8250_ports[co->index];
403+
404+
serial8250_console_write(up, wctxt, false);
405+
}
406+
407+
static void univ8250_console_device_lock(struct console *co, unsigned long *flags)
408+
{
409+
struct uart_port *up = &serial8250_ports[co->index].port;
410+
411+
__uart_port_lock_irqsave(up, flags);
412+
}
413+
414+
static void univ8250_console_device_unlock(struct console *co, unsigned long flags)
415+
{
416+
struct uart_port *up = &serial8250_ports[co->index].port;
417+
418+
__uart_port_unlock_irqrestore(up, flags);
397419
}
398420

399421
static int univ8250_console_setup(struct console *co, char *options)
@@ -494,12 +516,15 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
494516

495517
static struct console univ8250_console = {
496518
.name = "ttyS",
497-
.write = univ8250_console_write,
519+
.write_atomic = univ8250_console_write_atomic,
520+
.write_thread = univ8250_console_write_thread,
521+
.device_lock = univ8250_console_device_lock,
522+
.device_unlock = univ8250_console_device_unlock,
498523
.device = uart_console_device,
499524
.setup = univ8250_console_setup,
500525
.exit = univ8250_console_exit,
501526
.match = univ8250_console_match,
502-
.flags = CON_PRINTBUFFER | CON_ANYTIME,
527+
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
503528
.index = -1,
504529
.data = &serial8250_reg,
505530
};

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

Lines changed: 146 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -711,14 +711,24 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
711711
serial8250_rpm_put(p);
712712
}
713713

714-
static void serial8250_clear_IER(struct uart_8250_port *up)
714+
/*
715+
* Only to be used directly by the callback helper serial8250_console_write(),
716+
* which may not require the port lock. Use serial8250_clear_IER() instead for
717+
* all other cases.
718+
*/
719+
static void __serial8250_clear_IER(struct uart_8250_port *up)
715720
{
716721
if (up->capabilities & UART_CAP_UUE)
717722
serial_out(up, UART_IER, UART_IER_UUE);
718723
else
719724
serial_out(up, UART_IER, 0);
720725
}
721726

727+
static inline void serial8250_clear_IER(struct uart_8250_port *up)
728+
{
729+
__serial8250_clear_IER(up);
730+
}
731+
722732
#ifdef CONFIG_SERIAL_8250_RSA
723733
/*
724734
* Attempts to turn on the RSA FIFO. Returns zero on failure.
@@ -1406,9 +1416,6 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier)
14061416
{
14071417
unsigned char mcr = serial8250_in_MCR(p);
14081418

1409-
/* Port locked to synchronize UART_IER access against the console. */
1410-
lockdep_assert_held_once(&p->port.lock);
1411-
14121419
if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
14131420
mcr |= UART_MCR_RTS;
14141421
else
@@ -1424,6 +1431,16 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier)
14241431
serial8250_clear_and_reinit_fifos(p);
14251432

14261433
if (toggle_ier) {
1434+
/*
1435+
* Port locked to synchronize UART_IER access against
1436+
* the console. The lockdep_assert must be restricted
1437+
* to this condition because only here is it
1438+
* guaranteed that the port lock is held. The other
1439+
* hardware access in this function is synchronized
1440+
* by console ownership.
1441+
*/
1442+
lockdep_assert_held_once(&p->port.lock);
1443+
14271444
p->ier |= UART_IER_RLSI | UART_IER_RDI;
14281445
serial_port_out(&p->port, UART_IER, p->ier);
14291446
}
@@ -3303,7 +3320,11 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults);
33033320

33043321
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
33053322
{
3323+
struct uart_8250_port *up = up_to_u8250p(port);
3324+
33063325
serial_port_out(port, UART_TX, ch);
3326+
3327+
up->console_line_ended = (ch == '\n');
33073328
}
33083329

33093330
static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch)
@@ -3340,11 +3361,22 @@ static void serial8250_console_restore(struct uart_8250_port *up)
33403361
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
33413362
}
33423363

3343-
static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
3364+
static void fifo_wait_for_lsr(struct uart_8250_port *up,
3365+
struct nbcon_write_context *wctxt,
3366+
unsigned int count)
33443367
{
33453368
unsigned int i;
33463369

33473370
for (i = 0; i < count; i++) {
3371+
/*
3372+
* Pass the ownership as quickly as possible to a higher
3373+
* priority context. Otherwise, its attempt to take over
3374+
* the ownership might timeout. The new owner will wait
3375+
* for UART_LSR_THRE before reusing the fifo.
3376+
*/
3377+
if (!nbcon_can_proceed(wctxt))
3378+
return;
3379+
33483380
if (wait_for_lsr(up, UART_LSR_THRE))
33493381
return;
33503382
}
@@ -3357,27 +3389,38 @@ static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
33573389
* to get empty.
33583390
*/
33593391
static void serial8250_console_fifo_write(struct uart_8250_port *up,
3360-
const char *s, unsigned int count)
3392+
struct nbcon_write_context *wctxt)
33613393
{
3362-
const char *end = s + count;
33633394
unsigned int fifosize = up->tx_loadsz;
33643395
struct uart_port *port = &up->port;
3396+
const char *s = wctxt->outbuf;
3397+
const char *end = s + wctxt->len;
33653398
unsigned int tx_count = 0;
33663399
bool cr_sent = false;
33673400
unsigned int i;
33683401

33693402
while (s != end) {
33703403
/* Allow timeout for each byte of a possibly full FIFO */
3371-
fifo_wait_for_lsr(up, fifosize);
3404+
fifo_wait_for_lsr(up, wctxt, fifosize);
33723405

3406+
/*
3407+
* Fill the FIFO. If a handover or takeover occurs, writing
3408+
* must be aborted since wctxt->outbuf and wctxt->len are no
3409+
* longer valid.
3410+
*/
33733411
for (i = 0; i < fifosize && s != end; ++i) {
3412+
if (!nbcon_enter_unsafe(wctxt))
3413+
return;
3414+
33743415
if (*s == '\n' && !cr_sent) {
33753416
serial8250_console_putchar(port, '\r');
33763417
cr_sent = true;
33773418
} else {
33783419
serial8250_console_putchar(port, *s++);
33793420
cr_sent = false;
33803421
}
3422+
3423+
nbcon_exit_unsafe(wctxt);
33813424
}
33823425
tx_count = i;
33833426
}
@@ -3386,39 +3429,57 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
33863429
* Allow timeout for each byte written since the caller will only wait
33873430
* for UART_LSR_BOTH_EMPTY using the timeout of a single character
33883431
*/
3389-
fifo_wait_for_lsr(up, tx_count);
3432+
fifo_wait_for_lsr(up, wctxt, tx_count);
3433+
}
3434+
3435+
static void serial8250_console_byte_write(struct uart_8250_port *up,
3436+
struct nbcon_write_context *wctxt)
3437+
{
3438+
struct uart_port *port = &up->port;
3439+
const char *s = wctxt->outbuf;
3440+
const char *end = s + wctxt->len;
3441+
3442+
/*
3443+
* Write out the message. If a handover or takeover occurs, writing
3444+
* must be aborted since wctxt->outbuf and wctxt->len are no longer
3445+
* valid.
3446+
*/
3447+
while (s != end) {
3448+
if (!nbcon_enter_unsafe(wctxt))
3449+
return;
3450+
3451+
uart_console_write(port, s++, 1, serial8250_console_wait_putchar);
3452+
3453+
nbcon_exit_unsafe(wctxt);
3454+
}
33903455
}
33913456

33923457
/*
3393-
* Print a string to the serial port trying not to disturb
3394-
* any possible real use of the port...
3395-
*
3396-
* The console_lock must be held when we get here.
3458+
* Print a string to the serial port trying not to disturb
3459+
* any possible real use of the port...
33973460
*
3398-
* Doing runtime PM is really a bad idea for the kernel console.
3399-
* Thus, we assume the function is called when device is powered up.
3461+
* Doing runtime PM is really a bad idea for the kernel console.
3462+
* Thus, assume it is called when device is powered up.
34003463
*/
3401-
void serial8250_console_write(struct uart_8250_port *up, const char *s,
3402-
unsigned int count)
3464+
void serial8250_console_write(struct uart_8250_port *up,
3465+
struct nbcon_write_context *wctxt,
3466+
bool is_atomic)
34033467
{
34043468
struct uart_8250_em485 *em485 = up->em485;
34053469
struct uart_port *port = &up->port;
3406-
unsigned long flags;
3407-
unsigned int ier, use_fifo;
3408-
int locked = 1;
3409-
3410-
touch_nmi_watchdog();
3470+
unsigned int ier;
3471+
bool use_fifo;
34113472

3412-
if (oops_in_progress)
3413-
locked = uart_port_trylock_irqsave(port, &flags);
3414-
else
3415-
uart_port_lock_irqsave(port, &flags);
3473+
if (!nbcon_enter_unsafe(wctxt))
3474+
return;
34163475

34173476
/*
3418-
* First save the IER then disable the interrupts
3477+
* First, save the IER, then disable the interrupts. The special
3478+
* variant to clear the IER is used because console printing may
3479+
* occur without holding the port lock.
34193480
*/
34203481
ier = serial_port_in(port, UART_IER);
3421-
serial8250_clear_IER(up);
3482+
__serial8250_clear_IER(up);
34223483

34233484
/* check scratch reg to see if port powered off during system sleep */
34243485
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
@@ -3432,6 +3493,18 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
34323493
mdelay(port->rs485.delay_rts_before_send);
34333494
}
34343495

3496+
/* If ownership was lost, no writing is allowed */
3497+
if (!nbcon_can_proceed(wctxt))
3498+
goto skip_write;
3499+
3500+
/*
3501+
* If console printer did not fully output the previous line, it must
3502+
* have been handed or taken over. Insert a newline in order to
3503+
* maintain clean output.
3504+
*/
3505+
if (!up->console_line_ended)
3506+
uart_console_write(port, "\n", 1, serial8250_console_wait_putchar);
3507+
34353508
use_fifo = (up->capabilities & UART_CAP_FIFO) &&
34363509
/*
34373510
* BCM283x requires to check the fifo
@@ -3452,10 +3525,23 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
34523525
*/
34533526
!(up->port.flags & UPF_CONS_FLOW);
34543527

3528+
nbcon_exit_unsafe(wctxt);
3529+
34553530
if (likely(use_fifo))
3456-
serial8250_console_fifo_write(up, s, count);
3531+
serial8250_console_fifo_write(up, wctxt);
34573532
else
3458-
uart_console_write(port, s, count, serial8250_console_wait_putchar);
3533+
serial8250_console_byte_write(up, wctxt);
3534+
skip_write:
3535+
/*
3536+
* If ownership was lost, this context must reacquire ownership and
3537+
* re-enter the unsafe section in order to perform final actions
3538+
* (such as re-enabling interrupts).
3539+
*/
3540+
if (!nbcon_can_proceed(wctxt)) {
3541+
do {
3542+
nbcon_reacquire_nobuf(wctxt);
3543+
} while (!nbcon_enter_unsafe(wctxt));
3544+
}
34593545

34603546
/*
34613547
* Finally, wait for transmitter to become empty
@@ -3478,11 +3564,18 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
34783564
* call it if we have saved something in the saved flags
34793565
* while processing with interrupts off.
34803566
*/
3481-
if (up->msr_saved_flags)
3482-
serial8250_modem_status(up);
3567+
if (up->msr_saved_flags) {
3568+
/*
3569+
* For atomic, it must be deferred to irq_work because this
3570+
* may be a context that does not permit waking up tasks.
3571+
*/
3572+
if (is_atomic)
3573+
irq_work_queue(&up->modem_status_work);
3574+
else
3575+
serial8250_modem_status(up);
3576+
}
34833577

3484-
if (locked)
3485-
uart_port_unlock_irqrestore(port, flags);
3578+
nbcon_exit_unsafe(wctxt);
34863579
}
34873580

34883581
static unsigned int probe_baud(struct uart_port *port)
@@ -3500,8 +3593,24 @@ static unsigned int probe_baud(struct uart_port *port)
35003593
return (port->uartclk / 16) / quot;
35013594
}
35023595

3596+
/*
3597+
* irq_work handler to perform modem control. Only triggered via
3598+
* ->write_atomic() callback because it may be in a scheduler or
3599+
* NMI context, unable to wake tasks.
3600+
*/
3601+
static void modem_status_handler(struct irq_work *iwp)
3602+
{
3603+
struct uart_8250_port *up = container_of(iwp, struct uart_8250_port, modem_status_work);
3604+
struct uart_port *port = &up->port;
3605+
3606+
uart_port_lock(port);
3607+
serial8250_modem_status(up);
3608+
uart_port_unlock(port);
3609+
}
3610+
35033611
int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
35043612
{
3613+
struct uart_8250_port *up = up_to_u8250p(port);
35053614
int baud = 9600;
35063615
int bits = 8;
35073616
int parity = 'n';
@@ -3511,6 +3620,9 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
35113620
if (!port->iobase && !port->membase)
35123621
return -ENODEV;
35133622

3623+
up->console_line_ended = true;
3624+
init_irq_work(&up->modem_status_work, modem_status_handler);
3625+
35143626
if (options)
35153627
uart_parse_options(options, &baud, &parity, &bits, &flow);
35163628
else if (probe)

include/linux/serial_8250.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,17 @@ struct uart_8250_port {
150150
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
151151
u16 lsr_saved_flags;
152152
u16 lsr_save_mask;
153+
154+
/*
155+
* Track when a console line has been fully written to the
156+
* hardware, i.e. true when the most recent byte written to
157+
* UART_TX by the console was '\n'.
158+
*/
159+
bool console_line_ended;
160+
153161
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
154162
unsigned char msr_saved_flags;
163+
struct irq_work modem_status_work;
155164

156165
struct uart_8250_dma *dma;
157166
const struct uart_8250_ops *ops;
@@ -202,8 +211,8 @@ void serial8250_tx_chars(struct uart_8250_port *up);
202211
unsigned int serial8250_modem_status(struct uart_8250_port *up);
203212
void serial8250_init_port(struct uart_8250_port *up);
204213
void serial8250_set_defaults(struct uart_8250_port *up);
205-
void serial8250_console_write(struct uart_8250_port *up, const char *s,
206-
unsigned int count);
214+
void serial8250_console_write(struct uart_8250_port *up,
215+
struct nbcon_write_context *wctxt, bool in_atomic);
207216
int serial8250_console_setup(struct uart_port *port, char *options, bool probe);
208217
int serial8250_console_exit(struct uart_port *port);
209218

0 commit comments

Comments
 (0)