Skip to content

Commit 08d5470

Browse files
jhovoldgregkh
authored andcommitted
serial: core: fix sysrq overhead regression
Commit 8e20fc3 ("serial_core: Move sysrq functions from header file") converted the inline sysrq helpers to exported functions which are now called for every received character, interrupt and break signal also on systems without CONFIG_MAGIC_SYSRQ_SERIAL instead of being optimised away by the compiler. Inlining these helpers again also avoids the function call overhead when CONFIG_MAGIC_SYSRQ_SERIAL is enabled (e.g. when the port is not used as a console). Fixes: 8e20fc3 ("serial_core: Move sysrq functions from header file") Cc: Dmitry Safonov <[email protected]> Signed-off-by: Johan Hovold <[email protected]> Cc: stable <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Reviewed-by: Dmitry Safonov <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 10652a9 commit 08d5470

File tree

2 files changed

+100
-102
lines changed

2 files changed

+100
-102
lines changed

drivers/tty/serial/serial_core.c

Lines changed: 2 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ static struct lock_class_key port_lock_key;
4141

4242
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
4343

44-
#define SYSRQ_TIMEOUT (HZ * 5)
45-
4644
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
4745
struct ktermios *old_termios);
4846
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -3163,7 +3161,7 @@ static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on);
31633161
* Returns false if @ch is out of enabling sequence and should be
31643162
* handled some other way, true if @ch was consumed.
31653163
*/
3166-
static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
3164+
bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
31673165
{
31683166
int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq);
31693167

@@ -3186,102 +3184,9 @@ static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
31863184
port->sysrq = 0;
31873185
return true;
31883186
}
3189-
#else
3190-
static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
3191-
{
3192-
return false;
3193-
}
3187+
EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq);
31943188
#endif
31953189

3196-
int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
3197-
{
3198-
if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
3199-
return 0;
3200-
3201-
if (!port->has_sysrq || !port->sysrq)
3202-
return 0;
3203-
3204-
if (ch && time_before(jiffies, port->sysrq)) {
3205-
if (sysrq_mask()) {
3206-
handle_sysrq(ch);
3207-
port->sysrq = 0;
3208-
return 1;
3209-
}
3210-
if (uart_try_toggle_sysrq(port, ch))
3211-
return 1;
3212-
}
3213-
port->sysrq = 0;
3214-
3215-
return 0;
3216-
}
3217-
EXPORT_SYMBOL_GPL(uart_handle_sysrq_char);
3218-
3219-
int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
3220-
{
3221-
if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
3222-
return 0;
3223-
3224-
if (!port->has_sysrq || !port->sysrq)
3225-
return 0;
3226-
3227-
if (ch && time_before(jiffies, port->sysrq)) {
3228-
if (sysrq_mask()) {
3229-
port->sysrq_ch = ch;
3230-
port->sysrq = 0;
3231-
return 1;
3232-
}
3233-
if (uart_try_toggle_sysrq(port, ch))
3234-
return 1;
3235-
}
3236-
port->sysrq = 0;
3237-
3238-
return 0;
3239-
}
3240-
EXPORT_SYMBOL_GPL(uart_prepare_sysrq_char);
3241-
3242-
void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
3243-
{
3244-
int sysrq_ch;
3245-
3246-
if (!port->has_sysrq) {
3247-
spin_unlock_irqrestore(&port->lock, irqflags);
3248-
return;
3249-
}
3250-
3251-
sysrq_ch = port->sysrq_ch;
3252-
port->sysrq_ch = 0;
3253-
3254-
spin_unlock_irqrestore(&port->lock, irqflags);
3255-
3256-
if (sysrq_ch)
3257-
handle_sysrq(sysrq_ch);
3258-
}
3259-
EXPORT_SYMBOL_GPL(uart_unlock_and_check_sysrq);
3260-
3261-
/*
3262-
* We do the SysRQ and SAK checking like this...
3263-
*/
3264-
int uart_handle_break(struct uart_port *port)
3265-
{
3266-
struct uart_state *state = port->state;
3267-
3268-
if (port->handle_break)
3269-
port->handle_break(port);
3270-
3271-
if (port->has_sysrq && uart_console(port)) {
3272-
if (!port->sysrq) {
3273-
port->sysrq = jiffies + SYSRQ_TIMEOUT;
3274-
return 1;
3275-
}
3276-
port->sysrq = 0;
3277-
}
3278-
3279-
if (port->flags & UPF_SAK)
3280-
do_SAK(state->port.tty);
3281-
return 0;
3282-
}
3283-
EXPORT_SYMBOL_GPL(uart_handle_break);
3284-
32853190
EXPORT_SYMBOL(uart_write_wakeup);
32863191
EXPORT_SYMBOL(uart_register_driver);
32873192
EXPORT_SYMBOL(uart_unregister_driver);

