linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
@ 2017-04-01 22:21 Nicolas Pitre
  2017-04-01 22:21 ` [PATCH v2 1/5] console: move console_init() out of tty_io.c Nicolas Pitre
                   ` (7 more replies)
  0 siblings, 8 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-01 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

Many embedded systems don't need the full TTY layer support. Most of the
time, the TTY layer is only a conduit for outputting debugging messages
over a serial port. The TTY layer also implements many features that are
very unlikely to ever be used in such a setup. There is great potential
for both code and dynamic memory size reduction on small systems. This is
what this patch series is achieving.

The existing TTY code is quite large and complex. Trying to shrink it
is risky as the potential for breakage is non negligeable, and its
interchangeable layers impose a lower limit on the code to implement it.
Therefore, the approach used here consists in the creation of a parallel
implementation with the very minimal amount of code collapsed together
that interfaces with existing UART drivers directly and provides TTY-like
character devices to user space. When the regular TTY layer is disabled,
then this minitty alternative layer is proposed by Kconfig.

For more details on the rationale and motivations driving this approach
please see: https://lkml.org/lkml/2017/3/24/634

Of course, making it "mini" means there are limitations to what it does:

- This supports serial ports only. No VT's, no PTY's.

- The default n_tty line discipline is hardcoded and no other line
  discipline are supported.

- The line discipline features are not all implemented. Notably, XON/XOFF
  is currently not implemented (although this might not require a lot of
  code to do it if someone were to need it).

- Hung-up state is not implemented.

- No error handling on RX bytes other than counting them.

- Job control is currently not supported (this may change in the future and 
  be configurable).

But again, most small embedded systems simply don't need those things.

This can be used on any architecture of course, but here's some numbers
using a minimal ARM config.

When CONFIG_TTY=y, the following files are linked into the kernel:

   text	   data	    bss	    dec	    hex	filename
   8796	    128	      0	   8924	   22dc	drivers/tty/n_tty.o
  11809	    276	      0	  12085	   2f35	drivers/tty/serial/fulltty_serial.o
   1376	      0	      0	   1376	    560	drivers/tty/tty_buffer.o
  13571	    172	    132	  13875	   3633	drivers/tty/tty_io.o
   3072	      0	      0	   3072	    c00	drivers/tty/tty_ioctl.o
   2457	      2	    120	   2579	    a13	drivers/tty/tty_ldisc.o
   1328	      0	      0	   1328	    530	drivers/tty/tty_ldsem.o
    316	      0	      0	    316	    13c	drivers/tty/tty_mutex.o
   2516	      0	      0	   2516	    9d4	drivers/tty/tty_port.o
  45241	    578	    252	  46071	   b3f7	(TOTALS)

When CONFIG_TTY=n and CONFIG_MINITTY_SERIAL=y, the above files are replaced
by the following:

   text	   data	    bss	    dec	    hex	filename
   8063	      8	     64	   8135	   1fc7	drivers/tty/serial/minitty_serial.o

That's it!  And the runtime buffer usage is much less as well. Future plans
such as removing runtime baudrate handling for those targets with a known
fixed baudrate will shrink the code even more.

Changes from v1:

- Added an entry to the MAINTAINERS file.
- Factored out more common core code into serial_lib.c.
- Implemented a few more TTY callback functions to be compatible with
  more UART drivers.

Overall diffstat:

 MAINTAINERS                                     |    8 +-
 drivers/tty/Kconfig                             |   10 +-
 drivers/tty/Makefile                            |    3 +-
 drivers/tty/serial/Kconfig                      |   12 +-
 drivers/tty/serial/Makefile                     |    7 +-
 .../serial/{serial_core.c => fulltty_serial.c}  |  419 +---
 drivers/tty/serial/minitty_serial.c             | 1793 +++++++++++++++++
 drivers/tty/serial/serial_lib.c                 |  440 ++++
 drivers/tty/tty_baudrate.c                      |  232 +++
 drivers/tty/tty_io.c                            |   24 -
 drivers/tty/tty_ioctl.c                         |  222 --
 include/linux/console.h                         |    2 +
 include/linux/serial_core.h                     |    1 +
 include/linux/tty.h                             |    7 +-
 include/linux/tty_flip.h                        |    9 +
 init/main.c                                     |    2 +-
 kernel/printk/printk.c                          |   24 +
 17 files changed, 2538 insertions(+), 677 deletions(-)

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 1/5] console: move console_init() out of tty_io.c
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
@ 2017-04-01 22:21 ` Nicolas Pitre
  2017-04-01 22:21 ` [PATCH v2 2/5] tty: move baudrate handling code to a file of its own Nicolas Pitre
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-01 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

All the console driver handling code lives in printk.c.
Move console_init() there as well so console support can still be used
when the TTY code is configured out.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
 drivers/tty/tty_io.c    | 24 ------------------------
 include/linux/console.h |  2 ++
 include/linux/tty.h     |  7 ++++---
 init/main.c             |  2 +-
 kernel/printk/printk.c  | 24 ++++++++++++++++++++++++
 5 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index e6d1a65108..2100295861 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3578,30 +3578,6 @@ void tty_default_fops(struct file_operations *fops)
 	*fops = tty_fops;
 }
 
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
-	initcall_t *call;
-
-	/* Setup the default TTY line discipline. */
-	n_tty_init();
-
-	/*
-	 * set up the console device so that later boot sequences can
-	 * inform about problems etc..
-	 */
-	call = __con_initcall_start;
-	while (call < __con_initcall_end) {
-		(*call)();
-		call++;
-	}
-}
-
 static char *tty_devnode(struct device *dev, umode_t *mode)
 {
 	if (!mode)
diff --git a/include/linux/console.h b/include/linux/console.h
index 5949d18555..b8920a031a 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -212,4 +212,6 @@ extern bool vgacon_text_force(void);
 static inline bool vgacon_text_force(void) { return false; }
 #endif
 
+extern void console_init(void);
+
 #endif /* _LINUX_CONSOLE_H */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 1017e904c0..f1106d7c73 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -390,7 +390,6 @@ static inline bool tty_throttled(struct tty_struct *tty)
 }
 
 #ifdef CONFIG_TTY
-extern void console_init(void);
 extern void tty_kref_put(struct tty_struct *tty);
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
 extern void tty_vhangup_self(void);
@@ -402,8 +401,6 @@ extern struct tty_struct *get_current_tty(void);
 extern int __init tty_init(void);
 extern const char *tty_name(const struct tty_struct *tty);
 #else
-static inline void console_init(void)
-{ }
 static inline void tty_kref_put(struct tty_struct *tty)
 { }
 static inline struct pid *tty_get_pgrp(struct tty_struct *tty)
@@ -669,7 +666,11 @@ extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
 
 /* n_tty.c */
 extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops);
+#ifdef CONFIG_TTY
 extern void __init n_tty_init(void);
+#else
+static inline void n_tty_init(void) { }
+#endif
 
 /* tty_audit.c */
 #ifdef CONFIG_AUDIT
diff --git a/init/main.c b/init/main.c
index f9c9d99482..b9bd0edf21 100644
--- a/init/main.c
+++ b/init/main.c
@@ -27,7 +27,7 @@
 #include <linux/initrd.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
-#include <linux/tty.h>
+#include <linux/console.h>
 #include <linux/nmi.h>
 #include <linux/percpu.h>
 #include <linux/kmod.h>
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2984fb0f02..3a09406526 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2611,6 +2611,30 @@ int unregister_console(struct console *console)
 EXPORT_SYMBOL(unregister_console);
 
 /*
+ * Initialize the console device. This is called *early*, so
+ * we can't necessarily depend on lots of kernel help here.
+ * Just do some early initializations, and do the complex setup
+ * later.
+ */
+void __init console_init(void)
+{
+	initcall_t *call;
+
+	/* Setup the default TTY line discipline. */
+	n_tty_init();
+
+	/*
+	 * set up the console device so that later boot sequences can
+	 * inform about problems etc..
+	 */
+	call = __con_initcall_start;
+	while (call < __con_initcall_end) {
+		(*call)();
+		call++;
+	}
+}
+
+/*
  * Some boot consoles access data that is in the init section and which will
  * be discarded after the initcalls have been run. To make sure that no code
  * will access this data, unregister the boot consoles in a late initcall.
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 2/5] tty: move baudrate handling code to a file of its own
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
  2017-04-01 22:21 ` [PATCH v2 1/5] console: move console_init() out of tty_io.c Nicolas Pitre
@ 2017-04-01 22:21 ` Nicolas Pitre
  2017-04-01 22:21 ` [PATCH v2 3/5] serial: small Makefile reordering Nicolas Pitre
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-01 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

To allow reuse without the rest of the tty_ioctl code.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
 drivers/tty/Makefile       |   2 +-
 drivers/tty/tty_baudrate.c | 232 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/tty/tty_ioctl.c    | 222 -------------------------------------------
 3 files changed, 233 insertions(+), 223 deletions(-)
 create mode 100644 drivers/tty/tty_baudrate.c

diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index b95bed92da..1461be6b90 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_TTY)		+= tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
-				   tty_buffer.o tty_port.o tty_mutex.o tty_ldsem.o
+				   tty_buffer.o tty_port.o tty_mutex.o tty_ldsem.o tty_baudrate.o
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
 obj-$(CONFIG_AUDIT)		+= tty_audit.o
diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c
new file mode 100644
index 0000000000..5c33fd2567
--- /dev/null
+++ b/drivers/tty/tty_baudrate.c
@@ -0,0 +1,232 @@
+/*
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/export.h>
+
+
+/*
+ * Routine which returns the baud rate of the tty
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
+ */
+static const speed_t baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+	76800, 153600, 307200, 614400, 921600
+#else
+	500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+	2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+#ifndef __sparc__
+static const tcflag_t baud_bits[] = {
+	B0, B50, B75, B110, B134, B150, B200, B300, B600,
+	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+	B57600, B115200, B230400, B460800, B500000, B576000,
+	B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
+	B3000000, B3500000, B4000000
+};
+#else
+static const tcflag_t baud_bits[] = {
+	B0, B50, B75, B110, B134, B150, B200, B300, B600,
+	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+	B57600, B115200, B230400, B460800, B76800, B153600,
+	B307200, B614400, B921600
+};
+#endif
+
+static int n_baud_table = ARRAY_SIZE(baud_table);
+
+/**
+ *	tty_termios_baud_rate
+ *	@termios: termios structure
+ *
+ *	Convert termios baud rate data into a speed. This should be called
+ *	with the termios lock held if this termios is a terminal termios
+ *	structure. May change the termios data. Device drivers can call this
+ *	function but should use ->c_[io]speed directly as they are updated.
+ *
+ *	Locking: none
+ */
+
+speed_t tty_termios_baud_rate(struct ktermios *termios)
+{
+	unsigned int cbaud;
+
+	cbaud = termios->c_cflag & CBAUD;
+
+#ifdef BOTHER
+	/* Magic token for arbitrary speed via c_ispeed/c_ospeed */
+	if (cbaud == BOTHER)
+		return termios->c_ospeed;
+#endif
+	if (cbaud & CBAUDEX) {
+		cbaud &= ~CBAUDEX;
+
+		if (cbaud < 1 || cbaud + 15 > n_baud_table)
+			termios->c_cflag &= ~CBAUDEX;
+		else
+			cbaud += 15;
+	}
+	return baud_table[cbaud];
+}
+EXPORT_SYMBOL(tty_termios_baud_rate);
+
+/**
+ *	tty_termios_input_baud_rate
+ *	@termios: termios structure
+ *
+ *	Convert termios baud rate data into a speed. This should be called
+ *	with the termios lock held if this termios is a terminal termios
+ *	structure. May change the termios data. Device drivers can call this
+ *	function but should use ->c_[io]speed directly as they are updated.
+ *
+ *	Locking: none
+ */
+
+speed_t tty_termios_input_baud_rate(struct ktermios *termios)
+{
+#ifdef IBSHIFT
+	unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
+
+	if (cbaud == B0)
+		return tty_termios_baud_rate(termios);
+
+	/* Magic token for arbitrary speed via c_ispeed*/
+	if (cbaud == BOTHER)
+		return termios->c_ispeed;
+
+	if (cbaud & CBAUDEX) {
+		cbaud &= ~CBAUDEX;
+
+		if (cbaud < 1 || cbaud + 15 > n_baud_table)
+			termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
+		else
+			cbaud += 15;
+	}
+	return baud_table[cbaud];
+#else
+	return tty_termios_baud_rate(termios);
+#endif
+}
+EXPORT_SYMBOL(tty_termios_input_baud_rate);
+
+/**
+ *	tty_termios_encode_baud_rate
+ *	@termios: ktermios structure holding user requested state
+ *	@ispeed: input speed
+ *	@ospeed: output speed
+ *
+ *	Encode the speeds set into the passed termios structure. This is
+ *	used as a library helper for drivers so that they can report back
+ *	the actual speed selected when it differs from the speed requested
+ *
+ *	For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
+ *	we need to carefully set the bits when the user does not get the
+ *	desired speed. We allow small margins and preserve as much of possible
+ *	of the input intent to keep compatibility.
+ *
+ *	Locking: Caller should hold termios lock. This is already held
+ *	when calling this function from the driver termios handler.
+ *
+ *	The ifdefs deal with platforms whose owners have yet to update them
+ *	and will all go away once this is done.
+ */
+
+void tty_termios_encode_baud_rate(struct ktermios *termios,
+				  speed_t ibaud, speed_t obaud)
+{
+	int i = 0;
+	int ifound = -1, ofound = -1;
+	int iclose = ibaud/50, oclose = obaud/50;
+	int ibinput = 0;
+
+	if (obaud == 0)			/* CD dropped 		  */
+		ibaud = 0;		/* Clear ibaud to be sure */
+
+	termios->c_ispeed = ibaud;
+	termios->c_ospeed = obaud;
+
+#ifdef BOTHER
+	/* If the user asked for a precise weird speed give a precise weird
+	   answer. If they asked for a Bfoo speed they may have problems
+	   digesting non-exact replies so fuzz a bit */
+
+	if ((termios->c_cflag & CBAUD) == BOTHER)
+		oclose = 0;
+	if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
+		iclose = 0;
+	if ((termios->c_cflag >> IBSHIFT) & CBAUD)
+		ibinput = 1;	/* An input speed was specified */
+#endif
+	termios->c_cflag &= ~CBAUD;
+
+	/*
+	 *	Our goal is to find a close match to the standard baud rate
+	 *	returned. Walk the baud rate table and if we get a very close
+	 *	match then report back the speed as a POSIX Bxxxx value by
+	 *	preference
+	 */
+
+	do {
+		if (obaud - oclose <= baud_table[i] &&
+		    obaud + oclose >= baud_table[i]) {
+			termios->c_cflag |= baud_bits[i];
+			ofound = i;
+		}
+		if (ibaud - iclose <= baud_table[i] &&
+		    ibaud + iclose >= baud_table[i]) {
+			/* For the case input == output don't set IBAUD bits
+			   if the user didn't do so */
+			if (ofound == i && !ibinput)
+				ifound  = i;
+#ifdef IBSHIFT
+			else {
+				ifound = i;
+				termios->c_cflag |= (baud_bits[i] << IBSHIFT);
+			}
+#endif
+		}
+	} while (++i < n_baud_table);
+
+	/*
+	 *	If we found no match then use BOTHER if provided or warn
+	 *	the user their platform maintainer needs to wake up if not.
+	 */
+#ifdef BOTHER
+	if (ofound == -1)
+		termios->c_cflag |= BOTHER;
+	/* Set exact input bits only if the input and output differ or the
+	   user already did */
+	if (ifound == -1 && (ibaud != obaud || ibinput))
+		termios->c_cflag |= (BOTHER << IBSHIFT);
+#else
+	if (ifound == -1 || ofound == -1)
+		pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n");
+#endif
+}
+EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
+
+/**
+ *	tty_encode_baud_rate		-	set baud rate of the tty
+ *	@ibaud: input baud rate
+ *	@obad: output baud rate
+ *
+ *	Update the current termios data for the tty with the new speed
+ *	settings. The caller must hold the termios_rwsem for the tty in
+ *	question.
+ */
+
+void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
+{
+	tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
+}
+EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index a9a978731c..efa96e6c4c 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -258,228 +258,6 @@ static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
 	/* FIXME: What should we do for i/ospeed */
 }
 
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static const speed_t baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
-	76800, 153600, 307200, 614400, 921600
-#else
-	500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
-	2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-#ifndef __sparc__
-static const tcflag_t baud_bits[] = {
-	B0, B50, B75, B110, B134, B150, B200, B300, B600,
-	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-	B57600, B115200, B230400, B460800, B500000, B576000,
-	B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
-	B3000000, B3500000, B4000000
-};
-#else
-static const tcflag_t baud_bits[] = {
-	B0, B50, B75, B110, B134, B150, B200, B300, B600,
-	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-	B57600, B115200, B230400, B460800, B76800, B153600,
-	B307200, B614400, B921600
-};
-#endif
-
-static int n_baud_table = ARRAY_SIZE(baud_table);
-
-/**
- *	tty_termios_baud_rate
- *	@termios: termios structure
- *
- *	Convert termios baud rate data into a speed. This should be called
- *	with the termios lock held if this termios is a terminal termios
- *	structure. May change the termios data. Device drivers can call this
- *	function but should use ->c_[io]speed directly as they are updated.
- *
- *	Locking: none
- */
-
-speed_t tty_termios_baud_rate(struct ktermios *termios)
-{
-	unsigned int cbaud;
-
-	cbaud = termios->c_cflag & CBAUD;
-
-#ifdef BOTHER
-	/* Magic token for arbitrary speed via c_ispeed/c_ospeed */
-	if (cbaud == BOTHER)
-		return termios->c_ospeed;
-#endif
-	if (cbaud & CBAUDEX) {
-		cbaud &= ~CBAUDEX;
-
-		if (cbaud < 1 || cbaud + 15 > n_baud_table)
-			termios->c_cflag &= ~CBAUDEX;
-		else
-			cbaud += 15;
-	}
-	return baud_table[cbaud];
-}
-EXPORT_SYMBOL(tty_termios_baud_rate);
-
-/**
- *	tty_termios_input_baud_rate
- *	@termios: termios structure
- *
- *	Convert termios baud rate data into a speed. This should be called
- *	with the termios lock held if this termios is a terminal termios
- *	structure. May change the termios data. Device drivers can call this
- *	function but should use ->c_[io]speed directly as they are updated.
- *
- *	Locking: none
- */
-
-speed_t tty_termios_input_baud_rate(struct ktermios *termios)
-{
-#ifdef IBSHIFT
-	unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
-
-	if (cbaud == B0)
-		return tty_termios_baud_rate(termios);
-
-	/* Magic token for arbitrary speed via c_ispeed*/
-	if (cbaud == BOTHER)
-		return termios->c_ispeed;
-
-	if (cbaud & CBAUDEX) {
-		cbaud &= ~CBAUDEX;
-
-		if (cbaud < 1 || cbaud + 15 > n_baud_table)
-			termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
-		else
-			cbaud += 15;
-	}
-	return baud_table[cbaud];
-#else
-	return tty_termios_baud_rate(termios);
-#endif
-}
-EXPORT_SYMBOL(tty_termios_input_baud_rate);
-
-/**
- *	tty_termios_encode_baud_rate
- *	@termios: ktermios structure holding user requested state
- *	@ispeed: input speed
- *	@ospeed: output speed
- *
- *	Encode the speeds set into the passed termios structure. This is
- *	used as a library helper for drivers so that they can report back
- *	the actual speed selected when it differs from the speed requested
- *
- *	For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
- *	we need to carefully set the bits when the user does not get the
- *	desired speed. We allow small margins and preserve as much of possible
- *	of the input intent to keep compatibility.
- *
- *	Locking: Caller should hold termios lock. This is already held
- *	when calling this function from the driver termios handler.
- *
- *	The ifdefs deal with platforms whose owners have yet to update them
- *	and will all go away once this is done.
- */
-
-void tty_termios_encode_baud_rate(struct ktermios *termios,
-				  speed_t ibaud, speed_t obaud)
-{
-	int i = 0;
-	int ifound = -1, ofound = -1;
-	int iclose = ibaud/50, oclose = obaud/50;
-	int ibinput = 0;
-
-	if (obaud == 0)			/* CD dropped 		  */
-		ibaud = 0;		/* Clear ibaud to be sure */
-
-	termios->c_ispeed = ibaud;
-	termios->c_ospeed = obaud;
-
-#ifdef BOTHER
-	/* If the user asked for a precise weird speed give a precise weird
-	   answer. If they asked for a Bfoo speed they may have problems
-	   digesting non-exact replies so fuzz a bit */
-
-	if ((termios->c_cflag & CBAUD) == BOTHER)
-		oclose = 0;
-	if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
-		iclose = 0;
-	if ((termios->c_cflag >> IBSHIFT) & CBAUD)
-		ibinput = 1;	/* An input speed was specified */
-#endif
-	termios->c_cflag &= ~CBAUD;
-
-	/*
-	 *	Our goal is to find a close match to the standard baud rate
-	 *	returned. Walk the baud rate table and if we get a very close
-	 *	match then report back the speed as a POSIX Bxxxx value by
-	 *	preference
-	 */
-
-	do {
-		if (obaud - oclose <= baud_table[i] &&
-		    obaud + oclose >= baud_table[i]) {
-			termios->c_cflag |= baud_bits[i];
-			ofound = i;
-		}
-		if (ibaud - iclose <= baud_table[i] &&
-		    ibaud + iclose >= baud_table[i]) {
-			/* For the case input == output don't set IBAUD bits
-			   if the user didn't do so */
-			if (ofound == i && !ibinput)
-				ifound  = i;
-#ifdef IBSHIFT
-			else {
-				ifound = i;
-				termios->c_cflag |= (baud_bits[i] << IBSHIFT);
-			}
-#endif
-		}
-	} while (++i < n_baud_table);
-
-	/*
-	 *	If we found no match then use BOTHER if provided or warn
-	 *	the user their platform maintainer needs to wake up if not.
-	 */
-#ifdef BOTHER
-	if (ofound == -1)
-		termios->c_cflag |= BOTHER;
-	/* Set exact input bits only if the input and output differ or the
-	   user already did */
-	if (ifound == -1 && (ibaud != obaud || ibinput))
-		termios->c_cflag |= (BOTHER << IBSHIFT);
-#else
-	if (ifound == -1 || ofound == -1)
-		pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n");
-#endif
-}
-EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
-
-/**
- *	tty_encode_baud_rate		-	set baud rate of the tty
- *	@ibaud: input baud rate
- *	@obad: output baud rate
- *
- *	Update the current termios data for the tty with the new speed
- *	settings. The caller must hold the termios_rwsem for the tty in
- *	question.
- */
-
-void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
-{
-	tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
-}
-EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
-
 /**
  *	tty_termios_copy_hw	-	copy hardware settings
  *	@new: New termios
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 3/5] serial: small Makefile reordering
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
  2017-04-01 22:21 ` [PATCH v2 1/5] console: move console_init() out of tty_io.c Nicolas Pitre
  2017-04-01 22:21 ` [PATCH v2 2/5] tty: move baudrate handling code to a file of its own Nicolas Pitre
@ 2017-04-01 22:21 ` Nicolas Pitre
  2017-04-02 12:55   ` Andy Shevchenko
  2017-04-01 22:21 ` [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file Nicolas Pitre
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-01 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

Move 21285 entry down alongside other UART drivers to be more consistent
with the rest of the file. It is kept before 8250 though, to preserve the
existing link ordering between those two.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
 drivers/tty/serial/Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 2d6288bc45..53c03e0051 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -3,7 +3,6 @@
 #
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
-obj-$(CONFIG_SERIAL_21285) += 21285.o
 
 obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
 obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
@@ -17,6 +16,8 @@ obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
 obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
 obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
 
+obj-$(CONFIG_SERIAL_21285) += 21285.o
+
 # Now bring in any enabled 8250/16450/16550 type drivers.
 obj-$(CONFIG_SERIAL_8250) += 8250/
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
                   ` (2 preceding siblings ...)
  2017-04-01 22:21 ` [PATCH v2 3/5] serial: small Makefile reordering Nicolas Pitre
@ 2017-04-01 22:21 ` Nicolas Pitre
  2017-04-02 13:16   ` Andy Shevchenko
  2017-04-03  7:35   ` kbuild test robot
  2017-04-01 22:21 ` [PATCH v2 5/5] minitty: minimal TTY support alternative for serial ports Nicolas Pitre
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-01 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

This contains code that is common between serial_core.c and the
minitty code to come. Mainly helper functions used by UART drivers.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
 drivers/tty/serial/Makefile      |   2 +-
 drivers/tty/serial/serial_core.c | 419 +------------------------------------
 drivers/tty/serial/serial_lib.c  | 440 +++++++++++++++++++++++++++++++++++++++
 include/linux/serial_core.h      |   1 +
 4 files changed, 443 insertions(+), 419 deletions(-)
 create mode 100644 drivers/tty/serial/serial_lib.c

diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 53c03e0051..073afd10c5 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the kernel serial device drivers.
 #
 
-obj-$(CONFIG_SERIAL_CORE) += serial_core.o
+obj-$(CONFIG_SERIAL_CORE) += serial_core.o serial_lib.o
 
 obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
 obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 3fe5689497..20214e1d87 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -44,12 +44,6 @@
  */
 static DEFINE_MUTEX(port_mutex);
 
