#include <linux/device.h>
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
 #include <linux/serial_core.h>
+#include <linux/sysrq.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/security.h>
 
 #define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
 
+#define SYSRQ_TIMEOUT  (HZ * 5)
+
 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
                                        struct ktermios *old_termios);
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
 }
 EXPORT_SYMBOL_GPL(uart_insert_char);
 
+#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
+static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE;
+
+static void uart_sysrq_on(struct work_struct *w)
+{
+       sysrq_toggle_support(1);
+       pr_info("SysRq is enabled by magic sequence on serial\n");
+}
+static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on);
+
+/**
+ *     uart_try_toggle_sysrq - Enables SysRq from serial line
+ *     @port: uart_port structure where char(s) after BREAK met
+ *     @ch: new character in the sequence after received BREAK
+ *
+ *     Enables magic SysRq when the required sequence is met on port
+ *     (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE).
+ *
+ *     Returns false if @ch is out of enabling sequence and should be
+ *     handled some other way, true if @ch was consumed.
+ */
+static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
+{
+       if (ARRAY_SIZE(sysrq_toggle_seq) <= 1)
+               return false;
+
+       BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= U8_MAX);
+       if (sysrq_toggle_seq[port->sysrq_seq] != ch) {
+               port->sysrq_seq = 0;
+               return false;
+       }
+
+       /* Without the last \0 */
+       if (++port->sysrq_seq < (ARRAY_SIZE(sysrq_toggle_seq) - 1)) {
+               port->sysrq = jiffies + SYSRQ_TIMEOUT;
+               return true;
+       }
+
+       schedule_work(&sysrq_enable_work);
+
+       port->sysrq = 0;
+       return true;
+}
+#else
+static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
+{
+       return false;
+}
+#endif
+
 int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
 {
        if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
                return 0;
 
        if (ch && time_before(jiffies, port->sysrq)) {
-               handle_sysrq(ch);
-               port->sysrq = 0;
-               return 1;
+               if (sysrq_mask()) {
+                       handle_sysrq(ch);
+                       port->sysrq = 0;
+                       return 1;
+               }
+               if (uart_try_toggle_sysrq(port, ch))
+                       return 1;
        }
        port->sysrq = 0;
 
                return 0;
 
        if (ch && time_before(jiffies, port->sysrq)) {
-               port->sysrq_ch = ch;
-               port->sysrq = 0;
-               return 1;
+               if (sysrq_mask()) {
+                       port->sysrq_ch = ch;
+                       port->sysrq = 0;
+                       return 1;
+               }
+               if (uart_try_toggle_sysrq(port, ch))
+                       return 1;
        }
        port->sysrq = 0;
 
        if (port->has_sysrq) {
                if (port->cons && port->cons->index == port->line) {
                        if (!port->sysrq) {
-                               port->sysrq = jiffies + HZ*5;
+                               port->sysrq = jiffies + SYSRQ_TIMEOUT;
                                return 1;
                        }
                        port->sysrq = 0;