From patchwork Fri Jul 10 13:12:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sumit Garg X-Patchwork-Id: 235231 Delivered-To: patches@linaro.org Received: by 2002:a92:d244:0:0:0:0:0 with SMTP id v4csp442595ilg; Fri, 10 Jul 2020 06:12:35 -0700 (PDT) X-Received: by 2002:a63:3ece:: with SMTP id l197mr39770673pga.313.1594386754907; Fri, 10 Jul 2020 06:12:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594386754; cv=none; d=google.com; s=arc-20160816; b=uPcWvTztVexAvgw+bAA5HXJLT32A4P2XkSoH4ZoTzHQ570K55fB36NHhA9ba+R4Qa+ SmSubz7ZAOxn0QerbNNuT8WcDow9/YWElKca75dmhk9oeNqMY7TrX381/+b+FZlJrXtA HUsX5apLUg1YuZBEpzojGiZuz1ra3kRQTCAtVjbtee7mQb5JHo7iLxwICQrQB/wlZbQF DyeBH1kLNDVB5Bj8MEXeECHHKkoESVs4JciIkympxMU5P92cKqCJdGxyJ1wcDjqGZMWs 9KzqvtHj6qeNntzNFlmAZKHBkzBlAuHf1k6CN6NA3F4zYz5qxrEKi8zrGpEZQaV6odFo 8KYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=wxHIhBMETpDFFxgUbCHxQv41vIYY+Vv4oIYlRuwNjXQ=; b=t5uXpmTzLp7secFfJNFJCX0wdeqIrlcCueA51C47DoJm2tDkxm/vVVlMFoAgoJZxrN EUxhhW51k/maJ4E4C8JILlg0ExMBnrV/FmtkdUcCcnXyyT7HCh+D0McpSrMJnDkSbdd9 QwVZhYj+Wt8qG7Yp5j4O8rHYnh+moxj3ctG19dB7crc4k2X5xWmpxW097hsjTH5uOz5s e764DSh4jkTlc4+dPkW4oSWZ7d4aDG2QQp/8JycuhJ5d5E2B/tF8FdJ8MgEVhUTOrE5q EyIw8Xaxhj9Z9RjsZH3QIccB53ZYqyx7akXGfiE3o4UJ8JtM3v3bSXb/SPnl0Mg0WOci /Qiw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=i48LXWmy; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id ay8sor7796917pjb.36.2020.07.10.06.12.34 for (Google Transport Security); Fri, 10 Jul 2020 06:12:34 -0700 (PDT) Received-SPF: pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=i48LXWmy; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=wxHIhBMETpDFFxgUbCHxQv41vIYY+Vv4oIYlRuwNjXQ=; b=i48LXWmywPjwueW6WbYBLES8sSEoS0bt2WE7VlYB+tNcjhWcUXMVQMxvU0hxYGvYmq dlFCOI5hs+JESQz6YLlkRkGGBfGnccJzPpOfXp/6rBA8ZbmeL8pi7XLTpUUg9mqdFinV 34fpu7qP2yf07vS68nCRQ0UwVfdh2ui3WmS3QX9w3MZ77NZ0rP637+YqmU8rsiLHLf5W vLQmC0RoyK0gcabDEorPYEmcIj9twhj4VPjnxlL/4AG4qOkAJjkw219qEBUxjYirsKPi U3rcdI0wDmmcTUAQHv7A7BS96jax6Y3LGNKfRI3SehYIx9KSoh9fYV1GutcX3mh4PENI bR+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=wxHIhBMETpDFFxgUbCHxQv41vIYY+Vv4oIYlRuwNjXQ=; b=dTLavTMvV4HRs52LJkzjCu5g2sAWeSRQudWc5deoAjcUnjF1yh8E9vnqIC7mjWSPGb kpfdyf7q17Muphx9XlFSk5/Hx2liidy3Yc4uXyHPZbut++wfdwjkvVyvhPMiM3t9D6dA O3kJqy6Vv6m2dMZPiKBncjsAiQYnededzUoWeFFl+Rdvuga/O7M8h1NwqyjDMKn+HdKO FhjvjcVdQe+RA/Y6s4OtS1P7qwC09XT1DLoGzKX4xQn8LNTxk9sUFpuEUTVqljU8u5l0 gsz3CCRRfmZPAO0+I1o3E2OpF4NOp11+PJT7iC87VMmbTlqDwP/+ZMGxQ/GSnUb5ZnSg PThQ== X-Gm-Message-State: AOAM533mH+LgPfUpf8TM0fl3TCEeHzF1cUmbsmAt/j5CbJXkn1ysuHJo AOS2HX4NC3+bwsvGu/c7hRCjtbk1 X-Google-Smtp-Source: ABdhPJygFyifscAJSewj5TKrCqxZoG6YJoWjgiS3S0KUU0cuRu6eFihASV9HMsDh3UNy7PazSEP8xg== X-Received: by 2002:a17:90a:26ac:: with SMTP id m41mr5466921pje.169.1594386754494; Fri, 10 Jul 2020 06:12:34 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([117.210.211.230]) by smtp.gmail.com with ESMTPSA id d25sm5553279pgn.2.2020.07.10.06.12.31 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Jul 2020 06:12:33 -0700 (PDT) From: Sumit Garg To: daniel.thompson@linaro.org Cc: patches@linaro.org, Sumit Garg Subject: [RFC INTERNAL v2 1/4] tty/sysrq: Make sysrq handler NMI aware Date: Fri, 10 Jul 2020 18:42:02 +0530 Message-Id: <1594386725-10346-2-git-send-email-sumit.garg@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> References: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> With the advent of pseudo NMIs on arm64 its been possible to raise serial device interrupt as an NMI in polling mode. With that its now possible to do a magic sysrq in NMI context rather than in normal IRQ context. So make sysrq handler NMI aware and allow system requests to be marked as NMI safe which can run directly in NMI context while categorized as not being NMI safe will be queued as irq_work for later processing in normal interrupt context. This feature is especially helpful in case the primary CPU is stuck in deadlock with interrupts disabled won't honour serial device interrupt. So with sysrq running in NMI context is helpful to debug such scenarios. Signed-off-by: Sumit Garg --- drivers/tty/sysrq.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/sysrq.h | 1 + kernel/debug/debug_core.c | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) -- 2.7.4 diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 7c95afa9..97393c7 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include #include @@ -111,6 +113,7 @@ static const struct sysrq_key_op sysrq_loglevel_op = { .help_msg = "loglevel(0-9)", .action_msg = "Changing Loglevel", .enable_mask = SYSRQ_ENABLE_LOG, + .nmi_safe = true, }; #ifdef CONFIG_VT @@ -157,6 +160,7 @@ static const struct sysrq_key_op sysrq_crash_op = { .help_msg = "crash(c)", .action_msg = "Trigger a crash", .enable_mask = SYSRQ_ENABLE_DUMP, + .nmi_safe = true, }; static void sysrq_handle_reboot(int key) @@ -170,6 +174,7 @@ static const struct sysrq_key_op sysrq_reboot_op = { .help_msg = "reboot(b)", .action_msg = "Resetting", .enable_mask = SYSRQ_ENABLE_BOOT, + .nmi_safe = true, }; const struct sysrq_key_op *__sysrq_reboot_op = &sysrq_reboot_op; @@ -217,6 +222,7 @@ static const struct sysrq_key_op sysrq_showlocks_op = { .handler = sysrq_handle_showlocks, .help_msg = "show-all-locks(d)", .action_msg = "Show Locks Held", + .nmi_safe = true, }; #else #define sysrq_showlocks_op (*(const struct sysrq_key_op *)NULL) @@ -289,6 +295,7 @@ static const struct sysrq_key_op sysrq_showregs_op = { .help_msg = "show-registers(p)", .action_msg = "Show Regs", .enable_mask = SYSRQ_ENABLE_DUMP, + .nmi_safe = true, }; static void sysrq_handle_showstate(int key) @@ -326,6 +333,7 @@ static const struct sysrq_key_op sysrq_ftrace_dump_op = { .help_msg = "dump-ftrace-buffer(z)", .action_msg = "Dump ftrace buffer", .enable_mask = SYSRQ_ENABLE_DUMP, + .nmi_safe = true, }; #else #define sysrq_ftrace_dump_op (*(const struct sysrq_key_op *)NULL) @@ -538,6 +546,26 @@ static void __sysrq_put_key_op(int key, const struct sysrq_key_op *op_p) sysrq_key_table[i] = op_p; } +#define SYSRQ_NMI_FIFO_SIZE 64 +static DEFINE_KFIFO(sysrq_nmi_fifo, int, SYSRQ_NMI_FIFO_SIZE); + +static void sysrq_do_nmi_work(struct irq_work *work) +{ + struct sysrq_key_op *op_p; + int key; + + if (!kfifo_len(&sysrq_nmi_fifo)) + return; + + while (kfifo_out(&sysrq_nmi_fifo, &key, 1)) { + op_p = __sysrq_get_key_op(key); + if (op_p) + op_p->handler(key); + } +} + +static DEFINE_IRQ_WORK(sysrq_nmi_work, sysrq_do_nmi_work); + void __handle_sysrq(int key, bool check_mask) { const struct sysrq_key_op *op_p; @@ -568,7 +596,13 @@ void __handle_sysrq(int key, bool check_mask) if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { pr_info("%s\n", op_p->action_msg); console_loglevel = orig_log_level; - op_p->handler(key); + + if (in_nmi() && !op_p->nmi_safe) { + kfifo_in(&sysrq_nmi_fifo, &key, 1); + irq_work_queue(&sysrq_nmi_work); + } else { + op_p->handler(key); + } } else { pr_info("This sysrq operation is disabled.\n"); console_loglevel = orig_log_level; diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 3a582ec..630b5b9 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -34,6 +34,7 @@ struct sysrq_key_op { const char * const help_msg; const char * const action_msg; const int enable_mask; + const bool nmi_safe; }; #ifdef CONFIG_MAGIC_SYSRQ diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 9e59347..2b51173 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -943,6 +943,7 @@ static const struct sysrq_key_op sysrq_dbg_op = { .handler = sysrq_handle_dbg, .help_msg = "debug(g)", .action_msg = "DEBUG", + .nmi_safe = true, }; #endif From patchwork Fri Jul 10 13:12:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sumit Garg X-Patchwork-Id: 235232 Delivered-To: patches@linaro.org Received: by 2002:a92:d244:0:0:0:0:0 with SMTP id v4csp442661ilg; Fri, 10 Jul 2020 06:12:38 -0700 (PDT) X-Received: by 2002:a62:7e0d:: with SMTP id z13mr59245977pfc.161.1594386758184; Fri, 10 Jul 2020 06:12:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594386758; cv=none; d=google.com; s=arc-20160816; b=kqxbWaeBbu3Y2AOCAznsZHFAenG3Eb9GqxbjvPmHCso62hNm0cYjen1Rx9K67N0ga2 boaOL5qywUESMroYe9Z+bPW/X36WyZM33WBgMPkbdvKu+O25ErsVc3eiZKJyJbQ7UeGf zLA0z+qOhnPjjjP0n4deqZf5VWza4v9AuMknn9M5SYgWBUdQdqcGjxT3RtLz8knUHf2B lZ5wMWnzrJlbWcpqBsUa5FJoCb8iqozds8la6W4Pnl6MuekY63nSTrsPDJl4GK9G+zgL X7vlN1ggxJYz3XNiQr35FnJ6SYvQpN2jr0YIa11RBQQEzDB5AqKvlPNRCjgtMVpEf41o U6lA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=ggNZqpqXwncDazTh/hsPA0z2SqrkNlF0s1+2splHy4I=; b=V8x0JD7DmCBXJ8LxayyL4yzEZLQ2bxKo2RZOGMKztZhtEjJfv4vK+uimciNZe0YY/A V7597tt9TPQWbd/8PTy0s/nvn3AzSa63rtlOOyA2XbJOTooMrOAA51ay4nqTZNHP67/r lEZ6+pFT83BeCA2nb1pZA5nresUfXPi/ua5ddvxGeEwEJ64xWyP8lukn8q63g+ve7fWP /ZPH+FIOCldqwVNt7uGJyjlTE61u+iV4icdGDHzxxNYaU9dlr2ezPL1mjapXeyIGi2H0 VDGFjaEA1I75DN1onnubtFGULhGFCa/k9IejnjK/b+c+2af0iAU2PtrgbHUes/hOLHy5 wjEQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=bRSwE7Xn; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id p22sor8078927pjv.27.2020.07.10.06.12.38 for (Google Transport Security); Fri, 10 Jul 2020 06:12:38 -0700 (PDT) Received-SPF: pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=bRSwE7Xn; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ggNZqpqXwncDazTh/hsPA0z2SqrkNlF0s1+2splHy4I=; b=bRSwE7Xn72jNoTl+Z9mMPNbq2tgzoYdAoNJgR1xcbQ8nIBtmYH3q4GyviAjh+Al5Q1 /1eRuUXQJIxSn3c4tkpyHfg99pr7Y0J3ATswtRrWR2mWahN+YtrbHUcn6pYkt1O1ev/+ TSeT9dgaUUB3IyacpcW4Me00v6GHzZ4dxZoGx68SOOC8KKZ4EF0753w4jtLJ4db+yZGt b92yt3yHYCf1gNADCLIZdaGvnc3jtC92+8cdy6IJgePiYjMY4crIl+gKfl1HfgpF92Ds 0fqeNh36xHGGWDrJHyUc9TLLoGoM5Aam42j3bS1lAmU/eWXAmjS6TYCrFjXIXAsLoGzy Rzzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ggNZqpqXwncDazTh/hsPA0z2SqrkNlF0s1+2splHy4I=; b=PMsBq8OOyLJilzOBvd5A3pxtQts/2RlDtggPRBDBYNYhipAaqzWAQFDIRwl++MQsZ/ wHwhsccjyZLVpLql/k0cTgzAFZzY9tZtk8uUkpHqoExeNcNUIIRRxo1/H41++WQ2gaTQ y4Sdiew2jH32WVpxx81N9U1jDMUtCqYj5DCNHCa5TolEJ44ObOccr/4JWtGpVOwjccsk 0yiYE1gpYRJHQbTBmnghAnypc/vC2Zk79e96MDRejuPX+D87X43n7ku1kGQ5f/OI/cCr UehptTyOeFTMNcW0sU3DM5TF35PARFkfvCUtwgpvxbmpsxScwVzW2is/dTqcl2wasJFL Mtdg== X-Gm-Message-State: AOAM533claQyRmUPgFPP5Hp+TUwd355sBlvNz2wc/3m/EwP8tyOupr7Y 0quRNEzHIQvZNcYi3suMbfG7fLYL X-Google-Smtp-Source: ABdhPJyZM676YzN290bcALoFGjeiBPsbknFGrzkzbxF+waitHV35zKA7jnpZ5Cm8bPF/iwU2bp+0Dg== X-Received: by 2002:a17:90a:ea0f:: with SMTP id w15mr5969065pjy.138.1594386757819; Fri, 10 Jul 2020 06:12:37 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([117.210.211.230]) by smtp.gmail.com with ESMTPSA id d25sm5553279pgn.2.2020.07.10.06.12.34 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Jul 2020 06:12:37 -0700 (PDT) From: Sumit Garg To: daniel.thompson@linaro.org Cc: patches@linaro.org, Sumit Garg Subject: [RFC INTERNAL v2 2/4] serial: core: Add framework to allow NMI aware serial drivers Date: Fri, 10 Jul 2020 18:42:03 +0530 Message-Id: <1594386725-10346-3-git-send-email-sumit.garg@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> References: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> With the advent of pseudo NMIs on arm64 platforms, its been now possible to have NMI driven serial drivers which enables us to have magic sysrq running in NMI context that could be helpful to debug hardlockup scenarios especially via enabling kernel debugger to run in NMI context. So add corresponding NMI helper APIs that can be leveraged by serial drivers. Also, make sysrq handler APIs NMI safe. Signed-off-by: Sumit Garg --- drivers/tty/serial/serial_core.c | 97 +++++++++++++++++++++++++++++++++++++++- include/linux/serial_core.h | 43 ++++++++++++++++++ 2 files changed, 138 insertions(+), 2 deletions(-) -- 2.7.4 diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 57840cf..a59d7ff 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3181,16 +3181,28 @@ static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) return true; } - schedule_work(&sysrq_enable_work); + if (in_nmi()) + irq_work_queue(&port->nmi_state.sysrq_toggle_work); + else + schedule_work(&sysrq_enable_work); port->sysrq = 0; return true; } + +static void uart_nmi_toggle_work(struct irq_work *work) +{ + schedule_work(&sysrq_enable_work); +} #else static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) { return false; } + +static void uart_nmi_toggle_work(struct irq_work *work) +{ +} #endif int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) @@ -3273,12 +3285,93 @@ int uart_handle_break(struct uart_port *port) port->sysrq = 0; } - if (port->flags & UPF_SAK) + if (in_nmi() && (port->flags & UPF_SAK)) + irq_work_queue(&port->nmi_state.sysrq_sak_work); + else if (port->flags & UPF_SAK) do_SAK(state->port.tty); return 0; } EXPORT_SYMBOL_GPL(uart_handle_break); +static void uart_nmi_sak_work(struct irq_work *work) +{ + struct uart_nmi_state *nmi_state = + container_of(work, struct uart_nmi_state, sysrq_sak_work); + struct uart_port *port = nmi_state->port; + + do_SAK(port->state->port.tty); +} + +static void uart_nmi_rx_work(struct irq_work *rx_work) +{ + struct uart_nmi_state *nmi_state = + container_of(rx_work, struct uart_nmi_state, rx_work); + struct uart_port *port = nmi_state->port; + struct uart_nmi_rx_data rx_data; + + /* + * In polling mode, serial device is initialized much prior to + * TTY port becoming active. This scenario is especially useful + * from debugging perspective such that magic sysrq or debugger + * entry would still be possible even when TTY port isn't + * active (consider a boot hang case or if a user hasn't opened + * the serial port). So we discard any other RX data apart from + * magic sysrq commands in case TTY port isn't active. + */ + if (!port->state || !tty_port_active(&port->state->port)) { + kfifo_reset(&nmi_state->rx_fifo); + return; + } + + if (unlikely(!kfifo_len(&nmi_state->rx_fifo))) + return; + + spin_lock(&port->lock); + while (kfifo_out(&nmi_state->rx_fifo, &rx_data, 1)) + uart_insert_char(port, rx_data.ch, rx_data.overrun, + rx_data.ch, rx_data.flag); + spin_unlock(&port->lock); + + tty_flip_buffer_push(&port->state->port); +} + +static void uart_nmi_tx_work(struct irq_work *tx_work) +{ + struct uart_nmi_state *nmi_state = + container_of(tx_work, struct uart_nmi_state, tx_work); + struct uart_port *port = nmi_state->port; + + spin_lock(&port->lock); + if (nmi_state->tx_irq_callback) + nmi_state->tx_irq_callback(port); + spin_unlock(&port->lock); +} + +void uart_nmi_handle_rx_data(struct uart_port *port, + struct uart_nmi_rx_data *rx_data) +{ + WARN_ON_ONCE(!kfifo_in(&port->nmi_state.rx_fifo, rx_data, 1)); +} +EXPORT_SYMBOL_GPL(uart_nmi_handle_rx_data); + +int uart_nmi_state_init(struct uart_port *port) +{ + int ret; + + ret = kfifo_alloc(&port->nmi_state.rx_fifo, 256, GFP_KERNEL); + if (ret) + return ret; + + port->nmi_state.port = port; + init_irq_work(&port->nmi_state.tx_work, uart_nmi_tx_work); + init_irq_work(&port->nmi_state.rx_work, uart_nmi_rx_work); + init_irq_work(&port->nmi_state.sysrq_sak_work, uart_nmi_sak_work); + init_irq_work(&port->nmi_state.sysrq_toggle_work, uart_nmi_toggle_work); + + return ret; +} +EXPORT_SYMBOL_GPL(uart_nmi_state_init); + EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_unregister_driver); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 9fd550e..51d62f4 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #ifdef CONFIG_SERIAL_CORE_CONSOLE @@ -103,6 +105,27 @@ struct uart_icount { typedef unsigned int __bitwise upf_t; typedef unsigned int __bitwise upstat_t; +struct uart_nmi_rx_data { + unsigned int ch; + unsigned int overrun; + unsigned int flag; +}; + +struct uart_nmi_state { + bool active; + + struct irq_work tx_work; + void (*tx_irq_callback)(struct uart_port *port); + + struct irq_work rx_work; + DECLARE_KFIFO_PTR(rx_fifo, struct uart_nmi_rx_data); + + struct irq_work sysrq_sak_work; + struct irq_work sysrq_toggle_work; + + struct uart_port *port; +}; + struct uart_port { spinlock_t lock; /* port lock */ unsigned long iobase; /* in/out[bwl] */ @@ -255,6 +278,7 @@ struct uart_port { struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */ struct serial_iso7816 iso7816; void *private_data; /* generic platform data pointer */ + struct uart_nmi_state nmi_state; }; static inline int serial_port_in(struct uart_port *up, int offset) @@ -475,4 +499,23 @@ extern int uart_handle_break(struct uart_port *port); !((cflag) & CLOCAL)) int uart_get_rs485_mode(struct uart_port *port); + +/* + * The following are helper functions for the NMI aware serial drivers. + */ + +int uart_nmi_state_init(struct uart_port *port); +void uart_nmi_handle_rx_data(struct uart_port *port, + struct uart_nmi_rx_data *rx_data); + +static inline bool uart_nmi_active(struct uart_port *port) +{ + return port->nmi_state.active; +} + +static inline void uart_set_nmi_active(struct uart_port *port, bool val) +{ + port->nmi_state.active = val; +} + #endif /* LINUX_SERIAL_CORE_H */ From patchwork Fri Jul 10 13:12:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sumit Garg X-Patchwork-Id: 235233 Delivered-To: patches@linaro.org Received: by 2002:a92:d244:0:0:0:0:0 with SMTP id v4csp442729ilg; Fri, 10 Jul 2020 06:12:42 -0700 (PDT) X-Received: by 2002:aa7:8e0c:: with SMTP id c12mr21344194pfr.38.1594386762026; Fri, 10 Jul 2020 06:12:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594386762; cv=none; d=google.com; s=arc-20160816; b=v5KG/p87YU969wQjivT2zcMqKbvYTBldg3ZtL7Hi5vGldPsC/Ef/xvXeaI+Zidzf09 3YnhHZjUs5cffzyf63sn8N61Ii7X7x8HQrvSYWAgghITQztnDqNKF0cq90AE6cpW93mW AYIY35fHsNH0Ra//nC9rwuMKJTIUbCJytFtoQscjCE0aRFRaMKKeDQPXgHvgHditF5MV 1RuPpsIk3Uczyna4s6r9PT3WBt4z4IXo15KrWtBrYFjO++4JWjJWMjYlyFIPtOeEe+Bu VRvo125Ho/Ni6q/XUzI86irNRgyS3HJaN1UBOAQa6H8kHl/dPSglJzyTaoNrupiwDOup IPHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=L5QBpzbQ08BmWVXWQQ1Ei99UM9wMUTbD0qwaSmoJOcI=; b=nbdn483C8fR54acXGJJVGr/srApjSFZ0ID+WutiK/cxOWVFf6q4mVqZWvbYGZq2bUp s7kSi5raWtGAJUy0JOn3SVGaIHThR3bz4V8b8M3icRHUhRXiwhJSetLLQ18kkx5oPyf+ kn8F5jeQG19ZaNse5UCu90L3j5E+szA7gcpVbuWx0cs0FvhP1Drr9BGSoAN5j8wcLKiM gi1Fhe9JJPwZwiz+VH8JxneESKfuBgmgx5B7jJOlDsryNcpbqCXLaAbR9OUKb0f/Rooa 4pclj1B3vgxyNnRVstCUqVFpE3uv1JkmVnnZvwTdvnNX4b/Z3cm13laNf0mWDgmCgRwZ didQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=f0RW6sIN; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id k11sor7348562pfu.9.2020.07.10.06.12.41 for (Google Transport Security); Fri, 10 Jul 2020 06:12:42 -0700 (PDT) Received-SPF: pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=f0RW6sIN; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=L5QBpzbQ08BmWVXWQQ1Ei99UM9wMUTbD0qwaSmoJOcI=; b=f0RW6sINEnRvP5/8ARWSnCe5qeicZ+JQkHNFbLZj3lYowZCL9XhqzcTt+ftQ7kH9Ae IqW+dFwpywuKLUYx4YKxuOoCioT6OCso9mQP/I9rgQjm0V6QaxbnbJus4i+6z+jqbnmC VwUaI7IGKoyFHj8dfAdqHgcS+Cn+lhbZ/2l4IqfNkj13dx+Tap4nu/2dCdbs8DgLyHrx /7aWjgm6y1HcpKtEaTF5JEcxQLBu4oQv8AVmj/uviX1icGJleWjxUEmcdlhrUwjg1RB4 GJzsKW7QZ+9uhbcawsYVmO7V+luaAi61EJnvE8kA5sw7ktCyF/6T3ByFVMLGHIcsOH4o fvTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=L5QBpzbQ08BmWVXWQQ1Ei99UM9wMUTbD0qwaSmoJOcI=; b=R3KClf7ocr2hhorbsBBY767SynTDnDzq6UDEXhMSLdoLv+QYas7EYvbhZPJkKEUXns JqJPnmw5eKln/iPXOupV0Y+AXHdpy97ODRmIs6OQIhDO3Ct1d/hwq1fsaKZ7GK/xCgnP LjMqOSDeQHQ910PjGWfCHwTIAaBJOl+Xr6GN2hVqAWHtkxIDKQhwfffu66iHdrkIX8nx 6ndAYrkuGqU9D21p0bE6oKuIOCSjHdqpYkgF6KN715CCQegM9ieXL3waP4PFNbzFCtwI 4SRdUE4FPTW77RDAT74c45uToWalkZ2XAvXfANTVWXVwku1MAN3jMkP8p4x4PGM/iYuL mNLA== X-Gm-Message-State: AOAM5329PQ2NeD1Nt9YvEn4br9ibITPdepwTBV9T+pUtQsyEbDR59lIi GBuItoauC79LR0nHzZoLItqWPBP/6FVKgQ== X-Google-Smtp-Source: ABdhPJzm/WSpZzSCqxDz4d/6I4pf78uvBk1qbQUyLji0vwRD+v5PjGrCIL7tOXlzT113i8mQEssvQg== X-Received: by 2002:aa7:9303:: with SMTP id 3mr53508499pfj.108.1594386761414; Fri, 10 Jul 2020 06:12:41 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([117.210.211.230]) by smtp.gmail.com with ESMTPSA id d25sm5553279pgn.2.2020.07.10.06.12.38 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Jul 2020 06:12:40 -0700 (PDT) From: Sumit Garg To: daniel.thompson@linaro.org Cc: patches@linaro.org, Sumit Garg Subject: [RFC INTERNAL v2 3/4] serial: amba-pl011: Re-order APIs definition Date: Fri, 10 Jul 2020 18:42:04 +0530 Message-Id: <1594386725-10346-4-git-send-email-sumit.garg@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> References: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> Re-order pl011_hwinit() and pl011_enable_interrupts() APIs definition to allow their re-use in polling mode. Signed-off-by: Sumit Garg --- drivers/tty/serial/amba-pl011.c | 148 ++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 74 deletions(-) -- 2.7.4 diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8efd7c2..0983c5e 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1581,6 +1581,80 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&uap->port.lock, flags); } +static int pl011_hwinit(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + int retval; + + /* Optionaly enable pins to be muxed in and configured */ + pinctrl_pm_select_default_state(port->dev); + + /* + * Try to enable the clock producer. + */ + retval = clk_prepare_enable(uap->clk); + if (retval) + return retval; + + uap->port.uartclk = clk_get_rate(uap->clk); + + /* Clear pending error and receive interrupts */ + pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS | + UART011_FEIS | UART011_RTIS | UART011_RXIS, + uap, REG_ICR); + + /* + * Save interrupts enable mask, and enable RX interrupts in case if + * the interrupt is used for NMI entry. + */ + uap->im = pl011_read(uap, REG_IMSC); + pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC); + + if (dev_get_platdata(uap->port.dev)) { + struct amba_pl011_data *plat; + + plat = dev_get_platdata(uap->port.dev); + if (plat->init) + plat->init(); + } + return 0; +} + +/* + * Enable interrupts, only timeouts when using DMA + * if initial RX DMA job failed, start in interrupt mode + * as well. + */ +static void pl011_enable_interrupts(struct uart_amba_port *uap) +{ + unsigned int i; + + spin_lock_irq(&uap->port.lock); + + /* Clear out any spuriously appearing RX interrupts */ + pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); + + /* + * RXIS is asserted only when the RX FIFO transitions from below + * to above the trigger threshold. If the RX FIFO is already + * full to the threshold this can't happen and RXIS will now be + * stuck off. Drain the RX FIFO explicitly to fix this: + */ + for (i = 0; i < uap->fifosize * 2; ++i) { + if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE) + break; + + pl011_read(uap, REG_DR); + } + + uap->im = UART011_RTIM; + if (!pl011_dma_rx_running(uap)) + uap->im |= UART011_RXIM; + pl011_write(uap->im, uap, REG_IMSC); + spin_unlock_irq(&uap->port.lock); +} + #ifdef CONFIG_CONSOLE_POLL static void pl011_quiesce_irqs(struct uart_port *port) @@ -1639,46 +1713,6 @@ static void pl011_put_poll_char(struct uart_port *port, #endif /* CONFIG_CONSOLE_POLL */ -static int pl011_hwinit(struct uart_port *port) -{ - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); - int retval; - - /* Optionaly enable pins to be muxed in and configured */ - pinctrl_pm_select_default_state(port->dev); - - /* - * Try to enable the clock producer. - */ - retval = clk_prepare_enable(uap->clk); - if (retval) - return retval; - - uap->port.uartclk = clk_get_rate(uap->clk); - - /* Clear pending error and receive interrupts */ - pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS | - UART011_FEIS | UART011_RTIS | UART011_RXIS, - uap, REG_ICR); - - /* - * Save interrupts enable mask, and enable RX interrupts in case if - * the interrupt is used for NMI entry. - */ - uap->im = pl011_read(uap, REG_IMSC); - pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC); - - if (dev_get_platdata(uap->port.dev)) { - struct amba_pl011_data *plat; - - plat = dev_get_platdata(uap->port.dev); - if (plat->init) - plat->init(); - } - return 0; -} - static bool pl011_split_lcrh(const struct uart_amba_port *uap) { return pl011_reg_to_offset(uap, REG_LCRH_RX) != @@ -1707,40 +1741,6 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap); } -/* - * Enable interrupts, only timeouts when using DMA - * if initial RX DMA job failed, start in interrupt mode - * as well. - */ -static void pl011_enable_interrupts(struct uart_amba_port *uap) -{ - unsigned int i; - - spin_lock_irq(&uap->port.lock); - - /* Clear out any spuriously appearing RX interrupts */ - pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); - - /* - * RXIS is asserted only when the RX FIFO transitions from below - * to above the trigger threshold. If the RX FIFO is already - * full to the threshold this can't happen and RXIS will now be - * stuck off. Drain the RX FIFO explicitly to fix this: - */ - for (i = 0; i < uap->fifosize * 2; ++i) { - if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE) - break; - - pl011_read(uap, REG_DR); - } - - uap->im = UART011_RTIM; - if (!pl011_dma_rx_running(uap)) - uap->im |= UART011_RXIM; - pl011_write(uap->im, uap, REG_IMSC); - spin_unlock_irq(&uap->port.lock); -} - static int pl011_startup(struct uart_port *port) { struct uart_amba_port *uap = From patchwork Fri Jul 10 13:12:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sumit Garg X-Patchwork-Id: 235234 Delivered-To: patches@linaro.org Received: by 2002:a92:d244:0:0:0:0:0 with SMTP id v4csp442787ilg; Fri, 10 Jul 2020 06:12:45 -0700 (PDT) X-Received: by 2002:a62:e119:: with SMTP id q25mr45766186pfh.300.1594386765570; Fri, 10 Jul 2020 06:12:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594386765; cv=none; d=google.com; s=arc-20160816; b=qQqoMx/UwD6TkcGc0T1i+KeYjkjj+xXumjpEGWpoLi5+UmcAsC67NwkYR+e/oJbjOa /Gbdbd9JLZPmxYbU1w+tS1O6Y/8N4ILpQIlSoQ17ZOQZLHKtx7it+sr6jb7zdNkwVGKP UgUO+i8QbOqSYRGrSv/AsxUxJUCaf+RgAfSLMdtE9EMctbFvSK1PmEXQH5kNuQ8T+XLT ZpSbGlr59coCmF5Sl0FQ0oCA4Rk9Ge+OtP+K2UUo+NTFF11vikyDqMVzyTa64tTrRgVe Y5h/HEFR1G4lLvk983YxbNiNaq0hk1lHBewid652jS71iKi0D4IGkj8psTqSDxJ0cGgP 5Xhg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=UmTx7X0+S/l8Ncd1/nl65s9vcMmDlzDE1V+od3xcrvs=; b=A9QKt3TIowRJm+Lw3ZuWHQwrzVLDeUTLAy0xXAoJXApPRUeIUUIIGrV9ZF3hTNbxWs JxmrLoyd7LqOGHYjJXFMd99nwnCRwasGJeikWcVb+ITZdLhn1eYsG++U8pX398+C85j4 NZuFtd03YarvDshyS0c+hQnWfeW+3cr8TCZoykOUg1eUueY1XmwKPpKMM9uUk4KenlyE h7sh0t4xvR70JkiTTdXScLSFv3jF8BXB00Ej53oM/uOF0uXT3Vms/y3N1nUWI0orlibo Tggfz39b+fAWQWphA3NvYo26M1Lt792Y3aZdg4U04coZ+cW75PF7QKZIK/rF6SrmL7Ku Sgjw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=dj8Vfhpl; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id a22sor7415433pfg.30.2020.07.10.06.12.45 for (Google Transport Security); Fri, 10 Jul 2020 06:12:45 -0700 (PDT) Received-SPF: pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=dj8Vfhpl; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=UmTx7X0+S/l8Ncd1/nl65s9vcMmDlzDE1V+od3xcrvs=; b=dj8VfhplPnNoybWDgUFQwCTiXpGojlfgZVLcuWJUzIwk2B2AaomdJgKipIDEfsRoxQ LqRQk4Aj1781zoeNe+kJ4G7NRdjNgBW+PN2Dv7vEDXhzLJYjgAyaBJJy0dZfzwAHXwTw KV47uuhdihdvloquZgk7dI8SJC/yg5JhdKqNyFMM1GIFMseb5hEoFUIG3R7T0aNPgivz BHYT5fU5uoqo40RWSXPCQNMP7u2NK8wqjCacAMpxyNSCuhL1VXvYWjomBmZpu0nbetx8 nDjI4SOgV3SxlTxCPDWTlll5KnelkHFIs5RINiO/VR9G6cb72b+s2+Tb5ibnvAY7aGKN r7tA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=UmTx7X0+S/l8Ncd1/nl65s9vcMmDlzDE1V+od3xcrvs=; b=nsZtjSe9cwPQkuhB1Ka2KX+sPFZpxR18xJJKSeGoOwpbua51ifN1r9Lpb4qvLN7i+Q OmclXASfpzUf1b75XxON1Sr/myXHiNQyYPRtnldU6pkudvJEGfXF24c6maItxch2osjK 7Cue2XbAK7imSyAHUM6gKKV7mfWmqtpdElRdX3RhlFVG2rCwqfR1YFUY3xC8qptPUFYO 0FpICZWivT5xajLAU6AaMkUz7QSnoCOdy9CMBLtLckxN5zqk1w1pX05+gJ5vDefRxMf0 OBVGXjj5ClsdZ+rsawBIkEGWARsMgSe7J/6F5n1rArzodZXBOaU9KwG8cfnhszl1IN2V iGPg== X-Gm-Message-State: AOAM532TPtNWOs44TLnlXCc1pWvX4Lx4LFQtdBPmgS43IO066AC7SgE4 0olJgiMzVHWTICiUk44VSPWYdo/H X-Google-Smtp-Source: ABdhPJwuonh0EHODmNag6KdVTi9ZpoRBazcuJwakSmLdlDqaHCM4TSJh38JpdqOW3AdPNV4fud9XyQ== X-Received: by 2002:aa7:970a:: with SMTP id a10mr50492486pfg.319.1594386765171; Fri, 10 Jul 2020 06:12:45 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([117.210.211.230]) by smtp.gmail.com with ESMTPSA id d25sm5553279pgn.2.2020.07.10.06.12.41 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Jul 2020 06:12:44 -0700 (PDT) From: Sumit Garg To: daniel.thompson@linaro.org Cc: patches@linaro.org, Sumit Garg Subject: [RFC INTERNAL v2 4/4] serial: amba-pl011: Enable NMI aware polling mode Date: Fri, 10 Jul 2020 18:42:05 +0530 Message-Id: <1594386725-10346-5-git-send-email-sumit.garg@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> References: <1594386725-10346-1-git-send-email-sumit.garg@linaro.org> Allow serial interrupt to be requested as an NMI in polling mode. Currently this NMI aware polling mode only supports NMI driven RX and TX data. DMA operation isn't supported. Also, while operating in NMI mode, RX always remains active irrespective of whether corresponding TTY port is active or not. So we directly bail out of startup, shutdown and rx_stop APIs if NMI mode is active. Signed-off-by: Sumit Garg --- drivers/tty/serial/amba-pl011.c | 133 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 11 deletions(-) -- 2.7.4 diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 0983c5e..71d1325 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "amba-pl011.h" @@ -347,6 +349,16 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) if (uart_handle_sysrq_char(&uap->port, ch & 255)) continue; + if (in_nmi()) { + struct uart_nmi_rx_data rx_data; + + rx_data.ch = ch; + rx_data.overrun = UART011_DR_OE; + rx_data.flag = flag; + uart_nmi_handle_rx_data(&uap->port, &rx_data); + continue; + } + uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); } @@ -1316,6 +1328,9 @@ static void pl011_stop_rx(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + if (uart_nmi_active(port)) + return; + uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| UART011_PEIM|UART011_BEIM|UART011_OEIM); pl011_write(uap->im, uap, REG_IMSC); @@ -1604,13 +1619,6 @@ static int pl011_hwinit(struct uart_port *port) UART011_FEIS | UART011_RTIS | UART011_RXIS, uap, REG_ICR); - /* - * Save interrupts enable mask, and enable RX interrupts in case if - * the interrupt is used for NMI entry. - */ - uap->im = pl011_read(uap, REG_IMSC); - pl011_write(UART011_RTIM | UART011_RXIM, uap, REG_IMSC); - if (dev_get_platdata(uap->port.dev)) { struct amba_pl011_data *plat; @@ -1711,6 +1719,99 @@ static void pl011_put_poll_char(struct uart_port *port, pl011_write(ch, uap, REG_DR); } +static void pl011_nmi_rx_chars(struct uart_amba_port *uap) +{ + pl011_fifo_to_tty(uap); + irq_work_queue(&uap->port.nmi_state.rx_work); +} + +static irqreturn_t pl011_nmi_int(int irq, void *dev_id) +{ + struct uart_amba_port *uap = dev_id; + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + int handled = 0; + + status = pl011_read(uap, REG_MIS); + if (status) { + do { + check_apply_cts_event_workaround(uap); + + pl011_write(status, uap, REG_ICR); + + if (status & (UART011_RTIS|UART011_RXIS)) + pl011_nmi_rx_chars(uap); + + if (status & UART011_TXIS) + irq_work_queue(&uap->port.nmi_state.tx_work); + + if (pass_counter-- == 0) + break; + + status = pl011_read(uap, REG_MIS); + } while (status != 0); + handled = 1; + } + + return IRQ_RETVAL(handled); +} + +static int pl011_allocate_nmi(struct uart_amba_port *uap) +{ + int ret; + + irq_set_status_flags(uap->port.irq, IRQ_NOAUTOEN); + ret = request_nmi(uap->port.irq, pl011_nmi_int, IRQF_PERCPU, + "uart-pl011", uap); + if (ret) { + irq_clear_status_flags(uap->port.irq, IRQ_NOAUTOEN); + return ret; + } + + enable_irq(uap->port.irq); + + return ret; +} + +static void pl011_tx_irq_callback(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + spin_lock(&port->lock); + pl011_tx_chars(uap, true); + spin_unlock(&port->lock); +} + +static int pl011_poll_init(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + int retval; + + retval = pl011_hwinit(port); + goto clk_dis; + + /* In case NMI isn't supported, fallback to normal interrupt mode */ + retval = pl011_allocate_nmi(uap); + if (retval) + return 0; + + retval = uart_nmi_state_init(port); + if (retval) + goto clk_dis; + + port->nmi_state.tx_irq_callback = pl011_tx_irq_callback; + uart_set_nmi_active(port, true); + + pl011_enable_interrupts(uap); + + return 0; + + clk_dis: + clk_disable_unprepare(uap->clk); + return retval; +} + #endif /* CONFIG_CONSOLE_POLL */ static bool pl011_split_lcrh(const struct uart_amba_port *uap) @@ -1736,8 +1837,6 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) static int pl011_allocate_irq(struct uart_amba_port *uap) { - pl011_write(uap->im, uap, REG_IMSC); - return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap); } @@ -1748,6 +1847,9 @@ static int pl011_startup(struct uart_port *port) unsigned int cr; int retval; + if (uart_nmi_active(port)) + return 0; + retval = pl011_hwinit(port); if (retval) goto clk_dis; @@ -1790,6 +1892,9 @@ static int sbsa_uart_startup(struct uart_port *port) container_of(port, struct uart_amba_port, port); int retval; + if (uart_nmi_active(port)) + return 0; + retval = pl011_hwinit(port); if (retval) return retval; @@ -1859,6 +1964,9 @@ static void pl011_shutdown(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + if (uart_nmi_active(port)) + return; + pl011_disable_interrupts(uap); pl011_dma_shutdown(uap); @@ -1891,6 +1999,9 @@ static void sbsa_uart_shutdown(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + if (uart_nmi_active(port)) + return; + pl011_disable_interrupts(uap); free_irq(uap->port.irq, uap); @@ -2142,7 +2253,7 @@ static const struct uart_ops amba_pl011_pops = { .config_port = pl011_config_port, .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL - .poll_init = pl011_hwinit, + .poll_init = pl011_poll_init, .poll_get_char = pl011_get_poll_char, .poll_put_char = pl011_put_poll_char, #endif @@ -2173,7 +2284,7 @@ static const struct uart_ops sbsa_uart_pops = { .config_port = pl011_config_port, .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL - .poll_init = pl011_hwinit, + .poll_init = pl011_poll_init, .poll_get_char = pl011_get_poll_char, .poll_put_char = pl011_put_poll_char, #endif