-/*
- * lockdep: port->lock is initialized in two places, but we
- *          want only one lock-class:
- */
-static struct lock_class_key port_lock_key;
-
 #define HIGH_BITS_OFFSET	((sizeof(long)-sizeof(int))*8)
 
 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
@@ -293,183 +287,6 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
 	}
 }
 
-/**
- *	uart_update_timeout - update per-port FIFO timeout.
- *	@port:  uart_port structure describing the port
- *	@cflag: termios cflag value
- *	@baud:  speed of the port
- *
- *	Set the port FIFO timeout value.  The @cflag value should
- *	reflect the actual hardware settings.
- */
-void
-uart_update_timeout(struct uart_port *port, unsigned int cflag,
-		    unsigned int baud)
-{
-	unsigned int bits;
-
-	/* byte size and parity */
-	switch (cflag & CSIZE) {
-	case CS5:
-		bits = 7;
-		break;
-	case CS6:
-		bits = 8;
-		break;
-	case CS7:
-		bits = 9;
-		break;
-	default:
-		bits = 10;
-		break; /* CS8 */
-	}
-
-	if (cflag & CSTOPB)
-		bits++;
-	if (cflag & PARENB)
-		bits++;
-
-	/*
-	 * The total number of bits to be transmitted in the fifo.
-	 */
-	bits = bits * port->fifosize;
-
-	/*
-	 * Figure the timeout to send the above number of bits.
-	 * Add .02 seconds of slop
-	 */
-	port->timeout = (HZ * bits) / baud + HZ/50;
-}
-
-EXPORT_SYMBOL(uart_update_timeout);
-
-/**
- *	uart_get_baud_rate - return baud rate for a particular port
- *	@port: uart_port structure describing the port in question.
- *	@termios: desired termios settings.
- *	@old: old termios (or NULL)
- *	@min: minimum acceptable baud rate
- *	@max: maximum acceptable baud rate
- *
- *	Decode the termios structure into a numeric baud rate,
- *	taking account of the magic 38400 baud rate (with spd_*
- *	flags), and mapping the %B0 rate to 9600 baud.
- *
- *	If the new baud rate is invalid, try the old termios setting.
- *	If it's still invalid, we try 9600 baud.
- *
- *	Update the @termios structure to reflect the baud rate
- *	we're actually going to be using. Don't do this for the case
- *	where B0 is requested ("hang up").
- */
-unsigned int
-uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
-		   struct ktermios *old, unsigned int min, unsigned int max)
-{
-	unsigned int try;
-	unsigned int baud;
-	unsigned int altbaud;
-	int hung_up = 0;
-	upf_t flags = port->flags & UPF_SPD_MASK;
-
-	switch (flags) {
-	case UPF_SPD_HI:
-		altbaud = 57600;
-		break;
-	case UPF_SPD_VHI:
-		altbaud = 115200;
-		break;
-	case UPF_SPD_SHI:
-		altbaud = 230400;
-		break;
-	case UPF_SPD_WARP:
-		altbaud = 460800;
-		break;
-	default:
-		altbaud = 38400;
-		break;
-	}
-
-	for (try = 0; try < 2; try++) {
-		baud = tty_termios_baud_rate(termios);
-
-		/*
-		 * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
-		 * Die! Die! Die!
-		 */
-		if (try == 0 && baud == 38400)
-			baud = altbaud;
-
-		/*
-		 * Special case: B0 rate.
-		 */
-		if (baud == 0) {
-			hung_up = 1;
-			baud = 9600;
-		}
-
-		if (baud >= min && baud <= max)
-			return baud;
-
-		/*
-		 * Oops, the quotient was zero.  Try again with
-		 * the old baud rate if possible.
-		 */
-		termios->c_cflag &= ~CBAUD;
-		if (old) {
-			baud = tty_termios_baud_rate(old);
-			if (!hung_up)
-				tty_termios_encode_baud_rate(termios,
-								baud, baud);
-			old = NULL;
-			continue;
-		}
-
-		/*
-		 * As a last resort, if the range cannot be met then clip to
-		 * the nearest chip supported rate.
-		 */
-		if (!hung_up) {
-			if (baud <= min)
-				tty_termios_encode_baud_rate(termios,
-							min + 1, min + 1);
-			else
-				tty_termios_encode_baud_rate(termios,
-							max - 1, max - 1);
-		}
-	}
-	/* Should never happen */
-	WARN_ON(1);
-	return 0;
-}
-
-EXPORT_SYMBOL(uart_get_baud_rate);
-
-/**
- *	uart_get_divisor - return uart clock divisor
- *	@port: uart_port structure describing the port.
- *	@baud: desired baud rate
- *
- *	Calculate the uart clock divisor for the port.
- */
-unsigned int
-uart_get_divisor(struct uart_port *port, unsigned int baud)
-{
-	unsigned int quot;
-
-	/*
-	 * Old custom speed handling.
-	 */
-	if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
-		quot = port->custom_divisor;
-	else
-		quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
-
-	return quot;
-}
-
-EXPORT_SYMBOL(uart_get_divisor);
-
 /* Caller holds port mutex */
 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
 					struct ktermios *old_termios)
@@ -1837,207 +1654,6 @@ static const struct file_operations uart_proc_fops = {
 };
 #endif
 
-#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
-/**
- *	uart_console_write - write a console message to a serial port
- *	@port: the port to write the message
- *	@s: array of characters
- *	@count: number of characters in string to write
- *	@putchar: function to write character to port
- */
-void uart_console_write(struct uart_port *port, const char *s,
-			unsigned int count,
-			void (*putchar)(struct uart_port *, int))
-{
-	unsigned int i;
-
-	for (i = 0; i < count; i++, s++) {
-		if (*s == '\n')
-			putchar(port, '\r');
-		putchar(port, *s);
-	}
-}
-EXPORT_SYMBOL_GPL(uart_console_write);
-
-/*
- *	Check whether an invalid uart number has been specified, and
- *	if so, search for the first available port that does have
- *	console support.
- */
-struct uart_port * __init
-uart_get_console(struct uart_port *ports, int nr, struct console *co)
-{
-	int idx = co->index;
-
-	if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
-				     ports[idx].membase == NULL))
-		for (idx = 0; idx < nr; idx++)
-			if (ports[idx].iobase != 0 ||
-			    ports[idx].membase != NULL)
-				break;
-
-	co->index = idx;
-
-	return ports + idx;
-}
-
-/**
- *	uart_parse_earlycon - Parse earlycon options
- *	@p:	  ptr to 2nd field (ie., just beyond '<name>,')
- *	@iotype:  ptr for decoded iotype (out)
- *	@addr:    ptr for decoded mapbase/iobase (out)
- *	@options: ptr for <options> field; NULL if not present (out)
- *
- *	Decodes earlycon kernel command line parameters of the form
- *	   earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
- *	   console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
- *
- *	The optional form
- *	   earlycon=<name>,0x<addr>,<options>
- *	   console=<name>,0x<addr>,<options>
- *	is also accepted; the returned @iotype will be UPIO_MEM.
- *
- *	Returns 0 on success or -EINVAL on failure
- */
-int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
-			char **options)
-{
-	if (strncmp(p, "mmio,", 5) == 0) {
-		*iotype = UPIO_MEM;
-		p += 5;
-	} else if (strncmp(p, "mmio16,", 7) == 0) {
-		*iotype = UPIO_MEM16;
-		p += 7;
-	} else if (strncmp(p, "mmio32,", 7) == 0) {
-		*iotype = UPIO_MEM32;
-		p += 7;
-	} else if (strncmp(p, "mmio32be,", 9) == 0) {
-		*iotype = UPIO_MEM32BE;
-		p += 9;
-	} else if (strncmp(p, "mmio32native,", 13) == 0) {
-		*iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
-			UPIO_MEM32BE : UPIO_MEM32;
-		p += 13;
-	} else if (strncmp(p, "io,", 3) == 0) {
-		*iotype = UPIO_PORT;
-		p += 3;
-	} else if (strncmp(p, "0x", 2) == 0) {
-		*iotype = UPIO_MEM;
-	} else {
-		return -EINVAL;
-	}
-
-	/*
-	 * Before you replace it with kstrtoull(), think about options separator
-	 * (',') it will not tolerate
-	 */
-	*addr = simple_strtoull(p, NULL, 0);
-	p = strchr(p, ',');
-	if (p)
-		p++;
-
-	*options = p;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(uart_parse_earlycon);
-
-/**
- *	uart_parse_options - Parse serial port baud/parity/bits/flow control.
- *	@options: pointer to option string
- *	@baud: pointer to an 'int' variable for the baud rate.
- *	@parity: pointer to an 'int' variable for the parity.
- *	@bits: pointer to an 'int' variable for the number of data bits.
- *	@flow: pointer to an 'int' variable for the flow control character.
- *
- *	uart_parse_options decodes a string containing the serial console
- *	options.  The format of the string is <baud><parity><bits><flow>,
- *	eg: 115200n8r
- */
-void
-uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
-{
-	char *s = options;
-
-	*baud = simple_strtoul(s, NULL, 10);
-	while (*s >= '0' && *s <= '9')
-		s++;
-	if (*s)
-		*parity = *s++;
-	if (*s)
-		*bits = *s++ - '0';
-	if (*s)
-		*flow = *s;
-}
-EXPORT_SYMBOL_GPL(uart_parse_options);
-
-/**
- *	uart_set_options - setup the serial console parameters
- *	@port: pointer to the serial ports uart_port structure
- *	@co: console pointer
- *	@baud: baud rate
- *	@parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
- *	@bits: number of data bits
- *	@flow: flow control character - 'r' (rts)
- */
-int
-uart_set_options(struct uart_port *port, struct console *co,
-		 int baud, int parity, int bits, int flow)
-{
-	struct ktermios termios;
-	static struct ktermios dummy;
-
-	/*
-	 * Ensure that the serial console lock is initialised
-	 * early.
-	 * If this port is a console, then the spinlock is already
-	 * initialised.
-	 */
-	if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
-		spin_lock_init(&port->lock);
-		lockdep_set_class(&port->lock, &port_lock_key);
-	}
-
-	memset(&termios, 0, sizeof(struct ktermios));
-
-	termios.c_cflag |= CREAD | HUPCL | CLOCAL;
-	tty_termios_encode_baud_rate(&termios, baud, baud);
-
-	if (bits == 7)
-		termios.c_cflag |= CS7;
-	else
-		termios.c_cflag |= CS8;
-
-	switch (parity) {
-	case 'o': case 'O':
-		termios.c_cflag |= PARODD;
-		/*fall through*/
-	case 'e': case 'E':
-		termios.c_cflag |= PARENB;
-		break;
-	}
-
-	if (flow == 'r')
-		termios.c_cflag |= CRTSCTS;
-
-	/*
-	 * some uarts on other side don't support no flow control.
-	 * So we set * DTR in host uart to make them happy
-	 */
-	port->mctrl |= TIOCM_DTR;
-
-	port->ops->set_termios(port, &termios, &dummy);
-	/*
-	 * Allow the setting of the UART parameters with a NULL console
-	 * too:
-	 */
-	if (co)
-		co->cflag = termios.c_cflag;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(uart_set_options);
-#endif /* CONFIG_SERIAL_CORE_CONSOLE */
-
 /**
  * uart_change_pm - set power state of the port
  *
@@ -2751,15 +2367,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
 	state->pm_state = UART_PM_STATE_UNDEFINED;
 	uport->cons = drv->cons;
 	uport->minor = drv->tty_driver->minor_start + uport->line;
+	uart_port_lock_init(uport);
 
-	/*
-	 * If this port is a console, then the spinlock is already
-	 * initialised.
-	 */
-	if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
-		spin_lock_init(&uport->lock);
-		lockdep_set_class(&uport->lock, &port_lock_key);
-	}
 	if (uport->cons && uport->dev)
 		of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
 
@@ -2885,32 +2494,6 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
 	return ret;
 }
 
