linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Anton Vorontsov <anton.vorontsov@linaro.org>
To: Russell King <linux@arm.linux.org.uk>,
	Jason Wessel <jason.wessel@windriver.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Alan Cox <alan@linux.intel.com>
Cc: "Arve Hjønnevåg" <arve@android.com>,
	"Colin Cross" <ccross@android.com>,
	"John Stultz" <john.stultz@linaro.org>,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linaro-kernel@lists.linaro.org, patches@linaro.org,
	kernel-team@android.com, kgdb-bugreport@lists.sourceforge.net
Subject: [PATCH 06/12] tty/serial/kgdboc: Add and wire up clear_irqs callback
Date: Mon, 20 Aug 2012 07:47:24 -0700	[thread overview]
Message-ID: <1345474050-8339-6-git-send-email-anton.vorontsov@linaro.org> (raw)
In-Reply-To: <20120820144449.GA32560@lizard>

This patch implements a new callback: clear_irqs. It is used for the
cases when KDB-entry (e.g. NMI) and KDB IO (e.g. serial port) shares
the same interrupt. To get the idea, let's take some real example (ARM
machine): we have a serial port which interrupt is routed to an NMI,
and the interrupt is used to enter KDB. Once there is some activity on
the serial port, the CPU receives NMI exception, and we fall into KDB
shell. So, it is our "debug console", and it is able to interrupt (and
thus debug) even IRQ handlers themselves.

When used that way, the interrupt never reaches serial driver's IRQ
handler routine, which means that serial driver will not silence the
interrupt. NMIs behaviour are quite arch-specific, and we can't assume
that we can use them as ordinary IRQs, e.g. on some arches (like ARM)
we can't handle data aborts, the behaviour is undefined then. So we
can't just handle execution to serial driver's IRQ handler from the
NMI context once we're done with KDB (plus this would defeat the
debugger's purpose: we want the NMI handler be as simple as possible,
so it will have less chances to hang).

So, given that have to deal with it somehow, we have two options:

1. Implement something that clears the interrupt;
2. Implement a whole new concept of grabbing tty for exclusive KDB use,
   plus implement mask/unmask callbacks, i.e.:
   - Since consoles might use ttys w/o opending them, we would have
     to make kdb respect CON_ENABLED flag (maybe a good idea to do it
     anyway);
   - Add 'bool exclusive' argument to tty_find_polling_driver(), if set
     to 1, the function will refuse to return an already tty; and will
     use the flag in tty_reopen() to not allow multiple users (there are
     already checks for pty masters, which are "open once" ttys);
   - Once we got the tty exclusively, we would need to call some new
     uart->mask_all_but_rx_interrupts call before we want to use the
     port for NMI/KDB, and unmask_all_but_rx_interrupts after we're
     done with it.

The second option is obviously more complex, needlessly so, and less
generic. So I went with the first one: we just consume all the interrupts.
The tty becomes silently unusable for the rest of the world when we use
it with KDB; but once we reroute the serial IRQ source back from NMI to
an ordinary IRQ (in KDB this can be done with 'disable_nmi' command), it
will behave as normal.

p.s. Since the callback is so far used only by polling user, we place
it under the appropriate #ifdef.

Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
---
 drivers/tty/serial/kgdboc.c      | 10 ++++++++++
 drivers/tty/serial/serial_core.c | 15 +++++++++++++++
 include/linux/kgdb.h             |  1 +
 include/linux/serial_core.h      |  1 +
 include/linux/tty_driver.h       |  1 +
 5 files changed, 28 insertions(+)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 2b42a01..0aa08c8 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -227,6 +227,15 @@ static int kgdboc_get_char(void)
 						kgdb_tty_line);
 }
 
+static void kgdboc_clear_irqs(void)
+{
+	if (!kgdb_tty_driver)
+		return;
+	if (kgdb_tty_driver->ops->clear_irqs)
+		kgdb_tty_driver->ops->clear_irqs(kgdb_tty_driver,
+						 kgdb_tty_line);
+}
+
 static void kgdboc_put_char(u8 chr)
 {
 	if (!kgdb_tty_driver)
@@ -298,6 +307,7 @@ static struct kgdb_io kgdboc_io_ops = {
 	.name			= "kgdboc",
 	.read_char		= kgdboc_get_char,
 	.write_char		= kgdboc_put_char,
+	.clear_irqs		= kgdboc_clear_irqs,
 	.pre_exception		= kgdboc_pre_exp_handler,
 	.post_exception		= kgdboc_post_exp_handler,
 };
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index cba8443..908d108 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2169,6 +2169,20 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
 	port = state->uart_port;
 	port->ops->poll_put_char(port, ch);
 }