include/linux/serial_core.h

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,11 +462,104 @@ extern void uart_handle_cts_change(struct uart_port *uport,
462462
extern void uart_insert_char(struct uart_port *port, unsigned int status,
463463
unsigned int overrun, unsigned int ch, unsigned int flag);
464464

465-
extern int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch);
466-
extern int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch);
467-
extern void uart_unlock_and_check_sysrq(struct uart_port *port,
468-
unsigned long irqflags);
469-
extern int uart_handle_break(struct uart_port *port);
465+
#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
466+
#define SYSRQ_TIMEOUT (HZ * 5)
467+
468+
bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch);
469+
470+
static inline int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
471+
{
472+
if (!port->has_sysrq || !port->sysrq)
473+
return 0;
474+
475+
if (ch && time_before(jiffies, port->sysrq)) {
476+
if (sysrq_mask()) {
477+
handle_sysrq(ch);
478+
port->sysrq = 0;
479+
return 1;
480+
}
481+
if (uart_try_toggle_sysrq(port, ch))
482+
return 1;
483+
}
484+
port->sysrq = 0;
485+
486+
return 0;
487+
}
488+
489+
static inline int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
490+
{
491+
if (!port->has_sysrq || !port->sysrq)
492+
return 0;
493+
494+
if (ch && time_before(jiffies, port->sysrq)) {
495+
if (sysrq_mask()) {
496+
port->sysrq_ch = ch;
497+
port->sysrq = 0;
498+
return 1;
499+
}
500+
if (uart_try_toggle_sysrq(port, ch))
501+
return 1;
502+
}
503+
port->sysrq = 0;
504+
505+
return 0;
506+
}
507+
508+
static inline void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
509+
{
510+
int sysrq_ch;
511+
512+
if (!port->has_sysrq) {
513+
spin_unlock_irqrestore(&port->lock, irqflags);
514+
return;
515+
}
516+
517+
sysrq_ch = port->sysrq_ch;
518+
port->sysrq_ch = 0;
519+
520+
spin_unlock_irqrestore(&port->lock, irqflags);
521+
522+
if (sysrq_ch)
523+
handle_sysrq(sysrq_ch);
524+
}
525+
#else /* CONFIG_MAGIC_SYSRQ_SERIAL */
526+
static inline int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
527+
{
528+
return 0;
529+
}
530+
static inline int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
531+
{
532+
return 0;
533+
}
534+
static inline void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
535+
{
536+
spin_unlock_irqrestore(&port->lock, irqflags);
537+
}
538+
#endif /* CONFIG_MAGIC_SYSRQ_SERIAL */
539+
540+
/*
541+
* We do the SysRQ and SAK checking like this...
542+
*/
543+
static inline int uart_handle_break(struct uart_port *port)
544+
{
545+
struct uart_state *state = port->state;
546+
547+
if (port->handle_break)
548+
port->handle_break(port);
549+
550+
#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
551+
if (port->has_sysrq && uart_console(port)) {
552+
if (!port->sysrq) {
553+
port->sysrq = jiffies + SYSRQ_TIMEOUT;
554+
return 1;
555+
}
556+
port->sysrq = 0;
557+
}
558+
#endif
559+
if (port->flags & UPF_SAK)
560+
do_SAK(state->port.tty);
561+
return 0;
562+
}
470563

471564
/*
472565
* UART_ENABLE_MS - determine if port should enable modem status irqs

0 commit comments

Comments
 (0)