-/*
- *	Are the two ports equivalent?
- */
-int uart_match_port(struct uart_port *port1, struct uart_port *port2)
-{
-	if (port1->iotype != port2->iotype)
-		return 0;
-
-	switch (port1->iotype) {
-	case UPIO_PORT:
-		return (port1->iobase == port2->iobase);
-	case UPIO_HUB6:
-		return (port1->iobase == port2->iobase) &&
-		       (port1->hub6   == port2->hub6);
-	case UPIO_MEM:
-	case UPIO_MEM16:
-	case UPIO_MEM32:
-	case UPIO_MEM32BE:
-	case UPIO_AU:
-	case UPIO_TSI:
-		return (port1->mapbase == port2->mapbase);
-	}
-	return 0;
-}
-EXPORT_SYMBOL(uart_match_port);
-
 /**
  *	uart_handle_dcd_change - handle a change of carrier detect state
  *	@uport: uart_port structure for the open port
diff --git a/drivers/tty/serial/serial_lib.c b/drivers/tty/serial/serial_lib.c
new file mode 100644
index 0000000000..c3f521b401
--- /dev/null
+++ b/drivers/tty/serial/serial_lib.c
@@ -0,0 +1,440 @@
+/*
+ *  Common support functions for serial port drivers
+ *
+ *  Copyright 1999 ARM Limited
+ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/export.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+
+/*
+ * lockdep: port->lock is initialized in two places, but we
+ *          want only one lock-class:
+ */
+static struct lock_class_key port_lock_key;
+
+void uart_port_lock_init(struct uart_port *port)
+{
+	/*
+	 * If this port is a console, then the spinlock is already
+	 * initialised.
+	 */
+	if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
+		spin_lock_init(&port->lock);
+		lockdep_set_class(&port->lock, &port_lock_key);
+	}
+}
+
+/**
+ *	uart_update_timeout - update per-port FIFO timeout.
+ *	@port:  uart_port structure describing the port
+ *	@cflag: termios cflag value
+ *	@baud:  speed of the port
+ *
+ *	Set the port FIFO timeout value.  The @cflag value should
+ *	reflect the actual hardware settings.
+ */
+void
+uart_update_timeout(struct uart_port *port, unsigned int cflag,
+		    unsigned int baud)
+{
+	unsigned int bits;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	case CS5:
+		bits = 7;
+		break;
+	case CS6:
+		bits = 8;
+		break;
+	case CS7:
+		bits = 9;
+		break;
+	default:
+		bits = 10;
+		break; /* CS8 */
+	}
+
+	if (cflag & CSTOPB)
+		bits++;
+	if (cflag & PARENB)
+		bits++;
+
+	/*
+	 * The total number of bits to be transmitted in the fifo.
+	 */
+	bits = bits * port->fifosize;
+
+	/*
+	 * Figure the timeout to send the above number of bits.
+	 * Add .02 seconds of slop
+	 */
+	port->timeout = (HZ * bits) / baud + HZ/50;
+}
+EXPORT_SYMBOL(uart_update_timeout);
+
+/**
+ *	uart_get_baud_rate - return baud rate for a particular port
+ *	@port: uart_port structure describing the port in question.
+ *	@termios: desired termios settings.
+ *	@old: old termios (or NULL)
+ *	@min: minimum acceptable baud rate
+ *	@max: maximum acceptable baud rate
+ *
+ *	Decode the termios structure into a numeric baud rate,
+ *	taking account of the magic 38400 baud rate (with spd_*
+ *	flags), and mapping the %B0 rate to 9600 baud.
+ *
+ *	If the new baud rate is invalid, try the old termios setting.
+ *	If it's still invalid, we try 9600 baud.
+ *
+ *	Update the @termios structure to reflect the baud rate
+ *	we're actually going to be using. Don't do this for the case
+ *	where B0 is requested ("hang up").
+ */
+unsigned int
+uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+		   struct ktermios *old, unsigned int min, unsigned int max)
+{
+	unsigned int try;
+	unsigned int baud;
+	unsigned int altbaud;
+	int hung_up = 0;
+	upf_t flags = port->flags & UPF_SPD_MASK;
+
+	switch (flags) {
+	case UPF_SPD_HI:
+		altbaud = 57600;
+		break;
+	case UPF_SPD_VHI:
+		altbaud = 115200;
+		break;
+	case UPF_SPD_SHI:
+		altbaud = 230400;
+		break;
+	case UPF_SPD_WARP:
+		altbaud = 460800;
+		break;
+	default:
+		altbaud = 38400;
+		break;
+	}
+
+	for (try = 0; try < 2; try++) {
+		baud = tty_termios_baud_rate(termios);
+
+		/*
+		 * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
+		 * Die! Die! Die!
+		 */
+		if (try == 0 && baud == 38400)
+			baud = altbaud;
+
+		/*
+		 * Special case: B0 rate.
+		 */
+		if (baud == 0) {
+			hung_up = 1;
+			baud = 9600;
+		}
+
+		if (baud >= min && baud <= max)
+			return baud;
+
+		/*
+		 * Oops, the quotient was zero.  Try again with
+		 * the old baud rate if possible.
+		 */
+		termios->c_cflag &= ~CBAUD;
+		if (old) {
+			baud = tty_termios_baud_rate(old);
+			if (!hung_up)
+				tty_termios_encode_baud_rate(termios,
+								baud, baud);
+			old = NULL;
+			continue;
+		}
+
+		/*
+		 * As a last resort, if the range cannot be met then clip to
+		 * the nearest chip supported rate.
+		 */
+		if (!hung_up) {
+			if (baud <= min)
+				tty_termios_encode_baud_rate(termios,
+							min + 1, min + 1);
+			else
+				tty_termios_encode_baud_rate(termios,
+							max - 1, max - 1);
+		}
+	}
+	/* Should never happen */
+	WARN_ON(1);
+	return 0;
+}
+EXPORT_SYMBOL(uart_get_baud_rate);
+
+/**
+ *	uart_get_divisor - return uart clock divisor
+ *	@port: uart_port structure describing the port.
+ *	@baud: desired baud rate
+ *
+ *	Calculate the uart clock divisor for the port.
+ */
+unsigned int
+uart_get_divisor(struct uart_port *port, unsigned int baud)
+{
+	unsigned int quot;
+
+	/*
+	 * Old custom speed handling.
+	 */
+	if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+		quot = port->custom_divisor;
+	else
+		quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
+
+	return quot;
+}
+EXPORT_SYMBOL(uart_get_divisor);
+
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
+/**
+ *	uart_console_write - write a console message to a serial port
+ *	@port: the port to write the message
+ *	@s: array of characters
+ *	@count: number of characters in string to write
+ *	@putchar: function to write character to port
+ */
+void uart_console_write(struct uart_port *port, const char *s,
+			unsigned int count,
+			void (*putchar)(struct uart_port *, int))
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++, s++) {
+		if (*s == '\n')
+			putchar(port, '\r');
+		putchar(port, *s);
+	}
+}
+EXPORT_SYMBOL_GPL(uart_console_write);
+
+/*
+ *	Check whether an invalid uart number has been specified, and
+ *	if so, search for the first available port that does have
+ *	console support.
+ */
+struct uart_port * __init
+uart_get_console(struct uart_port *ports, int nr, struct console *co)
+{
+	int idx = co->index;
+
+	if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
+				     ports[idx].membase == NULL))
+		for (idx = 0; idx < nr; idx++)
+			if (ports[idx].iobase != 0 ||
+			    ports[idx].membase != NULL)
+				break;
+
+	co->index = idx;
+
+	return ports + idx;
+}
+
+/**
+ *	uart_parse_earlycon - Parse earlycon options
+ *	@p:	  ptr to 2nd field (ie., just beyond '<name>,')
+ *	@iotype:  ptr for decoded iotype (out)
+ *	@addr:    ptr for decoded mapbase/iobase (out)
+ *	@options: ptr for <options> field; NULL if not present (out)
+ *
+ *	Decodes earlycon kernel command line parameters of the form
+ *	   earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
+ *	   console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
+ *
+ *	The optional form
+ *	   earlycon=<name>,0x<addr>,<options>
+ *	   console=<name>,0x<addr>,<options>
+ *	is also accepted; the returned @iotype will be UPIO_MEM.
+ *
+ *	Returns 0 on success or -EINVAL on failure
+ */
+int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
+			char **options)
+{
+	if (strncmp(p, "mmio,", 5) == 0) {
+		*iotype = UPIO_MEM;
+		p += 5;
+	} else if (strncmp(p, "mmio16,", 7) == 0) {
+		*iotype = UPIO_MEM16;
+		p += 7;
+	} else if (strncmp(p, "mmio32,", 7) == 0) {
+		*iotype = UPIO_MEM32;
+		p += 7;
+	} else if (strncmp(p, "mmio32be,", 9) == 0) {
+		*iotype = UPIO_MEM32BE;
+		p += 9;
+	} else if (strncmp(p, "mmio32native,", 13) == 0) {
+		*iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
+			UPIO_MEM32BE : UPIO_MEM32;
+		p += 13;
+	} else if (strncmp(p, "io,", 3) == 0) {
+		*iotype = UPIO_PORT;
+		p += 3;
+	} else if (strncmp(p, "0x", 2) == 0) {
+		*iotype = UPIO_MEM;
+	} else {
+		return -EINVAL;
+	}
+
+	/*
+	 * Before you replace it with kstrtoull(), think about options separator
+	 * (',') it will not tolerate
+	 */
+	*addr = simple_strtoull(p, NULL, 0);
+	p = strchr(p, ',');
+	if (p)
+		p++;
+
+	*options = p;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(uart_parse_earlycon);
+
+/**
+ *	uart_parse_options - Parse serial port baud/parity/bits/flow control.
+ *	@options: pointer to option string
+ *	@baud: pointer to an 'int' variable for the baud rate.
+ *	@parity: pointer to an 'int' variable for the parity.
+ *	@bits: pointer to an 'int' variable for the number of data bits.
+ *	@flow: pointer to an 'int' variable for the flow control character.
+ *
+ *	uart_parse_options decodes a string containing the serial console
+ *	options.  The format of the string is <baud><parity><bits><flow>,
+ *	eg: 115200n8r
+ */
+void
+uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
+{
+	char *s = options;
+
+	*baud = simple_strtoul(s, NULL, 10);
+	while (*s >= '0' && *s <= '9')
+		s++;
+	if (*s)
+		*parity = *s++;
+	if (*s)
+		*bits = *s++ - '0';
+	if (*s)
+		*flow = *s;
+}
+EXPORT_SYMBOL_GPL(uart_parse_options);
+
+/**
+ *	uart_set_options - setup the serial console parameters
+ *	@port: pointer to the serial ports uart_port structure
+ *	@co: console pointer
+ *	@baud: baud rate
+ *	@parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
+ *	@bits: number of data bits
+ *	@flow: flow control character - 'r' (rts)
+ */
+int
+uart_set_options(struct uart_port *port, struct console *co,
+		 int baud, int parity, int bits, int flow)
+{
+	struct ktermios termios;
+	static struct ktermios dummy;
+
+	/*
+	 * Ensure that the serial console lock is initialised
+	 * early.
+	 */
+	uart_port_lock_init(port);
+
+	memset(&termios, 0, sizeof(struct ktermios));
+
+	termios.c_cflag |= CREAD | HUPCL | CLOCAL;
+	tty_termios_encode_baud_rate(&termios, baud, baud);
+
+	if (bits == 7)
+		termios.c_cflag |= CS7;
+	else
+		termios.c_cflag |= CS8;
+
+	switch (parity) {
+	case 'o': case 'O':
+		termios.c_cflag |= PARODD;
+		/*fall through*/
+	case 'e': case 'E':
+		termios.c_cflag |= PARENB;
+		break;
+	}
+
+	if (flow == 'r')
+		termios.c_cflag |= CRTSCTS;
+
+	/*
+	 * some uarts on other side don't support no flow control.
+	 * So we set * DTR in host uart to make them happy
+	 */
+	port->mctrl |= TIOCM_DTR;
+
+	port->ops->set_termios(port, &termios, &dummy);
+	/*
+	 * Allow the setting of the UART parameters with a NULL console
+	 * too:
+	 */
+	if (co)
+		co->cflag = termios.c_cflag;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(uart_set_options);
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+
+/*
+ *	Are the two ports equivalent?
+ */
+int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+{
+	if (port1->iotype != port2->iotype)
+		return 0;
+
+	switch (port1->iotype) {
+	case UPIO_PORT:
+		return (port1->iobase == port2->iobase);
+	case UPIO_HUB6:
+		return (port1->iobase == port2->iobase) &&
+		       (port1->hub6   == port2->hub6);
+	case UPIO_MEM:
+	case UPIO_MEM16:
+	case UPIO_MEM32:
+	case UPIO_MEM32BE:
+	case UPIO_AU:
+	case UPIO_TSI:
+		return (port1->mapbase == port2->mapbase);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(uart_match_port);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 58484fb35c..505b51db59 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -402,6 +402,7 @@ void uart_unregister_driver(struct uart_driver *uart);
 int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
 int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
 int uart_match_port(struct uart_port *port1, struct uart_port *port2);
+void uart_port_lock_init(struct uart_port *port);
 
 /*
  * Power Management
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 5/5] minitty: minimal TTY support alternative for serial ports
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
                   ` (3 preceding siblings ...)
  2017-04-01 22:21 ` [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file Nicolas Pitre
@ 2017-04-01 22:21 ` Nicolas Pitre
  2017-04-02 13:22 ` [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Andy Shevchenko
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-01 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

This is a minimal TTY layer alternative for embedded systems with limited
capabilities. This supports only serial ports, supports only a subset of
the default line discipline, and dispense with anything that is of no use
for a small embedded system.

The goal here is to minimize memory footprint. The code size is more than 5x
smaller than the regular code providing the same functionalities. Runtime
memory usage is greatly reduced as well.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
 MAINTAINERS                                        |    8 +-
 drivers/tty/Kconfig                                |   10 +-
 drivers/tty/Makefile                               |    1 +
 drivers/tty/serial/Kconfig                         |   12 +-
 drivers/tty/serial/Makefile                        |    2 +
 .../tty/serial/{serial_core.c => fulltty_serial.c} |    0
 drivers/tty/serial/minitty_serial.c                | 1793 ++++++++++++++++++++
 include/linux/tty_flip.h                           |    9 +
 8 files changed, 1829 insertions(+), 6 deletions(-)
 rename drivers/tty/serial/{serial_core.c => fulltty_serial.c} (100%)
 create mode 100644 drivers/tty/serial/minitty_serial.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c776906f67..12523d7f97 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8410,6 +8410,12 @@ F:	include/linux/cciss*.h
 F:	include/uapi/linux/cciss*.h
 F:	Documentation/scsi/smartpqi.txt
 
+MINI TTY SUBSTITUTION FOR SERIAL PORTS
+M:	Nicolas Pitre <nico@linaro.org>
+L:	linux-serial at vger.kernel.org
+S:	Maintained
+F:	drivers/tty/serial/minitty_serial.c
+
 MN88472 MEDIA DRIVER
 M:	Antti Palosaari <crope@iki.fi>
 L:	linux-media at vger.kernel.org
@@ -12743,7 +12749,7 @@ S:	Supported
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:	Documentation/serial/
 F:	drivers/tty/
-F:	drivers/tty/serial/serial_core.c
+F:	drivers/tty/serial/fulltty_serial.c
 F:	include/linux/serial_core.h
 F:	include/linux/serial.h
 F:	include/linux/tty.h
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 95103054c0..8517c353d8 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -2,10 +2,12 @@ config TTY
 	bool "Enable TTY" if EXPERT
 	default y
 	---help---
-	  Allows you to remove TTY support which can save space, and
-	  blocks features that require TTY from inclusion in the kernel.
-	  TTY is required for any text terminals or serial port
-	  communication. Most users should leave this enabled.
+	  Allows you to remove the full-featured TTY support which can save
+	  space, and blocks features that require it from inclusion in the
+	  kernel. TTY support is required for any text terminals or serial
+	  port communication. If turned off, a much smaller TTY implementation
+	  that only supports serial ports in a limited capacity may be
+	  selected instead. Most users should leave this enabled.
 
 if TTY
 
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 1461be6b90..9b7b3418cd 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_TTY)		+= tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
 				   tty_buffer.o tty_port.o tty_mutex.o tty_ldsem.o tty_baudrate.o
+obj-$(CONFIG_MINITTY_SERIAL)	+= tty_baudrate.o
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
 obj-$(CONFIG_AUDIT)		+= tty_audit.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 6117ac8da4..a552387a39 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -2,7 +2,17 @@
 # Serial device configuration
 #
 
-if TTY
+config MINITTY_SERIAL
+	bool "Enable mini TTY for serial ports"
+	depends on !TTY
+	default y
+	help
+	  This enables a much smaller TTY implementation that only supports
+	  serial ports in a limited capacity. This is however sufficient for
+	  many embedded use cases that use serial ports mainly as a debug
+	  console where the saving in kernel code size is welcome.
+
+if TTY || MINITTY_SERIAL
 
 menu "Serial drivers"
 	depends on HAS_IOMEM
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 073afd10c5..92027db811 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -2,6 +2,8 @@
 # Makefile for the kernel serial device drivers.
 #
 
+serial_core-$(CONFIG_TTY) := fulltty_serial.o
+serial_core-$(CONFIG_MINITTY_SERIAL) := minitty_serial.o
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o serial_lib.o
 
 obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/fulltty_serial.c
similarity index 100%
rename from drivers/tty/serial/serial_core.c
rename to drivers/tty/serial/fulltty_serial.c
diff --git a/drivers/tty/serial/minitty_serial.c b/drivers/tty/serial/minitty_serial.c
new file mode 100644
index 0000000000..99af6dc180
--- /dev/null
+++ b/drivers/tty/serial/minitty_serial.c
@@ -0,0 +1,1793 @@
+/*
+ * Smallest shortcut replacement for tty and serial core layers.
+ *
+ * Based mainly on tty_io.c, n_tty.c and serial_core.c from many smart people.
+ *
+ * Created by:  Nicolas Pitre, January 2017
+ * Copyright:   (C) 2017  Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ctype.h>
+#include <linux/console.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
+#include <linux/serial_core.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct minitty_data {
+	struct uart_state state;
+	struct ktermios termios;
+	struct mutex mutex;
+	unsigned char *rx_buf;
+	int rx_head, rx_vetted, rx_tail;
+	int rx_lines, column, canon_start_pos;
+	bool rx_raw;
+	bool rx_overflow;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t read_wait;
+	struct work_struct rx_work;
+	struct cdev cdev;
+	struct device *dev;
+	int usecount;
+};
+
+#define RX_BUF_SIZE PAGE_SIZE
+#define RX_BUF_WRAP(x) ((x) & (RX_BUF_SIZE - 1))
+
+/*
+ * Functions called back by low level UART drivers when
+ * the TX buffer is getting near empty.
+ */
+void uart_write_wakeup(struct uart_port *port)
+{
+	struct uart_state *state = port->state;
+	struct minitty_data *mtty = container_of(state, typeof(*mtty), state);
+
+	wake_up_interruptible_poll(&mtty->write_wait, POLLOUT);
+}
+EXPORT_SYMBOL(uart_write_wakeup);
+
+static void
+uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
+{
+	unsigned long flags;
+	unsigned int old;
+
+	spin_lock_irqsave(&port->lock, flags);
+	old = port->mctrl;
+	port->mctrl = (old & ~clear) | set;
+	if (old != port->mctrl)
+		port->ops->set_mctrl(port, port->mctrl);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+#define uart_set_mctrl(port, set)	uart_update_mctrl(port, set, 0)
+#define uart_clear_mctrl(port, clear)	uart_update_mctrl(port, 0, clear)
+
+static void uart_change_pm(struct uart_state *state,
+			   enum uart_pm_state pm_state)
+{
+	struct uart_port *port =state->uart_port; 
+
+	if (state->pm_state != pm_state) {
+		if (port && port->ops->pm)
+			port->ops->pm(port, pm_state, state->pm_state);
+		state->pm_state = pm_state;
+	}
+}
+
+int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
+{
+	return -EPROTONOSUPPORT;
+}
+EXPORT_SYMBOL(uart_suspend_port);
+
+int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
+{
+	return -EPROTONOSUPPORT;
+}
+EXPORT_SYMBOL(uart_resume_port);
+
+/**
+ *	uart_handle_dcd_change - handle a change of carrier detect state
+ *	@port: uart_port structure for the open port
+ *	@status: new carrier detect status, nonzero if active
+ *
+ *	Caller must hold port->lock
+ */
+void uart_handle_dcd_change(struct uart_port *port, unsigned int status)
+{
+	port->icount.dcd++;
+}
+EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
+
+/**
+ *	uart_handle_cts_change - handle a change of clear-to-send state
+ *	@port: uart_port structure for the open port
+ *	@status: new clear to send status, nonzero if active
+ *
+ *	Caller must hold port->lock
+ */
+void uart_handle_cts_change(struct uart_port *port, unsigned int status)
+{
+	port->icount.cts++;
+
+	if (uart_softcts_mode(port)) {
+		if (port->hw_stopped) {
+			if (status) {
+				port->hw_stopped = 0;
+				port->ops->start_tx(port);
+				uart_write_wakeup(port);
+			}
+		} else {
+			if (!status) {
+				port->hw_stopped = 1;
+				port->ops->stop_tx(port);
+			}
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(uart_handle_cts_change);
+
+static void uart_start_tx(struct minitty_data *mtty)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	spin_lock_irq(&port->lock);
+	if (!port->hw_stopped)
+		port->ops->start_tx(port);
+	spin_unlock_irq(&port->lock);
+}
+
+static int uart_chars_in_buffer(struct minitty_data *mtty)
+{
+	struct uart_state *state = &mtty->state;
+	struct uart_port *port = mtty->state.uart_port;
+	int ret;
+
+	spin_lock_irq(&port->lock);
+	ret = uart_circ_chars_pending(&state->xmit);
+	spin_unlock_irq(&port->lock);
+	return ret;
+}
+
+static void uart_flush_tx_buffer(struct minitty_data *mtty)
+{
+	struct uart_state *state = &mtty->state;
+	struct uart_port *port = mtty->state.uart_port;
+
+	spin_lock_irq(&port->lock);
+	uart_circ_clear(&state->xmit);
+	if (port->ops->flush_buffer)
+		port->ops->flush_buffer(port);
+	spin_unlock_irq(&port->lock);
+	uart_write_wakeup(port);
+}
+
+static int uart_get_lsr_info(struct minitty_data *mtty, unsigned int __user *p)
+{
+	struct uart_state *state = &mtty->state;
+	struct uart_port *port = mtty->state.uart_port;
+	unsigned int result;
+
+	mutex_lock(&mtty->mutex);
+	result = port->ops->tx_empty(port);
+
+	/*
+	 * If we're about to load something into the transmit
+	 * register, we'll pretend the transmitter isn't empty to
+	 * avoid a race condition (depending on when the transmit
+	 * interrupt happens).
+	 */
+	if (port->x_char ||
+	    ((uart_circ_chars_pending(&state->xmit) > 0) &&
+	     !uart_tx_stopped(port)))
+		result &= ~TIOCSER_TEMT;
+	mutex_unlock(&mtty->mutex);
+	return put_user(result, p);
+}
+
+static int uart_tiocmget(struct minitty_data *mtty, int __user *p)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	int ret = -EIO;
+
+	mutex_lock(&mtty->mutex);
+	ret = port->mctrl;
+	spin_lock_irq(&port->lock);
+	ret |= port->ops->get_mctrl(port);
+	spin_unlock_irq(&port->lock);
+	mutex_unlock(&mtty->mutex);
+	if (ret >= 0)
+		ret = put_user(ret, p);
+	return ret;
+}
+
+static int
+uart_tiocmset(struct minitty_data *mtty, unsigned int cmd, unsigned __user *p)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	unsigned int set, clear, val;
+	int ret;
+
+	ret = get_user(val, p);
+	if (ret)
+		return ret;
+	set = clear = 0;
+	switch (cmd) {
+	case TIOCMBIS:
+		set = val;
+		break;
+	case TIOCMBIC:
+		clear = val;
+		break;
+	case TIOCMSET:
+		set = val;
+		clear = ~val;
+		break;
+	}
+	set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+	clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+
+	mutex_lock(&mtty->mutex);
+	uart_update_mctrl(port, set, clear);
+	mutex_unlock(&mtty->mutex);
+	return 0;
+}
+
+static int uart_break_ctl(struct minitty_data *mtty, int break_state)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	int ret = -EIO;
+
+	mutex_lock(&mtty->mutex);
+	port->ops->break_ctl(port, break_state);
+	mutex_unlock(&mtty->mutex);
+	return ret;
+}
+
+/*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+static int uart_wait_modem_status(struct minitty_data *mtty, unsigned long arg)
+{
+	struct uart_port *uport = mtty->state.uart_port;
+	struct tty_port *port = &mtty->state.port;
+	DECLARE_WAITQUEUE(wait, current);
+	struct uart_icount cprev, cnow;
+	int ret;
+
+	/*
+	 * note the counters on entry
+	 */
+	spin_lock_irq(&uport->lock);
+	memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
+	if (uport->ops->enable_ms)
+		uport->ops->enable_ms(uport);
+	spin_unlock_irq(&uport->lock);
+
+	add_wait_queue(&port->delta_msr_wait, &wait);
+	for (;;) {
+		spin_lock_irq(&uport->lock);
+		memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
+		spin_unlock_irq(&uport->lock);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+		    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+		    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+		    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+			ret = 0;
+			break;
+		}
+
+		schedule();
+
+		/* see if a signal did it */
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		cprev = cnow;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&port->delta_msr_wait, &wait);
+
+	return ret;
+}
+
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ *     RI where only 0->1 is counted.
+ */
+static int uart_tiocgicount(struct minitty_data *mtty, void __user *p)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	struct serial_icounter_struct icount;
+	struct uart_icount cnow;
+
+	spin_lock_irq(&port->lock);
+	memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
+	spin_unlock_irq(&port->lock);
+
+	memset(&icount, 0, sizeof(icount));
+	icount.cts         = cnow.cts;
+	icount.dsr         = cnow.dsr;
+	icount.rng         = cnow.rng;
+	icount.dcd         = cnow.dcd;
+	icount.rx          = cnow.rx;
+	icount.tx          = cnow.tx;
+	icount.frame       = cnow.frame;
+	icount.overrun     = cnow.overrun;
+	icount.parity      = cnow.parity;
+	icount.brk         = cnow.brk;
+	icount.buf_overrun = cnow.buf_overrun;
+	if (copy_to_user(p, &icount, sizeof(icount)))
+		return -EFAULT;
+	return 0;
+}
+
+static void uart_change_speed(struct minitty_data *mtty,
+			      struct ktermios *old_termios)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	struct ktermios *termios = &mtty->termios;
+	int hw_stopped;
+
+	port->ops->set_termios(port, termios, old_termios);
+
+	/*
+	 * Set modem status enables based on termios cflag
+	 */
+	spin_lock_irq(&port->lock);
+	if (termios->c_cflag & CRTSCTS)
+		port->status |= UPSTAT_CTS_ENABLE;
+	else
+		port->status &= ~UPSTAT_CTS_ENABLE;
+
+	if (termios->c_cflag & CLOCAL)
+		port->status &= ~UPSTAT_DCD_ENABLE;
+	else
+		port->status |= UPSTAT_DCD_ENABLE;
+
+	/* reset sw-assisted CTS flow control based on (possibly) new mode */
+	hw_stopped = port->hw_stopped;
+	port->hw_stopped = uart_softcts_mode(port) &&
+				!(port->ops->get_mctrl(port) & TIOCM_CTS);
+	if (port->hw_stopped) {
+		if (!hw_stopped)
+			port->ops->stop_tx(port);
+	} else {
+		if (hw_stopped)
+			port->ops->start_tx(port);
+	}
+	spin_unlock_irq(&port->lock);
+}
+
+static void uart_set_termios(struct minitty_data *mtty,
+			     struct ktermios *old_termios)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	unsigned int cflag = mtty->termios.c_cflag;
+	unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
+	bool sw_changed = false;
+
+	/*
+	 * Drivers doing software flow control also need to know
+	 * about changes to these input settings.
+	 */
+	if (port->flags & UPF_SOFT_FLOW) {
+		iflag_mask |= IXANY|IXON|IXOFF;
+		sw_changed =
+		   mtty->termios.c_cc[VSTART] != old_termios->c_cc[VSTART] ||
+		   mtty->termios.c_cc[VSTOP] != old_termios->c_cc[VSTOP];
+	}
+
+	/*
+	 * These are the bits that are used to setup various
+	 * flags in the low level driver. We can ignore the Bfoo
+	 * bits in c_cflag; c_[io]speed will always be set
+	 * appropriately by set_termios(). 
+	 */
+	if ((cflag ^ old_termios->c_cflag) == 0 &&
+	    mtty->termios.c_ospeed == old_termios->c_ospeed &&
+	    mtty->termios.c_ispeed == old_termios->c_ispeed &&
+	    ((mtty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
+	    !sw_changed)
+		return;
+
+	uart_change_speed(mtty, old_termios);
+	/* reload cflag from termios; port driver may have overriden flags */
+	cflag = mtty->termios.c_cflag;
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+		uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+	/* Handle transition away from B0 status */
+	else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+		unsigned int mask = TIOCM_DTR;
+		if (!(cflag & CRTSCTS))
+			mask |= TIOCM_RTS;
+		uart_set_mctrl(port, mask);
+	}
+}
+
+static void uart_wait_until_sent(struct minitty_data *mtty)
+{
+	struct uart_port *port = mtty->state.uart_port;
+	unsigned long char_time, expire, timeout;
+
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.
+	 *
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = (port->timeout - HZ/50) / port->fifosize;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+
+	/*
+	 * If the transmitter hasn't cleared in twice the approximate
+	 * amount of time to send the entire FIFO, it probably won't
+	 * ever clear.  This assumes the UART isn't doing flow
+	 * control, which is currently the case.  Hence, if it ever
+	 * takes longer than port->timeout, this is probably due to a
+	 * UART bug of some kind.  So, we clamp the timeout parameter at
+	 * 2*port->timeout.
+	 */
+	timeout = 2 * port->timeout;
+
+	expire = jiffies + timeout;
+	while (!port->ops->tx_empty(port)) {
+		        msleep_interruptible(jiffies_to_msecs(char_time));
+			        if (signal_pending(current))
+					                break;
+				        if (time_after(jiffies, expire))
+						                break;
+	}
+}
+
+static void mtty_wait_until_sent(struct minitty_data *mtty)
+{
+	long timeout = MAX_SCHEDULE_TIMEOUT;
+
+	timeout = wait_event_interruptible_timeout(mtty->write_wait,
+			                !uart_chars_in_buffer(mtty), timeout);
+	if (timeout > 0)
+		uart_wait_until_sent(mtty);
+}
+
+static void mtty_set_termios(struct minitty_data *mtty,
+			     struct ktermios *old_termios)
+{
+	bool was_raw = mtty->rx_raw;
+
+	mtty->rx_raw = !I_IGNCR(mtty) && !I_ICRNL(mtty) && !I_INLCR(mtty) &&
+		       !L_ICANON(mtty) && !L_ISIG(mtty) && !L_ECHO(mtty);
+	if (!mtty->rx_raw && was_raw)
+		mtty->rx_lines = mtty->column = mtty->canon_start_pos = 0;
+
+	/* mark things we don't support. */
+	mtty->termios.c_iflag |= IGNBRK | IGNPAR;
+	mtty->termios.c_iflag &= ~(ISTRIP | IUCLC | IXON | IXOFF);
+	mtty->termios.c_lflag &= ~IEXTEN;
+
+	/* The termios change make the tty ready for I/O */
+	wake_up_interruptible(&mtty->write_wait);
+	wake_up_interruptible(&mtty->read_wait);
+}
+
+static int set_termios(struct minitty_data *mtty, unsigned int cmd,
+		       void __user *arg)
+{
+	struct ktermios new_termios, old_termios;
+	int ret;
+
+	mutex_lock(&mtty->mutex);
+	new_termios = mtty->termios;
+	mutex_unlock(&mtty->mutex);
+
+	switch (cmd) {
+	case TCSETAF:
+	case TCSETAW:
+	case TCSETA:
+		ret = user_termio_to_kernel_termios(&new_termios,
+						    (struct termio __user *)arg);
+		break;
+#ifdef TCGETS2
+	case TCSETSF2:
+	case TCSETSW2:
+	case TCSETS2:
+		ret = user_termios_to_kernel_termios(&new_termios,
+						     (struct termios2 __user *)arg);
+		break;
+	default:
+		ret = user_termios_to_kernel_termios_1(&new_termios,
+						       (struct termios __user *)arg);
+		break;
+#else
+	default:
+		ret = user_termios_to_kernel_termios(&new_termios,
+						     (struct termios __user *)arg);
+		break;
+#endif
+	}
+	if (ret)
+		return -EFAULT;
+
+	switch (cmd) {
+	case TCSETSF:
+#ifdef TCGETS2
+	case TCSETSF2:
+#endif
+	case TCSETAF:
+		uart_flush_tx_buffer(mtty);
+	}
+
+	switch (cmd) {
+	case TCSETSF:
+	case TCSETSW:
+#ifdef TCGETS2
+	case TCSETSF2:
+	case TCSETSW2:
+#endif
+	case TCSETAF:
+	case TCSETAW:
+		mtty_wait_until_sent(mtty);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	/*
+	 * If old style Bfoo values are used then load c_ispeed/c_ospeed
+	 * with the real speed so its unconditionally usable.
+	 */
+	new_termios.c_ispeed = tty_termios_input_baud_rate(&new_termios);
+	new_termios.c_ospeed = tty_termios_baud_rate(&new_termios);
+
+	mutex_lock(&mtty->mutex);
+	old_termios = mtty->termios;
+	mtty->termios = new_termios;
+	mtty_set_termios(mtty, &old_termios);
+	uart_set_termios(mtty, &old_termios);
+	mutex_unlock(&mtty->mutex);
+	return 0;
+}
+
+static int tiocsetd(int __user *p)
+{
+	int ldisc;
+
+	if (get_user(ldisc, p))
+		return -EFAULT;
+	if (ldisc != N_TTY)
+		return -EINVAL;
+	return 0;
+}
+
+static int tiocgetd(int __user *p)
+{
+	return put_user(N_TTY, p);
+}
+
+static void copy_termios(struct minitty_data *mtty, struct ktermios *kterm)
+{
+	mutex_lock(&mtty->mutex);
+	*kterm = mtty->termios;
+	mutex_unlock(&mtty->mutex);
+}
+
+static long minitty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct minitty_data *mtty = file->private_data;
+	struct uart_port *port = mtty->state.uart_port;
+	void __user *p = (void __user *)arg;
+	struct ktermios kterm;
+	int ret = -ENOIOCTLCMD;
+
+	switch (cmd) {
+	case TIOCSETD:
+		return tiocsetd(p);
+	case TIOCGETD:
+		return tiocgetd(p);
+	case TIOCSBRK:
+		return uart_break_ctl(mtty, -1);
+	case TIOCCBRK:
+		return uart_break_ctl(mtty, 0);
+	case TIOCMGET:
+		return uart_tiocmget(mtty, p);
+	case TIOCMSET:
+	case TIOCMBIC:
+	case TIOCMBIS:
+		return uart_tiocmset(mtty, cmd, p);
+	case TIOCGICOUNT:
+		return uart_tiocgicount(mtty, p);
+	case TIOCMIWAIT:
+		return uart_wait_modem_status(mtty, arg);
+	case TIOCSERGETLSR:
+		return uart_get_lsr_info(mtty, p);
+
+#ifndef TCGETS2
+	case TCGETS:
+		copy_termios(mtty, &kterm);
+		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
+			return -EFAULT;
+		return 0;
+#else
+	case TCGETS:
+		copy_termios(mtty, &kterm);
+		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
+			return -EFAULT;
+		return 0;
+	case TCGETS2:
+		copy_termios(mtty, &kterm);
+		if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
+			return -EFAULT;
+		return 0;
+	case TCSETSF2:
+	case TCSETSW2:
+	case TCSETS2:
+#endif
+	case TCSETSF:
+	case TCSETSW:
+	case TCSETS:
+	case TCSETAF:
+	case TCSETAW:
+	case TCSETA:
+		return set_termios(mtty, cmd, p);
+	case TCGETA:
+		copy_termios(mtty, &kterm);
+		if (kernel_termios_to_user_termio((struct termio __user *)arg, &kterm))
+			return -EFAULT;
+		return 0;
+
+	default:
+		mutex_lock(&mtty->mutex);
+		if (port->ops->ioctl)
+			ret = port->ops->ioctl(port, cmd, arg);
+		mutex_unlock(&mtty->mutex);
+		break;
+	}
+
+	if (ret == -ENOIOCTLCMD)
+		ret = -EINVAL;
+	return ret;
+}
+
+/*
+ * Functions called back by low level UART drivers normally provided by
+ * the regular TTY layer to deliver RX data that we have to emulate.
+ * We ssimply ignore characters with errors here.
+ */
+
+int tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag)
+{
+	struct uart_state *state = container_of(port, struct uart_state, port);
+	struct minitty_data *mtty = container_of(state, typeof(*mtty), state);
+
+	if (flag == TTY_NORMAL) {
+		int tail = smp_load_acquire(&mtty->rx_tail);
+		int head = mtty->rx_head;
+		int next = RX_BUF_WRAP(head + 1);
+		/*
+		 * Advance head only if buffer is not full.
+		 * Keep on overwriting last char otherwise.
+		 */
+		mtty->rx_buf[head] = ch;
+		if (next != tail) {
+			smp_store_release(&mtty->rx_head, next);
+			return 1;
+		} else {
+			smp_store_release(&mtty->rx_overflow, true);
+		}
+	}		
+	return 0;
+}
+EXPORT_SYMBOL(tty_insert_flip_char);
+
+void uart_insert_char(struct uart_port *port, unsigned int status,
+		      unsigned int overrun, unsigned int ch, unsigned int flag)
+{
+	struct uart_state *state = port->state;
+	struct minitty_data *mtty = container_of(state, typeof(*mtty), state);
+
+	if (flag == TTY_NORMAL) {
+		int tail = smp_load_acquire(&mtty->rx_tail);
+		int head = mtty->rx_head;
+		int next = RX_BUF_WRAP(head + 1);
+		/*
+		 * Advance head only if buffer is not full.
+		 * Keep on overwriting last char otherwise.
+		 */
+		mtty->rx_buf[head] = ch;
+		if (next != tail) {
+			smp_store_release(&mtty->rx_head, next);
+		} else {
+			smp_store_release(&mtty->rx_overflow, true);
+			port->icount.buf_overrun++;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(uart_insert_char);
+
+int tty_insert_flip_string(struct tty_port *port, const unsigned char *chars,
+			   size_t size)
+{
+	struct uart_state *state = container_of(port, struct uart_state, port);
+	struct minitty_data *mtty = container_of(state, typeof(*mtty), state);
+	int head, tail, len, ret = 0;
+
+	tail = smp_load_acquire(&mtty->rx_tail);
+	head = mtty->rx_head;
+	do {
+		len = CIRC_SPACE(head, tail, RX_BUF_SIZE);
+		if (len > size)
+			len = size;
+		memcpy(mtty->rx_buf+head, chars, len);
+		head = RX_BUF_WRAP(head + len);
+		chars += len;
+		size -= len;
+		ret += len;
+	} while (size && len && head == 0);
+	smp_store_release(&mtty->rx_head, head);
+	return ret;
+}
+EXPORT_SYMBOL(tty_insert_flip_string);
+
+int tty_buffer_request_room(struct tty_port *port, size_t size)
+{
+	struct uart_state *state = container_of(port, struct uart_state, port);
+	struct minitty_data *mtty = container_of(state, typeof(*mtty), state);
+	int tail = smp_load_acquire(&mtty->rx_tail);
+	int head = mtty->rx_head;
+	int space = CIRC_SPACE(head, tail, RX_BUF_SIZE);
+	return size < space ? size : space;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+void tty_schedule_flip(struct tty_port *port)
+{
+	struct uart_state *state = container_of(port, struct uart_state, port);
+	struct minitty_data *mtty = container_of(state, typeof(*mtty), state);
+
+	queue_work(system_unbound_wq, &mtty->rx_work);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+void tty_flip_buffer_push(struct tty_port *port)
+{
+	tty_schedule_flip(port);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/*
+ * Line Discipline Stuff
+ */
+
+static bool is_utf8_continuation(struct minitty_data *mtty, unsigned char c)
+{
+	return (I_IUTF8(mtty) && (c & 0xc0) == 0x80);
+}
+
+static bool is_line_termination(struct minitty_data *mtty, unsigned char c)
+{
+	return (c == '\n' || c == EOF_CHAR(mtty) || c == EOL_CHAR(mtty));
+}
+
+/*
+ * Queue the provided character string in its entirety or nothing.
+ * Return true if queued, false otherwise.
+ */
+static bool queue_tx_chars(struct minitty_data *mtty, unsigned char *s, int len)
+{
+	struct circ_buf *circ = &mtty->state.xmit;
+	int head, tail, space;
+
+	tail = smp_load_acquire(&circ->tail);
+	head = circ->head;
+	space = CIRC_SPACE(head, tail, UART_XMIT_SIZE);
+	if (space < len)
+		return false;
+	while (len--) {
+		circ->buf[head] = *s++;
+		head = (head + 1) & (UART_XMIT_SIZE - 1);
+	}
+	smp_store_release(&circ->head, head);
+	return true;
+}
+
+/*
+ * Queue characters in their cooked sequence.
+ * Return true if queued, or false otherwise.
+ */
+static bool tx_cooked_char(struct minitty_data *mtty, unsigned char c)
+{
+	int spaces, next_col = mtty->column;
+
+	switch (c) {
+	case '\n':
+		if (O_ONLRET(mtty))
+			next_col = 0;
+		if (O_ONLCR(mtty)) {
+			if (!queue_tx_chars(mtty, "\r\n", 2))
+				return false;
+			mtty->column = mtty->canon_start_pos = 0;
+			return true;
+		}
+		break;
+	case '\r':
+		if (O_ONOCR(mtty) && mtty->column == 0)
+			return true;
+		if (O_OCRNL(mtty)) {
+			c = '\n';
+			if (O_ONLRET(mtty))
+				next_col = 0;
+		} else
+			next_col = 0;
+		break;
+	case '\t':
+		spaces = 8 - (mtty->column & 7);
+		if (O_TABDLY(mtty) == XTABS) {
+			if (!queue_tx_chars(mtty, "        ", spaces))
+				return false;
+			mtty->column += spaces;
+			return true;
+		}
+		next_col += spaces;
+		break;
+	case '\b':
+		if (next_col > 0)
+			next_col--;
+		break;
+	default:
+		if (iscntrl(c))
+			break;
+		if (is_utf8_continuation(mtty, c))
+			break;
+		next_col++;
+		break;
+	}
+	if (!queue_tx_chars(mtty, &c, 1))
+		return false;
+	mtty->column = next_col;
+	if (next_col == 0)
+		mtty->canon_start_pos = 0;
+	return true;
+}
+
+/*
+ * Queue echoed characters, converting CTRL sequences into "^X" if need be.
+ * Return true if queued, or false otherwise.
+ */
+static bool echo_rx_char(struct minitty_data *mtty, unsigned char c)
+{
+	if (L_ECHOCTL(mtty) && iscntrl(c) && c != '\t' && c != '\n') {
+		unsigned char buf[2];
+		buf[0] = '^';
+		buf[1] = c ^ 0100;
+		return queue_tx_chars(mtty, buf, 2);
+	}
+	if (O_OPOST(mtty))
+		return tx_cooked_char(mtty, c);
+	else
+		return queue_tx_chars(mtty, &c, 1);
+}
+
+/*
+ * Remove character from RX buffer at given position by shifting
+ * all preceding characters ahead.
+ */
+static void eat_rx_char(struct minitty_data *mtty, int pos)
+{
+	unsigned char *buf = mtty->rx_buf;
+	int tail = mtty->rx_tail;
+	int bottom = (tail <= pos) ? tail : 0;
+
+	memmove(&buf[bottom+1], &buf[bottom], pos - bottom);
+	if (tail > pos) {
+		buf[0] = buf[RX_BUF_SIZE-1];
+		memmove(&buf[tail+1], &buf[tail], RX_BUF_SIZE - 1 - tail);
+	}
+	smp_store_release(&mtty->rx_tail, RX_BUF_WRAP(tail + 1));
+}
+
+/*
+ * Create needed erase sequence according to the erase character c at
+ * position pos in the RX buffer. The erase sequence is sent for each
+ * erased characters and only if that succeeds then the character is
+ * actually removed from the buffer. The erase character itself is removed
+ * last so if the whole erase sequence cannot be completed then this can
+ * be resumed later.
+ */
+static bool erase_rx_char(struct minitty_data *mtty, unsigned char c, int pos)
+{
+	int prev_pos = RX_BUF_WRAP(pos - 1);
+	bool seen_alnum = false;
+
+	while (pos != mtty->rx_tail) {
+		unsigned char prev_c = mtty->rx_buf[prev_pos];
+
+		if (is_line_termination(mtty, prev_c)) {
+			/* End of previous line: we don't erase further. */
+			break;
+		}
+
+		if (is_utf8_continuation(mtty, prev_c)) {
+			/* UTF8 continuation char: we just drop it */
+			eat_rx_char(mtty, prev_pos);
+			continue;
+		}
+
+		if (c == WERASE_CHAR(mtty) && seen_alnum && !isalnum(prev_c)) {
+			/* Beginning of previous word: we don't erase further */
+			break;
+		}
+
+		if (prev_c == '\t') {
+			/* depends on characters before the tab */
+			int spaces = 0;
+			int i = prev_pos;
+			while (i != mtty->rx_tail) {
+				unsigned char before;
+				i = RX_BUF_WRAP(i - 1);
+				before = mtty->rx_buf[i];
+				if (before == '\t')
+					break;
+				if (is_line_termination(mtty, before))
+					break;
+				if (L_ECHOCTL(mtty) && iscntrl(before))
+					spaces += 2;
+				else if (is_utf8_continuation(mtty, before))
+					continue;
+				else if (!iscntrl(before))
+					spaces++;
+			}
+			if (i == mtty->rx_tail)
+				spaces += mtty->canon_start_pos;
+			spaces = 8 - (spaces & 7);
+			if (!queue_tx_chars(mtty, "\b\b\b\b\b\b\b\b", spaces))
+				return false;
+			mtty->column -= spaces;
+		} else if (L_ECHOCTL(mtty) && iscntrl(prev_c)) {
+			/* control chars were printed as "^X" */
+			if (!queue_tx_chars(mtty, "\b\b  \b\b", 6))
+				return false;
+			mtty->column -= 2;
+		} else if (!iscntrl(prev_c)) {
+			if (!queue_tx_chars(mtty, "\b \b", 3))
+				return false;
+			mtty->column -= 1;
+		}
+
+		/* erase sequence sent, now remove the char from the buffer */
+		eat_rx_char(mtty, prev_pos);
+
+		if (c == ERASE_CHAR(mtty))
+			break;
+	}
+
+	/* Finally remove the erase character itself. */
+	eat_rx_char(mtty, pos);
+	return true;
+}
+
+/*
+ * Process RX bytes: canonical mode, echo, signals, etc.
+ * This might not process all RX characters if e.g. there is not enough
+ * room in the TX buffer to contain corresponding echo sequences.
+ */
+static void minitty_process_rx(struct minitty_data *mtty)
+{
+	bool xmit = false;
+	int i, head;
+       
+	head = smp_load_acquire(&mtty->rx_head);
+
+	if (mtty->rx_raw) {
+		smp_store_release(&mtty->rx_vetted, head);
+		return;
+	}
+
+	/*
+	 * RX overflow mitigation: evaluate the last received character
+	 * stored at the very head of the buffer in case it might be a
+	 * signal or newline character that could kick the reader into
+	 * action. We potentially overwrite the last vetted character but
+	 * we're past any concern for lost characters at this point.
+	 */
+	if (unlikely(mtty->rx_overflow)) {
+		WRITE_ONCE(mtty->rx_overflow, false);
+		if (RX_BUF_WRAP(head + 1) == mtty->rx_tail) {
+			i = RX_BUF_WRAP(head - 1);
+			mtty->rx_buf[i] = mtty->rx_buf[head];
+			if (mtty->rx_vetted == head)
+				mtty->rx_vetted = i;
+		}
+	}
+
+	for (i = mtty->rx_vetted; i != head; i = RX_BUF_WRAP(i + 1)) {
+		unsigned char c = mtty->rx_buf[i];
+
+		if (c == '\r') {
+			if (I_IGNCR(mtty)) {
+				eat_rx_char(mtty, i);
+				continue;
+			}
+			if (I_ICRNL(mtty))
+				mtty->rx_buf[i] = c = '\n';
+		} else if (c == '\n' && I_INLCR(mtty))
+			mtty->rx_buf[i] = c = '\r';
+
+		if (L_ICANON(mtty)) {
+			if ((L_ECHOE(mtty) && c == ERASE_CHAR(mtty)) ||
+			    (L_ECHOE(mtty) && c == WERASE_CHAR(mtty)) ||
+			    (L_ECHOK(mtty) && c == KILL_CHAR(mtty))) {
+				xmit = true;
+				if (!erase_rx_char(mtty, c, i))
+						break;
+				continue;
+			}
+			if (is_line_termination(mtty, c)) {
+				mtty->rx_lines++;
+				if (c != '\n')
+					continue;
+			}
+		}
+
+		if (L_ECHO(mtty) || (c == '\n' && L_ECHONL(mtty))) {
+			xmit = true;
+			if (!echo_rx_char(mtty, c))
+				break;
+		}
+	}
+
+	smp_store_release(&mtty->rx_vetted, i);
+
+	if (xmit)
+		uart_start_tx(mtty);
+}
+
+static bool rx_data_available(struct minitty_data *mtty, bool poll)
+{
+	bool data_avail = (mtty->rx_tail != mtty->rx_vetted);
+	if (data_avail && !L_ICANON(mtty)) {
+		int amt = poll && !TIME_CHAR(mtty) && MIN_CHAR(mtty) ?
+				MIN_CHAR(mtty) : 1;
+		data_avail = RX_BUF_WRAP(mtty->rx_vetted - mtty->rx_tail) >= amt;
+	} else if (data_avail && !mtty->rx_lines) {
+		/* wait for a full line */
+		data_avail = false;
+	} else if (!data_avail && mtty->rx_lines) {
+		/*
+		 * This may happen if the RX buffer was flushed by a signal
+		 * or during RX overflow. Let's just reset it to zero.
+		 */
+		mtty->rx_lines = 0;
+	}
+	return data_avail;
+}
+
+static void uart_rx_work(struct work_struct *work)
+{
+	struct minitty_data *mtty = container_of(work, typeof(*mtty), rx_work);
+
+	mutex_lock(&mtty->mutex);
+	minitty_process_rx(mtty);
+	if (rx_data_available(mtty, true))
+		wake_up_interruptible_poll(&mtty->read_wait, POLLIN);
+	mutex_unlock(&mtty->mutex);
+}
+
+static ssize_t minitty_raw_read(struct minitty_data *mtty, char __user *buf,
+				size_t count)
+{
+	int head, tail, len, ret = 0;
+
+	head = smp_load_acquire(&mtty->rx_vetted); 
+	tail = mtty->rx_tail;
+	do {
+		len = CIRC_CNT(head, tail, RX_BUF_SIZE);
+		if (len > count)
+			len = count;
+		if (copy_to_user(buf, mtty->rx_buf+tail, len) != 0)
+			return -EFAULT;
+		tail = RX_BUF_WRAP(tail + len);
+		buf += len;
+		count -= len;
+		ret += len;
+	} while (count && len && tail == 0);
+	smp_store_release(&mtty->rx_tail, tail);
+	return ret;
+}
+
+static ssize_t minitty_cooked_read(struct minitty_data *mtty, char __user *buf,
+				   size_t count)
+{
+	int head, tail, i, ret;
+	bool eol = false;
+
+	head = smp_load_acquire(&mtty->rx_vetted);
+	tail = mtty->rx_tail;
+
+	/* First, locate the end-of-line marker if any. */
+	for (i = tail; i != head && count; i = RX_BUF_WRAP(i + 1), count--) {
+		unsigned char c = mtty->rx_buf[i];
+		if (is_line_termination(mtty, c)) {
+			eol = true;
+			break;
+		}
+	}
+
+	count = CIRC_CNT(i, tail, RX_BUF_SIZE);
+
+	if (eol) {
+		/* Include the line delimiter except for EOF */
+		if (mtty->rx_buf[i] != EOF_CHAR(mtty))
+			count++;
+		i = RX_BUF_WRAP(i + 1);
+	}
+
+	ret = minitty_raw_read(mtty, buf, count);
+	if (ret >= 0 && eol) {
+		/* we consumed a whole line */
+		mtty->rx_lines--;
+		/* adjust tail in case EOF was skipped */
+		smp_store_release(&mtty->rx_tail, i);
+	}
+	return ret;
+}
+
+static ssize_t minitty_read(struct file *file, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct minitty_data *mtty = file->private_data;
+	char __user *buf0 = buf;
+	DEFINE_WAIT_FUNC(wait, woken_wake_function);
+	int minimum, time;
+	long timeout;
+	int ret = 0;
+
+	mutex_lock(&mtty->mutex);
+
+	minimum = time = 0;
+	timeout = MAX_SCHEDULE_TIMEOUT;
+	if (!L_ICANON(mtty)) {
+		minimum = MIN_CHAR(mtty);
+		if (minimum) {
+			time = (HZ / 10) * TIME_CHAR(mtty);
+		} else {
+			timeout = (HZ / 10) * TIME_CHAR(mtty);
+			minimum = 1;
+		}
+	}
+
+	add_wait_queue(&mtty->read_wait, &wait);
+
+	while (count) {
+		minitty_process_rx(mtty);
+
+		if (!rx_data_available(mtty, false)) {
+			if (!timeout)
+				break;
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+			mutex_unlock(&mtty->mutex);
+			timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
+					     timeout);
+			mutex_lock(&mtty->mutex);
+			continue;
+		}
+
+		if (L_ICANON(mtty)) {
+			ret = minitty_cooked_read(mtty, buf, count);
+			if (ret > 0)
+				buf += ret;
+			break;
+		}
+
+		ret = minitty_raw_read(mtty, buf, count);
+		if (ret < 0)
+			break;
+		buf += ret;
+		count -= ret;
+		if (buf - buf0 >= minimum)
+			break;
+		if (time)
+			timeout = time;
+	}
+
+	remove_wait_queue(&mtty->read_wait, &wait);
+	mutex_unlock(&mtty->mutex);
+	if (buf - buf0)
+		ret = buf - buf0;
+	return ret;
+}
+
+static ssize_t minitty_raw_write(struct minitty_data *mtty, const char __user *buf,
+				 size_t count)
+{
+	struct circ_buf *circ = &mtty->state.xmit;
+	int head, tail, len, ret = 0;
+
+	tail = smp_load_acquire(&circ->tail);
+	head = circ->head;
+	do {
+		len = CIRC_SPACE_TO_END(head, tail, UART_XMIT_SIZE);
+		if (len > count)
+			len = count;
+		if (copy_from_user(circ->buf + head, buf, len) != 0)
+			return -EFAULT;
+		head = (head + len) & (UART_XMIT_SIZE - 1);
+		buf += len;
+		count -= len;
+		ret += len;
+	} while (count && len && head == 0);
+	smp_store_release(&circ->head, head);
+
+	uart_start_tx(mtty);
+	return ret;
+}
+
+static ssize_t minitty_cooked_write(struct minitty_data *mtty, const char __user *buf,
+				    size_t count)
+{
+	const char __user *buf0 = buf;
+
+	while (count--) {
+		unsigned char c;
+		if (get_user(c, buf) != 0)
+			return -EFAULT;
+		if (!tx_cooked_char(mtty, c))
+			break;
+		buf++;
+	}
+	mtty->canon_start_pos = mtty->column;
+
+	uart_start_tx(mtty);
+	return buf - buf0;
+}
+
+static ssize_t minitty_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	struct minitty_data *mtty = file->private_data;
+	const char __user *buf0 = buf;
+	DEFINE_WAIT_FUNC(wait, woken_wake_function);
+	int ret;
+
+	mutex_lock(&mtty->mutex);
+	add_wait_queue(&mtty->write_wait, &wait);
+
+	while (1) {
+		/* give priority to RX echo and signals */
+		minitty_process_rx(mtty);
+
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		if (O_OPOST(mtty))
+			ret = minitty_cooked_write(mtty, buf, count);
+		else
+			ret = minitty_raw_write(mtty, buf, count);
+		if (ret < 0)
+			break;
+		buf += ret;
+		count -= ret;
+		if (!count)
+			break;
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			break;
+		}
+		mutex_unlock(&mtty->mutex);
+		wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+		mutex_lock(&mtty->mutex);
+	}
+
+	remove_wait_queue(&mtty->write_wait, &wait);
+	mutex_unlock(&mtty->mutex);
+	return (buf - buf0) ? buf - buf0 : ret;
+}
+
+static unsigned int minitty_poll(struct file *file, poll_table *wait)
+{
+	struct minitty_data *mtty = file->private_data;
+	struct uart_port *port = mtty->state.uart_port;
+	unsigned int mask = 0;
+
+	mutex_lock(&mtty->mutex);
+
+	poll_wait(file, &mtty->read_wait, wait);
+	poll_wait(file, &mtty->write_wait, wait);
+
+	if (rx_data_available(mtty, true)) {
+		mask |= POLLIN | POLLRDNORM;
+	} else {
+		minitty_process_rx(mtty);
+		if (rx_data_available(mtty, true))
+			mask |= POLLIN | POLLRDNORM;
+	}
+
+	if (!port->hw_stopped) {
+		struct circ_buf *circ = &mtty->state.xmit;
+		int tail = smp_load_acquire(&circ->tail);
+		int head = circ->head;
+		int count = CIRC_CNT(head, tail, UART_XMIT_SIZE);
+		if (count < WAKEUP_CHARS)
+			mask |= POLLOUT | POLLWRNORM;
+	}
+
+	mutex_unlock(&mtty->mutex);
+
+	return mask;
+}
+
+static int uart_port_startup(struct minitty_data *mtty)
+{
+	struct uart_state *state = &mtty->state;
+	struct uart_port *port = state->uart_port;
+	unsigned long page;
+	int ret;
+
+	/* Make sure the device is in D0 state. */
+	uart_change_pm(state, UART_PM_STATE_ON);
+
+	/* Initialise and allocate the transmit buffer. */
+	page = get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	state->xmit.buf = (unsigned char *) page;
+	uart_circ_clear(&state->xmit);
+
+	/* Initialise and allocate the receive buffer. */
+	page = get_zeroed_page(GFP_KERNEL);
+	if (!page) {
+		ret = -ENOMEM;
+		goto err_free_tx;
+	}
+	mtty->rx_buf = (unsigned char *) page;
+	mtty->rx_head = mtty->rx_tail = mtty->rx_vetted = mtty->rx_lines = 0;
+	mtty->rx_overflow = false;
+
+	ret = port->ops->startup(port);
+	if (ret)
+		goto err_free_rx;
+
+	if (uart_console(port) && port->cons->cflag) {
+		mtty->termios.c_cflag = port->cons->cflag;
+		port->cons->cflag = 0;
+	}
+
+	/* Initialise the hardware port settings. */
+	uart_change_speed(mtty, NULL);
+
+	/*
+	 * Setup the RTS and DTR signals once the
+	 * port is open and ready to respond.
+	 */
+	uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+
+	return 0;
+
+err_free_rx:
+	free_page((unsigned long)mtty->rx_buf);
+	mtty->rx_buf = NULL;
+err_free_tx:
+	free_page((unsigned long)state->xmit.buf);
+	state->xmit.buf = NULL;
+	return ret;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void uart_port_shutdown(struct minitty_data *mtty)
+{
+	struct uart_state *state = &mtty->state;
+	struct uart_port *port = state->uart_port;
+
+	spin_lock_irq(&port->lock);
+	port->ops->stop_rx(port);
+	spin_unlock_irq(&port->lock);
+
+	if (uart_console(port))
+		port->cons->cflag = mtty->termios.c_cflag;
+
+	/* Turn off DTR and RTS early. */
+	if (C_HUPCL(mtty))
+		uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+	/* Free the IRQ and disable the port. */
+	port->ops->shutdown(port);
+	synchronize_irq(port->irq);
+
+	/* Free the transmit buffer page. */
+	free_page((unsigned long)state->xmit.buf);
+	state->xmit.buf = NULL;
+
+	/* Free the receive buffer page. */
+	free_page((unsigned long)mtty->rx_buf);
+	mtty->rx_buf = NULL;
+}
+
+static int minitty_open(struct inode *inode, struct file *file)
+{
+	struct minitty_data *mtty = NULL;
+	dev_t devt = inode->i_rdev;
+	int ret = 0;
+
+	if (devt == MKDEV(TTYAUX_MAJOR, 1)) {
+		struct console *co;
+		struct uart_driver *drv;
+		console_lock();
+		for_each_console(co) {
+			if (co->device  != uart_console_device)
+				continue;
+			drv = co->data;
+			mtty = container_of(drv->state, typeof(*mtty), state);
+			mtty +=	co->index;
+			break;
+		}
+		console_unlock();
+		if (!mtty)
+			return -ENODEV;
+	} else {
+		mtty = container_of(inode->i_cdev, typeof(*mtty), cdev);
+	}
+
+	nonseekable_open(inode, file);
+
+	file->private_data = mtty;
+
+	mutex_lock(&mtty->mutex);
+	if (!mtty->usecount++) {
+		ret = uart_port_startup(mtty);
+		if (ret)
+			mtty->usecount--;
+	}
+	mutex_unlock(&mtty->mutex);
+	return ret;
+}
+
+static int minitty_release(struct inode *inode, struct file *file)
+{
+	struct minitty_data *mtty = file->private_data;
+	struct uart_state *state = &mtty->state;
+	struct uart_port *port = state->uart_port;
+
+	mutex_lock(&mtty->mutex);
+	mtty->usecount--;
+	if (!mtty->usecount) {
+		uart_flush_tx_buffer(mtty);
+		uart_port_shutdown(mtty);
+		if (!uart_console(port))
+			uart_change_pm(state, UART_PM_STATE_OFF);
+	}
+	mutex_unlock(&mtty->mutex);
+	return 0;
+}
+
+static const struct file_operations minitty_fops = {
+	.llseek		= no_llseek,
+	.read		= minitty_read,
+	.write		= minitty_write,
+	.poll		= minitty_poll,
+	.unlocked_ioctl	= minitty_ioctl,
+	.open		= minitty_open,
+	.release	= minitty_release,
+};
+
+struct class *minitty_class;
+
+static int
+uart_configure_port(struct uart_driver *drv, struct uart_state *state,
+		    struct uart_port *port)
+{
+	unsigned int flags;
+
+	/*
+	 * If there isn't a port here, don't do anything further.
+	 */
+	if (!port->iobase && !port->mapbase && !port->membase)
+		return -ENXIO;
+
+	/*
+	 * Now do the auto configuration stuff.  Note that config_port
+	 * is expected to claim the resources and map the port for us.
+	 */
+	flags = 0;
+	if (port->flags & UPF_BOOT_AUTOCONF) {
+		if (!(port->flags & UPF_FIXED_TYPE)) {
+			port->type = PORT_UNKNOWN;
+			flags |= UART_CONFIG_TYPE;
+		}
+		port->ops->config_port(port, flags);
+	}
+
+	if (port->type != PORT_UNKNOWN) {
+		unsigned long flags;
+
+		pr_info("%s%d %s\n", drv->dev_name, port->line,
+			port->ops->type ? port->ops->type(port) : "");
+
+		/* Power up port for set_mctrl() */
+		uart_change_pm(state, UART_PM_STATE_ON);
+
+		/*
+		 * Ensure that the modem control lines are de-activated.
+		 * keep the DTR setting that is set in uart_set_options()
+		 * We probably don't need a spinlock around this, but
+		 */
+		spin_lock_irqsave(&port->lock, flags);
+		port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		/*
+		 * If this driver supports console, and it hasn't been
+		 * successfully registered yet, try to re-register it.
+		 * It may be that the port was not available.
+		 */
+		if (port->cons && !(port->cons->flags & CON_ENABLED))
+			register_console(port->cons);
+
+		/*
+		 * Power down all ports by default, except the
+		 * console if we have one.
+		 */
+		if (!uart_console(port))
+			uart_change_pm(state, UART_PM_STATE_OFF);
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/**
+ *	uart_add_one_port - attach a driver-defined port structure
+ *	@drv: pointer to the uart low level driver structure for this port
+ *	@port: uart port structure to use for this port.
+ */
+int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
+{
+	unsigned int index = port->line;
+	dev_t devt = MKDEV(drv->major, drv->minor) + index;
+	struct minitty_data *mtty;
+	struct uart_state *state;
+	int ret;
+
+	mtty = container_of(drv->state, typeof(*mtty), state) + index;
+	state = &mtty->state;
+
+	state->uart_port = port;
+	state->pm_state = UART_PM_STATE_UNDEFINED;
+	port->state = state;
+	port->cons = drv->cons;
+	port->minor = drv->minor + index;
+	uart_port_lock_init(port);
+
+	/* our default termios */
+	mtty->termios.c_iflag = ICRNL;
+	mtty->termios.c_oflag = OPOST | ONLCR;
+	mtty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	mtty->termios.c_lflag = ICANON | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL;
+	mtty->termios.c_ispeed = 9600;
+	mtty->termios.c_ospeed = 9600;
+	memcpy(mtty->termios.c_cc, INIT_C_CC, sizeof(cc_t)*NCCS);
+
+	mutex_init(&mtty->mutex);
+	init_waitqueue_head(&mtty->write_wait);
+	init_waitqueue_head(&mtty->read_wait);
+	INIT_WORK(&mtty->rx_work, uart_rx_work);
+
+	if (port->cons && port->dev)
+		of_console_check(port->dev->of_node, port->cons->name, index);
+
+	ret = uart_configure_port(drv, state, port);
+	/*
+	 * We don't support setserial so no point registering a nonexistent
+	 * device . Silently ignore this port if not present.
+	 */
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
+
+	state->port.console = uart_console(port);
+
+	cdev_init(&mtty->cdev, &minitty_fops);
+	mtty->cdev.owner = drv->owner;
+	ret = cdev_add(&mtty->cdev, devt, 1);
+	if (ret)
+		goto out;
+	mtty->dev = device_create(minitty_class, port->dev, devt, mtty,
+				  "%s%d", drv->dev_name, index);
+	if (IS_ERR(mtty->dev)) {
+		ret = PTR_ERR(mtty->dev);
+		goto err_cdev_del;
+	}
+
+	return 0;
+
+err_cdev_del:
+	cdev_del(&mtty->cdev);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(uart_add_one_port);
+
+/**
+ *	uart_remove_one_port - detach a driver defined port structure
+ *	@drv: pointer to the uart low level driver structure for this port
+ *	@port: uart port structure for this port
+ *
+ *	This unhooks the specified port structure from the core driver.
+ *	No further calls will be made to the low-level code for this port.
+ */
+int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
+{
+	unsigned int index = port->line;
+	dev_t devt = MKDEV(drv->major, drv->minor) + index;
+	struct minitty_data *mtty;
+	struct uart_state *state;
+
+	mtty = container_of(drv->state, typeof(*mtty), state) + index;
+	state = &mtty->state;
+	BUG_ON(state != port->state);
+
+	device_destroy(minitty_class, devt);
+	cdev_del(&mtty->cdev);
+
+	if (uart_console(port))
+		unregister_console(port->cons);
+
+	if (port->type != PORT_UNKNOWN && port->ops->release_port)
+		port->ops->release_port(port);
+	port->type = PORT_UNKNOWN;
+	state->uart_port = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(uart_remove_one_port);
+
+/**
+ *	uart_register_driver - register a driver with the uart core layer
+ *	@drv: low level driver structure
+ *
+ *	Register a uart driver. The per-port structures should be
+ *	registered using uart_add_one_port after this call has succeeded.
+ */
+int uart_register_driver(struct uart_driver *drv)
+{
+	struct minitty_data *mtty;
+	int ret;
+
+	BUG_ON(drv->state);
+
+	mtty = kzalloc(sizeof(*mtty) * drv->nr, GFP_KERNEL);
+	if (!mtty)
+		return -ENOMEM;
+
+	if (!drv->major) {
+		dev_t devt;
+		ret = alloc_chrdev_region(&devt, drv->minor, drv->nr, drv->driver_name);
+		drv->major = MAJOR(devt);
+		drv->minor = MINOR(devt);
+	} else {
+		dev_t devt = MKDEV(drv->major, drv->minor);
+		ret = register_chrdev_region(devt, drv->nr, drv->driver_name);
+	}
+	if (ret < 0)
+		goto err;
+
+	drv->state = &mtty->state;
+	return 0;
+
+err:
+	kfree(mtty);
+	return ret;
+}
+EXPORT_SYMBOL(uart_register_driver);
+
+/**
+ *	uart_unregister_driver - remove a driver from the uart core layer
+ *	@drv: low level driver structure
+ *
+ *	Remove all references to a driver from the core driver.  The low
+ *	level driver must have removed all its ports via the
+ *	uart_remove_one_port() if it registered them with uart_add_one_port().
+ */
+void uart_unregister_driver(struct uart_driver *drv)
+{
+	dev_t devt = MKDEV(drv->major, drv->minor);
+	struct minitty_data *mtty;
+
+	unregister_chrdev_region(devt, drv->nr);
+	mtty = container_of(drv->state, typeof(*mtty), state);
+	drv->state = NULL;
+	kfree(mtty);
+}
+EXPORT_SYMBOL(uart_unregister_driver);
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+	return NULL;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+void do_SAK(struct tty_struct *tty)
+{
+}
+EXPORT_SYMBOL(do_SAK);
+
+struct tty_driver *uart_console_device(struct console *co, int *index)
+{
+	return NULL;
+}
+
+static struct cdev console_cdev;
+
+static char *minitty_devnode(struct device *dev, umode_t *mode)
+{
+	if (!mode)
+		return NULL;
+	if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
+			dev->devt == MKDEV(TTYAUX_MAJOR, 2))
+		*mode = 0666;
+	return NULL;
+}
+
+static int __init minitty_class_init(void)
+{
+	minitty_class = class_create(THIS_MODULE, "tty");
+	if (IS_ERR(minitty_class))
+		return PTR_ERR(minitty_class);
+	minitty_class->devnode = minitty_devnode;
+	return 0;
+}
+postcore_initcall(minitty_class_init);
+
+int __init minitty_init(void)
+{
+	dev_t devt = MKDEV(TTYAUX_MAJOR, 1);
+	cdev_init(&console_cdev, &minitty_fops);
+	if (cdev_add(&console_cdev, devt, 1) ||
+	    register_chrdev_region(devt, 1, "/dev/console") < 0)
+		panic("Couldn't register /dev/console driver\n");
+	device_create(minitty_class, NULL, devt, NULL, "console");
+	return 0;
+}
+device_initcall(minitty_init);
diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h
index c28dd523f9..1d3dc2c237 100644
--- a/include/linux/tty_flip.h
+++ b/include/linux/tty_flip.h
@@ -13,6 +13,8 @@ extern int tty_prepare_flip_string(struct tty_port *port,
 extern void tty_flip_buffer_push(struct tty_port *port);
 void tty_schedule_flip(struct tty_port *port);
 
+#ifndef CONFIG_MINITTY_SERIAL
+
 static inline int tty_insert_flip_char(struct tty_port *port,
 					unsigned char ch, char flag)
 {
@@ -35,6 +37,13 @@ static inline int tty_insert_flip_string(struct tty_port *port,
 	return tty_insert_flip_string_fixed_flag(port, chars, TTY_NORMAL, size);
 }
 
+#else
+extern int tty_insert_flip_char(struct tty_port *port, unsigned char ch,
+				char flag);
+extern int tty_insert_flip_string(struct tty_port *port,
+				  const unsigned char *chars, size_t size);
+#endif
+
 extern void tty_buffer_lock_exclusive(struct tty_port *port);
 extern void tty_buffer_unlock_exclusive(struct tty_port *port);
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 3/5] serial: small Makefile reordering
  2017-04-01 22:21 ` [PATCH v2 3/5] serial: small Makefile reordering Nicolas Pitre
@ 2017-04-02 12:55   ` Andy Shevchenko
  2017-04-02 15:49     ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Andy Shevchenko @ 2017-04-02 12:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Apr 2, 2017 at 1:21 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> Move 21285 entry down alongside other UART drivers to be more consistent
> with the rest of the file. It is kept before 8250 though, to preserve the
> existing link ordering between those two.

I did once for entire Makefile (some logical reordering), but Greg
objected it. Perhaps you can sell it better.

http://www.spinics.net/lists/linux-serial/msg23616.html

>
> Signed-off-by: Nicolas Pitre <nico@linaro.org>
> ---
>  drivers/tty/serial/Makefile | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 2d6288bc45..53c03e0051 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -3,7 +3,6 @@
>  #
>
>  obj-$(CONFIG_SERIAL_CORE) += serial_core.o
> -obj-$(CONFIG_SERIAL_21285) += 21285.o
>
>  obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
>  obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
> @@ -17,6 +16,8 @@ obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
>  obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
>  obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
>
> +obj-$(CONFIG_SERIAL_21285) += 21285.o
> +
>  # Now bring in any enabled 8250/16450/16550 type drivers.
>  obj-$(CONFIG_SERIAL_8250) += 8250/
>
> --
> 2.9.3
>



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file
  2017-04-01 22:21 ` [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file Nicolas Pitre
@ 2017-04-02 13:16   ` Andy Shevchenko
  2017-04-02 15:44     ` Nicolas Pitre
  2017-04-03  7:35   ` kbuild test robot
  1 sibling, 1 reply; 44+ messages in thread
From: Andy Shevchenko @ 2017-04-02 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Apr 2, 2017 at 1:21 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> This contains code that is common between serial_core.c and the
> minitty code to come. Mainly helper functions used by UART drivers.


I have two questions:
- why minitty (what is that by the way?) can't use serial_core.c as a library?
- does -M -C help to make this diff shorter?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
                   ` (4 preceding siblings ...)
  2017-04-01 22:21 ` [PATCH v2 5/5] minitty: minimal TTY support alternative for serial ports Nicolas Pitre
@ 2017-04-02 13:22 ` Andy Shevchenko
  2017-04-02 15:55   ` Nicolas Pitre
  2017-04-02 20:47 ` Andi Kleen
  2017-04-03  7:44 ` Greg Kroah-Hartman
  7 siblings, 1 reply; 44+ messages in thread
From: Andy Shevchenko @ 2017-04-02 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

+Cc people, who have a key roles in all TTY stuff (btw, why you did
miss them? why you didn't include people who reacted on your v1
either?).
I'm pretty sure they are interested in what's going on here.

On Sun, Apr 2, 2017 at 1:21 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> Many embedded systems don't need the full TTY layer support. Most of the
> time, the TTY layer is only a conduit for outputting debugging messages
> over a serial port. The TTY layer also implements many features that are
> very unlikely to ever be used in such a setup. There is great potential
> for both code and dynamic memory size reduction on small systems. This is
> what this patch series is achieving.
>
> The existing TTY code is quite large and complex. Trying to shrink it
> is risky as the potential for breakage is non negligeable, and its
> interchangeable layers impose a lower limit on the code to implement it.
> Therefore, the approach used here consists in the creation of a parallel
> implementation with the very minimal amount of code collapsed together
> that interfaces with existing UART drivers directly and provides TTY-like
> character devices to user space. When the regular TTY layer is disabled,
> then this minitty alternative layer is proposed by Kconfig.
>
> For more details on the rationale and motivations driving this approach
> please see: https://lkml.org/lkml/2017/3/24/634
>
> Of course, making it "mini" means there are limitations to what it does:
>
> - This supports serial ports only. No VT's, no PTY's.
>
> - The default n_tty line discipline is hardcoded and no other line
>   discipline are supported.
>
> - The line discipline features are not all implemented. Notably, XON/XOFF
>   is currently not implemented (although this might not require a lot of
>   code to do it if someone were to need it).
>
> - Hung-up state is not implemented.
>
> - No error handling on RX bytes other than counting them.
>
> - Job control is currently not supported (this may change in the future and
>   be configurable).
>
> But again, most small embedded systems simply don't need those things.
>
> This can be used on any architecture of course, but here's some numbers
> using a minimal ARM config.
>
> When CONFIG_TTY=y, the following files are linked into the kernel:
>
>    text    data     bss     dec     hex filename
>    8796     128       0    8924    22dc drivers/tty/n_tty.o
>   11809     276       0   12085    2f35 drivers/tty/serial/fulltty_serial.o
>    1376       0       0    1376     560 drivers/tty/tty_buffer.o
>   13571     172     132   13875    3633 drivers/tty/tty_io.o
>    3072       0       0    3072     c00 drivers/tty/tty_ioctl.o
>    2457       2     120    2579     a13 drivers/tty/tty_ldisc.o
>    1328       0       0    1328     530 drivers/tty/tty_ldsem.o
>     316       0       0     316     13c drivers/tty/tty_mutex.o
>    2516       0       0    2516     9d4 drivers/tty/tty_port.o
>   5241     578     252   46071    b3f7 (TOTALS)
>
> When CONFIG_TTY=n and CONFIG_MINITTY_SERIAL=y, the above files are replaced
> by the following:
>
>    text    data     bss     dec     hex filename
>    8063       8      64    8135    1fc7 drivers/tty/serial/minitty_serial.o
>
> That's it!  And the runtime buffer usage is much less as well. Future plans
> such as removing runtime baudrate handling for those targets with a known
> fixed baudrate will shrink the code even more.
>
> Changes from v1:
>
> - Added an entry to the MAINTAINERS file.
> - Factored out more common core code into serial_lib.c.
> - Implemented a few more TTY callback functions to be compatible with
>   more UART drivers.
>
> Overall diffstat:
>
>  MAINTAINERS                                     |    8 +-
>  drivers/tty/Kconfig                             |   10 +-
>  drivers/tty/Makefile                            |    3 +-
>  drivers/tty/serial/Kconfig                      |   12 +-
>  drivers/tty/serial/Makefile                     |    7 +-
>  .../serial/{serial_core.c => fulltty_serial.c}  |  419 +---
>  drivers/tty/serial/minitty_serial.c             | 1793 +++++++++++++++++
>  drivers/tty/serial/serial_lib.c                 |  440 ++++
>  drivers/tty/tty_baudrate.c                      |  232 +++
>  drivers/tty/tty_io.c                            |   24 -
>  drivers/tty/tty_ioctl.c                         |  222 --
>  include/linux/console.h                         |    2 +
>  include/linux/serial_core.h                     |    1 +
>  include/linux/tty.h                             |    7 +-
>  include/linux/tty_flip.h                        |    9 +
>  init/main.c                                     |    2 +-
>  kernel/printk/printk.c                          |   24 +
>  17 files changed, 2538 insertions(+), 677 deletions(-)



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file
  2017-04-02 13:16   ` Andy Shevchenko
@ 2017-04-02 15:44     ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-02 15:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, 2 Apr 2017, Andy Shevchenko wrote:

> On Sun, Apr 2, 2017 at 1:21 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> > This contains code that is common between serial_core.c and the
> > minitty code to come. Mainly helper functions used by UART drivers.
> 
> 
> I have two questions:
> - why minitty (what is that by the way?) can't use serial_core.c as a library?

See patch 5/5. It is a compatible replacement for serial_core.c and the 
entire TTY layer collapsed into the smallest code possible, and the 
result is itself smaller than serial_core.c alone.

> - does -M -C help to make this diff shorter?

No it doesn't. Maybe I should have mentioned that there is no functional 
change resulting from this patch.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 3/5] serial: small Makefile reordering
  2017-04-02 12:55   ` Andy Shevchenko
@ 2017-04-02 15:49     ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-02 15:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, 2 Apr 2017, Andy Shevchenko wrote:

> On Sun, Apr 2, 2017 at 1:21 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> > Move 21285 entry down alongside other UART drivers to be more consistent
> > with the rest of the file. It is kept before 8250 though, to preserve the
> > existing link ordering between those two.
> 
> I did once for entire Makefile (some logical reordering), but Greg
> objected it. Perhaps you can sell it better.
> http://www.spinics.net/lists/linux-serial/msg23616.html

The 21285 entry is the only one that clearly is out of place.
I suppose that the rest is debatable.

> 
> >
> > Signed-off-by: Nicolas Pitre <nico@linaro.org>
> > ---
> >  drivers/tty/serial/Makefile | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> > index 2d6288bc45..53c03e0051 100644
> > --- a/drivers/tty/serial/Makefile
> > +++ b/drivers/tty/serial/Makefile
> > @@ -3,7 +3,6 @@
> >  #
> >
> >  obj-$(CONFIG_SERIAL_CORE) += serial_core.o
> > -obj-$(CONFIG_SERIAL_21285) += 21285.o
> >
> >  obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
> >  obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
> > @@ -17,6 +16,8 @@ obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
> >  obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
> >  obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
> >
> > +obj-$(CONFIG_SERIAL_21285) += 21285.o
> > +
> >  # Now bring in any enabled 8250/16450/16550 type drivers.
> >  obj-$(CONFIG_SERIAL_8250) += 8250/
> >
> > --
> > 2.9.3
> >
> 
> 
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-02 13:22 ` [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Andy Shevchenko
@ 2017-04-02 15:55   ` Nicolas Pitre
  2017-04-03 12:56     ` Alan Cox
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-02 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, 2 Apr 2017, Andy Shevchenko wrote:

> +Cc people, who have a key roles in all TTY stuff (btw, why you did
> miss them?

I used what MAINTAINERS and get_maintainer.pl gave me.

> why you didn't include people who reacted on your v1
> either?).
> I'm pretty sure they are interested in what's going on here.

The only one I missed is Ard.

Thanks for pulling more people in.


> 
> On Sun, Apr 2, 2017 at 1:21 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> > Many embedded systems don't need the full TTY layer support. Most of the
> > time, the TTY layer is only a conduit for outputting debugging messages
> > over a serial port. The TTY layer also implements many features that are
> > very unlikely to ever be used in such a setup. There is great potential
> > for both code and dynamic memory size reduction on small systems. This is
> > what this patch series is achieving.
> >
> > The existing TTY code is quite large and complex. Trying to shrink it
> > is risky as the potential for breakage is non negligeable, and its
> > interchangeable layers impose a lower limit on the code to implement it.
> > Therefore, the approach used here consists in the creation of a parallel
> > implementation with the very minimal amount of code collapsed together
> > that interfaces with existing UART drivers directly and provides TTY-like
> > character devices to user space. When the regular TTY layer is disabled,
> > then this minitty alternative layer is proposed by Kconfig.
> >
> > For more details on the rationale and motivations driving this approach
> > please see: https://lkml.org/lkml/2017/3/24/634
> >
> > Of course, making it "mini" means there are limitations to what it does:
> >
> > - This supports serial ports only. No VT's, no PTY's.
> >
> > - The default n_tty line discipline is hardcoded and no other line
> >   discipline are supported.
> >
> > - The line discipline features are not all implemented. Notably, XON/XOFF
> >   is currently not implemented (although this might not require a lot of
> >   code to do it if someone were to need it).
> >
> > - Hung-up state is not implemented.
> >
> > - No error handling on RX bytes other than counting them.
> >
> > - Job control is currently not supported (this may change in the future and
> >   be configurable).
> >
> > But again, most small embedded systems simply don't need those things.
> >
> > This can be used on any architecture of course, but here's some numbers
> > using a minimal ARM config.
> >
> > When CONFIG_TTY=y, the following files are linked into the kernel:
> >
> >    text    data     bss     dec     hex filename
> >    8796     128       0    8924    22dc drivers/tty/n_tty.o
> >   11809     276       0   12085    2f35 drivers/tty/serial/fulltty_serial.o
> >    1376       0       0    1376     560 drivers/tty/tty_buffer.o
> >   13571     172     132   13875    3633 drivers/tty/tty_io.o
> >    3072       0       0    3072     c00 drivers/tty/tty_ioctl.o
> >    2457       2     120    2579     a13 drivers/tty/tty_ldisc.o
> >    1328       0       0    1328     530 drivers/tty/tty_ldsem.o
> >     316       0       0     316     13c drivers/tty/tty_mutex.o
> >    2516       0       0    2516     9d4 drivers/tty/tty_port.o
> >   5241     578     252   46071    b3f7 (TOTALS)
> >
> > When CONFIG_TTY=n and CONFIG_MINITTY_SERIAL=y, the above files are replaced
> > by the following:
> >
> >    text    data     bss     dec     hex filename
> >    8063       8      64    8135    1fc7 drivers/tty/serial/minitty_serial.o
> >
> > That's it!  And the runtime buffer usage is much less as well. Future plans
> > such as removing runtime baudrate handling for those targets with a known
> > fixed baudrate will shrink the code even more.
> >
> > Changes from v1:
> >
> > - Added an entry to the MAINTAINERS file.
> > - Factored out more common core code into serial_lib.c.
> > - Implemented a few more TTY callback functions to be compatible with
> >   more UART drivers.
> >
> > Overall diffstat:
> >
> >  MAINTAINERS                                     |    8 +-
> >  drivers/tty/Kconfig                             |   10 +-
> >  drivers/tty/Makefile                            |    3 +-
> >  drivers/tty/serial/Kconfig                      |   12 +-
> >  drivers/tty/serial/Makefile                     |    7 +-
> >  .../serial/{serial_core.c => fulltty_serial.c}  |  419 +---
> >  drivers/tty/serial/minitty_serial.c             | 1793 +++++++++++++++++
> >  drivers/tty/serial/serial_lib.c                 |  440 ++++
> >  drivers/tty/tty_baudrate.c                      |  232 +++
> >  drivers/tty/tty_io.c                            |   24 -
> >  drivers/tty/tty_ioctl.c                         |  222 --
> >  include/linux/console.h                         |    2 +
> >  include/linux/serial_core.h                     |    1 +
> >  include/linux/tty.h                             |    7 +-
> >  include/linux/tty_flip.h                        |    9 +
> >  init/main.c                                     |    2 +-
> >  kernel/printk/printk.c                          |   24 +
> >  17 files changed, 2538 insertions(+), 677 deletions(-)
> 
> 
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
                   ` (5 preceding siblings ...)
  2017-04-02 13:22 ` [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Andy Shevchenko
@ 2017-04-02 20:47 ` Andi Kleen
  2017-04-02 21:41   ` Nicolas Pitre
  2017-04-03  7:44 ` Greg Kroah-Hartman
  7 siblings, 1 reply; 44+ messages in thread
From: Andi Kleen @ 2017-04-02 20:47 UTC (permalink / raw)
  To: linux-arm-kernel

Nicolas Pitre <nicolas.pitre@linaro.org> writes:
>
> Of course, making it "mini" means there are limitations to what it does:
>
> - This supports serial ports only. No VT's, no PTY's.

No PTYs seems like a big limitation. This means no sshd?

> But again, most small embedded systems simply don't need those things.

They don't need a (debug) way to login over the network? Hard to
believe.

Most of the other stuff we could indeed do without even on larger
systems.

-Andi

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-02 20:47 ` Andi Kleen
@ 2017-04-02 21:41   ` Nicolas Pitre
  2017-04-02 22:44     ` Stuart Longland
  2017-04-03  7:54     ` Andy Shevchenko
  0 siblings, 2 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-02 21:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, 2 Apr 2017, Andi Kleen wrote:

> Nicolas Pitre <nicolas.pitre@linaro.org> writes:
> >
> > Of course, making it "mini" means there are limitations to what it does:
> >
> > - This supports serial ports only. No VT's, no PTY's.
> 
> No PTYs seems like a big limitation. This means no sshd?

Again, my ultimate system target is in the sub-megabyte of RAM.  I 
really doubt you'll be able to fit an SSH server in there even if PTYs 
were supported, unless sshd (or dropbear) can be made really tiny. 
Otherwise you most probably have sufficient resources to run the regular 
TTY code.

That being said, maybe there could be a way to cheaply support PTYs. I 
just didn't investigate it.

> > But again, most small embedded systems simply don't need those things.
> 
> They don't need a (debug) way to login over the network? Hard to
> believe.

This most likely won't be via a standard shell.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-02 21:41   ` Nicolas Pitre
@ 2017-04-02 22:44     ` Stuart Longland
  2017-04-03  1:01       ` Nicolas Pitre
  2017-04-03 18:14       ` Geert Uytterhoeven
  2017-04-03  7:54     ` Andy Shevchenko
  1 sibling, 2 replies; 44+ messages in thread
From: Stuart Longland @ 2017-04-02 22:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/04/17 07:41, Nicolas Pitre wrote:
>> No PTYs seems like a big limitation. This means no sshd?
> Again, my ultimate system target is in the sub-megabyte of RAM.  I 
> really doubt you'll be able to fit an SSH server in there even if PTYs 
> were supported, unless sshd (or dropbear) can be made really tiny. 
> Otherwise you most probably have sufficient resources to run the regular 
> TTY code.

Are we talking small microcontrollers here?  The smallest machine in
terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
RAM, and that had a MMU.

I recall Slackware requiring that you booted with a mounted floppy (no
ramdisk) and possibly even required that you had a second floppy drive
formatted as swap so you'd be able to get through the install without
oomkiller knocking on your door.

The same machine could also "run" Windows 95.  When I say "run", it was
more like a slow crawl.  Bull sharks washed onto land by flood waters
run faster.

Sub-megabyte system support is a noble goal, but I'm wondering how
practical such systems would be, and whether an embedded real-time
kernel might be a better choice than Linux on such systems.
-- 
Stuart Longland (aka Redhatter, VK4MSL)

I haven't lost my mind...
  ...it's backed up on a tape somewhere.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170403/4a0490a2/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-02 22:44     ` Stuart Longland
@ 2017-04-03  1:01       ` Nicolas Pitre
  2017-04-04  0:39         ` Stuart Longland
  2017-04-03 18:14       ` Geert Uytterhoeven
  1 sibling, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-03  1:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 3 Apr 2017, Stuart Longland wrote:

> On 03/04/17 07:41, Nicolas Pitre wrote:
> >> No PTYs seems like a big limitation. This means no sshd?
> > Again, my ultimate system target is in the sub-megabyte of RAM.  I 
> > really doubt you'll be able to fit an SSH server in there even if PTYs 
> > were supported, unless sshd (or dropbear) can be made really tiny. 
> > Otherwise you most probably have sufficient resources to run the regular 
> > TTY code.
> 
> Are we talking small microcontrollers here?  The smallest machine in
> terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
> RAM, and that had a MMU.

Not to repeat what I've said already, I invite you to have a look at 
https://lkml.org/lkml/2017/3/24/634

> I recall Slackware requiring that you booted with a mounted floppy (no
> ramdisk) and possibly even required that you had a second floppy drive
> formatted as swap so you'd be able to get through the install without
> oomkiller knocking on your door.

Did the oom killer even exist in those days? I don't remember.
All I remember is the stack of 73 flopies or so to install Slackware... 
and of course floppy #68 would have developed a bad sector preventing 
you from completing the installation.

> Sub-megabyte system support is a noble goal, but I'm wondering how
> practical such systems would be, and whether an embedded real-time
> kernel might be a better choice than Linux on such systems.

Obviously, you need to leave the idea of a _distribution_ behind. If you 
think of a single user app, and a kernel that only provides those 
syscalls used by that app, and the minimal subset of kernel services 
that such an app require, then nothing prevents such and app/kernel from 
using the actual Linux API. And that's where you get a big advantage 
over other RTOSes. See the link above for the full rationale.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file
  2017-04-01 22:21 ` [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file Nicolas Pitre
  2017-04-02 13:16   ` Andy Shevchenko
@ 2017-04-03  7:35   ` kbuild test robot
  1 sibling, 0 replies; 44+ messages in thread
From: kbuild test robot @ 2017-04-03  7:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Nicolas,

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on v4.11-rc5 next-20170331]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Nicolas-Pitre/minitty-a-minimal-TTY-layer-alternative-for-embedded-systems/20170403-103907
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
config: mips-rm200_defconfig (attached as .config)
compiler: mipsel-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=mips 

All errors (new ones prefixed by >>):

>> ERROR: "uart_port_lock_init" [drivers/tty/serial/serial_core.ko] undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 16937 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170403/7b3be7ac/attachment.gz>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
                   ` (6 preceding siblings ...)
  2017-04-02 20:47 ` Andi Kleen
@ 2017-04-03  7:44 ` Greg Kroah-Hartman
  7 siblings, 0 replies; 44+ messages in thread
From: Greg Kroah-Hartman @ 2017-04-03  7:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 01, 2017 at 06:21:14PM -0400, Nicolas Pitre wrote:
> Many embedded systems don't need the full TTY layer support. Most of the
> time, the TTY layer is only a conduit for outputting debugging messages
> over a serial port. The TTY layer also implements many features that are
> very unlikely to ever be used in such a setup. There is great potential
> for both code and dynamic memory size reduction on small systems. This is
> what this patch series is achieving.
> 
> The existing TTY code is quite large and complex. Trying to shrink it
> is risky as the potential for breakage is non negligeable, and its
> interchangeable layers impose a lower limit on the code to implement it.
> Therefore, the approach used here consists in the creation of a parallel
> implementation with the very minimal amount of code collapsed together
> that interfaces with existing UART drivers directly and provides TTY-like
> character devices to user space. When the regular TTY layer is disabled,
> then this minitty alternative layer is proposed by Kconfig.
> 
> For more details on the rationale and motivations driving this approach
> please see: https://lkml.org/lkml/2017/3/24/634
> 
> Of course, making it "mini" means there are limitations to what it does:
> 
> - This supports serial ports only. No VT's, no PTY's.
> 
> - The default n_tty line discipline is hardcoded and no other line
>   discipline are supported.
> 
> - The line discipline features are not all implemented. Notably, XON/XOFF
>   is currently not implemented (although this might not require a lot of
>   code to do it if someone were to need it).
> 
> - Hung-up state is not implemented.
> 
> - No error handling on RX bytes other than counting them.
> 
> - Job control is currently not supported (this may change in the future and 
>   be configurable).
> 
> But again, most small embedded systems simply don't need those things.
> 
> This can be used on any architecture of course, but here's some numbers
> using a minimal ARM config.
> 
> When CONFIG_TTY=y, the following files are linked into the kernel:
> 
>    text	   data	    bss	    dec	    hex	filename
>    8796	    128	      0	   8924	   22dc	drivers/tty/n_tty.o
>   11809	    276	      0	  12085	   2f35	drivers/tty/serial/fulltty_serial.o
>    1376	      0	      0	   1376	    560	drivers/tty/tty_buffer.o
>   13571	    172	    132	  13875	   3633	drivers/tty/tty_io.o
>    3072	      0	      0	   3072	    c00	drivers/tty/tty_ioctl.o
>    2457	      2	    120	   2579	    a13	drivers/tty/tty_ldisc.o
>    1328	      0	      0	   1328	    530	drivers/tty/tty_ldsem.o
>     316	      0	      0	    316	    13c	drivers/tty/tty_mutex.o
>    2516	      0	      0	   2516	    9d4	drivers/tty/tty_port.o
>   45241	    578	    252	  46071	   b3f7	(TOTALS)
> 
> When CONFIG_TTY=n and CONFIG_MINITTY_SERIAL=y, the above files are replaced
> by the following:
> 
>    text	   data	    bss	    dec	    hex	filename
>    8063	      8	     64	   8135	   1fc7	drivers/tty/serial/minitty_serial.o
> 
> That's it!  And the runtime buffer usage is much less as well. Future plans
> such as removing runtime baudrate handling for those targets with a known
> fixed baudrate will shrink the code even more.

Thanks for the resend.  I agree with your goal of getting Linux running
on these very tiny chips, I want that to happen too.  I'm traveling at
the moment for the next 2 weeks, but will review it in detail when I get
back.  It's in my queue, don't worry, it's not lost.

Ideally others would review it as well...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-02 21:41   ` Nicolas Pitre
  2017-04-02 22:44     ` Stuart Longland
@ 2017-04-03  7:54     ` Andy Shevchenko
  2017-04-03 15:31       ` Andi Kleen
  2017-04-03 16:40       ` Nicolas Pitre
  1 sibling, 2 replies; 44+ messages in thread
From: Andy Shevchenko @ 2017-04-03  7:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 3, 2017 at 12:41 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> On Sun, 2 Apr 2017, Andi Kleen wrote:
>> No PTYs seems like a big limitation. This means no sshd?

> Again, my ultimate system target is in the sub-megabyte of RAM.  I
> really doubt you'll be able to fit an SSH server in there even if PTYs
> were supported, unless sshd (or dropbear) can be made really tiny.

Are you sure you need Linux there? There is a nice Zephyr project
(OpenSource RTOS, POSIX compatible) exactly for microcontrollers.

While I can agree on making Linux stuff less fatty, I can't agree on
doing this way. We have for now two subsystems to serve for serial
devices, you are proposing third one for only narrow class of devices.
>From my point of view is better to achive your goal with existing
system (as a proof of concept maybe even with ugly #ifdef:fery).

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-02 15:55   ` Nicolas Pitre
@ 2017-04-03 12:56     ` Alan Cox
  2017-04-03 16:06       ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Alan Cox @ 2017-04-03 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, 2017-04-02 at 11:55 -0400, Nicolas Pitre wrote:
> On Sun, 2 Apr 2017, Andy Shevchenko wrote:
> 
> > 
> > +Cc people, who have a key roles in all TTY stuff (btw, why you did
> > miss them?
> 
> I used what MAINTAINERS and get_maintainer.pl gave me.
> 

I didn't see this until now as I'm mid house move so not following a
lot of l/k.

If you need a tiny tiny tty layer console for some kind of not quite
mini-Linux please just steal the one from Fuzix or something similar
thats only a couple of K in size and only needs extremely simple send
byte/rx byte type handlers.

Alternatively just compile out tty support entirely. What do you
actually need ? Console doesn't need tty layer and if you have a
debug/management interface that doesn't have to be tty and text based
either.

Being able to compile out tty support would be useful, having two tty
layers that are intertwined and now both totally unmaintable is not
IMHO progress.

Alan

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03  7:54     ` Andy Shevchenko
@ 2017-04-03 15:31       ` Andi Kleen
  2017-04-03 17:27         ` Nicolas Pitre
  2017-04-03 19:57         ` Adam Borowski
  2017-04-03 16:40       ` Nicolas Pitre
  1 sibling, 2 replies; 44+ messages in thread
From: Andi Kleen @ 2017-04-03 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

> While I can agree on making Linux stuff less fatty, I can't agree on
> doing this way. We have for now two subsystems to serve for serial
> devices, you are proposing third one for only narrow class of devices.

It should be actually most (all?) real serial ones.

> From my point of view is better to achive your goal with existing
> system (as a proof of concept maybe even with ugly #ifdef:fery).

I like the idea of mintty (if it supported ptys).

Except for that (and possibly VT) it is unlikely that people really
rely on the obsolete terminal features from the 70ies. So it's a kind
of cleanup.

-Andi

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 12:56     ` Alan Cox
@ 2017-04-03 16:06       ` Nicolas Pitre
  2017-04-03 18:05         ` Alan Cox
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-03 16:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 3 Apr 2017, Alan Cox wrote:

> If you need a tiny tiny tty layer console for some kind of not quite
> mini-Linux please just steal the one from Fuzix or something similar
> thats only a couple of K in size and only needs extremely simple send
> byte/rx byte type handlers.

This, however, requires that every UART driver be rewritten to suit this 
code. I don't want to lose one of Linux's best advantage which is 
extensive hardware support. I want to reuse as much of the existing 
hardware drivers as possible unchanged.

I already have code that fits the Linux model and it weights 
only 8K.

> Alternatively just compile out tty support entirely. What do you
> actually need ? Console doesn't need tty layer and if you have a
> debug/management interface that doesn't have to be tty and text based
> either.

It is nevertheless very convenient to be able to use a standard shell 
with it. I can easily remove canonical mode support and then it is down 
to 7.3K. Modem line control and runtime baudrate handling could also 
trivially be configured out for yet more saving.

> Being able to compile out tty support would be useful, having two tty
> layers that are intertwined and now both totally unmaintable is not
> IMHO progress.

I beg to disagree here.  First, before you call my code "totally 
unmaintainable" I'd politely ask you to have a look at it first.

There is also very little intertwining here. My code does not rely on 
the existing TTY code (except for the termios baudrate handling which I 
factored out). I'm creating my own char devices on one end and 
interacting with UART drivers using the same low-level call interface 
used by the existing code at the other end. And given that it is much 
simpler in termps of capabilities, it is also very easy to maintain.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03  7:54     ` Andy Shevchenko
  2017-04-03 15:31       ` Andi Kleen
@ 2017-04-03 16:40       ` Nicolas Pitre
  1 sibling, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-03 16:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 3 Apr 2017, Andy Shevchenko wrote:

> On Mon, Apr 3, 2017 at 12:41 AM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> > On Sun, 2 Apr 2017, Andi Kleen wrote:
> >> No PTYs seems like a big limitation. This means no sshd?
> 
> > Again, my ultimate system target is in the sub-megabyte of RAM.  I
> > really doubt you'll be able to fit an SSH server in there even if PTYs
> > were supported, unless sshd (or dropbear) can be made really tiny.
> 
> Are you sure you need Linux there? There is a nice Zephyr project
> (OpenSource RTOS, POSIX compatible) exactly for microcontrollers.

I know that Zephyr is LF endorsed, aim to slow fragmentation in that 
space, etc.  But it is in itself yet another RTOS. It doesn't look like 
it is really POSIX compatible yet, and is certainly not Linux 
compatible.

I don't pretend that Linux should always be preferred to Zephyr. For 
example, I don't think Linux could ever be used with 32KB of RAM while 
Zephyr easily can.  However, in the hundreds of KB of RAM, given the 
choice between Linux and anything else, I can tell you that many people 
would go with Linux.

The goal is really to be able to leverage the existing Linux knowledge 
and ecosystem. Be able to develop your application on your PC 
workstation, singlestep it, strace it, validate the tiny version of 
those kernel subsystems there too with existing fuzers, etc.  If a 
security issue turns up in your product, you have plenty of people who 
are already familiar with the Linux environment, much more than Zephyr 
or any other RTOSes.

> While I can agree on making Linux stuff less fatty, I can't agree on
> doing this way. We have for now two subsystems to serve for serial
> devices, you are proposing third one for only narrow class of devices.
> From my point of view is better to achive your goal with existing
> system (as a proof of concept maybe even with ugly #ifdef:fery).

Been there already. It doesn't work. The #ifdef:fery in the existing 
code simply doesn't cut it. Because of its flexibility, the existing 
code constitutes a stack of many layers each with its own interface and 
buffering. It uses much more runtime memory simply because it can afford 
it on all existing systems supported by Linux. It can drive a large bank 
of modems without a single hiccup if you're still into running a BBS. 
That's why the existing code is how it is.

I don't want a proof of concept. I want something that is maintainable. 
Adding #ifdef's to the existing code will make the end result way less 
maintainable, either for the standard or the mini use case. By being 
really small, the maintenance cost of a parallel implementation isn't 
very high, certainly much less than trying to maintain a single version 
that can scale to both extremes.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 15:31       ` Andi Kleen
@ 2017-04-03 17:27         ` Nicolas Pitre
  2017-04-03 19:57         ` Adam Borowski
  1 sibling, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-03 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 3 Apr 2017, Andi Kleen wrote:

> I like the idea of mintty (if it supported ptys).

In fact PTYs could probably be implemented like another UART driver for 
the master side.

But that may come later.

> Except for that (and possibly VT) it is unlikely that people really
> rely on the obsolete terminal features from the 70ies. So it's a kind
> of cleanup.

I wouldn't push for replacing the existing code though. It is stable and 
full featured. The mini version may well never be fully standard 
compliant to keep the code small.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 16:06       ` Nicolas Pitre
@ 2017-04-03 18:05         ` Alan Cox
  2017-04-03 19:50           ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Alan Cox @ 2017-04-03 18:05 UTC (permalink / raw)
  To: linux-arm-kernel

> evertheless very convenient to be able to use a standard
> shell?
> with it.

A standard shell will work over things other than a tty device. It
really doesn't care so long as it gets a stream of data punctuated by
end of statement symbols. It'll work over pipes, sockets, from files.

> I beg to disagree here.??First, before you call my code "totally?
> unmaintainable" I'd politely ask you to have a look at it first.

I said the combination makes it more unmaintainable. If you have two
tty layers one of them faking the API of the other at various interface
points then if the core tty layer wants to make a major change it no
longer can - because it'll break the other tty layer. In addition I
worry it won't be long before someone wants kgdb, gdbstubs and sysrq
over the cut down console and on it will go.

The uart layer is also known broken as an API - it is itself bloated
and over-locking (for example if it was being written today kfifo would
be used). What happens if we want to abolish it or encourage people to
move away from it (as we IMHO should be) ?

The serio code started with exactly the same problem, but now at least
talks tty layer. In your case you are tying it to something we
eventually ought to get rid of.

I also find the large scale need for it hard to believe. If you are
within 64K of running out of memory on your debug/devel device how are
you going to have space to fix security holes and do upgrades as they
occur in production (where presumably you don't need the tty driver) ?
The kernel doesn't exactly get smaller each release.

Alan

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-02 22:44     ` Stuart Longland
  2017-04-03  1:01       ` Nicolas Pitre
@ 2017-04-03 18:14       ` Geert Uytterhoeven
  2017-04-03 18:57         ` Rob Herring
  2017-04-03 21:05         ` Andy Shevchenko
  1 sibling, 2 replies; 44+ messages in thread
From: Geert Uytterhoeven @ 2017-04-03 18:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 3, 2017 at 12:44 AM, Stuart Longland
<stuartl@longlandclan.id.au> wrote:
> On 03/04/17 07:41, Nicolas Pitre wrote:
>>> No PTYs seems like a big limitation. This means no sshd?
>> Again, my ultimate system target is in the sub-megabyte of RAM.  I
>> really doubt you'll be able to fit an SSH server in there even if PTYs
>> were supported, unless sshd (or dropbear) can be made really tiny.
>> Otherwise you most probably have sufficient resources to run the regular
>> TTY code.
>
> Are we talking small microcontrollers here?  The smallest machine in
> terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
> RAM, and that had a MMU.

Let's halve that. I once tried and ran Linux in 2 MiB, incl. X, twm, and xterm.
Of course with swap enabled.  And swapping like hell.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 18:14       ` Geert Uytterhoeven
@ 2017-04-03 18:57         ` Rob Herring
  2017-04-03 19:46           ` Geert Uytterhoeven
  2017-04-03 21:05         ` Andy Shevchenko
  1 sibling, 1 reply; 44+ messages in thread
From: Rob Herring @ 2017-04-03 18:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 3, 2017 at 1:14 PM, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Mon, Apr 3, 2017 at 12:44 AM, Stuart Longland
> <stuartl@longlandclan.id.au> wrote:
>> On 03/04/17 07:41, Nicolas Pitre wrote:
>>>> No PTYs seems like a big limitation. This means no sshd?
>>> Again, my ultimate system target is in the sub-megabyte of RAM.  I
>>> really doubt you'll be able to fit an SSH server in there even if PTYs
>>> were supported, unless sshd (or dropbear) can be made really tiny.
>>> Otherwise you most probably have sufficient resources to run the regular
>>> TTY code.
>>
>> Are we talking small microcontrollers here?  The smallest machine in
>> terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
>> RAM, and that had a MMU.
>
> Let's halve that. I once tried and ran Linux in 2 MiB, incl. X, twm, and xterm.
> Of course with swap enabled.  And swapping like hell.

These are different target uses. We're talking about fixed function,
statically linked user space at the minimum (some may want no
userspace even). Applications that could use an RTOS instead but
benefit from the Linux hardware support, features and ecosystem. It's
not a whole new code base or environment to learn. Maybe Zephyr will
have traction and improve things, but projects I've been involved with
using RTOSs generally have discussions around needing to re-write the
crappy RTOS.

The absolute amount of RAM target is not so important. What's
important is getting to a size feasible for onchip RAM. That's always
moving (up), but has generally been out of reach for Linux.

Rob

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 18:57         ` Rob Herring
@ 2017-04-03 19:46           ` Geert Uytterhoeven
  0 siblings, 0 replies; 44+ messages in thread
From: Geert Uytterhoeven @ 2017-04-03 19:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 3, 2017 at 8:57 PM, Rob Herring <robh@kernel.org> wrote:
> On Mon, Apr 3, 2017 at 1:14 PM, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>> On Mon, Apr 3, 2017 at 12:44 AM, Stuart Longland
>> <stuartl@longlandclan.id.au> wrote:
>>> On 03/04/17 07:41, Nicolas Pitre wrote:
>>>>> No PTYs seems like a big limitation. This means no sshd?
>>>> Again, my ultimate system target is in the sub-megabyte of RAM.  I
>>>> really doubt you'll be able to fit an SSH server in there even if PTYs
>>>> were supported, unless sshd (or dropbear) can be made really tiny.
>>>> Otherwise you most probably have sufficient resources to run the regular
>>>> TTY code.
>>>
>>> Are we talking small microcontrollers here?  The smallest machine in
>>> terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
>>> RAM, and that had a MMU.
>>
>> Let's halve that. I once tried and ran Linux in 2 MiB, incl. X, twm, and xterm.
>> Of course with swap enabled.  And swapping like hell.
>
> These are different target uses. We're talking about fixed function,
> statically linked user space at the minimum (some may want no
> userspace even). Applications that could use an RTOS instead but
> benefit from the Linux hardware support, features and ecosystem. It's
> not a whole new code base or environment to learn. Maybe Zephyr will
> have traction and improve things, but projects I've been involved with
> using RTOSs generally have discussions around needing to re-write the
> crappy RTOS.

Sure. I just wanted to point out that there was a time you could have
_more_ than you need for small fixed function embedded systems in
2 MiB of RAM.

> The absolute amount of RAM target is not so important. What's
> important is getting to a size feasible for onchip RAM. That's always
> moving (up), but has generally been out of reach for Linux.

DigiKey shows 39 ARM SoCs with 1 MiB or more of RAM.
But once you want 3 MiB or more, the lone winner is Renesas' RZ/A1 (up to
10 MiB).

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 18:05         ` Alan Cox
@ 2017-04-03 19:50           ` Nicolas Pitre
  2017-04-04 13:40             ` Alan Cox
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-03 19:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 3 Apr 2017, Alan Cox wrote:

> > evertheless very convenient to be able to use a standard
> > shell?
> > with it.
> 
> A standard shell will work over things other than a tty device. It
> really doesn't care so long as it gets a stream of data punctuated by
> end of statement symbols. It'll work over pipes, sockets, from files.

But no job control. No line editing with echo when the shell is busy, 
etc.

And actually it is not the TTY support per se that takes the most code. 
Just the chardev read/write/poll/open/release stuff is rather 
significant. Removing canonical support makes it 7.3K down from 8K. 
Removing echo support makes it down to 7.2K. Removing baudrate support = 
7.0K. Copying termios to/from user space is horrid: removing that and 
we're down to 5.6K. At which point there's only a raw device interface 
to serial hardware.

> > I beg to disagree here.??First, before you call my code "totally?
> > unmaintainable" I'd politely ask you to have a look at it first.
> 
> I said the combination makes it more unmaintainable. If you have two
> tty layers one of them faking the API of the other at various interface
> points then if the core tty layer wants to make a major change it no
> longer can - because it'll break the other tty layer. In addition I
> worry it won't be long before someone wants kgdb, gdbstubs and sysrq
> over the cut down console and on it will go.

sysrq is already there. It is handled directly at the UART driver level. 
I didn't have to do anything for it.

Isn't kgdb and gdbstubs the same thing?  In any case the TTY layer is 
also already completely bypassed in that case. Those are in fact just 
like kernel console targets that also can read and not just write.

Again, what I'm using is the same low-level UART interface as 
drivers/tty/serial/serial_core.c is using to interact with UART drivers. 
If someone wants to make a change to that interface, the 30 or so UART 
drivers will have to be changed as well. I don't think that would be a 
big deal to change the minitty code to follow suit. And I won't hide 
under a rock while this happens.

If you're making a change in any of the rest of the existing TTY stack, 
then my code won't care as it does not interact with it. I'm not even 
using tty_struct at all!

> The uart layer is also known broken as an API - it is itself bloated
> and over-locking (for example if it was being written today kfifo would
> be used). What happens if we want to abolish it or encourage people to
> move away from it (as we IMHO should be) ?

Same answer as above.

> The serio code started with exactly the same problem, but now at least
> talks tty layer. In your case you are tying it to something we
> eventually ought to get rid of.

You won't get rid of UART drivers, right?

> I also find the large scale need for it hard to believe. If you are
> within 64K of running out of memory on your debug/devel device how are
> you going to have space to fix security holes and do upgrades as they
> occur in production (where presumably you don't need the tty driver) ?

Some production devices can do it all in much less RAM than that and 
they are being connected to the net. Don't worry, that's not where I see 
any Linux derivative go.

Some devices, though, have 256K of on-chip RAM. Those devices will make 
it into your surrounding. Having so much more RAM (no pun intended) 
they'll be capable of even more damage. Would you be more confident, 
when a security issue arises (because it will), to know that some Linux 
code base is used rather than any random RTOS out there with only one 
hundredth of the actual Linux following? If so please indulge me a bit.

> The kernel doesn't exactly get smaller each release.

No kidding.

This is why a slight shift in the Linux model has to be accommodated 
for. We cannot just have a single subsystem to scale to both extremes 
all the time anymore.  We already have different memory allocators for 
different sizes and needs so precedents do exist.

The greatest value in Linux his its interfaces. Doesn't matter if the 
kernel internal interfaces change, the value is in having common 
interfaces for all Linux developers available anywhere. We should allow 
for parallel implementations of subsystems as long as they remain 
interchangeable. Hence this mini TTY alternative, and that's only the 
beginning.

I'd invite you to read more of the rationale for that here:

https://lkml.org/lkml/2017/3/24/634

It's rather long and I don't want to repeat it all.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 15:31       ` Andi Kleen
  2017-04-03 17:27         ` Nicolas Pitre
@ 2017-04-03 19:57         ` Adam Borowski
  2017-04-03 20:09           ` Nicolas Pitre
  1 sibling, 1 reply; 44+ messages in thread
From: Adam Borowski @ 2017-04-03 19:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 03, 2017 at 08:31:03AM -0700, Andi Kleen wrote:
> Except for that (and possibly VT) it is unlikely that people really
> rely on the obsolete terminal features from the 70ies. So it's a kind
> of cleanup.

But... but... but what shall we do without OLCUC?!?

I guess sending these features to the pasture would be nice even in
mainstream TTY.  Probably even without a Kconfig option to restore them.

-- 
??????? Meow!
???????
??????? Collisions shmolisions, let's see them find a collision or second
??????? preimage for double rot13!

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 19:57         ` Adam Borowski
@ 2017-04-03 20:09           ` Nicolas Pitre
  2017-04-03 20:32             ` Adam Borowski
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-03 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 3 Apr 2017, Adam Borowski wrote:

> On Mon, Apr 03, 2017 at 08:31:03AM -0700, Andi Kleen wrote:
> > Except for that (and possibly VT) it is unlikely that people really
> > rely on the obsolete terminal features from the 70ies. So it's a kind
> > of cleanup.
> 
> But... but... but what shall we do without OLCUC?!?
> 
> I guess sending these features to the pasture would be nice even in
> mainstream TTY.  Probably even without a Kconfig option to restore them.

Thing is... those arcane features don't take much code at all:

		if (O_OLCUC(tty))
			c = toupper(c);

That's it. I didn't make the minitty code 5x smaller just by omitting 
those.  ;-)


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 20:09           ` Nicolas Pitre
@ 2017-04-03 20:32             ` Adam Borowski
  0 siblings, 0 replies; 44+ messages in thread
From: Adam Borowski @ 2017-04-03 20:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 03, 2017 at 04:09:38PM -0400, Nicolas Pitre wrote:
> On Mon, 3 Apr 2017, Adam Borowski wrote:
> 
> > On Mon, Apr 03, 2017 at 08:31:03AM -0700, Andi Kleen wrote:
> > > Except for that (and possibly VT) it is unlikely that people really
> > > rely on the obsolete terminal features from the 70ies. So it's a kind
> > > of cleanup.
> > 
> > But... but... but what shall we do without OLCUC?!?
> > 
> > I guess sending these features to the pasture would be nice even in
> > mainstream TTY.  Probably even without a Kconfig option to restore them.
> 
> Thing is... those arcane features don't take much code at all:
> 
> 		if (O_OLCUC(tty))
> 			c = toupper(c);
> 
> That's it. I didn't make the minitty code 5x smaller just by omitting 
> those.  ;-)

Except, those two lines have two bugs:
* it mangles most non-ASCII (kernel's toupper() hard-codes ISO-8859-1
  which no one uses anymore)
* it mangles a number of ANSI codes, making them unusable on any vt100ish
  terminal (ie, any post-1980)

I just happened to send an April Fools pull request
(https://github.com/kilobyte/linux.git runes) in which the first commit
fixes these:
https://github.com/kilobyte/linux/commit/268cde7c6dde54fcbc81df68d66b2389d77d01f2

Even though it's a real fix (unlike the subsequent fun), guess why I'm not
sending it to Greg and Jiri...

-- 
??????? Meow!
???????
??????? Collisions shmolisions, let's see them find a collision or second
??????? preimage for double rot13!

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 18:14       ` Geert Uytterhoeven
  2017-04-03 18:57         ` Rob Herring
@ 2017-04-03 21:05         ` Andy Shevchenko
  2017-04-04 16:59           ` Tom Zanussi
  1 sibling, 1 reply; 44+ messages in thread
From: Andy Shevchenko @ 2017-04-03 21:05 UTC (permalink / raw)
  To: linux-arm-kernel

+Cc: Tom

Summon Tom to the discussion. He tried once hard to shrink a Linux
kernel to something working in 1M+ RAM on x86.

Tom, sorry, I recall this a bit late, perhaps you might be interested
in reading discussion from the beginning.

On Mon, Apr 3, 2017 at 9:14 PM, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Mon, Apr 3, 2017 at 12:44 AM, Stuart Longland
> <stuartl@longlandclan.id.au> wrote:
>> On 03/04/17 07:41, Nicolas Pitre wrote:
>>>> No PTYs seems like a big limitation. This means no sshd?
>>> Again, my ultimate system target is in the sub-megabyte of RAM.  I
>>> really doubt you'll be able to fit an SSH server in there even if PTYs
>>> were supported, unless sshd (or dropbear) can be made really tiny.
>>> Otherwise you most probably have sufficient resources to run the regular
>>> TTY code.
>>
>> Are we talking small microcontrollers here?  The smallest machine in
>> terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
>> RAM, and that had a MMU.
>
> Let's halve that. I once tried and ran Linux in 2 MiB, incl. X, twm, and xterm.
> Of course with swap enabled.  And swapping like hell.


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03  1:01       ` Nicolas Pitre
@ 2017-04-04  0:39         ` Stuart Longland
  0 siblings, 0 replies; 44+ messages in thread
From: Stuart Longland @ 2017-04-04  0:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/04/17 11:01, Nicolas Pitre wrote:
> On Mon, 3 Apr 2017, Stuart Longland wrote:
>> On 03/04/17 07:41, Nicolas Pitre wrote:
>>>> No PTYs seems like a big limitation. This means no sshd?
>>> Again, my ultimate system target is in the sub-megabyte of RAM.  I 
>>> really doubt you'll be able to fit an SSH server in there even if PTYs 
>>> were supported, unless sshd (or dropbear) can be made really tiny. 
>>> Otherwise you most probably have sufficient resources to run the regular 
>>> TTY code.
>>
>> Are we talking small microcontrollers here?  The smallest machine in
>> terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
>> RAM, and that had a MMU.
> 
> Not to repeat what I've said already, I invite you to have a look at 
> https://lkml.org/lkml/2017/3/24/634
> 
>> I recall Slackware requiring that you booted with a mounted floppy (no
>> ramdisk) and possibly even required that you had a second floppy drive
>> formatted as swap so you'd be able to get through the install without
>> oomkiller knocking on your door.
> 
> Did the oom killer even exist in those days? I don't remember.
> All I remember is the stack of 73 flopies or so to install Slackware... 
> and of course floppy #68 would have developed a bad sector preventing 
> you from completing the installation.

It probably didn't, my memory is a bit hazy, even though the machine in
question was long obsolete by the time I did this experiment.  The
version of Slackware was pretty old by that time too.

Luckily for me, I had a network, I could mount the CD disk sets over NFS
that way, and so the only floppies I had to worry about were the boot
and root floppies.

But I digress? :-)

>> Sub-megabyte system support is a noble goal, but I'm wondering how
>> practical such systems would be, and whether an embedded real-time
>> kernel might be a better choice than Linux on such systems.
> 
> Obviously, you need to leave the idea of a _distribution_ behind. If you 
> think of a single user app, and a kernel that only provides those 
> syscalls used by that app, and the minimal subset of kernel services 
> that such an app require, then nothing prevents such and app/kernel from 
> using the actual Linux API. And that's where you get a big advantage 
> over other RTOSes. See the link above for the full rationale.

Fair enough? so basically using the Linux kernel in place of an embedded
kernel like FreeRTOS or eCos.  Still, as I say a noble goal, I wish the
project well.  I guess it can be our answer to RetroBSD. :-)
-- 
Stuart Longland (aka Redhatter, VK4MSL)

I haven't lost my mind...
  ...it's backed up on a tape somewhere.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170404/6971d352/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 19:50           ` Nicolas Pitre
@ 2017-04-04 13:40             ` Alan Cox
  2017-04-04 19:26               ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Alan Cox @ 2017-04-04 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

> But no job control. No line editing with echo when the shell is
> busy,?
> etc.

This is a debug interface. If RAM is that precious do the line editing
on the other end of the link, like normal sane RTOS people do. Most
terminal apps support line by line modes.

> we're down to 5.6K. At which point there's only a raw device
> interface?
> to serial hardware.

Which if you did a simple plain chardev without trying to fake the
rather out of date uart layer would come down way further still.

> ?the same low-level UART interface as?
> drivers/tty/serial/serial_core.c is using to interact with UART
> drivers.?
> If someone wants to make a change to that interface, the 30 or so
> UART?
> drivers will have to be changed as well. I don't think that would be
> a?
> big deal to change the minitty code to follow suit. And I won't hide?
> under a rock while this happens.

Fair enough.


> > talks tty layer. In your case you are tying it to something we
> > eventually ought to get rid of.
> 
> You won't get rid of UART drivers, right?

Given infinite time the uart layer ought to go away and be replaced
with a simple kfifo queue.

> vices, though, have 256K of on-chip RAM. Those devices will
> make?
> it into your surrounding. Having so much more RAM (no pun intended)?
> they'll be capable of even more damage. Would you be more confident,?
> when a security issue arises (because it will), to know that some
> Linux?
> code base is used rather than any random RTOS out there with only
> one?
> hundredth of the actual Linux following? If so please indulge me a
> bit.

Actually for any safety critical system both terrify me about as much.
None of them are generally written to any appropriate ISO safety
standard, or in an appropriate language.

I did read your rationale. I am deeply dubious that re-doing the uart
layer is the right approach versus just doing a tiny char device, but
I've said my piece.

Alan

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-03 21:05         ` Andy Shevchenko
@ 2017-04-04 16:59           ` Tom Zanussi
  2017-04-04 17:08             ` Andy Shevchenko
  2017-04-04 18:53             ` Nicolas Pitre
  0 siblings, 2 replies; 44+ messages in thread
From: Tom Zanussi @ 2017-04-04 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Tue, 2017-04-04 at 00:05 +0300, Andy Shevchenko wrote:
> +Cc: Tom
> 
> Summon Tom to the discussion. He tried once hard to shrink a Linux
> kernel to something working in 1M+ RAM on x86.
> 

Yes, in a previous project, I had been working toward getting a < 1M
system to boot on Galileo hardware (which it did, but using more than
that - the Galileo2 has 256MB, but it was the target hardware at the
time, and I was hoping eventually to be able to boot out of the 512k
on-chip SRAM).

I was focused at that point mainly on the kernel static size, and using
a combination of Josh Triplett's tinification tree, Andi Kleen's LTO and
net-diet patches, and my own miscellaneous patches that I was planning
on eventually upstreaming, I ended up with a system that I could boot to
shell with a 455k text size:

Memory: 235636K/245176K available (455K kernel code, 61K rwdata,
64K rodata, 132K init, 56K bss, 3056K reserved, 0K cma-reserved)

virtual kernel memory layout:
    fixmap  : 0xfffe5000 - 0xfffff000   ( 104 kB)
    vmalloc : 0xd05f0000 - 0xfffe3000   ( 761 MB)
    lowmem  : 0xc0000000 - 0xcfdf0000   ( 253 MB)
      .init : 0xc1094000 - 0xc10b5000   ( 132 kB)
      .data : 0xc1071fac - 0xc1092760   ( 129 kB)
      .text : 0xc1000000 - 0xc1071fac   ( 455 kB)

That was without networking.  Enabling networking added about 250k, and
at that point I could ssh in and run a webserver, still less than 1M as
far as kernel static size, which of course completely ignores the kernel
dynamic size and userspace.

My goal was to get rid of shell access and dropbear altogether and have
all access be via webserver, which I did by using nostromo, mainly for
convenience, until I could get some 'cgi' added to Alan Cox's ?Web
(about 20k).

Anyway, that work, as I left it a couple years ago, is here, in case
anyone's interested (it's a yocto layer and yocto-based kernel
containing many topic branches, but building it according to the
directions in the README will yield a standard kernel and .config in the
working directory and allow you to ignore all the yocto stuff): 

https://github.com/tzanussi/linux-yocto-micro-4.1  
https://github.com/tzanussi/meta-microlinux/tree/jethro

It's nice to see tinification work being done again -@the time I
stopped working on it it seemed there was no desire from maintainers in
general to merge anything that would create new options designed only
for the purpose of tinification.

In fact, as a kind of backup plan for that, I also played around with
the idea of auto-generating a kernel that would contain only the
functions that were demonstrated to be used by the (single-purpose)
workload.  It was similar to the idea of making every system call
configurable and then including only the ones used by the workload, but
taking it a step further and doing that for every function in the
kernel, not just system calls.

I had a script that would take the output of the function_hist histogram
taken while exhaustively running the workload:

  https://lkml.org/lkml/2015/5/20/994

And with a kernel compiled using -ffunction-sections removing all
functions that were never referenced.  I never got a bootable kernel out
of it, but mainly just because I ran out of time and had to move onto
other things.  I may dust it off and try again, just for fun... ;-)

hth,

Tom

> Tom, sorry, I recall this a bit late, perhaps you might be interested
> in reading discussion from the beginning.
> 
> On Mon, Apr 3, 2017 at 9:14 PM, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > On Mon, Apr 3, 2017 at 12:44 AM, Stuart Longland
> > <stuartl@longlandclan.id.au> wrote:
> >> On 03/04/17 07:41, Nicolas Pitre wrote:
> >>>> No PTYs seems like a big limitation. This means no sshd?
> >>> Again, my ultimate system target is in the sub-megabyte of RAM.  I
> >>> really doubt you'll be able to fit an SSH server in there even if PTYs
> >>> were supported, unless sshd (or dropbear) can be made really tiny.
> >>> Otherwise you most probably have sufficient resources to run the regular
> >>> TTY code.
> >>
> >> Are we talking small microcontrollers here?  The smallest machine in
> >> terms of RAM I ever recall running Linux on was a 386SX/25 MHz with 4MB
> >> RAM, and that had a MMU.
> >
> > Let's halve that. I once tried and ran Linux in 2 MiB, incl. X, twm, and xterm.
> > Of course with swap enabled.  And swapping like hell.
> 
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 16:59           ` Tom Zanussi
@ 2017-04-04 17:08             ` Andy Shevchenko
  2017-04-04 17:59               ` Tom Zanussi
  2017-04-04 18:53             ` Nicolas Pitre
  1 sibling, 1 reply; 44+ messages in thread
From: Andy Shevchenko @ 2017-04-04 17:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 4, 2017 at 7:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
> On Tue, 2017-04-04 at 00:05 +0300, Andy Shevchenko wrote:

> Yes, in a previous project, I had been working toward getting a < 1M
> system to boot on Galileo hardware (which it did, but using more than
> that - the Galileo2 has 256MB, but it was the target hardware at the
> time, and I was hoping eventually to be able to boot out of the 512k
> on-chip SRAM).
>
> I was focused at that point mainly on the kernel static size, and using
> a combination of Josh Triplett's tinification tree, Andi Kleen's LTO and
> net-diet patches, and my own miscellaneous patches that I was planning
> on eventually upstreaming, I ended up with a system that I could boot to
> shell with a 455k text size:
>
> Memory: 235636K/245176K available (455K kernel code, 61K rwdata,
> 64K rodata, 132K init, 56K bss, 3056K reserved, 0K cma-reserved)
>
> virtual kernel memory layout:
>     fixmap  : 0xfffe5000 - 0xfffff000   ( 104 kB)
>     vmalloc : 0xd05f0000 - 0xfffe3000   ( 761 MB)
>     lowmem  : 0xc0000000 - 0xcfdf0000   ( 253 MB)
>       .init : 0xc1094000 - 0xc10b5000   ( 132 kB)
>       .data : 0xc1071fac - 0xc1092760   ( 129 kB)
>       .text : 0xc1000000 - 0xc1071fac   ( 455 kB)
>
> That was without networking.  Enabling networking added about 250k, and
> at that point I could ssh in and run a webserver, still less than 1M as
> far as kernel static size, which of course completely ignores the kernel
> dynamic size and userspace.

Thanks for sharing your experience. The question closer to this
discussion what did you do against TTY/UART/(related) layer(s)?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 17:08             ` Andy Shevchenko
@ 2017-04-04 17:59               ` Tom Zanussi
  2017-04-04 18:04                 ` Andy Shevchenko
  0 siblings, 1 reply; 44+ messages in thread
From: Tom Zanussi @ 2017-04-04 17:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2017-04-04 at 20:08 +0300, Andy Shevchenko wrote:
> On Tue, Apr 4, 2017 at 7:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
> > On Tue, 2017-04-04 at 00:05 +0300, Andy Shevchenko wrote:
> 
> > Yes, in a previous project, I had been working toward getting a < 1M
> > system to boot on Galileo hardware (which it did, but using more than
> > that - the Galileo2 has 256MB, but it was the target hardware at the
> > time, and I was hoping eventually to be able to boot out of the 512k
> > on-chip SRAM).
> >
> > I was focused at that point mainly on the kernel static size, and using
> > a combination of Josh Triplett's tinification tree, Andi Kleen's LTO and
> > net-diet patches, and my own miscellaneous patches that I was planning
> > on eventually upstreaming, I ended up with a system that I could boot to
> > shell with a 455k text size:
> >
> > Memory: 235636K/245176K available (455K kernel code, 61K rwdata,
> > 64K rodata, 132K init, 56K bss, 3056K reserved, 0K cma-reserved)
> >
> > virtual kernel memory layout:
> >     fixmap  : 0xfffe5000 - 0xfffff000   ( 104 kB)
> >     vmalloc : 0xd05f0000 - 0xfffe3000   ( 761 MB)
> >     lowmem  : 0xc0000000 - 0xcfdf0000   ( 253 MB)
> >       .init : 0xc1094000 - 0xc10b5000   ( 132 kB)
> >       .data : 0xc1071fac - 0xc1092760   ( 129 kB)
> >       .text : 0xc1000000 - 0xc1071fac   ( 455 kB)
> >
> > That was without networking.  Enabling networking added about 250k, and
> > at that point I could ssh in and run a webserver, still less than 1M as
> > far as kernel static size, which of course completely ignores the kernel
> > dynamic size and userspace.
> 
> Thanks for sharing your experience. The question closer to this
> discussion what did you do against TTY/UART/(related) layer(s)?
> 

I'd have to go back and take a look, but nothing special AFIAR.

No patches or hacks along those lines, and the only related thing I see
as far as config is:
	
	cfg/pty-disable.scc \

which maps to:

	# CONFIG_UNIX98_PTYS is not set

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 17:59               ` Tom Zanussi
@ 2017-04-04 18:04                 ` Andy Shevchenko
  2017-04-04 18:31                   ` Nicolas Pitre
  2017-04-04 19:58                   ` Tom Zanussi
  0 siblings, 2 replies; 44+ messages in thread
From: Andy Shevchenko @ 2017-04-04 18:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 4, 2017 at 8:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
> On Tue, 2017-04-04 at 20:08 +0300, Andy Shevchenko wrote:
>> On Tue, Apr 4, 2017 at 7:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
>> > On Tue, 2017-04-04 at 00:05 +0300, Andy Shevchenko wrote:

>> > I was focused at that point mainly on the kernel static size, and using
>> > a combination of Josh Triplett's tinification tree, Andi Kleen's LTO and
>> > net-diet patches, and my own miscellaneous patches that I was planning
>> > on eventually upstreaming, I ended up with a system that I could boot to
>> > shell with a 455k text size:
>> >
>> > Memory: 235636K/245176K available (455K kernel code, 61K rwdata,
>> > 64K rodata, 132K init, 56K bss, 3056K reserved, 0K cma-reserved)

>> Thanks for sharing your experience. The question closer to this
>> discussion what did you do against TTY/UART/(related) layer(s)?
>>
>
> I'd have to go back and take a look, but nothing special AFIAR.
>
> No patches or hacks along those lines, and the only related thing I see
> as far as config is:
>
>         cfg/pty-disable.scc \
>
> which maps to:
>
>         # CONFIG_UNIX98_PTYS is not set

But on your guestimation how much can we squeeze TTY/UART layer if we
do some compile-time configuration?
Does it even make sense or better to introduce something like minitty
special layer instead?

I believe you did some research during time of that project?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 18:04                 ` Andy Shevchenko
@ 2017-04-04 18:31                   ` Nicolas Pitre
  2017-04-04 19:58                   ` Tom Zanussi
  1 sibling, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-04 18:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 4 Apr 2017, Andy Shevchenko wrote:

> On Tue, Apr 4, 2017 at 8:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
> > On Tue, 2017-04-04 at 20:08 +0300, Andy Shevchenko wrote:
> >> On Tue, Apr 4, 2017 at 7:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
> >> > On Tue, 2017-04-04 at 00:05 +0300, Andy Shevchenko wrote:
> 
> >> > I was focused at that point mainly on the kernel static size, and using
> >> > a combination of Josh Triplett's tinification tree, Andi Kleen's LTO and
> >> > net-diet patches, and my own miscellaneous patches that I was planning
> >> > on eventually upstreaming, I ended up with a system that I could boot to
> >> > shell with a 455k text size:
> >> >
> >> > Memory: 235636K/245176K available (455K kernel code, 61K rwdata,
> >> > 64K rodata, 132K init, 56K bss, 3056K reserved, 0K cma-reserved)
> 
> >> Thanks for sharing your experience. The question closer to this
> >> discussion what did you do against TTY/UART/(related) layer(s)?
> >>
> >
> > I'd have to go back and take a look, but nothing special AFIAR.
> >
> > No patches or hacks along those lines, and the only related thing I see
> > as far as config is:
> >
> >         cfg/pty-disable.scc \
> >
> > which maps to:
> >
> >         # CONFIG_UNIX98_PTYS is not set
> 
> But on your guestimation how much can we squeeze TTY/UART layer if we
> do some compile-time configuration?
> Does it even make sense or better to introduce something like minitty
> special layer instead?

For the record I more or less came along the same path as Tom, playing 
with LTO, gc-sections, syscall removal, module_param() removal, etc. At 
the end of the day you still have that 45K of TTY code just to send 
debug out, 100K of VFS even if using only ramfs, 54K of timer code even 
if there's only one simple timer available, 28K of IRQ support code even 
if there is only one type of interrupt used, etc. LTO / gc-section 
cannot automatically get rid of those unused functions because they're 
runtime selected callbacks and optimization tools no longer can do their 
magic.

At some point there is no way other than having a parallel 
implementation specifically for a limited scope to reduce both code 
footprint and runtime RAM consumption. Who need a multicore scalable VFS 
cache when there's only 256K of RAM and a single user space process 
running?


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 16:59           ` Tom Zanussi
  2017-04-04 17:08             ` Andy Shevchenko
@ 2017-04-04 18:53             ` Nicolas Pitre
  1 sibling, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-04 18:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 4 Apr 2017, Tom Zanussi wrote:

> Yes, in a previous project, I had been working toward getting a < 1M
> system to boot on Galileo hardware (which it did, but using more than
> that - the Galileo2 has 256MB, but it was the target hardware at the
> time, and I was hoping eventually to be able to boot out of the 512k
> on-chip SRAM).
> 
> I was focused at that point mainly on the kernel static size, and using
> a combination of Josh Triplett's tinification tree, Andi Kleen's LTO and
> net-diet patches, and my own miscellaneous patches that I was planning
> on eventually upstreaming, I ended up with a system that I could boot to
> shell with a 455k text size:
> 
> Memory: 235636K/245176K available (455K kernel code, 61K rwdata,
> 64K rodata, 132K init, 56K bss, 3056K reserved, 0K cma-reserved)
> 
> virtual kernel memory layout:
>     fixmap  : 0xfffe5000 - 0xfffff000   ( 104 kB)
>     vmalloc : 0xd05f0000 - 0xfffe3000   ( 761 MB)
>     lowmem  : 0xc0000000 - 0xcfdf0000   ( 253 MB)
>       .init : 0xc1094000 - 0xc10b5000   ( 132 kB)
>       .data : 0xc1071fac - 0xc1092760   ( 129 kB)
>       .text : 0xc1000000 - 0xc1071fac   ( 455 kB)
> 
> That was without networking.  Enabling networking added about 250k, and
> at that point I could ssh in and run a webserver, still less than 1M as
> far as kernel static size, which of course completely ignores the kernel
> dynamic size and userspace.
> 
> My goal was to get rid of shell access and dropbear altogether and have
> all access be via webserver, which I did by using nostromo, mainly for
> convenience, until I could get some 'cgi' added to Alan Cox's ?Web
> (about 20k).
> 
> Anyway, that work, as I left it a couple years ago, is here, in case
> anyone's interested (it's a yocto layer and yocto-based kernel
> containing many topic branches, but building it according to the
> directions in the README will yield a standard kernel and .config in the
> working directory and allow you to ignore all the yocto stuff): 
> 
> https://github.com/tzanussi/linux-yocto-micro-4.1  
> https://github.com/tzanussi/meta-microlinux/tree/jethro

Thanks for sharing I'll certainly have a look.

> It's nice to see tinification work being done again - at the time I
> stopped working on it it seemed there was no desire from maintainers in
> general to merge anything that would create new options designed only
> for the purpose of tinification.

I successfully provided an option to disable POSIX timers lately. A 
round trip into the Kconfig parser was required to achieve that though.

Many maintainers are resistant to change as their role is to preserve 
stability of their code. Adding special cases in existing code makes it 
much harder to maintain and validate. Sometimes it is way better to have 
a parallel implementation rather that destabilizing the one version 
available... as long as the interface is the same and that the big and 
tiny versions can be used interchangeably.

> In fact, as a kind of backup plan for that, I also played around with
> the idea of auto-generating a kernel that would contain only the
> functions that were demonstrated to be used by the (single-purpose)
> workload.  It was similar to the idea of making every system call
> configurable and then including only the ones used by the workload, but
> taking it a step further and doing that for every function in the
> kernel, not just system calls.

I thought about that too... and dismissed the idea as being too 
frightening!

> I had a script that would take the output of the function_hist histogram
> taken while exhaustively running the workload:
> 
>   https://lkml.org/lkml/2015/5/20/994
> 
> And with a kernel compiled using -ffunction-sections removing all
> functions that were never referenced.  I never got a bootable kernel out
> of it, but mainly just because I ran out of time and had to move onto
> other things.  I may dust it off and try again, just for fun... ;-)

That would be great.

I really wish to stir up interest from more people and have Linux gain 
momentum in the tiny system space.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 13:40             ` Alan Cox
@ 2017-04-04 19:26               ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-04 19:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 4 Apr 2017, Alan Cox wrote:

> > we're down to 5.6K. At which point there's only a raw device
> > interface?
> > to serial hardware.
> 
> Which if you did a simple plain chardev without trying to fake the
> rather out of date uart layer would come down way further still.

Oh absolutely. I don't dispute that. Given infinite time as you said.

But I gained a 5x reduction already. I would prefer moving to some other 
part of the kernel where another 5x reduction could be achieved now 
rather than postponing that after I'm done rewriting the interface for 
all UART drivers.  Maybe someone else will feel inspired and take on 
this UART driver modernizing task (that could be a nice mentorred 
project for example).

PS: FUZIX is a real piece of art  ;-)


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 18:04                 ` Andy Shevchenko
  2017-04-04 18:31                   ` Nicolas Pitre
@ 2017-04-04 19:58                   ` Tom Zanussi
  2017-04-04 20:27                     ` Nicolas Pitre
  1 sibling, 1 reply; 44+ messages in thread
From: Tom Zanussi @ 2017-04-04 19:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2017-04-04 at 21:04 +0300, Andy Shevchenko wrote:
> On Tue, Apr 4, 2017 at 8:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
> > On Tue, 2017-04-04 at 20:08 +0300, Andy Shevchenko wrote:
> >> On Tue, Apr 4, 2017 at 7:59 PM, Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
> >> > On Tue, 2017-04-04 at 00:05 +0300, Andy Shevchenko wrote:
> 
> >> > I was focused at that point mainly on the kernel static size, and using
> >> > a combination of Josh Triplett's tinification tree, Andi Kleen's LTO and
> >> > net-diet patches, and my own miscellaneous patches that I was planning
> >> > on eventually upstreaming, I ended up with a system that I could boot to
> >> > shell with a 455k text size:
> >> >
> >> > Memory: 235636K/245176K available (455K kernel code, 61K rwdata,
> >> > 64K rodata, 132K init, 56K bss, 3056K reserved, 0K cma-reserved)
> 
> >> Thanks for sharing your experience. The question closer to this
> >> discussion what did you do against TTY/UART/(related) layer(s)?
> >>
> >
> > I'd have to go back and take a look, but nothing special AFIAR.
> >
> > No patches or hacks along those lines, and the only related thing I see
> > as far as config is:
> >
> >         cfg/pty-disable.scc \
> >
> > which maps to:
> >
> >         # CONFIG_UNIX98_PTYS is not set
> 
> But on your guestimation how much can we squeeze TTY/UART layer if we
> do some compile-time configuration?
> Does it even make sense or better to introduce something like minitty
> special layer instead?
> 
> I believe you did some research during time of that project?
> 

Yes, as a matter of fact I did, and just found some notes I took at the
time.  I didn't dive into the code in detail - that level of analysis
was supposed to come later but I did have these notes mentioning that I
thought it would show the largest savings for a single item (outside of
networking) 'if we could do it':

"- Largest is still drivers

- drivers/tty and serial is the biggest obvious win if we can do it
  - break down into granular config options
    - leave simplest possible tty/serial functionality
    - allow tailoring to specific hardware
  - also helps in effort to get rid of char devices
  - 65740/815190"

Basically 65k out of an 800k text size could be partially or mostly
saved by addressing that one item, which looks like it pretty much
matches Nicolas' numbers...

So no doubt it would be worthwhile to address one way or the other.
Whether to do that by refactoring the tty layer or partial refactoring
and creation of a parallel minimal version would best be left up to
someone who actually understands it I would think...

BTW, since I'm quoting my own notes on the subject, I thought I'd just
include the whole thing, which covers a bunch of other areas possibly
ripe for tinification, in case anyone might be interested (some of it
should be taken with a grain of salt though ;-)

Tom

--------

galileo SMALLEST_SIZE

$ size vmlinux
   text	          data			       bss	    dec	    hex	filename
 699668		   186432		       2271592	    3157692  302ebc	vmlinux

Not using this, because
 $ size xxx.o shows all 0s with LTO

----

Using this:

galileo SMALLEST_SIZE with LTO off

$ size vmlinux
   text	          data			       bss	    dec	    hex	filename
 815190		   165696		       2272760	    3253646  31a58e	vmlinux

This corresponds to LTO size:

$ size vmlinux
   text	          data			       bss	    dec	    hex	filename
 677183		   179528		       1207280	    2063991  1f7e77	vmlinux

$ ls -al arch/x86/boot/bzImage 
-rw-r--r--. 1 427264 Mar 12 22:34 arch/x86/boot/bzImage

And booted size:

Memory: 235388K/245240K available (534K kernel code, 100K rwdata, 52K rodata, 14
8K init, 64K bss, 3172K reserved, 0K cma-reserved)
virtual kernel memory layout:
    fixmap  : 0xfffa4000 - 0xfffff000   ( 364 kB)
    vmalloc : 0xd05f0000 - 0xfffa2000   ( 761 MB)
    lowmem  : 0xc0000000 - 0xcfdf0000   ( 253 MB)
      .init : 0xc10af000 - 0xc10d4000   ( 148 kB)
      .data : 0xc1085b9c - 0xc10ad120   ( 157 kB)
      .text : 0xc1000000 - 0xc1085b9c   ( 534 kB)

------
Totals - details below
------

- make ptrace configurable - this should help the hw breakpoints and x86 perf disable patches upstream
  - 5k
- remove things not needed for CONFIG_SMP
  - 5k
- support configuring out kswapd
  - about 5k in vmscan
- support configuring out vmstat
  - 0
- kernel capabilities
  - 1k
- exec domains
  - 1k
- tsc
     3030	    284	     40	   3354	    d1a	./arch/x86/kernel/tsc.o
    332		          0        0	        332	    14c	./arch/x86/kernel/tsc_msr.o
- support configuring out signals
  11852	       36           4	  11892	   2e74	./kernel/signal.o
   3188	             1	          0	      3189	    c75	./arch/x86/kernel/signal.o
  - about 15k
- kernel/pid.o simplification - more for dynamic memory - simpler pidhash
  1868	    160	      4	   2032	    7f0	./kernel/pid.o
  - about 2k
- remove kernel/exit.o
  - assume processes never exit
- remove lib/kfifo
  - about 2k
- remove kernel/irq/spurious
  - about 1k
- make sys configurable
  - about 7k
- remove xattr
  - about 4k
- /drivers total possible savings, some percentage of:
  - 136000/815190
- /kernel savings
  - say 30000/815190 savings
- /fs savings
  - 30000/815190 savings
- /arch/x86 savings
  - 20000/815190
- /mm
  - 5000/815190
- /lib
  - 10000/815190

Totals without mmu:
  146k + (2/3)*136k = 235k

  235k/815190 = 30% savings

- x86 nommu
  - about 50k

Totals with mmu:

  285k/815190 = 35% savings


Applied to the 534k boot figure, we end up with text size of:

  374k mmu
  347k nommu

We could probably go lower with more fine-grained analysis, but we may
also need to add drivers, etc.

-----
NONET details
-----

- Largest is still drivers

- drivers/tty and serial is the biggest obvious win if we can do it
  - break down into granular config options
    - leave simplest possible tty/serial functionality
    - allow tailoring to specific hardware
  - also helps in effort to get rid of char devices
  - 65740/815190 

- pci is next largest
  - assume we can break down into granular config options
    - leave simplest possible pci functionality
    - allow tailoring to specific hardware e.g. no discovery
  - 47144/815190

- drivers/base
  - simplify driver core for a small set of drivers
    - simple_char: New infrastructure to simplify chardev management
  - 25389/815190

- total possible savings, some percentage of:
  - 136000/815190

 206992	  29331	   6556	 242879	  3b4bf	./drivers/built-in.o

 65740	  16888	   3132	  85760	  14f00	./drivers/tty/built-in.o
 32077	  16680	   2688	  51445	   c8f5	./drivers/tty/serial/built-in.o
 21628	  15892	   2644	  40164	   9ce4	./drivers/tty/serial/8250/built-in.o
  47144	   1172	   2100	  50416	   c4f0	./drivers/pci/built-in.o
  25389	   1324	    112	  26825	   68c9	./drivers/base/built-in.o
  15733	    636	     20	  16389	   4005	./drivers/spi/built-in.o
  11504	    136	     28	  11668	   2d94	./drivers/clk/built-in.o
   9605	    460	     72	  10137	   2799	./drivers/thermal/built-in.o
   5066	    624	    912	   6602	   19ca	./drivers/char/built-in.o
   8531	    480	     36	   9047	   2357	./drivers/i2c/built-in.o

- 2nd largest is kernel

  - should be able to cut *something* from time and sched
    - we have a handful of processes at most
    - we have very simple time needs
  - say 30000/815190 savings

 150742	   6376	   8209	 165327	  285cf	./kernel/built-in.o

  40951	   1105	   4720	  46776	   b6b8	./kernel/time/built-in.o
  21760	   1318	    112	  23190	   5a96	./kernel/sched/built-in.o
   9800	    388	   1328	  11516	   2cfc	./kernel/irq/built-in.o
   4956	      4	      4	   4964	   1364	./kernel/locking/built-in.o
   1847	     88	    184	   2119	    847	./kernel/printk/built-in.o
   1757	     33	      0	   1790	    6fe	./kernel/rcu/built-in.o
   1408	    356	     44	   1808	    710	./kernel/power/built-in.o

- next is fs

  - completely turn off proc
    - requires userspace changes to cope with it
    - 22046/815190, 100% of this

  - simplify/featurize some core vfs?
    - e.g. namei, small set of file names, no need for complexity

  - disable vfs completely?
    - init reads executables directly from storage
    - all state in memory, no need to save anything

 133526	   1506	   1552	 136584	  21588	./fs/built-in.o
  22046	    140	     40	  22226	   56d2	./fs/proc/built-in.o

- next is arch/x86, mostly in arch/x86/kernel
  - not much to save here, maybe 10 here and there
  - maybe 3k in boot: video*
  - maybe 5k in cpu: amd, transmeta, cachinfo, etc
  - cut about 10k in arch/x86/mm for nommu

 120755	  50209	  52712	 223676	  369bc	./arch/x86/built-in.o

 100201	  29261	  19828	 149290	  2472a	./arch/x86/kernel/built-in.o

  21713	   8693	    720	  31126	   7996	./arch/x86/kernel/cpu/built-in.o
  17480	   5486	   6324	  29290	   726a	./arch/x86/kernel/apic/built-in.o
  10385	   4365	    532	  15282	   3bb2	./arch/x86/kernel/cpu/mcheck/built-in.o

  18237	    208	  30776	  49221	   c045	./arch/x86/mm/built-in.o
  14276	    412	    256	  14944	   3a60	./arch/x86/pci/built-in.o
   1345	      8	     28	   1381	    565	./arch/x86/platform/intel-quark/built-in.o
   1345	      8	     28	   1381	    565	./arch/x86/platform/built-in.o
    590	   8228	     16	   8834	   2282	./arch/x86/vdso/built-in.o
    379	  12500	      8	  12887	   3257	./arch/x86/realmode/built-in.o
    477	      0	      0	    477	    1dd	./arch/x86/lib/built-in.o

- next is mm
 
  - cut about 5k for percpu
  - cut about 40k for nommu

 119008	  13688	   1824	 134520	  20d78	./mm/built-in.o

   1358	      0        0	     1358	    54e	./mm/gup.o
  10612	     32	      24       10668	       29ac	./mm/memory.o
   1072	      0        0     1072	           430	./mm/mincore.o
   2453	      0        0		      2453	    995	./mm/mlock.o
   9918	    176        8	        10102	       2776	./mm/mmap.o
   1403	      0	      0		   1403	           57b	./mm/mprotect.o
   2155	      0          0	      2155	       86b	./mm/mremap.o
    520	      0          0       520	           208	./mm/msync.o
   4358	      0	        8    4366	      110e	./mm/rmap.o
   6355	      57	     28		         6440	   1928	./mm/vmalloc.o
    710	      0          0		     710       2c6	./mm/pagewalk.o
     92	      0	         0	          92        5c	./mm/pgtable-generic.o

- next is lib

  - no need for vsprintf if printk off, 10k

  30654	  24647	      5	  55306	   d80a	./lib/built-in.o

   9964	      0	      0	   9964	   26ec	./lib/zlib_inflate/built-in.o

-next is init

   8456	  16437	     81	  24974	   618e	./init/built-in.o



----
Net sizes, maybe later...

galileo SMALLEST_SIZE_NET with LTO off

- this is without ipv4 net-diet
- includes ipv6

$ size vmlinux
   text	          data			       bss	    dec	    hex	filename
1368973		   181184		       2288560	    3838717  3a92fd	vmlinux

---
NET details
---


- net now largest, larger than drivers (and drivers goes up too)

 465384	  13818	  17364	 496566	  793b6	./net/built-in.o

 183144	   5409	   7948	 196501	  2ff95	./net/ipv4/built-in.o
 128583	   4648	   6432	 139663	  2218f	./net/ipv6/built-in.o
 108158	   2092	   2804	 113054	  1b99e	./net/core/built-in.o
  15268	    264	      0	  15532	   3cac	./net/packet/built-in.o
  14787	    465	    148	  15400	   3c28	./net/netlink/built-in.o
   4011	    676	      0	   4687	   124f	./net/sched/built-in.o
    967	     12	      0	    979	    3d3	./net/ethernet/built-in.o

- drivers second largest

 255026	  30512	   6604	 292142	  4752e	./drivers/built-in.o

    359	     20	      0	    379	    17b	./drivers/reset/built-in.o
   2155	    152	     32	   2339	    923	./drivers/pps/built-in.o
   8870	    580	      0	   9450	   24ea	./drivers/net/phy/built-in.o
  42421	    861	      8	  43290	   a91a	./drivers/net/built-in.o
  30650	    233	      8	  30891	   78ab	./drivers/net/ethernet/stmicro/stmmac/built-in.o
  30650	    233	      8	  30891	   78ab	./drivers/net/ethernet/stmicro/built-in.o
  30650	    233	      8	  30891	   78ab	./drivers/net/ethernet/built-in.o
  47144	   1172	   2100	  50416	   c4f0	./drivers/pci/built-in.o
  11504	    136	     28	  11668	   2d94	./drivers/clk/built-in.o
  25389	   1324	    112	  26825	   68c9	./drivers/base/built-in.o
  15733	    636	     20	  16389	   4005	./drivers/spi/built-in.o
   5066	    624	    912	   6602	   19ca	./drivers/char/built-in.o
   9931	    548	     76	  10555	   293b	./drivers/thermal/built-in.o
   4927	    224	     36	   5187	   1443	./drivers/ptp/built-in.o
  65740	  16888	   3132	  85760	  14f00	./drivers/tty/built-in.o
  32077	  16680	   2688	  51445	   c8f5	./drivers/tty/serial/built-in.o
  21628	  15892	   2644	  40164	   9ce4	./drivers/tty/serial/8250/built-in.o
   8531	    480	     36	   9047	   2357	./drivers/i2c/built-in.o

- kernel next

 157407	   6376	   8209	 171992	  29fd8	./kernel/built-in.o

   9800	    388	   1328	  11516	   2cfc	./kernel/irq/built-in.o
  40951	   1105	   4720	  46776	   b6b8	./kernel/time/built-in.o
   6665	      0	      0	   6665	   1a09	./kernel/bpf/built-in.o
   1408	    356	     44	   1808	    710	./kernel/power/built-in.o
  21760	   1318	    112	  23190	   5a96	./kernel/sched/built-in.o
   4956	      4	      4	   4964	   1364	./kernel/locking/built-in.o
   1757	     33	      0	   1790	    6fe	./kernel/rcu/built-in.o
   1847	     88	    184	   2119	    847	./kernel/printk/built-in.o

- fs next

 134562	   1534	   1552	 137648	  219b0	./fs/built-in.o

   1395	    276	      4	   1675	    68b	./fs/ramfs/built-in.o
  22743	    168	     40	  22951	   59a7	./fs/proc/built-in.o
   1446	     44	      8	   1498	    5da	./fs/devpts/built-in.o

- arch/x86 next

 120755	  50209	  52712	 223676	  369bc	./arch/x86/built-in.o

    379	  12500	      8	  12887	   3257	./arch/x86/realmode/built-in.o
  14276	    412	    256	  14944	   3a60	./arch/x86/pci/built-in.o
    590	   8228	     16	   8834	   2282	./arch/x86/vdso/built-in.o
  18237	    208	  30776	  49221	   c045	./arch/x86/mm/built-in.o
    477	      0	      0	    477	    1dd	./arch/x86/lib/built-in.o
   1345	      8	     28	   1381	    565	./arch/x86/platform/intel-quark/built-in.o
   1345	      8	     28	   1381	    565	./arch/x86/platform/built-in.o
  17480	   5486	   6324	  29290	   726a	./arch/x86/kernel/apic/built-in.o
  21713	   8693	    720	  31126	   7996	./arch/x86/kernel/cpu/built-in.o
  10385	   4365	    532	  15282	   3bb2	./arch/x86/kernel/cpu/mcheck/built-in.o
 100201	  29261	  19828	 149290	  2472a	./arch/x86/kernel/built-in.o

- mm next

 119008	  13688	   1824	 134520	  20d78	./mm/built-in.o

- lib next

  33042	  24647	      5	  57694	   e15e	./lib/built-in.o

   9964	      0	      0	   9964	   26ec	./lib/zlib_inflate/built-in.o

- crypto next

  30068	    284	      0	  30352	   7690	./crypto/built-in.o

- init next

   8456	  16437	     81	  24974	   618e	./init/built-in.o

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems
  2017-04-04 19:58                   ` Tom Zanussi
@ 2017-04-04 20:27                     ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2017-04-04 20:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 4 Apr 2017, Tom Zanussi wrote:

> On Tue, 2017-04-04 at 21:04 +0300, Andy Shevchenko wrote:
> > I believe you did some research during time of that project?
> > 
> 
> Yes, as a matter of fact I did, and just found some notes I took at the
> time.  I didn't dive into the code in detail - that level of analysis
> was supposed to come later but I did have these notes mentioning that I
> thought it would show the largest savings for a single item (outside of
> networking) 'if we could do it':
> 
> "- Largest is still drivers
> 
> - drivers/tty and serial is the biggest obvious win if we can do it
>   - break down into granular config options
>     - leave simplest possible tty/serial functionality
>     - allow tailoring to specific hardware
>   - also helps in effort to get rid of char devices
>   - 65740/815190"
> 
> Basically 65k out of an 800k text size could be partially or mostly
> saved by addressing that one item, which looks like it pretty much
> matches Nicolas' numbers...

One thing on x86 that inflates the size is the 8250 driver itself. I'm 
looking at some ARM targets with their own UART whose driver is much 
smaller.

> BTW, since I'm quoting my own notes on the subject, I thought I'd just
> include the whole thing, which covers a bunch of other areas possibly
> ripe for tinification, in case anyone might be interested (some of it
> should be taken with a grain of salt though ;-)
> 
[...]
> 
> - 2nd largest is kernel
> 
>   - should be able to cut *something* from time and sched
>     - we have a handful of processes at most
>     - we have very simple time needs
>   - say 30000/815190 savings
> 
>  150742	   6376	   8209	 165327	  285cf	./kernel/built-in.o
> 
>   40951	   1105	   4720	  46776	   b6b8	./kernel/time/built-in.o

Commit baa73d9e47 allows for shaving off 25K here. More could probably 
be done.

>   21760	   1318	    112	  23190	   5a96	./kernel/sched/built-in.o

I already have an alternative scheduler implementation that weights 9K. 
It is on the backburner for now though. But don't let the scheduler 
guys know just yet.  ;-)


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2017-04-04 20:27 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-01 22:21 [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Nicolas Pitre
2017-04-01 22:21 ` [PATCH v2 1/5] console: move console_init() out of tty_io.c Nicolas Pitre
2017-04-01 22:21 ` [PATCH v2 2/5] tty: move baudrate handling code to a file of its own Nicolas Pitre
2017-04-01 22:21 ` [PATCH v2 3/5] serial: small Makefile reordering Nicolas Pitre
2017-04-02 12:55   ` Andy Shevchenko
2017-04-02 15:49     ` Nicolas Pitre
2017-04-01 22:21 ` [PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file Nicolas Pitre
2017-04-02 13:16   ` Andy Shevchenko
2017-04-02 15:44     ` Nicolas Pitre
2017-04-03  7:35   ` kbuild test robot
2017-04-01 22:21 ` [PATCH v2 5/5] minitty: minimal TTY support alternative for serial ports Nicolas Pitre
2017-04-02 13:22 ` [PATCH v2 0/5] minitty: a minimal TTY layer alternative for embedded systems Andy Shevchenko
2017-04-02 15:55   ` Nicolas Pitre
2017-04-03 12:56     ` Alan Cox
2017-04-03 16:06       ` Nicolas Pitre
2017-04-03 18:05         ` Alan Cox
2017-04-03 19:50           ` Nicolas Pitre
2017-04-04 13:40             ` Alan Cox
2017-04-04 19:26               ` Nicolas Pitre
2017-04-02 20:47 ` Andi Kleen
2017-04-02 21:41   ` Nicolas Pitre
2017-04-02 22:44     ` Stuart Longland
2017-04-03  1:01       ` Nicolas Pitre
2017-04-04  0:39         ` Stuart Longland
2017-04-03 18:14       ` Geert Uytterhoeven
2017-04-03 18:57         ` Rob Herring
2017-04-03 19:46           ` Geert Uytterhoeven
2017-04-03 21:05         ` Andy Shevchenko
2017-04-04 16:59           ` Tom Zanussi
2017-04-04 17:08             ` Andy Shevchenko
2017-04-04 17:59               ` Tom Zanussi
2017-04-04 18:04                 ` Andy Shevchenko
2017-04-04 18:31                   ` Nicolas Pitre
2017-04-04 19:58                   ` Tom Zanussi
2017-04-04 20:27                     ` Nicolas Pitre
2017-04-04 18:53             ` Nicolas Pitre
2017-04-03  7:54     ` Andy Shevchenko
2017-04-03 15:31       ` Andi Kleen
2017-04-03 17:27         ` Nicolas Pitre
2017-04-03 19:57         ` Adam Borowski
2017-04-03 20:09           ` Nicolas Pitre
2017-04-03 20:32             ` Adam Borowski
2017-04-03 16:40       ` Nicolas Pitre
2017-04-03  7:44 ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).