+
+static void uart_clear_irqs(struct tty_driver *driver, int line)
+{
+	struct uart_driver *drv = driver->driver_state;
+	struct uart_state *state = drv->state + line;
+	struct uart_port *port;
+
+	if (!state || !state->uart_port)
+		return;
+
+	port = state->uart_port;
+	if (port->ops->clear_irqs)
+		port->ops->clear_irqs(port);
+}
 #endif
 
 static const struct tty_operations uart_ops = {
@@ -2201,6 +2215,7 @@ static const struct tty_operations uart_ops = {
 	.poll_init	= uart_poll_init,
 	.poll_get_char	= uart_poll_get_char,
 	.poll_put_char	= uart_poll_put_char,
+	.clear_irqs	= uart_clear_irqs,
 #endif
 };
 
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index 3b111a6..1fd1cf0 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -295,6 +295,7 @@ struct kgdb_io {
 	const char		*name;
 	int			(*read_char) (void);
 	void			(*write_char) (u8);
+	void			(*clear_irqs) (void);
 	void			(*flush) (void);
 	int			(*init) (void);
 	void			(*pre_exception) (void);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 3642710..114b3f3 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -277,6 +277,7 @@ struct uart_ops {
 	int		(*poll_init)(struct uart_port *);
 	void	(*poll_put_char)(struct uart_port *, unsigned char);
 	int		(*poll_get_char)(struct uart_port *);
+	void	(*clear_irqs)(struct uart_port *);
 #endif
 };
 
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 6e6dbb7..94b14cd 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -287,6 +287,7 @@ struct tty_operations {
 	int (*poll_init)(struct tty_driver *driver, int line, char *options);
 	int (*poll_get_char)(struct tty_driver *driver, int line);
 	void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
+	void (*clear_irqs)(struct tty_driver *driver, int line);
 #endif
 	const struct file_operations *proc_fops;
 };
-- 
1.7.11.5


  parent reply	other threads:[~2012-08-20 14:53 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-20 14:44 [PATCH v4 0/12] KGDB/KDB FIQ (NMI) debugger Anton Vorontsov
2012-08-20 14:47 ` [PATCH 01/12] kernel/debug: Mask KGDB NMI upon entry Anton Vorontsov
2012-08-20 14:47 ` [PATCH 02/12] kdb: Implement disable_nmi command Anton Vorontsov
2012-08-20 14:47 ` [PATCH 03/12] kdb: Turn KGDB_KDB=n stubs into static inlines Anton Vorontsov
2012-08-20 14:47 ` [PATCH 04/12] tty/serial/core: Introduce poll_init callback Anton Vorontsov
2012-08-20 14:47 ` [PATCH 05/12] tty/serial/amba-pl011: Implement " Anton Vorontsov
2012-08-20 14:47 ` Anton Vorontsov [this message]
2012-08-20 14:47 ` [PATCH 07/12] tty/serial/amba-pl011: Implement clear_irqs callback Anton Vorontsov
2012-08-20 14:47 ` [PATCH 08/12] tty/serial: Add kgdb_nmi driver Anton Vorontsov
2012-08-20 14:47 ` [PATCH 09/12] ARM: Move some macros from entry-armv to entry-header Anton Vorontsov
2012-08-20 14:47 ` [PATCH 10/12] ARM: Add KGDB/KDB FIQ debugger generic code Anton Vorontsov
2012-08-20 14:47 ` [PATCH 11/12] ARM: VIC: Add a couple of low-level FIQ management helpers Anton Vorontsov
2012-08-20 14:47 ` [PATCH 12/12] ARM: versatile: Make able to use UART ports for KGDB FIQ debugger Anton Vorontsov
2012-08-20 20:51 ` [PATCH v4 0/12] KGDB/KDB FIQ (NMI) debugger Brian Swetland
2012-08-20 21:24   ` Anton Vorontsov
2012-09-11  9:30 [PATCH v6 " Anton Vorontsov
2012-09-11  9:35 ` [PATCH 06/12] tty/serial/kgdboc: Add and wire up clear_irqs callback Anton Vorontsov
2012-09-11 14:15   ` Alan Cox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1345474050-8339-6-git-send-email-anton.vorontsov@linaro.org \
    --to=anton.vorontsov@linaro.org \
    --cc=alan@linux.intel.com \
    --cc=arve@android.com \
    --cc=ccross@android.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jason.wessel@windriver.com \
    --cc=john.stultz@linaro.org \
    --cc=kernel-team@android.com \
    --cc=kgdb-bugreport@lists.sourceforge.net \
    --cc=linaro-kernel@lists.linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=patches@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).