* [PATCH 1/2] serial: imx: remove duplicate handling of CTS change
From: Sascha Hauer @ 2019-06-26 10:15 UTC (permalink / raw)
To: linux-serial
Cc: Pengutronix Kernel Team, Sascha Hauer, Sergey Organov,
NXP Linux Team, linux-arm-kernel
In-Reply-To: <20190626101557.26299-1-s.hauer@pengutronix.de>
We have an interrupt for the CTS input (RTS in FSL speech). Its handler
calls uart_handle_cts_change(), so we shouldn't do this in
imx_uart_mctrl_check() again.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/tty/serial/imx.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index a5e80a028e83..0419a084c0ed 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -805,12 +805,8 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport);
static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport)
{
unsigned int tmp = TIOCM_DSR;
- unsigned usr1 = imx_uart_readl(sport, USR1);
unsigned usr2 = imx_uart_readl(sport, USR2);
- if (usr1 & USR1_RTSS)
- tmp |= TIOCM_CTS;
-
/* in DCE mode DCDIN is always 0 */
if (!(usr2 & USR2_DCDIN))
tmp |= TIOCM_CAR;
@@ -843,8 +839,6 @@ static void imx_uart_mctrl_check(struct imx_port *sport)
sport->port.icount.dsr++;
if (changed & TIOCM_CAR)
uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
- if (changed & TIOCM_CTS)
- uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
}
--
2.20.1
^ permalink raw reply related
* [PATCH 0/2] serial: imx: use UPF_AUTO_CTS
From: Sascha Hauer @ 2019-06-26 10:15 UTC (permalink / raw)
To: linux-serial
Cc: Pengutronix Kernel Team, Sascha Hauer, Sergey Organov,
NXP Linux Team, linux-arm-kernel
This series eliminates a duplicate call to uart_handle_cts_change() and
sets the UPF_AUTO_CTS flag for the i.MX UART driver.
Normally setting the UPF_AUTO_CTS flag should only be a little
optimization as the transmitter is no longer enabled/disabled with every
CTS change, here it fixes an issue which initially brought me to
implement this patch. I am working on uploading a firmware to a Marvell
bluetooth chip. During download it often happened that a CTS interrupt
was lost and the upload stalled forever. This patch fixes the issue
(without knowing why we lost CTS interrupts in the first place)
This series is based on Sergei Shtylyovs series "serial: imx: fix RTS
and RTS/CTS handling" and should be applied ontop of it.
Sascha Hauer (2):
serial: imx: remove duplicate handling of CTS change
serial: imx: use UPF_AUTO_CTS
drivers/tty/serial/imx.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
--
2.20.1
^ permalink raw reply
* Re: [PATCH RFC v1 0/7] serial: imx: fix RTS and RTS/CTS handling
From: Sascha Hauer @ 2019-06-26 10:00 UTC (permalink / raw)
To: Sergey Organov
Cc: Pengutronix Kernel Team, NXP Linux Team, linux-arm-kernel,
linux-serial, Uwe Kleine-König
In-Reply-To: <1561042073-617-1-git-send-email-sorganov@gmail.com>
Hi Sergey,
On Thu, Jun 20, 2019 at 05:47:46PM +0300, Sergey Organov wrote:
> The patches are not tested yet, so the RFC in the header. I'll re-roll
> without RFC once Sasha Hauer tests them.
>
> Sasha, in addition to already discussed fixes, I've also reordered 2
> patches so that the sequence makes sense.
>
I reviewed and tested this series, so when resending you can add my:
Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de>
Tested-by: Sascha Hauer <s.hauer@pengutronix.de>
Thanks
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: DMA coherency in drivers/tty/serial/mpsc.c
From: Christoph Hellwig @ 2019-06-26 6:48 UTC (permalink / raw)
To: Mark Greer
Cc: Christoph Hellwig, Paul Gortmaker, Dale Farnsworth,
Greg Kroah-Hartman, linux-serial, linux-kernel, linuxppc-dev
In-Reply-To: <20190625163722.GA18626@animalcreek.com>
On Tue, Jun 25, 2019 at 09:37:22AM -0700, Mark Greer wrote:
> Yeah, the mpsc driver had lots of ugly cache related hacks because of
> cache coherency bugs in the early version of the MV64x60 bridge chips
> that it was embedded in. That chip is pretty much dead now and I've
> removed core support for it from the powerpc tree. Removing the mpsc
> driver is on my todo list but I've been busy and lazy. So, to sum it
> up, don't spend any more time worrying about it as it should be removed.
>
> I'll post a patch to do that tonight and I'm sorry for any time you've
> spent looking at it so far.
No problem. And if future such broken chips show up we now have
support for per-device DMA coherency settings and could actually
handle it in a reaѕonably clean way.
^ permalink raw reply
* Re: [PATCH v2 4/7] linux/signal.h: Ignore SIGINFO by default in new tasks
From: Theodore Ts'o @ 2019-06-25 21:32 UTC (permalink / raw)
To: Arseny Maslennikov
Cc: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel, Vladimir D. Seleznev, Rob Landley,
Eric W. Biederman, Pavel Machek
In-Reply-To: <20190625161153.29811-5-ar@cs.msu.ru>
On Tue, Jun 25, 2019 at 07:11:50PM +0300, Arseny Maslennikov wrote:
> This matches the behaviour of other Unix-like systems that have SIGINFO
> and causes less harm to processes that do not install handlers for this
> signal, making the keyboard status character non-fatal for them.
>
> This is implemented with the assumption that SIGINFO is defined
> to be equivalent to SIGPWR; still, there is no reason for PWR to
> result in termination of the signal recipient anyway — it does not
> indicate there is a fatal problem with the recipient's execution
> context (like e.g. FPE/ILL do), and we have TERM/KILL for explicit
> termination requests.
So this is a consequence of trying to overload SIGINFO with SIGPWR.
At least on some legacy Unix systems, the way SIGPWR worked was that
init would broadcast SIGPWR to all userspace process (with system
daemons on an exception list so they could get shutdown last).
Applications which didn't have a SIGPWR handler registered, would just
exit. Those that did, were expected to clean up in preparation with
the impending shutdown. After some period of time, then processes
would get hard killed and then system daemons would get shut down and
the system would cleanly shut itself down.
So SIGPWR acted much like SIGHUP, and that's why the default behavior
was "terminate". Now, as far as I know, we've not actually used in
that way, at least for most common distributions, but there is a sane
reason why things are they way there are, and in there are people who
have been using SIGPWR the way it had originally been intended, there
is risk in overloading SIGINFO with SIGPWR --- in particular, typing
^T might cause some enterprise database to start shutting itself down. :-)
(In particular it might be worth checking Linux ports of Oracle and
DB2.)
- Ted
^ permalink raw reply
* Re: DMA coherency in drivers/tty/serial/mpsc.c
From: Mark Greer @ 2019-06-25 16:37 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Mark Greer, Paul Gortmaker, Dale Farnsworth, Greg Kroah-Hartman,
linux-serial, linux-kernel, linuxppc-dev
In-Reply-To: <20190625122641.GA4421@lst.de>
On Tue, Jun 25, 2019 at 02:26:41PM +0200, Christoph Hellwig wrote:
> Hi Paul, Dale and Mark (I hope this reaches the right Mark),
Hi Christoph. Yes, you did reach the right Mark. :)
> I've started auditing all users of DMA_ATTR_NON_CONSISTENT ot prepare
> for major API improvements in that area.
>
> One of the odd users is the mpsc ѕerial driver, which allocates DMA
> memory with the above flag, and then actually properly calls
> dma_cache_sync. So far, so good. But it turns out it also has
> "#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)"
> ifdef blocks next to the dma_cache_sync calls that perform cache
> maintainance for platforms that according to the ifdef claim to
> be cache coherent. According to the Kconfig the driver can
> only build if the MV64X60 symbol is set, which is a ppc embedded 6xx
> SOC, which appears to be configurable as either cache coherent, or
> not. But according to the code in the driver at least this device
> always is not cache coherent.
>
> It seems like we need to always mark that platform as potentially
> not coherent, and then use the per-device flag to mark all device
> except for this one as coherent. Or did I miss anything? Maybe
> all this is actually dead code and can go away?
Yeah, the mpsc driver had lots of ugly cache related hacks because of
cache coherency bugs in the early version of the MV64x60 bridge chips
that it was embedded in. That chip is pretty much dead now and I've
removed core support for it from the powerpc tree. Removing the mpsc
driver is on my todo list but I've been busy and lazy. So, to sum it
up, don't spend any more time worrying about it as it should be removed.
I'll post a patch to do that tonight and I'm sorry for any time you've
spent looking at it so far.
Mark
--
^ permalink raw reply
* [PATCH v2 7/7] n_tty: Provide an informational line on VSTATUS receipt
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
In-Reply-To: <20190625161153.29811-1-ar@cs.msu.ru>
If the three termios local flags isig, icanon, iexten are enabled
and the local flag nokerninfo is disabled for a tty governed
by the n_tty line discipline, then on receiving the keyboard status
character n_tty will generate a status message and write it out to
the tty before sending SIGINFO to the tty's foreground process group.
This kerninfo line contains information about the current system load
as well as some properties of "the most interesting" process in the
tty's current foreground process group, namely:
- its PID as seen inside its deepest PID namespace;
* the whole process group ought to be in a single PID namespace,
so this is actually deterministic
- its saved command name truncated to 16 bytes (task_struct::comm);
* at the time of writing TASK_COMM_LEN == 16
- its state and some related bits, procps-style;
- for S and D: its symbolic wait channel, if available; or a short
description for other process states instead;
- its user, system and real rusage time values;
- its resident set size (as well as the high watermark) in kilobytes.
The "most interesting" process is chosen as follows:
- runnables over everything
- uninterruptibles over everything else
- among 2 runnables pick the biggest utime + stime
- any unresolved ties are decided in favour of greatest PID.
While the kerninfo line is not very useful for debugging the kernel
itself, since we have much more powerful debugging tools, it still gives
the user behind the terminal some meaningful feedback to a VSTATUS that
works even if no processes respond.
Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
---
drivers/tty/Makefile | 3 +-
drivers/tty/n_tty.c | 22 +++
drivers/tty/n_tty_status.c | 337 +++++++++++++++++++++++++++++++++++++
include/linux/sched.h | 7 +
include/linux/tty.h | 3 +
5 files changed, 371 insertions(+), 1 deletion(-)
create mode 100644 drivers/tty/n_tty_status.c
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 020b1cd9294f..8bb5efb40b81 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
+obj-$(CONFIG_TTY) += tty_io.o tty_ioctl.o tty_ldisc.o \
tty_buffer.o tty_port.o tty_mutex.o \
tty_ldsem.o tty_baudrate.o tty_jobctrl.o \
+ n_tty.o n_tty_status.o \
n_null.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 7d7d84adcffe..74e6b4bf86bd 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -34,6 +34,7 @@
#include <linux/signal.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
+#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/timer.h>
@@ -79,6 +80,8 @@
#define ECHO_BLOCK 256
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
+#define STATUS_LINE_LEN (2 * KSYM_NAME_LEN)
+
#define SIG_FLUSHING_MASK ( \
rt_sigmask(SIGINT) | rt_sigmask(SIGQUIT) | \
rt_sigmask(SIGTSTP) )
@@ -158,6 +161,8 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
}
+static void n_tty_status_line(struct tty_struct *tty);
+
/* If we are not echoing the data, perhaps this is a secret so erase it */
static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
{
@@ -1300,6 +1305,8 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
n_tty_receive_signal_char(tty, SIGTSTP, c);
return 0;
} else if (c == STATUS_CHAR(tty)) {
+ if (!L_NOKERNINFO(tty))
+ n_tty_status_line(tty);
n_tty_receive_signal_char(tty, SIGINFO, c);
return 0;
}
@@ -2489,6 +2496,21 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
}
}
+static void n_tty_status_line(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char *msg, *buf;
+ msg = buf = kzalloc(STATUS_LINE_LEN, GFP_KERNEL);
+ tty_sprint_status_line(tty, buf + 1, STATUS_LINE_LEN - 1);
+ /* The only current caller of this takes output_lock for us. */
+ if (ldata->column != 0)
+ *msg = '\n';
+ else
+ msg++;
+ do_n_tty_write(tty, NULL, msg, strlen(msg));
+ kfree(buf);
+}
+
static struct tty_ldisc_ops n_tty_ops = {
.magic = TTY_LDISC_MAGIC,
.name = "n_tty",
diff --git a/drivers/tty/n_tty_status.c b/drivers/tty/n_tty_status.c
new file mode 100644
index 000000000000..4836710a8306
--- /dev/null
+++ b/drivers/tty/n_tty_status.c
@@ -0,0 +1,337 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/kallsyms.h>
+#include <linux/pid.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
+#include <linux/sched/loadavg.h>
+#include <linux/sched/cputime.h>
+#include <linux/sched/mm.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+
+#define BCOMPARE(lbool, rbool) ((lbool) << 1 | (rbool))
+#define BCOMPARE_NONE 0
+#define BCOMPARE_RIGHT 1
+#define BCOMPARE_LEFT 2
+#define BCOMPARE_BOTH (BCOMPARE_LEFT | BCOMPARE_RIGHT)
+
+/*
+ * Select the most interesting task of two.
+ *
+ * The implemented approach is simple for now:
+ * - pick runnable
+ * - if no runnables, pick uninterruptible
+ * - if tie between runnables, pick highest utime + stime
+ * - if a tie is not broken by the above, pick highest pid nr.
+ *
+ * For reference, here's the one used in FreeBSD:
+ * - pick runnables over anything
+ * - if both runnables, pick highest cpu utilization
+ * - if no runnables, pick shortest sleep time (the scheduler
+ * actually takes care to maintain this statistic)
+ * - other ties are decided in favour of youngest process.
+ */
+static struct task_struct *__better_proc_R(struct task_struct *a,
+ struct task_struct *b)
+{
+ unsigned long flags;
+ u64 atime, btime, tgutime, tgstime;
+ struct task_struct *ret;
+
+ if (!lock_task_sighand(a, &flags))
+ goto out_a_unlocked;
+ thread_group_cputime_adjusted(a, &tgutime, &tgstime);
+ atime = tgutime + tgstime;
+ unlock_task_sighand(a, &flags);
+
+ if (!lock_task_sighand(b, &flags))
+ goto out_b_unlocked;
+ thread_group_cputime_adjusted(b, &tgutime, &tgstime);
+ btime = tgutime + tgstime;
+ unlock_task_sighand(b, &flags);
+
+ ret = atime > btime ? a : b;
+
+ return ret;
+
+out_b_unlocked:
+out_a_unlocked:
+ return task_pid_vinr(a) > task_pid_vinr(b) ? a : b;
+}
+
+static struct task_struct *__better_proc(struct task_struct *a,
+ struct task_struct *b)
+{
+ if (!pid_alive(a))
+ return b;
+ if (!pid_alive(b))
+ return a;
+
+ switch (BCOMPARE(a->state == TASK_RUNNING,
+ b->state == TASK_RUNNING)) {
+ case BCOMPARE_LEFT:
+ return a;
+ case BCOMPARE_RIGHT:
+ return b;
+ case BCOMPARE_BOTH:
+ return __better_proc_R(a, b);
+ }
+
+ switch (BCOMPARE(a->state == TASK_UNINTERRUPTIBLE,
+ b->state == TASK_UNINTERRUPTIBLE)) {
+ case BCOMPARE_LEFT:
+ return a;
+ case BCOMPARE_RIGHT:
+ return b;
+ case BCOMPARE_BOTH:
+ break;
+ }
+
+ /* TODO: Perhaps we should check something else... */
+ return task_pid_vinr(a) > task_pid_vinr(b) ? a : b;
+}
+
+/* Weed out NULLs. */
+static inline struct task_struct *better_proc(struct task_struct *a,
+ struct task_struct *b) {
+ return a ? (b ? __better_proc(a, b) : a) : b;
+}
+
+static int scnprint_load(char *msgp, size_t size)
+{
+ unsigned long la[3];
+
+ get_avenrun(la, FIXED_1/200, 0);
+ return scnprintf(msgp, size, "load: %lu.%02lu; ",
+ LOAD_INT(la[0]), LOAD_FRAC(la[0]));
+}
+
+static int scnprint_task(char *msgp, size_t size, struct task_struct *task)
+{
+ char commname[TASK_COMM_LEN];
+
+ get_task_comm(commname, task);
+ return scnprintf(msgp, size, "%d/%s:", task_pid_vinr(task), commname);
+}
+
+static int scnprint_rusage(char *msgp, ssize_t size,
+ struct task_struct *task, struct mm_struct *mm)
+{
+ struct rusage ru;
+ struct timeval utime, stime;
+ struct timespec rtime;
+ u64 now;
+ int ret = 0;
+ int psz = 0;
+
+ getrusage(task, RUSAGE_BOTH, &ru);
+ now = ktime_get_ns();
+
+ utime = ru.ru_utime;
+ stime = ru.ru_stime;
+ rtime.tv_nsec = now - task->start_time;
+ rtime.tv_sec = rtime.tv_nsec / 1000000000;
+ rtime.tv_nsec %= 1000000000;
+
+ psz = scnprintf(msgp, size,
+ "%lu.%03lur %lu.%03luu %lu.%03lus",
+ rtime.tv_sec, rtime.tv_nsec / 1000000,
+ utime.tv_sec, utime.tv_usec / 1000,
+ stime.tv_sec, stime.tv_usec / 1000);
+ ret += psz;
+ msgp += psz;
+ size -= psz;
+
+ if (mm) {
+ psz = scnprintf(msgp, size,
+ " %luk/%luk",
+ get_mm_rss(mm) * PAGE_SIZE / 1024,
+ get_mm_hiwater_rss(mm) * PAGE_SIZE / 1024);
+ ret += psz;
+ }
+ return ret;
+}
+
+static int scnprint_state(char *msgp, ssize_t size,
+ struct task_struct *task, struct mm_struct *mm)
+{
+ char stat[8] = {0};
+ const char *state_descr = "";
+ struct task_struct *parent = NULL;
+ struct task_struct *real_parent = NULL;
+ unsigned long wchan = 0;
+ int psz = 0;
+ char symname[KSYM_NAME_LEN];
+
+ stat[psz++] = task_state_to_char(task);
+ if (task_nice(task) < 0)
+ stat[psz++] = '<';
+ else if (task_nice(task) > 0)
+ stat[psz++] = 'N';
+ if (mm && mm->locked_vm)
+ stat[psz++] = 'L';
+ if (get_nr_threads(task) > 1)
+ stat[psz++] = 'l';
+
+ switch (stat[0]) {
+ case 'R':
+ if (task_curr(task))
+ stat[psz++] = '!';
+ break;
+ case 'S':
+ case 'D':
+ wchan = get_wchan(task);
+ if (!wchan)
+ break;
+ if (!lookup_symbol_name(wchan, symname))
+ state_descr = symname;
+ else
+ /* get_wchan() returned something
+ * that looks like no kernel symbol.
+ */
+ state_descr = "*unknown*";
+ break;
+ case 'T':
+ state_descr = "stopped";
+ break;
+ case 't':
+ state_descr = "traced";
+ break;
+ case 'Z':
+ rcu_read_lock();
+ real_parent = rcu_dereference(task->real_parent);
+ parent = rcu_dereference(task->parent);
+ psz = sprintf(symname, "zombie; ppid=%d",
+ task_tgid_nr_ns(real_parent,
+ ns_of_pid(task_pid(task))));
+ if (parent != real_parent)
+ sprintf(symname + psz, " reaper=%d",
+ task_tgid_nr_ns(parent,
+ ns_of_pid(task_pid(task))));
+ rcu_read_unlock();
+ state_descr = symname;
+ break;
+ case 'I':
+ /* Can this even happen? */
+ state_descr = "idle";
+ break;
+ default:
+ state_descr = "unknown";
+ }
+
+ psz = scnprintf(msgp, size, "%s", stat);
+ msgp += psz;
+ size -= psz;
+ if (*state_descr)
+ psz += scnprintf(msgp, size, wchan ? " [%s]" : " (%s)", state_descr);
+
+ return psz;
+}
+
+/**
+ * tty_sprint_status_line - produce kerninfo line
+ * @tty: terminal device
+ * @msg: preallocated memory buffer
+ * @length: maximum line length
+ *
+ * Reports state of foreground process group in a null-terminated string
+ * located at @msg, @length bytes long. If @length is insufficient,
+ * the line gets truncated.
+ */
+void tty_sprint_status_line(struct tty_struct *t, char *msg, size_t length)
+{
+ struct task_struct *tsk = NULL, *mit = NULL;
+ struct mm_struct *mm;
+ struct pid *pgrp = NULL;
+ char *msgp = msg;
+ int psz = 0;
+
+ if (!length)
+ return;
+ length--; /* Make room for trailing '\n' */
+
+ psz = scnprint_load(msgp, length);
+ if (psz > 0) {
+ msgp += psz;
+ length -= psz;
+ }
+ if (!length)
+ goto finalize_message;
+
+ /* Not sure if session pid is protected by ctrl_lock
+ * or tasklist_lock...
+ */
+ pgrp = t->session;
+ if (pgrp == NULL) {
+ psz = scnprintf(msgp, length, "not a controlling tty");
+ if (psz > 0)
+ msgp += psz;
+ goto finalize_message;
+ }
+ pgrp = tty_get_pgrp(t);
+ if (pgrp == NULL) {
+ psz = scnprintf(msgp, length, "no foreground process group");
+ if (psz > 0)
+ msgp += psz;
+ goto finalize_message;
+ }
+
+ read_lock(&tasklist_lock);
+ do_each_pid_task(pgrp, PIDTYPE_PGID, tsk)
+ {
+ /* Select the most interesting task. */
+ if (tsk == better_proc(mit, tsk))
+ mit = tsk;
+ } while_each_pid_task(pgrp, PIDTYPE_PGID, tsk);
+ read_unlock(&tasklist_lock);
+
+ if (!pid_alive(mit))
+ goto finalize_message;
+
+ /* Gather intel on most interesting task. */
+ /* Can the mm of a foreground process turn out to be NULL?
+ * Definitely; for example, if it is a zombie.
+ */
+ mm = get_task_mm(mit);
+
+ psz = scnprint_task(msgp, length, mit);
+ if (psz > 0) {
+ msgp += psz;
+ length -= psz;
+ }
+ if (!length)
+ goto finalize_message;
+ *msgp++ = ' ';
+ length--;
+
+ psz = scnprint_state(msgp, length, mit, mm);
+ if (psz > 0) {
+ msgp += psz;
+ length -= psz;
+ }
+ if (!length)
+ goto finalize_message;
+ *msgp++ = ' ';
+ length--;
+
+ psz = scnprint_rusage(msgp, length, mit, mm);
+ if (psz > 0) {
+ msgp += psz;
+ length -= psz;
+ }
+ if (!length)
+ goto finalize_message;
+ *msgp++ = ' ';
+ length--;
+
+ if (!mm)
+ goto finalize_message;
+
+ mmput(mm);
+
+finalize_message:
+ *msgp++ = '\n';
+ if (pgrp)
+ put_pid(pgrp);
+}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 11837410690f..21bcb7fb0888 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1229,6 +1229,8 @@ static inline struct pid *task_pid(struct task_struct *task)
* task_xid_nr() : global id, i.e. the id seen from the init namespace;
* task_xid_vnr() : virtual id, i.e. the id seen from the pid namespace of
* current.
+ * task_xid_vinr() : virtual inner id, i.e. the id seen from the namespace of
+ * the task itself;
* task_xid_nr_ns() : id seen from the ns specified;
*
* see also pid_nr() etc in include/linux/pid.h
@@ -1250,6 +1252,11 @@ static inline pid_t task_pid_vnr(struct task_struct *tsk)
return __task_pid_nr_ns(tsk, PIDTYPE_PID, NULL);
}
+static inline pid_t task_pid_vinr(struct task_struct *tsk)
+{
+ return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns_of_pid(task_pid(tsk)));
+}
+
static inline pid_t task_tgid_nr(struct task_struct *tsk)
{
diff --git a/include/linux/tty.h b/include/linux/tty.h
index ddb97704956d..a8e4df6d64b4 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -725,6 +725,9 @@ extern void __init n_tty_init(void);
static inline void n_tty_init(void) { }
#endif
+/* n_tty_status.c */
+extern void tty_sprint_status_line(struct tty_struct *tty, char *msg, size_t size);
+
/* tty_audit.c */
#ifdef CONFIG_AUDIT
extern void tty_audit_add_data(struct tty_struct *tty, const void *data,
--
2.20.1
^ permalink raw reply related
* [PATCH v2 6/7] n_tty: ->ops->write: Cut core logic out to a separate function
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
In-Reply-To: <20190625161153.29811-1-ar@cs.msu.ru>
To simplify internal re-use of the line discipline's write method,
we isolate the work it does to its own function.
Since in-kernel callers might not refer to the tty through a file,
the struct file* argument might make no sense, so we also stop
tty_io_nonblock() from dereferencing file too early, allowing
to pass NULL as the referring file here.
Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
---
drivers/tty/n_tty.c | 33 ++++++++++++++++++++++-----------
include/linux/tty.h | 2 +-
2 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 29f33798a6cd..7d7d84adcffe 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2309,22 +2309,15 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
* lock themselves)
*/
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
- const unsigned char *buf, size_t nr)
+static ssize_t do_n_tty_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr)
{
const unsigned char *b = buf;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
int c;
ssize_t retval = 0;
- /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
- if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- }
-
- down_read(&tty->termios_rwsem);
+ lockdep_assert_held_read(&tty->termios_rwsem);
/* Write out any echoed characters that are still pending */
process_echoes(tty);
@@ -2392,10 +2385,28 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
remove_wait_queue(&tty->write_wait, &wait);
if (nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- up_read(&tty->termios_rwsem);
return (b - buf) ? b - buf : retval;
}
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr)
+{
+ ssize_t retval = 0;
+
+ /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
+ if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ }
+
+ down_read(&tty->termios_rwsem);
+ retval = do_n_tty_write(tty, file, buf, nr);
+ up_read(&tty->termios_rwsem);
+
+ return retval;
+}
+
/**
* n_tty_poll - poll method for N_TTY
* @tty: terminal device
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 07189f18f93d..ddb97704956d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -388,7 +388,7 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val)
static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
{
- return file->f_flags & O_NONBLOCK ||
+ return (file && file->f_flags & O_NONBLOCK) ||
test_bit(TTY_LDISC_CHANGING, &tty->flags);
}
--
2.20.1
^ permalink raw reply related
* [PATCH v2 5/7] tty: Add NOKERNINFO lflag to termios
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
In-Reply-To: <20190625161153.29811-1-ar@cs.msu.ru>
Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
---
arch/alpha/include/uapi/asm/termbits.h | 1 +
arch/ia64/include/uapi/asm/termbits.h | 1 +
arch/mips/include/uapi/asm/termbits.h | 1 +
arch/parisc/include/uapi/asm/termbits.h | 1 +
arch/powerpc/include/uapi/asm/termbits.h | 1 +
arch/sparc/include/uapi/asm/termbits.h | 1 +
arch/xtensa/include/uapi/asm/termbits.h | 1 +
include/linux/tty.h | 1 +
include/uapi/asm-generic/termbits.h | 1 +
9 files changed, 9 insertions(+)
diff --git a/arch/alpha/include/uapi/asm/termbits.h b/arch/alpha/include/uapi/asm/termbits.h
index bb895d467033..850dd8dc4c51 100644
--- a/arch/alpha/include/uapi/asm/termbits.h
+++ b/arch/alpha/include/uapi/asm/termbits.h
@@ -204,6 +204,7 @@ struct ktermios {
#define PENDIN 0x20000000
#define IEXTEN 0x00000400
#define EXTPROC 0x10000000
+#define NOKERNINFO 0x40000000
/* Values for the ACTION argument to `tcflow'. */
#define TCOOFF 0
diff --git a/arch/ia64/include/uapi/asm/termbits.h b/arch/ia64/include/uapi/asm/termbits.h
index 86898e4c5905..f777b99bc5ab 100644
--- a/arch/ia64/include/uapi/asm/termbits.h
+++ b/arch/ia64/include/uapi/asm/termbits.h
@@ -190,6 +190,7 @@ struct ktermios {
#define PENDIN 0040000
#define IEXTEN 0100000
#define EXTPROC 0200000
+#define NOKERNINFO 0400000
/* tcflow() and TCXONC use these */
#define TCOOFF 0
diff --git a/arch/mips/include/uapi/asm/termbits.h b/arch/mips/include/uapi/asm/termbits.h
index 3dd60924f0ef..2755cfd1497e 100644
--- a/arch/mips/include/uapi/asm/termbits.h
+++ b/arch/mips/include/uapi/asm/termbits.h
@@ -206,6 +206,7 @@ struct ktermios {
#define TOSTOP 0100000 /* Send SIGTTOU for background output. */
#define ITOSTOP TOSTOP
#define EXTPROC 0200000 /* External processing on pty */
+#define NOKERNINFO 0400000 /* Disable kernel output from VSTATUS. */
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
diff --git a/arch/parisc/include/uapi/asm/termbits.h b/arch/parisc/include/uapi/asm/termbits.h
index ecca3b7d0c66..c7ba145adf02 100644
--- a/arch/parisc/include/uapi/asm/termbits.h
+++ b/arch/parisc/include/uapi/asm/termbits.h
@@ -183,6 +183,7 @@ struct ktermios {
#define PENDIN 0040000
#define IEXTEN 0100000
#define EXTPROC 0200000
+#define NOKERNINFO 0400000
/* tcflow() and TCXONC use these */
#define TCOOFF 0
diff --git a/arch/powerpc/include/uapi/asm/termbits.h b/arch/powerpc/include/uapi/asm/termbits.h
index c85e98d75e76..79dbcc546217 100644
--- a/arch/powerpc/include/uapi/asm/termbits.h
+++ b/arch/powerpc/include/uapi/asm/termbits.h
@@ -192,6 +192,7 @@ struct ktermios {
#define PENDIN 0x20000000
#define IEXTEN 0x00000400
#define EXTPROC 0x10000000
+#define NOKERNINFO 0x40000000
/* Values for the ACTION argument to `tcflow'. */
#define TCOOFF 0
diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/uapi/asm/termbits.h
index a1638c9cde8b..108c039ddefb 100644
--- a/arch/sparc/include/uapi/asm/termbits.h
+++ b/arch/sparc/include/uapi/asm/termbits.h
@@ -225,6 +225,7 @@ struct ktermios {
#define PENDIN 0x00004000
#define IEXTEN 0x00008000
#define EXTPROC 0x00010000
+#define NOKERNINFO 0x00020000
/* modem lines */
#define TIOCM_LE 0x001
diff --git a/arch/xtensa/include/uapi/asm/termbits.h b/arch/xtensa/include/uapi/asm/termbits.h
index 77969cb275b8..6155e1c81164 100644
--- a/arch/xtensa/include/uapi/asm/termbits.h
+++ b/arch/xtensa/include/uapi/asm/termbits.h
@@ -199,6 +199,7 @@ struct ktermios {
#define PENDIN 0040000
#define IEXTEN 0100000
#define EXTPROC 0200000
+#define NOKERNINFO 0400000
/* tcflow() and TCXONC use these */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 38d8ffe7f0e3..07189f18f93d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -186,6 +186,7 @@ struct tty_bufhead {
#define L_PENDIN(tty) _L_FLAG((tty), PENDIN)
#define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN)
#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC)
+#define L_NOKERNINFO(tty) _L_FLAG((tty), NOKERNINFO)
struct device;
struct signal_struct;
diff --git a/include/uapi/asm-generic/termbits.h b/include/uapi/asm-generic/termbits.h
index 11bb142ba844..6219803d6f4d 100644
--- a/include/uapi/asm-generic/termbits.h
+++ b/include/uapi/asm-generic/termbits.h
@@ -181,6 +181,7 @@ struct ktermios {
#define PENDIN 0040000
#define IEXTEN 0100000
#define EXTPROC 0200000
+#define NOKERNINFO 0400000
/* tcflow() and TCXONC use these */
#define TCOOFF 0
--
2.20.1
^ permalink raw reply related
* [PATCH v2 4/7] linux/signal.h: Ignore SIGINFO by default in new tasks
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
In-Reply-To: <20190625161153.29811-1-ar@cs.msu.ru>
This matches the behaviour of other Unix-like systems that have SIGINFO
and causes less harm to processes that do not install handlers for this
signal, making the keyboard status character non-fatal for them.
This is implemented with the assumption that SIGINFO is defined
to be equivalent to SIGPWR; still, there is no reason for PWR to
result in termination of the signal recipient anyway — it does not
indicate there is a fatal problem with the recipient's execution
context (like e.g. FPE/ILL do), and we have TERM/KILL for explicit
termination requests.
Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
---
include/linux/signal.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 9702016734b1..c365754ea647 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -360,7 +360,7 @@ extern bool unhandled_signal(struct task_struct *tsk, int sig);
* | SIGSYS/SIGUNUSED | coredump |
* | SIGSTKFLT | terminate |
* | SIGWINCH | ignore |
- * | SIGPWR | terminate |
+ * | SIGPWR | ignore |
* | SIGRTMIN-SIGRTMAX | terminate |
* +--------------------+------------------+
* | non-POSIX signal | default action |
@@ -411,7 +411,8 @@ extern bool unhandled_signal(struct task_struct *tsk, int sig);
#define SIG_KERNEL_IGNORE_MASK (\
rt_sigmask(SIGCONT) | rt_sigmask(SIGCHLD) | \
- rt_sigmask(SIGWINCH) | rt_sigmask(SIGURG) )
+ rt_sigmask(SIGWINCH) | rt_sigmask(SIGURG) | \
+ rt_sigmask(SIGINFO) )
#define SIG_SPECIFIC_SICODES_MASK (\
rt_sigmask(SIGILL) | rt_sigmask(SIGFPE) | \
--
2.20.1
^ permalink raw reply related
* [PATCH v2 3/7] n_tty: Send SIGINFO to fg pgrp on status request character
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
In-Reply-To: <20190625161153.29811-1-ar@cs.msu.ru>
No kerninfo line is printed yet.
No existing implementation of this on any Unix-like system echoes
the status character; no existing implementation discards or flushes
pending input on VSTATUS receipt.
There are existing popular TUI applications (e. g. mutt) that only
turn off icanon and not iexten, but still do not expect any special
treatment of the status request character — thus we require all three:
isig, icanon and iexten to trigger this.
Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
---
drivers/tty/n_tty.c | 15 +++++++++++++--
include/linux/tty.h | 1 +
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index f9c584244f72..29f33798a6cd 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -79,6 +79,10 @@
#define ECHO_BLOCK 256
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
+#define SIG_FLUSHING_MASK ( \
+ rt_sigmask(SIGINT) | rt_sigmask(SIGQUIT) | \
+ rt_sigmask(SIGTSTP) )
+#define SIG_FLUSHING(sig) ((1 << sig) & SIG_FLUSHING_MASK)
#undef N_TTY_TRACE
#ifdef N_TTY_TRACE
@@ -1122,7 +1126,7 @@ static void isig(int sig, struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- if (L_NOFLSH(tty)) {
+ if (L_NOFLSH(tty) || (!SIG_FLUSHING(sig))) {
/* signal only */
__isig(sig, tty);
@@ -1244,7 +1248,8 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
if (I_IXON(tty))
start_tty(tty);
if (L_ECHO(tty)) {
- echo_char(c, tty);
+ if (c != STATUS_CHAR(tty))
+ echo_char(c, tty);
commit_echoes(tty);
} else
process_echoes(tty);
@@ -1294,6 +1299,9 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
} else if (c == SUSP_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGTSTP, c);
return 0;
+ } else if (c == STATUS_CHAR(tty)) {
+ n_tty_receive_signal_char(tty, SIGINFO, c);
+ return 0;
}
}
@@ -1848,6 +1856,9 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
set_bit(INTR_CHAR(tty), ldata->char_map);
set_bit(QUIT_CHAR(tty), ldata->char_map);
set_bit(SUSP_CHAR(tty), ldata->char_map);
+ if (L_ICANON(tty) && L_IEXTEN(tty)) {
+ set_bit(STATUS_CHAR(tty), ldata->char_map);
+ }
}
clear_bit(__DISABLED_CHAR, ldata->char_map);
ldata->raw = 0;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index bfa4e2ee94a9..38d8ffe7f0e3 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -120,6 +120,7 @@ struct tty_bufhead {
#define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE])
#define LNEXT_CHAR(tty) ((tty)->termios.c_cc[VLNEXT])
#define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2])
+#define STATUS_CHAR(tty) ((tty)->termios.c_cc[VSTATUS])
#define _I_FLAG(tty, f) ((tty)->termios.c_iflag & (f))
#define _O_FLAG(tty, f) ((tty)->termios.c_oflag & (f))
--
2.20.1
^ permalink raw reply related
* [PATCH v2 2/7] tty: termios: Reserve space for VSTATUS in .c_cc
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
In-Reply-To: <20190625161153.29811-1-ar@cs.msu.ru>
There was no architecture we had to increase NCCS on,
so the size of struct termios did not change.
Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
---
arch/alpha/include/asm/termios.h | 4 ++--
arch/alpha/include/uapi/asm/termbits.h | 1 +
arch/ia64/include/asm/termios.h | 4 ++--
arch/ia64/include/uapi/asm/termbits.h | 1 +
arch/mips/include/asm/termios.h | 4 ++--
arch/mips/include/uapi/asm/termbits.h | 1 +
arch/parisc/include/asm/termios.h | 4 ++--
arch/parisc/include/uapi/asm/termbits.h | 1 +
arch/powerpc/include/asm/termios.h | 4 ++--
arch/powerpc/include/uapi/asm/termbits.h | 1 +
arch/s390/include/asm/termios.h | 4 ++--
arch/sparc/include/asm/termios.h | 4 ++--
arch/sparc/include/uapi/asm/termbits.h | 1 +
arch/xtensa/include/uapi/asm/termbits.h | 1 +
include/asm-generic/termios.h | 4 ++--
include/uapi/asm-generic/termbits.h | 1 +
16 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/arch/alpha/include/asm/termios.h b/arch/alpha/include/asm/termios.h
index b7c77bb1bfd2..3f6e9995f415 100644
--- a/arch/alpha/include/asm/termios.h
+++ b/arch/alpha/include/asm/termios.h
@@ -8,9 +8,9 @@
werase=^W kill=^U reprint=^R sxtc=\0
intr=^C quit=^\ susp=^Z <OSF/1 VDSUSP>
start=^Q stop=^S lnext=^V discard=^U
- vmin=\1 vtime=\0
+ vmin=\1 vtime=\0 vstatus=^T
*/
-#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000"
+#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/arch/alpha/include/uapi/asm/termbits.h b/arch/alpha/include/uapi/asm/termbits.h
index 4575ba34a0ea..bb895d467033 100644
--- a/arch/alpha/include/uapi/asm/termbits.h
+++ b/arch/alpha/include/uapi/asm/termbits.h
@@ -70,6 +70,7 @@ struct ktermios {
#define VDISCARD 15
#define VMIN 16
#define VTIME 17
+#define VSTATUS 18
/* c_iflag bits */
#define IGNBRK 0000001
diff --git a/arch/ia64/include/asm/termios.h b/arch/ia64/include/asm/termios.h
index 589c026444cc..b262e010baf2 100644
--- a/arch/ia64/include/asm/termios.h
+++ b/arch/ia64/include/asm/termios.h
@@ -15,9 +15,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/arch/ia64/include/uapi/asm/termbits.h b/arch/ia64/include/uapi/asm/termbits.h
index 000a1a297c75..86898e4c5905 100644
--- a/arch/ia64/include/uapi/asm/termbits.h
+++ b/arch/ia64/include/uapi/asm/termbits.h
@@ -67,6 +67,7 @@ struct ktermios {
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
+#define VSTATUS 17
/* c_iflag bits */
#define IGNBRK 0000001
diff --git a/arch/mips/include/asm/termios.h b/arch/mips/include/asm/termios.h
index bc29eeacc55a..9086e4f641f4 100644
--- a/arch/mips/include/asm/termios.h
+++ b/arch/mips/include/asm/termios.h
@@ -17,9 +17,9 @@
* vmin=\1 vtime=\0 eol2=\0 swtc=\0
* start=^Q stop=^S susp=^Z vdsusp=
* reprint=^R discard=^U werase=^W lnext=^V
- * eof=^D eol=\0
+ * eof=^D eol=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\1\0\0\0\021\023\032\0\022\017\027\026\004\0"
+#define INIT_C_CC "\003\034\177\025\1\0\0\0\021\023\032\0\022\017\027\026\004\0\024"
#include <linux/string.h>
diff --git a/arch/mips/include/uapi/asm/termbits.h b/arch/mips/include/uapi/asm/termbits.h
index dfeffba729b7..3dd60924f0ef 100644
--- a/arch/mips/include/uapi/asm/termbits.h
+++ b/arch/mips/include/uapi/asm/termbits.h
@@ -78,6 +78,7 @@ struct ktermios {
#define VLNEXT 15 /* Literal-next character [IEXTEN]. */
#define VEOF 16 /* End-of-file character [ICANON]. */
#define VEOL 17 /* End-of-line character [ICANON]. */
+#define VSTATUS 18 /* Status request character [ISIG]. */
/* c_iflag bits */
#define IGNBRK 0000001 /* Ignore break condition. */
diff --git a/arch/parisc/include/asm/termios.h b/arch/parisc/include/asm/termios.h
index cded9dc90c1b..37828b15a428 100644
--- a/arch/parisc/include/asm/termios.h
+++ b/arch/parisc/include/asm/termios.h
@@ -9,9 +9,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/arch/parisc/include/uapi/asm/termbits.h b/arch/parisc/include/uapi/asm/termbits.h
index 40e920f8d683..ecca3b7d0c66 100644
--- a/arch/parisc/include/uapi/asm/termbits.h
+++ b/arch/parisc/include/uapi/asm/termbits.h
@@ -58,6 +58,7 @@ struct ktermios {
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
+#define VSTATUS 17
/* c_iflag bits */
diff --git a/arch/powerpc/include/asm/termios.h b/arch/powerpc/include/asm/termios.h
index 205de8f8a9d3..263707fc3ec9 100644
--- a/arch/powerpc/include/asm/termios.h
+++ b/arch/powerpc/include/asm/termios.h
@@ -10,8 +10,8 @@
#include <uapi/asm/termios.h>
-/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U */
-#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025"
+/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U ^T */
+#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025\024"
#include <asm-generic/termios-base.h>
diff --git a/arch/powerpc/include/uapi/asm/termbits.h b/arch/powerpc/include/uapi/asm/termbits.h
index ed18bc61f63d..c85e98d75e76 100644
--- a/arch/powerpc/include/uapi/asm/termbits.h
+++ b/arch/powerpc/include/uapi/asm/termbits.h
@@ -62,6 +62,7 @@ struct ktermios {
#define VSTOP 14
#define VLNEXT 15
#define VDISCARD 16
+#define VSTATUS 17
/* c_iflag bits */
#define IGNBRK 0000001
diff --git a/arch/s390/include/asm/termios.h b/arch/s390/include/asm/termios.h
index 46fa3020b41e..c84e49ed76b4 100644
--- a/arch/s390/include/asm/termios.h
+++ b/arch/s390/include/asm/termios.h
@@ -14,9 +14,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
diff --git a/arch/sparc/include/asm/termios.h b/arch/sparc/include/asm/termios.h
index 4a558efdfa93..249c95cf285b 100644
--- a/arch/sparc/include/asm/termios.h
+++ b/arch/sparc/include/asm/termios.h
@@ -20,9 +20,9 @@
eof=^D eol=\0 eol2=\0 sxtc=\0
start=^Q stop=^S susp=^Z dsusp=^Y
reprint=^R discard=^U werase=^W lnext=^V
- vmin=\1 vtime=\0
+ vmin=\1 vtime=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\000\000\000\021\023\032\031\022\025\027\026\001"
+#define INIT_C_CC "\003\034\177\025\004\000\000\000\021\023\032\031\022\025\027\026\001\000\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/arch/sparc/include/uapi/asm/termbits.h b/arch/sparc/include/uapi/asm/termbits.h
index ce5ad5d0f105..a1638c9cde8b 100644
--- a/arch/sparc/include/uapi/asm/termbits.h
+++ b/arch/sparc/include/uapi/asm/termbits.h
@@ -80,6 +80,7 @@ struct ktermios {
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
+#define VSTATUS 16
/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
* shared with eof/eol
diff --git a/arch/xtensa/include/uapi/asm/termbits.h b/arch/xtensa/include/uapi/asm/termbits.h
index d4206a7c5138..77969cb275b8 100644
--- a/arch/xtensa/include/uapi/asm/termbits.h
+++ b/arch/xtensa/include/uapi/asm/termbits.h
@@ -72,6 +72,7 @@ struct ktermios {
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
+#define VSTATUS 17
/* c_iflag bits */
diff --git a/include/asm-generic/termios.h b/include/asm-generic/termios.h
index b1398d0d4a1d..06fbfb87c991 100644
--- a/include/asm-generic/termios.h
+++ b/include/asm-generic/termios.h
@@ -10,9 +10,9 @@
eof=^D vtime=\0 vmin=\1 sxtc=\0
start=^Q stop=^S susp=^Z eol=\0
reprint=^R discard=^U werase=^W lnext=^V
- eol2=\0
+ eol2=\0 status=^T
*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0\024"
/*
* Translate a "termio" structure into a "termios". Ugh.
diff --git a/include/uapi/asm-generic/termbits.h b/include/uapi/asm-generic/termbits.h
index 2fbaf9ae89dd..11bb142ba844 100644
--- a/include/uapi/asm-generic/termbits.h
+++ b/include/uapi/asm-generic/termbits.h
@@ -58,6 +58,7 @@ struct ktermios {
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
+#define VSTATUS 17
/* c_iflag bits */
#define IGNBRK 0000001
--
2.20.1
^ permalink raw reply related
* [PATCH v2 1/7] signal.h: Define SIGINFO on all architectures
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
In-Reply-To: <20190625161153.29811-1-ar@cs.msu.ru>
This complementary patch defines SIGINFO as a synonym for SIGPWR
on every architecture supported by the kernel.
The particular signal number chosen does not really matter and is only
required for the related tty functionality to work properly,
so if it does not suite expectations, any suggestions are warmly
welcome.
SIGPWR looks like a nice candidate for this role, because it is
defined on every supported arch and is already defined as a synonym
for SIGINFO on alpha; SIGPWR is currently only used to inform
PID 1 of power failures, and daemons that care about low-level
events do not tend to have a controlling terminal.
However, on sparcs SIGPWR is a synonym for SIGLOST, a signal unique
to that architecture, with a narrow set of intended uses that do not
combine well with interactively requesting status.
SIGLOST is not used by any kernel code at the moment.
I'm not sure there is a more reasonable alternative right now.
Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
---
arch/arm/include/uapi/asm/signal.h | 1 +
arch/h8300/include/uapi/asm/signal.h | 1 +
arch/ia64/include/uapi/asm/signal.h | 1 +
arch/m68k/include/uapi/asm/signal.h | 1 +
arch/mips/include/uapi/asm/signal.h | 1 +
arch/parisc/include/uapi/asm/signal.h | 1 +
arch/powerpc/include/uapi/asm/signal.h | 1 +
arch/s390/include/uapi/asm/signal.h | 1 +
arch/sparc/include/uapi/asm/signal.h | 2 ++
arch/x86/include/uapi/asm/signal.h | 1 +
arch/xtensa/include/uapi/asm/signal.h | 1 +
include/uapi/asm-generic/signal.h | 1 +
12 files changed, 13 insertions(+)
diff --git a/arch/arm/include/uapi/asm/signal.h b/arch/arm/include/uapi/asm/signal.h
index 9b4185ba4f8a..b80b53a17267 100644
--- a/arch/arm/include/uapi/asm/signal.h
+++ b/arch/arm/include/uapi/asm/signal.h
@@ -50,6 +50,7 @@ typedef unsigned long sigset_t;
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
diff --git a/arch/h8300/include/uapi/asm/signal.h b/arch/h8300/include/uapi/asm/signal.h
index e15521037348..7a2b783af22b 100644
--- a/arch/h8300/include/uapi/asm/signal.h
+++ b/arch/h8300/include/uapi/asm/signal.h
@@ -50,6 +50,7 @@ typedef unsigned long sigset_t;
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
diff --git a/arch/ia64/include/uapi/asm/signal.h b/arch/ia64/include/uapi/asm/signal.h
index aa98ff1b9e22..b4c98cb17165 100644
--- a/arch/ia64/include/uapi/asm/signal.h
+++ b/arch/ia64/include/uapi/asm/signal.h
@@ -45,6 +45,7 @@
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
/* signal 31 is no longer "unused", but the SIGUNUSED macro remains for backwards compatibility */
#define SIGUNUSED 31
diff --git a/arch/m68k/include/uapi/asm/signal.h b/arch/m68k/include/uapi/asm/signal.h
index 915cc755a184..a0b4e4108cb8 100644
--- a/arch/m68k/include/uapi/asm/signal.h
+++ b/arch/m68k/include/uapi/asm/signal.h
@@ -50,6 +50,7 @@ typedef unsigned long sigset_t;
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
diff --git a/arch/mips/include/uapi/asm/signal.h b/arch/mips/include/uapi/asm/signal.h
index 53104b10aae2..975a6f0d3b0b 100644
--- a/arch/mips/include/uapi/asm/signal.h
+++ b/arch/mips/include/uapi/asm/signal.h
@@ -43,6 +43,7 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */
#define SIGCHLD 18 /* Child status has changed (POSIX). */
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
#define SIGPWR 19 /* Power failure restart (System V). */
+#define SIGINFO SIGPWR /* Keyboard status request (4.2 BSD). */
#define SIGWINCH 20 /* Window size change (4.3 BSD, Sun). */
#define SIGURG 21 /* Urgent condition on socket (4.2 BSD). */
#define SIGIO 22 /* I/O now possible (4.2 BSD). */
diff --git a/arch/parisc/include/uapi/asm/signal.h b/arch/parisc/include/uapi/asm/signal.h
index d38563a394f2..fe2e00d590ac 100644
--- a/arch/parisc/include/uapi/asm/signal.h
+++ b/arch/parisc/include/uapi/asm/signal.h
@@ -22,6 +22,7 @@
#define SIGUSR2 17
#define SIGCHLD 18
#define SIGPWR 19
+#define SIGINFO SIGPWR
#define SIGVTALRM 20
#define SIGPROF 21
#define SIGIO 22
diff --git a/arch/powerpc/include/uapi/asm/signal.h b/arch/powerpc/include/uapi/asm/signal.h
index 85b0a7aa43e7..e7f3885905b4 100644
--- a/arch/powerpc/include/uapi/asm/signal.h
+++ b/arch/powerpc/include/uapi/asm/signal.h
@@ -53,6 +53,7 @@ typedef struct {
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
diff --git a/arch/s390/include/uapi/asm/signal.h b/arch/s390/include/uapi/asm/signal.h
index 9a14a611ed82..12ee62987971 100644
--- a/arch/s390/include/uapi/asm/signal.h
+++ b/arch/s390/include/uapi/asm/signal.h
@@ -58,6 +58,7 @@ typedef unsigned long sigset_t;
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
diff --git a/arch/sparc/include/uapi/asm/signal.h b/arch/sparc/include/uapi/asm/signal.h
index ff9505923b9a..b655163198bb 100644
--- a/arch/sparc/include/uapi/asm/signal.h
+++ b/arch/sparc/include/uapi/asm/signal.h
@@ -71,6 +71,8 @@
#define SIGWINCH 28
#define SIGLOST 29
#define SIGPWR SIGLOST
+/* XXX: is it OK for SIGINFO to collide with LOST? */
+#define SIGINFO SIGPWR
#define SIGUSR1 30
#define SIGUSR2 31
diff --git a/arch/x86/include/uapi/asm/signal.h b/arch/x86/include/uapi/asm/signal.h
index e5745d593dc7..1539bb28826c 100644
--- a/arch/x86/include/uapi/asm/signal.h
+++ b/arch/x86/include/uapi/asm/signal.h
@@ -55,6 +55,7 @@ typedef unsigned long sigset_t;
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
diff --git a/arch/xtensa/include/uapi/asm/signal.h b/arch/xtensa/include/uapi/asm/signal.h
index 005dec5bfde4..d644234305de 100644
--- a/arch/xtensa/include/uapi/asm/signal.h
+++ b/arch/xtensa/include/uapi/asm/signal.h
@@ -65,6 +65,7 @@ typedef struct {
#define SIGPOLL SIGIO
/* #define SIGLOST 29 */
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
diff --git a/include/uapi/asm-generic/signal.h b/include/uapi/asm-generic/signal.h
index 5c716a952cbe..9f9a1db0d43c 100644
--- a/include/uapi/asm-generic/signal.h
+++ b/include/uapi/asm-generic/signal.h
@@ -43,6 +43,7 @@
#define SIGLOST 29
*/
#define SIGPWR 30
+#define SIGINFO SIGPWR
#define SIGSYS 31
#define SIGUNUSED 31
--
2.20.1
^ permalink raw reply related
* [PATCH v2 0/7] TTY Keyboard Status Request
From: Arseny Maslennikov @ 2019-06-25 16:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Ingo Molnar, Peter Zijlstra,
linux-serial, linux-kernel
Cc: Vladimir D. Seleznev, Rob Landley, Eric W. Biederman,
Pavel Machek, Arseny Maslennikov
This patch series introduces TTY keyboard status request, a feature of
the n_tty line discipline that reserves a character in struct termios
(^T by default) and reacts to it by printing a short informational line
to the terminal and sending a Unix signal to the tty's foreground
process group. The processes may, in response to the signal, output a
textual description of what they're doing.
The feature has been present in a similar form at least in
Free/Open/NetBSD; it would be nice to have something like this in Linux
as well. There is an LKML thread[1] where users have previously
expressed the rationale for this.
The current implementation does not break existing kernel API in any
way, since, fortunately, all the architectures supported by the kernel
happen to have at least 1 free byte in the termios control character
array.
The series should cleanly apply to tty-next.
To thoroughly test these, one might need at least a patched stty among
other tools, so I've brought up a simple initrd generator[2] which can
be used to create a lightweight environment to boot up in a VM and to
fiddle with.
[1] https://lore.kernel.org/lkml/1415200663.3247743.187387481.75CE9317@webmail.messagingengine.com/
[2] https://github.com/porrided/tty-kb-status-userspace
v2 <- v1: removed useless debugging bits.
Discussion of v1:
https://lore.kernel.org/lkml/20190605081906.28938-1-ar@cs.msu.ru/
Arseny Maslennikov (7):
signal.h: Define SIGINFO on all architectures
tty: termios: Reserve space for VSTATUS in .c_cc
n_tty: Send SIGINFO to fg pgrp on status request character
linux/signal.h: Ignore SIGINFO by default in new tasks
tty: Add NOKERNINFO lflag to termios
n_tty: ->ops->write: Cut core logic out to a separate function
n_tty: Provide an informational line on VSTATUS receipt
arch/alpha/include/asm/termios.h | 4 +-
arch/alpha/include/uapi/asm/termbits.h | 2 +
arch/arm/include/uapi/asm/signal.h | 1 +
arch/h8300/include/uapi/asm/signal.h | 1 +
arch/ia64/include/asm/termios.h | 4 +-
arch/ia64/include/uapi/asm/signal.h | 1 +
arch/ia64/include/uapi/asm/termbits.h | 2 +
arch/m68k/include/uapi/asm/signal.h | 1 +
arch/mips/include/asm/termios.h | 4 +-
arch/mips/include/uapi/asm/signal.h | 1 +
arch/mips/include/uapi/asm/termbits.h | 2 +
arch/parisc/include/asm/termios.h | 4 +-
arch/parisc/include/uapi/asm/signal.h | 1 +
arch/parisc/include/uapi/asm/termbits.h | 2 +
arch/powerpc/include/asm/termios.h | 4 +-
arch/powerpc/include/uapi/asm/signal.h | 1 +
arch/powerpc/include/uapi/asm/termbits.h | 2 +
arch/s390/include/asm/termios.h | 4 +-
arch/s390/include/uapi/asm/signal.h | 1 +
arch/sparc/include/asm/termios.h | 4 +-
arch/sparc/include/uapi/asm/signal.h | 2 +
arch/sparc/include/uapi/asm/termbits.h | 2 +
arch/x86/include/uapi/asm/signal.h | 1 +
arch/xtensa/include/uapi/asm/signal.h | 1 +
arch/xtensa/include/uapi/asm/termbits.h | 2 +
drivers/tty/Makefile | 3 +-
drivers/tty/n_tty.c | 70 ++++-
drivers/tty/n_tty_status.c | 337 +++++++++++++++++++++++
include/asm-generic/termios.h | 4 +-
include/linux/sched.h | 7 +
include/linux/signal.h | 5 +-
include/linux/tty.h | 7 +-
include/uapi/asm-generic/signal.h | 1 +
include/uapi/asm-generic/termbits.h | 2 +
34 files changed, 457 insertions(+), 33 deletions(-)
create mode 100644 drivers/tty/n_tty_status.c
--
2.20.1
^ permalink raw reply
* DMA coherency in drivers/tty/serial/mpsc.c
From: Christoph Hellwig @ 2019-06-25 12:26 UTC (permalink / raw)
To: Mark Greer, Paul Gortmaker, Dale Farnsworth
Cc: Greg Kroah-Hartman, linux-serial, linux-kernel, linuxppc-dev
Hi Paul, Dale and Mark (I hope this reaches the right Mark),
I've started auditing all users of DMA_ATTR_NON_CONSISTENT ot prepare
for major API improvements in that area.
One of the odd users is the mpsc ѕerial driver, which allocates DMA
memory with the above flag, and then actually properly calls
dma_cache_sync. So far, so good. But it turns out it also has
"#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)"
ifdef blocks next to the dma_cache_sync calls that perform cache
maintainance for platforms that according to the ifdef claim to
be cache coherent. According to the Kconfig the driver can
only build if the MV64X60 symbol is set, which is a ppc embedded 6xx
SOC, which appears to be configurable as either cache coherent, or
not. But according to the code in the driver at least this device
always is not cache coherent.
It seems like we need to always mark that platform as potentially
not coherent, and then use the per-device flag to mark all device
except for this one as coherent. Or did I miss anything? Maybe
all this is actually dead code and can go away?
^ permalink raw reply
* Re: [PATCH 1/2 v9] serial: mctrl_gpio: Check if GPIO property exisits before requesting it
From: Andy Shevchenko @ 2019-06-25 11:19 UTC (permalink / raw)
To: Stefan Roese
Cc: Geert Uytterhoeven, open list:SERIAL DRIVERS,
Linux Kernel Mailing List, Mika Westerberg, Yegor Yefremov,
Greg Kroah-Hartman, Giulio Benetti, Linus Walleij,
Bartosz Golaszewski, open list:GPIO SUBSYSTEM
In-Reply-To: <d8ae626b-e574-be33-f698-3cb992653683@denx.de>
On Tue, Jun 25, 2019 at 07:27:33AM +0200, Stefan Roese wrote:
> On 24.06.19 17:35, Geert Uytterhoeven wrote:
> > On Mon, Jun 24, 2019 at 5:29 PM Stefan Roese <sr@denx.de> wrote:
> > > On 24.06.19 10:42, Geert Uytterhoeven wrote:
> > > Should both options be supported ("cts-gpio" vs "cts-gpios")?
> > > Documentation/devicetree/bindings/serial/serial.txt only mentions
> > > the "-gpios" variant.
> >
> > Well, the "-gpio" variant is deprecated, but still supported by
> > devm_gpiod_get_index_optional(), and there are active users in upstream
> > DTS files.
> >
> > My main objection is (trying to) replicate the matching logic inside
> > gpiolib.c, causing subtle semantic differences. And keeping it consistent,
> > of course.
> >
> > It would be nice if this could be fixed inside acpi_find_gpio(), so
> > users don't need to be updated. There may be other subsystems where
> > the difference between DT and ACPI may cause issues, unbeknownst.
>
> Sure, I can fix this. I would prefer to do this in a follow-up patch
> though, if nobody objects.
In case if you are going to do this, use approach from GPIO library. Perhaps,
it may require to create something like for_each_gpio_suffix() helper.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [patch 5/5] x86/irq: Seperate unused system vectors from spurious entry again
From: Thomas Gleixner @ 2019-06-25 11:13 UTC (permalink / raw)
To: LKML
Cc: x86, Robert Hodaszi, Vadim Pasternak, Ido Schimmel,
Greg Kroah-Hartman, linux-serial, Marc Zyngier, Jan Kiszka,
Jan Beulich
In-Reply-To: <20190625111353.863718167@linutronix.de>
Quite some time ago the interrupt entry stubs for unused vectors in the
system vector range got removed and directly mapped to the spurious
interrupt vector entry point.
Sounds reasonable, but it's subtly broken. The spurious interrupt vector
entry point pushes vector number 0xFF on the stack which makes the whole
logic in __smp_spurious_interrupt() pointless.
As a consequence any spurious interrupt which comes from a vector != 0xFF
is treated as a real spurious interrupt (vector 0xFF) and not
acknowledged. That subsequently stalls all interrupt vectors of equal and
lower priority, which brings the system to a grinding halt.
This can happen because even on 64-bit the system vector space is not
guaranteed to be fully populated. A full compile time handling of the
unused vectors is not possible because quite some of them are conditonally
populated at runtime.
Bring the entry stubs back, which wastes 160 bytes if all stubs are unused,
but gains the proper handling back. There is no point to selectively spare
some of the stubs which are known at compile time as the required code in
the IDT management would be way larger and convoluted.
Do not route the spurious entries through common_interrupt and do_IRQ() as
the original code did. Route it to smp_spurious_interrupt() which evaluates
the vector number and acts accordingly now that the real vector numbers are
handed in.
Fixup the pr_warn so the actual spurious vector (0xff) is clearly
distiguished from the other vectors and also note for the vectored case
whether it was pending in the ISR or not.
"Spurious APIC interrupt (vector 0xFF) on CPU#0, should never happen."
"Spurious interrupt vector 0xed on CPU#1. Acked."
"Spurious interrupt vector 0xee on CPU#1. Not pending!."
Fixes: 2414e021ac8d ("x86: Avoid building unused IRQ entry stubs")
Reported-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Jan Beulich <jbeulich@suse.com>
---
arch/x86/entry/entry_32.S | 24 ++++++++++++++++++++++++
arch/x86/entry/entry_64.S | 30 ++++++++++++++++++++++++++----
arch/x86/include/asm/hw_irq.h | 2 ++
arch/x86/kernel/apic/apic.c | 33 ++++++++++++++++++++++-----------
arch/x86/kernel/idt.c | 3 ++-
5 files changed, 76 insertions(+), 16 deletions(-)
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -1104,6 +1104,30 @@ ENTRY(irq_entries_start)
.endr
END(irq_entries_start)
+#ifdef CONFIG_X86_LOCAL_APIC
+ .align 8
+ENTRY(spurious_entries_start)
+ vector=FIRST_SYSTEM_VECTOR
+ .rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
+ pushl $(~vector+0x80) /* Note: always in signed byte range */
+ vector=vector+1
+ jmp common_spurious
+ .align 8
+ .endr
+END(spurious_entries_start)
+
+common_spurious:
+ ASM_CLAC
+ addl $-0x80, (%esp) /* Adjust vector into the [-256, -1] range */
+ SAVE_ALL switch_stacks=1
+ ENCODE_FRAME_POINTER
+ TRACE_IRQS_OFF
+ movl %esp, %eax
+ call smp_spurious_interrupt
+ jmp ret_from_intr
+ENDPROC(common_interrupt)
+#endif
+
/*
* the CPU automatically disables interrupts when executing an IRQ vector,
* so IRQ-flags tracing has to follow that:
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -375,6 +375,18 @@ ENTRY(irq_entries_start)
.endr
END(irq_entries_start)
+ .align 8
+ENTRY(spurious_entries_start)
+ vector=FIRST_SYSTEM_VECTOR
+ .rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
+ UNWIND_HINT_IRET_REGS
+ pushq $(~vector+0x80) /* Note: always in signed byte range */
+ jmp common_spurious
+ .align 8
+ vector=vector+1
+ .endr
+END(spurious_entries_start)
+
.macro DEBUG_ENTRY_ASSERT_IRQS_OFF
#ifdef CONFIG_DEBUG_ENTRY
pushq %rax
@@ -571,10 +583,20 @@ END(interrupt_entry)
/* Interrupt entry/exit. */
- /*
- * The interrupt stubs push (~vector+0x80) onto the stack and
- * then jump to common_interrupt.
- */
+/*
+ * The interrupt stubs push (~vector+0x80) onto the stack and
+ * then jump to common_spurious/interrupt.
+ */
+common_spurious:
+ addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
+ call interrupt_entry
+ UNWIND_HINT_REGS indirect=1
+ call smp_spurious_interrupt /* rdi points to pt_regs */
+ jmp ret_from_intr
+END(common_spurious)
+_ASM_NOKPROBE(common_spurious)
+
+/* common_interrupt is a hotpath. Align it */
.p2align CONFIG_X86_L1_CACHE_SHIFT
common_interrupt:
addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -150,6 +150,8 @@ extern char irq_entries_start[];
#define trace_irq_entries_start irq_entries_start
#endif
+extern char spurious_entries_start[];
+
#define VECTOR_UNUSED NULL
#define VECTOR_SHUTDOWN ((void *)~0UL)
#define VECTOR_RETRIGGERED ((void *)~1UL)
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -2040,21 +2040,32 @@ void __init register_lapic_address(unsig
entering_irq();
trace_spurious_apic_entry(vector);
+ inc_irq_stat(irq_spurious_count);
+
+ /*
+ * If this is a spurious interrupt then do not acknowledge
+ */
+ if (vector == SPURIOUS_APIC_VECTOR) {
+ /* See SDM vol 3 */
+ pr_info("Spurious APIC interrupt (vector 0xFF) on CPU#%d, should never happen.\n",
+ smp_processor_id());
+ goto out;
+ }
+
/*
- * Check if this really is a spurious interrupt and ACK it
- * if it is a vectored one. Just in case...
- * Spurious interrupts should not be ACKed.
+ * If it is a vectored one, verify it's set in the ISR. If set,
+ * acknowledge it.
*/
v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
- if (v & (1 << (vector & 0x1f)))
+ if (v & (1 << (vector & 0x1f))) {
+ pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Acked\n",
+ vector, smp_processor_id());
ack_APIC_irq();
-
- inc_irq_stat(irq_spurious_count);
-
- /* see sw-dev-man vol 3, chapter 7.4.13.5 */
- pr_info("spurious APIC interrupt through vector %02x on CPU#%d, "
- "should never happen.\n", vector, smp_processor_id());
-
+ } else {
+ pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Not pending!\n",
+ vector, smp_processor_id());
+ }
+out:
trace_spurious_apic_exit(vector);
exiting_irq();
}
--- a/arch/x86/kernel/idt.c
+++ b/arch/x86/kernel/idt.c
@@ -319,7 +319,8 @@ void __init idt_setup_apic_and_irq_gates
#ifdef CONFIG_X86_LOCAL_APIC
for_each_clear_bit_from(i, system_vectors, NR_VECTORS) {
set_bit(i, system_vectors);
- set_intr_gate(i, spurious_interrupt);
+ entry = spurious_entries_start + 8 * (i - FIRST_SYSTEM_VECTOR);
+ set_intr_gate(i, entry);
}
#endif
}
^ permalink raw reply
* [patch 4/5] x86/irq: Handle spurious interrupt after shutdown gracefully
From: Thomas Gleixner @ 2019-06-25 11:13 UTC (permalink / raw)
To: LKML
Cc: x86, Robert Hodaszi, Vadim Pasternak, Ido Schimmel,
Greg Kroah-Hartman, linux-serial, Marc Zyngier
In-Reply-To: <20190625111353.863718167@linutronix.de>
Since the rework of the vector management, warnings about spurious
interrupts have been reported. Robert provided some more information and
did an initial analysis. The following situation leads to these warnings:
CPU 0 CPU 1 IO_APIC
interrupt is raised
sent to CPU1
Unable to handle
immediately
(interrupts off,
deep idle delay)
mask()
...
free()
shutdown()
synchronize_irq()
clear_vector()
do_IRQ()
-> vector is clear
Before the rework the vector entries of legacy interrupts were statically
assigned and occupied precious vector space while most of them were
unused. Due to that the above situation was handled silently because the
vector was handled and the core handler of the assigned interrupt
descriptor noticed that it is shut down and returned.
While this has been usually observed with legacy interrupts, this situation
is not limited to them. Any other interrupt source, e.g. MSI, can cause the
same issue.
After adding proper synchronization for level triggered interrupts, this
can only happen for edge triggered interrupts where the IO-APIC obviously
cannot provide information about interrupts in flight.
While the spurious warning is actually harmless in this case it worries
users and driver developers.
Handle it gracefully by marking the vector entry as VECTOR_SHUTDOWN instead
of VECTOR_UNUSED when the vector is freed up.
If that above late handling happens the spurious detector will not complain
and switch the entry to VECTOR_UNUSED. Any subsequent spurious interrupt on
that line will trigger the spurious warning as before.
Fixes: 464d12309e1b ("x86/vector: Switch IOAPIC to global reservation mode")
Reported-by: Robert Hodaszi <Robert.Hodaszi@digi.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/include/asm/hw_irq.h | 3 ++-
arch/x86/kernel/apic/vector.c | 4 ++--
arch/x86/kernel/irq.c | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -151,7 +151,8 @@ extern char irq_entries_start[];
#endif
#define VECTOR_UNUSED NULL
-#define VECTOR_RETRIGGERED ((void *)~0UL)
+#define VECTOR_SHUTDOWN ((void *)~0UL)
+#define VECTOR_RETRIGGERED ((void *)~1UL)
typedef struct irq_desc* vector_irq_t[NR_VECTORS];
DECLARE_PER_CPU(vector_irq_t, vector_irq);
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -340,7 +340,7 @@ static void clear_irq_vector(struct irq_
trace_vector_clear(irqd->irq, vector, apicd->cpu, apicd->prev_vector,
apicd->prev_cpu);
- per_cpu(vector_irq, apicd->cpu)[vector] = VECTOR_UNUSED;
+ per_cpu(vector_irq, apicd->cpu)[vector] = VECTOR_SHUTDOWN;
irq_matrix_free(vector_matrix, apicd->cpu, vector, managed);
apicd->vector = 0;
@@ -349,7 +349,7 @@ static void clear_irq_vector(struct irq_
if (!vector)
return;
- per_cpu(vector_irq, apicd->prev_cpu)[vector] = VECTOR_UNUSED;
+ per_cpu(vector_irq, apicd->prev_cpu)[vector] = VECTOR_SHUTDOWN;
irq_matrix_free(vector_matrix, apicd->prev_cpu, vector, managed);
apicd->prev_vector = 0;
apicd->move_in_progress = 0;
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -247,7 +247,7 @@ u64 arch_irq_stat(void)
if (!handle_irq(desc, regs)) {
ack_APIC_irq();
- if (desc != VECTOR_RETRIGGERED) {
+ if (desc != VECTOR_RETRIGGERED && desc != VECTOR_SHUTDOWN) {
pr_emerg_ratelimited("%s: %d.%d No irq handler for vector\n",
__func__, smp_processor_id(),
vector);
^ permalink raw reply
* [patch 3/5] x86/ioapic: Implement irq_inflight() callback
From: Thomas Gleixner @ 2019-06-25 11:13 UTC (permalink / raw)
To: LKML
Cc: x86, Robert Hodaszi, Vadim Pasternak, Ido Schimmel,
Greg Kroah-Hartman, linux-serial, Marc Zyngier
In-Reply-To: <20190625111353.863718167@linutronix.de>
When an interrupt is shut down in free_irq() there might be an inflight
interrupt which is not yet serviced pending in the IO-APIC remote IRR. That
means the interrupt has been sent to the target CPUs local APIC, but the
target CPU is in a state which delays the servicing.
So free_irq() would proceed to free resources and to clear the vector
because synchronize_hardirq() does not see an interrupt handler in
progress.
That can trigger a spurious interrupt warning, which is harmless and just
confuses users, but it also can leave the remote IRR in a stale state
because once the handler is invoked the interrupt resources might be freed
already and therefore acknowledgement is not possible anymore.
Implement the new irq_inflight() callback for the IO-APIC irq chip. The
callback is invoked from free_irq() via __synchronize_hardirq(). Check the
remote IRR bit of the interrupt and return 'in flight' if it is set and the
interrupt is configured in level mode. For edge mode the remote IRR has no
meaning.
As this is only meaningful for level triggered interrupts this won't cure
the potential spurious interrupt warning for edge triggered interrupts, but
the edge trigger case does not result in stale hardware state. This has to
be addressed at the vector/interrupt entry level seperately.
Fixes: 464d12309e1b ("x86/vector: Switch IOAPIC to global reservation mode")
Reported-by: Robert Hodaszi <Robert.Hodaszi@digi.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/apic/io_apic.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1893,6 +1893,43 @@ static int ioapic_set_affinity(struct ir
return ret;
}
+/*
+ * Interrupt shutdown masks the ioapic pin, but the interrupt might already
+ * be on flight, but not yet serviced by the target CPU. That means
+ * __synchronize_hardirq() would return and claim that everything is calmed
+ * down. So free_irq() would proceed and deactivate the interrupt and free
+ * resources.
+ *
+ * Once the target CPU comes around to service it it will find a cleared
+ * vector and complain. While the spurious interrupt is harmless, the full
+ * release of resources might prevent the interrupt from being acknowledged
+ * which keeps the hardware in a weird state.
+ *
+ * Verify that the corresponding Remote-IRR bits are clear.
+ */
+static int ioapic_irq_inflight(struct irq_data *irqd)
+{
+ struct mp_chip_data *mcd = irqd->chip_data;
+ struct IO_APIC_route_entry rentry;
+ struct irq_pin_list *p;
+ int ret = 0;
+
+ raw_spin_lock(&ioapic_lock);
+ for_each_irq_pin(p, mcd->irq_2_pin) {
+ rentry = __ioapic_read_entry(p->apic, p->pin);
+ /*
+ * The remote IRR is only valid in level trigger mode. It's
+ * meaning is undefined for edge triggered interrupts.
+ */
+ if (rentry.irr && rentry.trigger) {
+ ret = 1;
+ break;
+ }
+ }
+ raw_spin_unlock(&ioapic_lock);
+ return ret;
+}
+
static struct irq_chip ioapic_chip __read_mostly = {
.name = "IO-APIC",
.irq_startup = startup_ioapic_irq,
@@ -1902,6 +1939,7 @@ static struct irq_chip ioapic_chip __rea
.irq_eoi = ioapic_ack_level,
.irq_set_affinity = ioapic_set_affinity,
.irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_inflight = ioapic_irq_inflight,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
@@ -1914,6 +1952,7 @@ static struct irq_chip ioapic_ir_chip __
.irq_eoi = ioapic_ir_ack_level,
.irq_set_affinity = ioapic_set_affinity,
.irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_inflight = ioapic_irq_inflight,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
^ permalink raw reply
* [patch 2/5] genirq: Add optional hardware synchronization for shutdown
From: Thomas Gleixner @ 2019-06-25 11:13 UTC (permalink / raw)
To: LKML
Cc: x86, Robert Hodaszi, Vadim Pasternak, Ido Schimmel,
Greg Kroah-Hartman, linux-serial, Marc Zyngier
In-Reply-To: <20190625111353.863718167@linutronix.de>
free_irq() ensures that no hardware interrupt handler is executing on a
different CPU before actually releasing resources and deactivating the
interrupt completely in a domain hierarchy.
But that does not catch the case where the interrupt is on flight at the
hardware level but not yet serviced by the target CPU. That creates an
interesing race condition:
CPU 0 CPU 1 IRQ CHIP
interrupt is raised
sent to CPU1
Unable to handle
immediately
(interrupts off,
deep idle delay)
mask()
...
free()
shutdown()
synchronize_irq()
release_resources()
do_IRQ()
-> resources are not available
That might be harmless and just trigger a spurious interrupt warning, but
some interrupt chips might get into a wedged state.
Provide infrastructure for interrupt chips to provide an optional
irq_inflight() callback and use it for the synchronization in free_irq().
synchronize_[hard]irq() are not using this mechanism as it might actually
deadlock unter certain conditions.
Fixes: 464d12309e1b ("x86/vector: Switch IOAPIC to global reservation mode")
Reported-by: Robert Hodaszi <Robert.Hodaszi@digi.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/irq.h | 2 ++
kernel/irq/manage.c | 29 ++++++++++++++++++++++++-----
2 files changed, 26 insertions(+), 5 deletions(-)
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -418,6 +418,7 @@ static inline irq_hw_number_t irqd_to_hw
* required. This is used for CPU hotplug where the
* target CPU is not yet set in the cpu_online_mask.
* @irq_retrigger: resend an IRQ to the CPU
+ * @irq_inflight: chip level detection of interrupts in flight (optional)
* @irq_set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
* @irq_set_wake: enable/disable power-management wake-on of an IRQ
* @irq_bus_lock: function to lock access to slow bus (i2c) chips
@@ -462,6 +463,7 @@ struct irq_chip {
int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
int (*irq_retrigger)(struct irq_data *data);
+ int (*irq_inflight)(struct irq_data *data);
int (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
int (*irq_set_wake)(struct irq_data *data, unsigned int on);
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -35,8 +35,10 @@ static int __init setup_forced_irqthread
early_param("threadirqs", setup_forced_irqthreads);
#endif
-static void __synchronize_hardirq(struct irq_desc *desc)
+static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip)
{
+ struct irq_data *irqd = irq_desc_get_irq_data(desc);
+ struct irq_chip *chip = irq_data_get_irq_chip(irqd);
bool inprogress;
do {
@@ -52,6 +54,13 @@ static void __synchronize_hardirq(struct
/* Ok, that indicated we're done: double-check carefully. */
raw_spin_lock_irqsave(&desc->lock, flags);
inprogress = irqd_irq_inprogress(&desc->irq_data);
+
+ /*
+ * If requested and supported, check at the chip whether it
+ * is in flight at the hardware level:
+ */
+ if (!inprogress && sync_chip && chip && chip->irq_inflight)
+ inprogress = chip->irq_inflight(irqd);
raw_spin_unlock_irqrestore(&desc->lock, flags);
/* Oops, that failed? */
@@ -74,13 +83,16 @@ static void __synchronize_hardirq(struct
* Returns: false if a threaded handler is active.
*
* This function may be called - with care - from IRQ context.
+ *
+ * It does not check whether there is an interrupt on flight at the
+ * hardware level, but not serviced yet, as this might deadlock.
*/
bool synchronize_hardirq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
if (desc) {
- __synchronize_hardirq(desc);
+ __synchronize_hardirq(desc, false);
return !atomic_read(&desc->threads_active);
}
@@ -97,13 +109,16 @@ EXPORT_SYMBOL(synchronize_hardirq);
* holding a resource the IRQ handler may need you will deadlock.
*
* This function may be called - with care - from IRQ context.
+ *
+ * It does not check whether there is an interrupt on flight at the
+ * hardware level, but not serviced yet, as this might deadlock.
*/
void synchronize_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
if (desc) {
- __synchronize_hardirq(desc);
+ __synchronize_hardirq(desc, false);
/*
* We made sure that no hardirq handler is
* running. Now verify that no threaded handlers are
@@ -1729,8 +1744,12 @@ static struct irqaction *__free_irq(stru
unregister_handler_proc(irq, action);
- /* Make sure it's not being used on another CPU: */
- synchronize_hardirq(irq);
+ /*
+ * Make sure it's not being used on another CPU and if the chip
+ * supports it also make sure that there is no (not yet serviced)
+ * interrupt on flight at the hardware level.
+ */
+ __synchronize_hardirq(desc, true);
#ifdef CONFIG_DEBUG_SHIRQ
/*
^ permalink raw reply
* [patch 1/5] genirq: Delay deactivation in free_irq()
From: Thomas Gleixner @ 2019-06-25 11:13 UTC (permalink / raw)
To: LKML
Cc: x86, Robert Hodaszi, Vadim Pasternak, Ido Schimmel,
Greg Kroah-Hartman, linux-serial, Marc Zyngier
In-Reply-To: <20190625111353.863718167@linutronix.de>
When interrupts are shutdown, they are immediately deactivated in the
irqdomain hierarchy. While this looks obviously correct there is a subtle
issue:
There might be an interrupt in flight when free_irq() is invoking the
shutdown. This is properly handled at the irq descriptor / primary handler
level, but the deactivation might completely disable resources which are
required to acknowledge the interrupt.
Split the shutdown code and deactivate the interrupt after synchronization
in free_irq(). Fixup all other usage sites where this is not an issue to
invoke the combined shutdown_and_deactivate() function instead.
This still might be an issue if the interrupt in flight servicing is
delayed on a remote CPU beyond the invocation of synchronize_irq(), but
that cannot be handled at that level and needs to be handled in the
synchronize_irq() context.
Fixes: f8264e34965a ("irqdomain: Introduce new interfaces to support hierarchy irqdomains")
Reported-by: Robert Hodaszi <Robert.Hodaszi@digi.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/irq/autoprobe.c | 6 +++---
kernel/irq/chip.c | 6 ++++++
kernel/irq/cpuhotplug.c | 2 +-
kernel/irq/internals.h | 1 +
kernel/irq/manage.c | 12 +++++++++++-
5 files changed, 22 insertions(+), 5 deletions(-)
--- a/kernel/irq/autoprobe.c
+++ b/kernel/irq/autoprobe.c
@@ -90,7 +90,7 @@ unsigned long probe_irq_on(void)
/* It triggered already - consider it spurious. */
if (!(desc->istate & IRQS_WAITING)) {
desc->istate &= ~IRQS_AUTODETECT;
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
} else
if (i < 32)
mask |= 1 << i;
@@ -127,7 +127,7 @@ unsigned int probe_irq_mask(unsigned lon
mask |= 1 << i;
desc->istate &= ~IRQS_AUTODETECT;
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
}
raw_spin_unlock_irq(&desc->lock);
}
@@ -169,7 +169,7 @@ int probe_irq_off(unsigned long val)
nr_of_irqs++;
}
desc->istate &= ~IRQS_AUTODETECT;
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
}
raw_spin_unlock_irq(&desc->lock);
}
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -314,6 +314,12 @@ void irq_shutdown(struct irq_desc *desc)
}
irq_state_clr_started(desc);
}
+}
+
+
+void irq_shutdown_and_deactivate(struct irq_desc *desc)
+{
+ irq_shutdown(desc);
/*
* This must be called even if the interrupt was never started up,
* because the activation can happen before the interrupt is
--- a/kernel/irq/cpuhotplug.c
+++ b/kernel/irq/cpuhotplug.c
@@ -116,7 +116,7 @@ static bool migrate_one_irq(struct irq_d
*/
if (irqd_affinity_is_managed(d)) {
irqd_set_managed_shutdown(d);
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
return false;
}
affinity = cpu_online_mask;
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -82,6 +82,7 @@ extern int irq_activate_and_startup(stru
extern int irq_startup(struct irq_desc *desc, bool resend, bool force);
extern void irq_shutdown(struct irq_desc *desc);
+extern void irq_shutdown_and_deactivate(struct irq_desc *desc);
extern void irq_enable(struct irq_desc *desc);
extern void irq_disable(struct irq_desc *desc);
extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/random.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/sched/rt.h>
@@ -1699,6 +1700,7 @@ static struct irqaction *__free_irq(stru
/* If this was the last handler, shut down the IRQ line: */
if (!desc->action) {
irq_settings_clr_disable_unlazy(desc);
+ /* Only shutdown. Deactivate after synchronize_irq() */
irq_shutdown(desc);
}
@@ -1768,6 +1770,14 @@ static struct irqaction *__free_irq(stru
* require it to deallocate resources over the slow bus.
*/
chip_bus_lock(desc);
+ /*
+ * There is no interrupt on the fly anymore. Deactivate it
+ * completely.
+ */
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ irq_domain_deactivate_irq(&desc->irq_data);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+
irq_release_resources(desc);
chip_bus_sync_unlock(desc);
irq_remove_timings(desc);
@@ -1855,7 +1865,7 @@ static const void *__cleanup_nmi(unsigne
}
irq_settings_clr_disable_unlazy(desc);
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
irq_release_resources(desc);
^ permalink raw reply
* [patch 0/5] x86/irq: Cure various interrupt issues
From: Thomas Gleixner @ 2019-06-25 11:13 UTC (permalink / raw)
To: LKML
Cc: x86, Robert Hodaszi, Vadim Pasternak, Ido Schimmel,
Greg Kroah-Hartman, linux-serial, Marc Zyngier
This series addresses a few long standing issues:
1) The spurious interrupt warning which is emitted occasionally for
no obvious reason. Partially harmless but annoying
2) The spurious system vector detection which got wreckaged quite some
time ago and can completely wedge a machine. Posted yesterday already
in a preliminary version. Now actually verified that it does what it
claims to do.
Details in the various patches.
For your conveniance the series is available from git:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git WIP.irq
Thanks,
tglx
8<-----------------
arch/x86/entry/entry_32.S | 24 ++++++++++++++++++++++++
arch/x86/entry/entry_64.S | 30 ++++++++++++++++++++++++++----
arch/x86/include/asm/hw_irq.h | 5 ++++-
arch/x86/kernel/apic/apic.c | 33 ++++++++++++++++++++++-----------
arch/x86/kernel/apic/io_apic.c | 39 +++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/apic/vector.c | 4 ++--
arch/x86/kernel/idt.c | 3 ++-
arch/x86/kernel/irq.c | 2 +-
include/linux/irq.h | 2 ++
kernel/irq/autoprobe.c | 6 +++---
kernel/irq/chip.c | 6 ++++++
kernel/irq/cpuhotplug.c | 2 +-
kernel/irq/internals.h | 1 +
kernel/irq/manage.c | 41 +++++++++++++++++++++++++++++++++++------
14 files changed, 168 insertions(+), 30 deletions(-)
^ permalink raw reply
* [patch v3 5/5] Documentation: DT bindings AST2500 DMA UART driver
From: sudheer.v @ 2019-06-25 10:44 UTC (permalink / raw)
To: gregkh, jslaby, joel, andrew, benh, robh+dt, mark.rutland,
shivahshankar.shankarnarayanrao, shivahshankar, sudheer.veliseti
Cc: sudheer veliseti, linux-kernel, linux-serial, devicetree,
linux-aspeed
In-Reply-To: <1561459476-14268-1-git-send-email-open.sudheer@gmail.com>
From: sudheer veliseti <sudheer.open@gmail.com>
documentation for Dt bindings for DMA based UARTs in AST2500
Signed-off-by: sudheer veliseti <sudheer.open@gmail.com>
---
Changes in v3:
- change logs added
.../bindings/serial/ast2500-dma-uart.txt | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt
diff --git a/Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt b/Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt
new file mode 100644
index 000000000000..6f01ddecba56
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/ast2500-dma-uart.txt
@@ -0,0 +1,40 @@
+
+node for DMA controller:
+ ast_uart_sdma: uart_sdma@1e79e000 {
+ compatible = "aspeed,ast-uart-sdma";
+ reg = <0x1e79e000 0x400>;
+ interrupts = <50>;
+ status = "disabled";
+ };
+this node doesn't binds with any driver.
+DMA controller is handled as a separate SW layer,and is included in the same driver.
+This DMA controller node is included in DT just for Register base and interrupt details
+
+
+
+node for DMA-UART :
+
+
+Required properties:
+
+- compatible: "aspeed,ast-sdma-uart"
+- reg: The base address of the UART register bank
+- interrupts: should contain interrupt specifier.
+- clocks: Clock driving the hardware;
+- pinctrl-0 : list of pinconfigurations
+- dma-channel: channel of DMA-controller which is used
+
+Example:
+
+ dma_uart1: dma_uart1@1e783000{
+ compatible = "aspeed,ast-sdma-uart";
+ reg = <0x1e783000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <9>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>;
+ dma-channel = <0>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>;
+ status = "disabled";
+ };
--
2.17.1
^ permalink raw reply related
* [patch v3 4/5] defconfig and MAINTAINERS updated for AST2500 DMA UART driver
From: sudheer.v @ 2019-06-25 10:44 UTC (permalink / raw)
To: gregkh, jslaby, joel, andrew, benh, robh+dt, mark.rutland,
shivahshankar.shankarnarayanrao, shivahshankar, sudheer.veliseti
Cc: sudheer veliseti, linux-kernel, linux-serial, devicetree,
linux-aspeed
In-Reply-To: <1561459476-14268-1-git-send-email-open.sudheer@gmail.com>
From: sudheer veliseti <sudheer.open@gmail.com>
defconfig changes to add DMA based UART in AST2500
Maintainers File updated.
Signed-off-by: sudheer veliseti <sudheer.open@gmail.com>
---
Changes in v3:
- Added changes logs
MAINTAINERS | 13 +++++++++++++
arch/arm/configs/aspeed_g5_defconfig | 1 +
2 files changed, 14 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 997e27ab492f..c9a9790b97f6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1347,6 +1347,19 @@ F: drivers/crypto/axis
F: drivers/pinctrl/pinctrl-artpec*
F: Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt
+ARM/ASPEED DMA UART DRIVER
+M: sudheer v <sudheer.open@gmail.com>
+M: ShivahShankar <shivahshankar.shankarnarayanrao@aspeedtech.com>
+R: Joel Stanley <joel@jms.id.au>
+R: Andrew Jeffery <andrew@aj.id.au>
+R: Vinod Koul <vkoul@kernel.org>
+L: dmaengine@vger.kernel.org
+L: openbmc@lists.ozlabs.org
+L: linux-aspeed@lists.ozlabs.org
+S: Maintained
+F: drivers/tty/serial/8250/8250_aspeed_uart_dma.c
+F: Documentation/devicetree/bindings/serial/ast-sdma-uart.txt
+
ARM/ASPEED I2C DRIVER
M: Brendan Higgins <brendanhiggins@google.com>
R: Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
index 1849cbc161b4..25bf26630939 100644
--- a/arch/arm/configs/aspeed_g5_defconfig
+++ b/arch/arm/configs/aspeed_g5_defconfig
@@ -144,6 +144,7 @@ CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=6
CONFIG_SERIAL_8250_RUNTIME_UARTS=6
+CONFIG_AST_SERIAL_DMA_UART=y
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_ASPEED_VUART=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
--
2.17.1
^ permalink raw reply related
* [patch v3 3/5] DT nodes for AST2500 DMA UART driver
From: sudheer.v @ 2019-06-25 10:44 UTC (permalink / raw)
To: gregkh, jslaby, joel, andrew, benh, robh+dt, mark.rutland,
shivahshankar.shankarnarayanrao, shivahshankar, sudheer.veliseti
Cc: sudheer veliseti, linux-kernel, linux-serial, devicetree,
linux-aspeed
In-Reply-To: <1561459476-14268-1-git-send-email-open.sudheer@gmail.com>
From: sudheer veliseti <sudheer.open@gmail.com>
DT node for DMA controller(ast_uart_sdma) doesn't bind to any DMA controller driver.
This is because Software for DMA controller is not based on DMA framework,but is dedicated
and serves only UARTs in AST2500. ast_uart_sdma node is searched by compatible string in the
driver software.basic use of this node is to provide register base address of DMA controller and DMA irq number(<50>).
IRQ of DMA controller is of crucial importance, which does RX and TX of UART data.
uart nodes dma_uart1,2...etc binds to the platform driver.
irq numbers <9>,<32>,<33>,<34> in dma_uart nodes install ISRs which are of not much interest in uart data TX/RX .
Signed-off-by: sudheer veliseti <sudheer.open@gmail.com>
---
changes in v3:
- change logs added
arch/arm/boot/dts/aspeed-ast2500-evb.dts | 21 +++++++
arch/arm/boot/dts/aspeed-g5.dtsi | 71 ++++++++++++++++++++++--
2 files changed, 88 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/aspeed-ast2500-evb.dts b/arch/arm/boot/dts/aspeed-ast2500-evb.dts
index 5dbb33c10c4f..4da09fbe94df 100644
--- a/arch/arm/boot/dts/aspeed-ast2500-evb.dts
+++ b/arch/arm/boot/dts/aspeed-ast2500-evb.dts
@@ -64,6 +64,27 @@
status = "okay";
};
+&ast_uart_sdma {
+ status = "okay";
+};
+
+&dma_uart1 {
+ status = "okay";
+};
+
+&dma_uart2 {
+ status = "okay";
+};
+
+&dma_uart3 {
+ status = "okay";
+};
+
+&dma_uart4 {
+ status = "okay";
+};
+
+
&mac0 {
status = "okay";
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index 674746513031..fb7b3ed463de 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -23,10 +23,10 @@
i2c11 = &i2c11;
i2c12 = &i2c12;
i2c13 = &i2c13;
- serial0 = &uart1;
- serial1 = &uart2;
- serial2 = &uart3;
- serial3 = &uart4;
+ serial0 = &dma_uart1;
+ serial1 = &dma_uart2;
+ serial2 = &dma_uart3;
+ serial3 = &dma_uart4;
serial4 = &uart5;
serial5 = &vuart;
peci0 = &peci0;
@@ -497,6 +497,69 @@
status = "disabled";
};
+ ast_uart_sdma: uart_sdma@1e79e000 {
+ compatible = "aspeed,ast-uart-sdma";
+ reg = <0x1e79e000 0x400>;
+ interrupts = <50>;
+ status = "disabled";
+ };
+
+ dma_uart1: dma_uart1@1e783000{
+ compatible = "aspeed,ast-sdma-uart";
+ reg = <0x1e783000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <9>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>;
+ dma-channel = <0>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd1_default
+ &pinctrl_rxd1_default>;
+ status = "disabled";
+ };
+
+ dma_uart2: dma_uart2@1e78d000{
+ compatible = "aspeed,ast-sdma-uart";
+ reg = <0x1e78d000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <32>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART2CLK>;
+ dma-channel = <1>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd2_default
+ &pinctrl_rxd2_default>;
+ status = "disabled";
+ };
+
+ dma_uart3: dma_uart3@1e78e000{
+ compatible = "aspeed,ast-sdma-uart";
+ reg = <0x1e78e000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <33>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART3CLK>;
+ dma-channel = <2>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd3_default
+ &pinctrl_rxd3_default>;
+ status = "disabled";
+ };
+
+ dma_uart4: dma_uart4@1e78f000{
+ compatible = "aspeed,ast-sdma-uart";
+ reg = <0x1e78f000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <34>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART4CLK>;
+ dma-channel = <3>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd4_default
+ &pinctrl_rxd4_default>;
+ status = "disabled";
+ };
+
i2c: bus@1e78a000 {
compatible = "simple-bus";
#address-cells = <1>;
--
2.17.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox