xref: /linux-6.15/drivers/tty/tty_buffer.c (revision 548fcf03)
1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
296fd7ce5SGreg Kroah-Hartman /*
396fd7ce5SGreg Kroah-Hartman  * Tty buffer allocation management
496fd7ce5SGreg Kroah-Hartman  */
596fd7ce5SGreg Kroah-Hartman 
696fd7ce5SGreg Kroah-Hartman #include <linux/types.h>
796fd7ce5SGreg Kroah-Hartman #include <linux/errno.h>
86bb6fa69SIlpo Järvinen #include <linux/minmax.h>
996fd7ce5SGreg Kroah-Hartman #include <linux/tty.h>
10*548fcf03SIlpo Järvinen #include <linux/tty_buffer.h>
1196fd7ce5SGreg Kroah-Hartman #include <linux/tty_driver.h>
1296fd7ce5SGreg Kroah-Hartman #include <linux/tty_flip.h>
1396fd7ce5SGreg Kroah-Hartman #include <linux/timer.h>
1496fd7ce5SGreg Kroah-Hartman #include <linux/string.h>
1596fd7ce5SGreg Kroah-Hartman #include <linux/slab.h>
1696fd7ce5SGreg Kroah-Hartman #include <linux/sched.h>
1796fd7ce5SGreg Kroah-Hartman #include <linux/wait.h>
1896fd7ce5SGreg Kroah-Hartman #include <linux/bitops.h>
1996fd7ce5SGreg Kroah-Hartman #include <linux/delay.h>
2096fd7ce5SGreg Kroah-Hartman #include <linux/module.h>
21593fb1aeSGeorge Spelvin #include <linux/ratelimit.h>
226c80c0b9SGreg Kroah-Hartman #include "tty.h"
231cef50e3SPeter Hurley 
241cef50e3SPeter Hurley #define MIN_TTYB_SIZE	256
2515730dc4SIlpo Järvinen #define TTYB_ALIGN_MASK	0xff
261cef50e3SPeter Hurley 
277bfe0b71SPeter Hurley /*
287bfe0b71SPeter Hurley  * Byte threshold to limit memory consumption for flip buffers.
297bfe0b71SPeter Hurley  * The actual memory limit is > 2x this amount.
307bfe0b71SPeter Hurley  */
317ab57b76SManfred Schlaegl #define TTYB_DEFAULT_MEM_LIMIT	(640 * 1024UL)
327bfe0b71SPeter Hurley 
339114fe8cSPeter Hurley /*
349114fe8cSPeter Hurley  * We default to dicing tty buffer allocations to this many characters
359114fe8cSPeter Hurley  * in order to avoid multiple page allocations. We know the size of
369114fe8cSPeter Hurley  * tty_buffer itself but it must also be taken into account that the
37dadc1049SXiaofei Tan  * buffer is 256 byte aligned. See tty_buffer_find for the allocation
38dadc1049SXiaofei Tan  * logic this must match.
399114fe8cSPeter Hurley  */
409114fe8cSPeter Hurley 
4115730dc4SIlpo Järvinen #define TTY_BUFFER_PAGE	(((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~TTYB_ALIGN_MASK)
429114fe8cSPeter Hurley 
437bfe0b71SPeter Hurley /**
44a7c8d58cSPeter Hurley  * tty_buffer_lock_exclusive	-	gain exclusive access to buffer
45fa441954SJiri Slaby  * @port: tty port owning the flip buffer
46a7c8d58cSPeter Hurley  *
47bc17b723SJiri Slaby  * Guarantees safe use of the &tty_ldisc_ops.receive_buf() method by excluding
48bc17b723SJiri Slaby  * the buffer work and any pending flush from using the flip buffer. Data can
49bc17b723SJiri Slaby  * continue to be added concurrently to the flip buffer from the driver side.
50a7c8d58cSPeter Hurley  *
51bc17b723SJiri Slaby  * See also tty_buffer_unlock_exclusive().
52a7c8d58cSPeter Hurley  */
tty_buffer_lock_exclusive(struct tty_port * port)53a7c8d58cSPeter Hurley void tty_buffer_lock_exclusive(struct tty_port *port)
54a7c8d58cSPeter Hurley {
55a7c8d58cSPeter Hurley 	struct tty_bufhead *buf = &port->buf;
56a7c8d58cSPeter Hurley 
57a7c8d58cSPeter Hurley 	atomic_inc(&buf->priority);
58a7c8d58cSPeter Hurley 	mutex_lock(&buf->lock);
59a7c8d58cSPeter Hurley }
6028a821c3SBen Hutchings EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive);
61a7c8d58cSPeter Hurley 
62bc17b723SJiri Slaby /**
63bc17b723SJiri Slaby  * tty_buffer_unlock_exclusive	-	release exclusive access
64bc17b723SJiri Slaby  * @port: tty port owning the flip buffer
65bc17b723SJiri Slaby  *
66bc17b723SJiri Slaby  * The buffer work is restarted if there is data in the flip buffer.
67bc17b723SJiri Slaby  *
68bc17b723SJiri Slaby  * See also tty_buffer_lock_exclusive().
69bc17b723SJiri Slaby  */
tty_buffer_unlock_exclusive(struct tty_port * port)70a7c8d58cSPeter Hurley void tty_buffer_unlock_exclusive(struct tty_port *port)
71a7c8d58cSPeter Hurley {
72a7c8d58cSPeter Hurley 	struct tty_bufhead *buf = &port->buf;
73083cfcf3SJiri Slaby (SUSE) 	bool restart = buf->head->commit != buf->head->read;
74a7c8d58cSPeter Hurley 
75a7c8d58cSPeter Hurley 	atomic_dec(&buf->priority);
76a7c8d58cSPeter Hurley 	mutex_unlock(&buf->lock);
77083cfcf3SJiri Slaby (SUSE) 
78a7c8d58cSPeter Hurley 	if (restart)
79a7c8d58cSPeter Hurley 		queue_work(system_unbound_wq, &buf->work);
80a7c8d58cSPeter Hurley }
8128a821c3SBen Hutchings EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive);
82a7c8d58cSPeter Hurley 
83a7c8d58cSPeter Hurley /**
847bfe0b71SPeter Hurley  * tty_buffer_space_avail	-	return unused buffer space
85fa441954SJiri Slaby  * @port: tty port owning the flip buffer
867bfe0b71SPeter Hurley  *
87bc17b723SJiri Slaby  * Returns: the # of bytes which can be written by the driver without reaching
88bc17b723SJiri Slaby  * the buffer limit.
897bfe0b71SPeter Hurley  *
90bc17b723SJiri Slaby  * Note: this does not guarantee that memory is available to write the returned
91bc17b723SJiri Slaby  * # of bytes (use tty_prepare_flip_string() to pre-allocate if memory
92bc17b723SJiri Slaby  * guarantee is required).
937bfe0b71SPeter Hurley  */
tty_buffer_space_avail(struct tty_port * port)949a33fbf9SJiri Slaby unsigned int tty_buffer_space_avail(struct tty_port *port)
957bfe0b71SPeter Hurley {
965dda4ca5SPeter Hurley 	int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);
97993c67b1SXiaofei Tan 
987bfe0b71SPeter Hurley 	return max(space, 0);
997bfe0b71SPeter Hurley }
100c4a8dab5SPeter Hurley EXPORT_SYMBOL_GPL(tty_buffer_space_avail);
1017bfe0b71SPeter Hurley 
tty_buffer_reset(struct tty_buffer * p,size_t size)1029dd5139fSPeter Hurley static void tty_buffer_reset(struct tty_buffer *p, size_t size)
1039dd5139fSPeter Hurley {
1049dd5139fSPeter Hurley 	p->used = 0;
1059dd5139fSPeter Hurley 	p->size = size;
1069dd5139fSPeter Hurley 	p->next = NULL;
1079dd5139fSPeter Hurley 	p->commit = 0;
1086bb6fa69SIlpo Järvinen 	p->lookahead = 0;
1099dd5139fSPeter Hurley 	p->read = 0;
1102e2b4b89SIlpo Järvinen 	p->flags = true;
1119dd5139fSPeter Hurley }
1129dd5139fSPeter Hurley 
11396fd7ce5SGreg Kroah-Hartman /**
11496fd7ce5SGreg Kroah-Hartman  * tty_buffer_free_all		-	free buffers used by a tty
115fa441954SJiri Slaby  * @port: tty port to free from
11696fd7ce5SGreg Kroah-Hartman  *
117bc17b723SJiri Slaby  * Remove all the buffers pending on a tty whether queued with data or in the
118bc17b723SJiri Slaby  * free ring. Must be called when the tty is no longer in use.
11996fd7ce5SGreg Kroah-Hartman  */
tty_buffer_free_all(struct tty_port * port)120ecbbfd44SJiri Slaby void tty_buffer_free_all(struct tty_port *port)
12196fd7ce5SGreg Kroah-Hartman {
122ecbbfd44SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
123809850b7SPeter Hurley 	struct tty_buffer *p, *next;
124809850b7SPeter Hurley 	struct llist_node *llist;
125feacbecbSJiri Slaby 	unsigned int freed = 0;
126feacbecbSJiri Slaby 	int still_used;
1275cff39c6SJiri Slaby 
1282cf7b67eSPeter Hurley 	while ((p = buf->head) != NULL) {
1292cf7b67eSPeter Hurley 		buf->head = p->next;
130feacbecbSJiri Slaby 		freed += p->size;
1317391ee16SPeter Hurley 		if (p->size > 0)
1322cf7b67eSPeter Hurley 			kfree(p);
13396fd7ce5SGreg Kroah-Hartman 	}
134809850b7SPeter Hurley 	llist = llist_del_all(&buf->free);
135809850b7SPeter Hurley 	llist_for_each_entry_safe(p, next, llist, free)
1362cf7b67eSPeter Hurley 		kfree(p);
137809850b7SPeter Hurley 
1387391ee16SPeter Hurley 	tty_buffer_reset(&buf->sentinel, 0);
1397391ee16SPeter Hurley 	buf->head = &buf->sentinel;
1407391ee16SPeter Hurley 	buf->tail = &buf->sentinel;
1417bfe0b71SPeter Hurley 
142feacbecbSJiri Slaby 	still_used = atomic_xchg(&buf->mem_used, 0);
143feacbecbSJiri Slaby 	WARN(still_used != freed, "we still have not freed %d bytes!",
144feacbecbSJiri Slaby 			still_used - freed);
14596fd7ce5SGreg Kroah-Hartman }
14696fd7ce5SGreg Kroah-Hartman 
14796fd7ce5SGreg Kroah-Hartman /**
14896fd7ce5SGreg Kroah-Hartman  * tty_buffer_alloc	-	allocate a tty buffer
149fa441954SJiri Slaby  * @port: tty port
15096fd7ce5SGreg Kroah-Hartman  * @size: desired size (characters)
15196fd7ce5SGreg Kroah-Hartman  *
152bc17b723SJiri Slaby  * Allocate a new tty buffer to hold the desired number of characters. We
153bc17b723SJiri Slaby  * round our buffers off in 256 character chunks to get better allocation
154bc17b723SJiri Slaby  * behaviour.
155bc17b723SJiri Slaby  *
156bc17b723SJiri Slaby  * Returns: %NULL if out of memory or the allocation would exceed the per
157bc17b723SJiri Slaby  * device queue.
15896fd7ce5SGreg Kroah-Hartman  */
tty_buffer_alloc(struct tty_port * port,size_t size)159ecbbfd44SJiri Slaby static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
16096fd7ce5SGreg Kroah-Hartman {
161809850b7SPeter Hurley 	struct llist_node *free;
16296fd7ce5SGreg Kroah-Hartman 	struct tty_buffer *p;
16396fd7ce5SGreg Kroah-Hartman 
16411b9faa4SPeter Hurley 	/* Round the buffer size out */
16511b9faa4SPeter Hurley 	size = __ALIGN_MASK(size, TTYB_ALIGN_MASK);
16611b9faa4SPeter Hurley 
16711b9faa4SPeter Hurley 	if (size <= MIN_TTYB_SIZE) {
168809850b7SPeter Hurley 		free = llist_del_first(&port->buf.free);
169809850b7SPeter Hurley 		if (free) {
170809850b7SPeter Hurley 			p = llist_entry(free, struct tty_buffer, free);
17111b9faa4SPeter Hurley 			goto found;
17211b9faa4SPeter Hurley 		}
17311b9faa4SPeter Hurley 	}
17411b9faa4SPeter Hurley 
17511b9faa4SPeter Hurley 	/* Should possibly check if this fails for the largest buffer we
17680e3fce1SXiaofei Tan 	 * have queued and recycle that ?
17780e3fce1SXiaofei Tan 	 */
1785dda4ca5SPeter Hurley 	if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
17996fd7ce5SGreg Kroah-Hartman 		return NULL;
18046bc78c8SJiri Slaby (SUSE) 	p = kmalloc(struct_size(p, data, 2 * size), GFP_ATOMIC | __GFP_NOWARN);
18196fd7ce5SGreg Kroah-Hartman 	if (p == NULL)
18296fd7ce5SGreg Kroah-Hartman 		return NULL;
1839dd5139fSPeter Hurley 
18411b9faa4SPeter Hurley found:
1859dd5139fSPeter Hurley 	tty_buffer_reset(p, size);
1865dda4ca5SPeter Hurley 	atomic_add(size, &port->buf.mem_used);
18796fd7ce5SGreg Kroah-Hartman 	return p;
18896fd7ce5SGreg Kroah-Hartman }
18996fd7ce5SGreg Kroah-Hartman 
19096fd7ce5SGreg Kroah-Hartman /**
19196fd7ce5SGreg Kroah-Hartman  * tty_buffer_free		-	free a tty buffer
192fa441954SJiri Slaby  * @port: tty port owning the buffer
19396fd7ce5SGreg Kroah-Hartman  * @b: the buffer to free
19496fd7ce5SGreg Kroah-Hartman  *
195bc17b723SJiri Slaby  * Free a tty buffer, or add it to the free list according to our internal
196bc17b723SJiri Slaby  * strategy.
19796fd7ce5SGreg Kroah-Hartman  */
tty_buffer_free(struct tty_port * port,struct tty_buffer * b)198ecbbfd44SJiri Slaby static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
19996fd7ce5SGreg Kroah-Hartman {
200ecbbfd44SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
2015cff39c6SJiri Slaby 
20296fd7ce5SGreg Kroah-Hartman 	/* Dumb strategy for now - should keep some stats */
2035dda4ca5SPeter Hurley 	WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0);
20496fd7ce5SGreg Kroah-Hartman 
2051cef50e3SPeter Hurley 	if (b->size > MIN_TTYB_SIZE)
20696fd7ce5SGreg Kroah-Hartman 		kfree(b);
2077391ee16SPeter Hurley 	else if (b->size > 0)
208809850b7SPeter Hurley 		llist_add(&b->free, &buf->free);
20996fd7ce5SGreg Kroah-Hartman }
21096fd7ce5SGreg Kroah-Hartman 
21196fd7ce5SGreg Kroah-Hartman /**
21296fd7ce5SGreg Kroah-Hartman  * tty_buffer_flush		-	flush full tty buffers
21396fd7ce5SGreg Kroah-Hartman  * @tty: tty to flush
21486c80a8eSPeter Hurley  * @ld: optional ldisc ptr (must be referenced)
21596fd7ce5SGreg Kroah-Hartman  *
216bc17b723SJiri Slaby  * Flush all the buffers containing receive data. If @ld != %NULL, flush the
217bc17b723SJiri Slaby  * ldisc input buffer.
21896fd7ce5SGreg Kroah-Hartman  *
219bc17b723SJiri Slaby  * Locking: takes buffer lock to ensure single-threaded flip buffer 'consumer'.
22096fd7ce5SGreg Kroah-Hartman  */
tty_buffer_flush(struct tty_struct * tty,struct tty_ldisc * ld)22186c80a8eSPeter Hurley void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
22296fd7ce5SGreg Kroah-Hartman {
2232fc20661SJiri Slaby 	struct tty_port *port = tty->port;
224ecbbfd44SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
22547aa658aSPeter Hurley 	struct tty_buffer *next;
2265cff39c6SJiri Slaby 
227a7c8d58cSPeter Hurley 	atomic_inc(&buf->priority);
228e9975fdeSPeter Hurley 
229a7c8d58cSPeter Hurley 	mutex_lock(&buf->lock);
2309e6b7cd7SDmitry Vyukov 	/* paired w/ release in __tty_buffer_request_room; ensures there are
2319e6b7cd7SDmitry Vyukov 	 * no pending memory accesses to the freed buffer
2329e6b7cd7SDmitry Vyukov 	 */
2339e6b7cd7SDmitry Vyukov 	while ((next = smp_load_acquire(&buf->head->next)) != NULL) {
23447aa658aSPeter Hurley 		tty_buffer_free(port, buf->head);
23547aa658aSPeter Hurley 		buf->head = next;
23647aa658aSPeter Hurley 	}
23747aa658aSPeter Hurley 	buf->head->read = buf->head->commit;
2386bb6fa69SIlpo Järvinen 	buf->head->lookahead = buf->head->read;
23986c80a8eSPeter Hurley 
24086c80a8eSPeter Hurley 	if (ld && ld->ops->flush_buffer)
24186c80a8eSPeter Hurley 		ld->ops->flush_buffer(tty);
24286c80a8eSPeter Hurley 
243a7c8d58cSPeter Hurley 	atomic_dec(&buf->priority);
244a7c8d58cSPeter Hurley 	mutex_unlock(&buf->lock);
24596fd7ce5SGreg Kroah-Hartman }
24696fd7ce5SGreg Kroah-Hartman 
24796fd7ce5SGreg Kroah-Hartman /**
248a1c0da88SLee Jones  * __tty_buffer_request_room	-	grow tty buffer if needed
249fa441954SJiri Slaby  * @port: tty port
25096fd7ce5SGreg Kroah-Hartman  * @size: size desired
2512e2b4b89SIlpo Järvinen  * @flags: buffer has to store flags along character data
25296fd7ce5SGreg Kroah-Hartman  *
253bc17b723SJiri Slaby  * Make at least @size bytes of linear space available for the tty buffer.
254acc0f67fSPeter Hurley  *
255acc0f67fSPeter Hurley  * Will change over to a new buffer if the current buffer is encoded as
256bc17b723SJiri Slaby  * %TTY_NORMAL (so has no flags buffer) and the new buffer requires a flags
257bc17b723SJiri Slaby  * buffer.
258bc17b723SJiri Slaby  *
259bc17b723SJiri Slaby  * Returns: the size we managed to find.
26096fd7ce5SGreg Kroah-Hartman  */
__tty_buffer_request_room(struct tty_port * port,size_t size,bool flags)261acc0f67fSPeter Hurley static int __tty_buffer_request_room(struct tty_port *port, size_t size,
2622e2b4b89SIlpo Järvinen 				     bool flags)
26396fd7ce5SGreg Kroah-Hartman {
264ecbbfd44SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
265035197c9SJiri Slaby (SUSE) 	struct tty_buffer *n, *b = buf->tail;
266035197c9SJiri Slaby (SUSE) 	size_t left = (b->flags ? 1 : 2) * b->size - b->used;
267035197c9SJiri Slaby (SUSE) 	bool change = !b->flags && flags;
268e8437d7eSPeter Hurley 
269ebee41c8SJiri Slaby (SUSE) 	if (!change && left >= size)
270ebee41c8SJiri Slaby (SUSE) 		return size;
271ebee41c8SJiri Slaby (SUSE) 
27296fd7ce5SGreg Kroah-Hartman 	/* This is the slow path - looking for new buffers to use */
273e16cb0a7SGreg Kroah-Hartman 	n = tty_buffer_alloc(port, size);
274ebee41c8SJiri Slaby (SUSE) 	if (n == NULL)
275ebee41c8SJiri Slaby (SUSE) 		return change ? 0 : left;
276ebee41c8SJiri Slaby (SUSE) 
277acc0f67fSPeter Hurley 	n->flags = flags;
2785cff39c6SJiri Slaby 	buf->tail = n;
2796bb6fa69SIlpo Järvinen 	/*
2806bb6fa69SIlpo Järvinen 	 * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs()
2816bb6fa69SIlpo Järvinen 	 * ensures they see all buffer data.
282facd885cSDmitry Vyukov 	 */
283facd885cSDmitry Vyukov 	smp_store_release(&b->commit, b->used);
2846bb6fa69SIlpo Järvinen 	/*
2856bb6fa69SIlpo Järvinen 	 * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs()
2866bb6fa69SIlpo Järvinen 	 * ensures the latest commit value can be read before the head
2876bb6fa69SIlpo Järvinen 	 * is advanced to the next buffer.
28862a0d8d7SPeter Hurley 	 */
289069f38b4SPeter Hurley 	smp_store_release(&b->next, n);
290ebee41c8SJiri Slaby (SUSE) 
29196fd7ce5SGreg Kroah-Hartman 	return size;
29296fd7ce5SGreg Kroah-Hartman }
293acc0f67fSPeter Hurley 
tty_buffer_request_room(struct tty_port * port,size_t size)294acc0f67fSPeter Hurley int tty_buffer_request_room(struct tty_port *port, size_t size)
295acc0f67fSPeter Hurley {
2962e2b4b89SIlpo Järvinen 	return __tty_buffer_request_room(port, size, true);
297acc0f67fSPeter Hurley }
29896fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tty_buffer_request_room);
29996fd7ce5SGreg Kroah-Hartman 
__tty_insert_flip_string_flags(struct tty_port * port,const u8 * chars,const u8 * flags,bool mutable_flags,size_t size)3006144922eSJiri Slaby (SUSE) size_t __tty_insert_flip_string_flags(struct tty_port *port, const u8 *chars,
301c26405fdSJiri Slaby (SUSE) 				      const u8 *flags, bool mutable_flags,
302c26405fdSJiri Slaby (SUSE) 				      size_t size)
30396fd7ce5SGreg Kroah-Hartman {
304c26405fdSJiri Slaby (SUSE) 	bool need_flags = mutable_flags || flags[0] != TTY_NORMAL;
3056144922eSJiri Slaby (SUSE) 	size_t copied = 0;
306993c67b1SXiaofei Tan 
30796fd7ce5SGreg Kroah-Hartman 	do {
3086144922eSJiri Slaby (SUSE) 		size_t goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
3096144922eSJiri Slaby (SUSE) 		size_t space = __tty_buffer_request_room(port, goal, need_flags);
31064325a3bSIlya Zykov 		struct tty_buffer *tb = port->buf.tail;
311993c67b1SXiaofei Tan 
3127391ee16SPeter Hurley 		if (unlikely(space == 0))
31396fd7ce5SGreg Kroah-Hartman 			break;
314c26405fdSJiri Slaby (SUSE) 
3151fc359fcSPeter Hurley 		memcpy(char_buf_ptr(tb, tb->used), chars, space);
316c26405fdSJiri Slaby (SUSE) 
317c26405fdSJiri Slaby (SUSE) 		if (mutable_flags) {
3181fc359fcSPeter Hurley 			memcpy(flag_buf_ptr(tb, tb->used), flags, space);
319c26405fdSJiri Slaby (SUSE) 			flags += space;
320c26405fdSJiri Slaby (SUSE) 		} else if (tb->flags) {
321c26405fdSJiri Slaby (SUSE) 			memset(flag_buf_ptr(tb, tb->used), flags[0], space);
3224a8d99a4SJiri Slaby (SUSE) 		} else {
3234a8d99a4SJiri Slaby (SUSE) 			/* tb->flags should be available once requested */
3244a8d99a4SJiri Slaby (SUSE) 			WARN_ON_ONCE(need_flags);
325c26405fdSJiri Slaby (SUSE) 		}
326c26405fdSJiri Slaby (SUSE) 
32796fd7ce5SGreg Kroah-Hartman 		tb->used += space;
32896fd7ce5SGreg Kroah-Hartman 		copied += space;
32996fd7ce5SGreg Kroah-Hartman 		chars += space;
330c26405fdSJiri Slaby (SUSE) 
33196fd7ce5SGreg Kroah-Hartman 		/* There is a small chance that we need to split the data over
33280e3fce1SXiaofei Tan 		 * several buffers. If this is the case we must loop.
33380e3fce1SXiaofei Tan 		 */
33496fd7ce5SGreg Kroah-Hartman 	} while (unlikely(size > copied));
335c26405fdSJiri Slaby (SUSE) 
33696fd7ce5SGreg Kroah-Hartman 	return copied;
33796fd7ce5SGreg Kroah-Hartman }
338c26405fdSJiri Slaby (SUSE) EXPORT_SYMBOL(__tty_insert_flip_string_flags);
33996fd7ce5SGreg Kroah-Hartman 
34096fd7ce5SGreg Kroah-Hartman /**
34196fd7ce5SGreg Kroah-Hartman  * tty_prepare_flip_string	-	make room for characters
3422f693357SJiri Slaby  * @port: tty port
34396fd7ce5SGreg Kroah-Hartman  * @chars: return pointer for character write area
34496fd7ce5SGreg Kroah-Hartman  * @size: desired size
34596fd7ce5SGreg Kroah-Hartman  *
346bc17b723SJiri Slaby  * Prepare a block of space in the buffer for data.
347bc17b723SJiri Slaby  *
348bc17b723SJiri Slaby  * This is used for drivers that need their own block copy routines into the
349bc17b723SJiri Slaby  * buffer. There is no guarantee the buffer is a DMA target!
350bc17b723SJiri Slaby  *
351bc17b723SJiri Slaby  * Returns: the length available and buffer pointer (@chars) to the space which
352bc17b723SJiri Slaby  * is now allocated and accounted for as ready for normal characters.
35396fd7ce5SGreg Kroah-Hartman  */
tty_prepare_flip_string(struct tty_port * port,u8 ** chars,size_t size)3542ce2983cSJiri Slaby (SUSE) size_t tty_prepare_flip_string(struct tty_port *port, u8 **chars, size_t size)
35596fd7ce5SGreg Kroah-Hartman {
3562ce2983cSJiri Slaby (SUSE) 	size_t space = __tty_buffer_request_room(port, size, false);
357993c67b1SXiaofei Tan 
35896fd7ce5SGreg Kroah-Hartman 	if (likely(space)) {
35964325a3bSIlya Zykov 		struct tty_buffer *tb = port->buf.tail;
360993c67b1SXiaofei Tan 
3611fc359fcSPeter Hurley 		*chars = char_buf_ptr(tb, tb->used);
3622e2b4b89SIlpo Järvinen 		if (tb->flags)
3631fc359fcSPeter Hurley 			memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
36496fd7ce5SGreg Kroah-Hartman 		tb->used += space;
36596fd7ce5SGreg Kroah-Hartman 	}
3662ce2983cSJiri Slaby (SUSE) 
36796fd7ce5SGreg Kroah-Hartman 	return space;
36896fd7ce5SGreg Kroah-Hartman }
36996fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
37096fd7ce5SGreg Kroah-Hartman 
3718d082cd3SPeter Hurley /**
3728d082cd3SPeter Hurley  * tty_ldisc_receive_buf	-	forward data to line discipline
3738d082cd3SPeter Hurley  * @ld: line discipline to process input
3748d082cd3SPeter Hurley  * @p: char buffer
375bc17b723SJiri Slaby  * @f: %TTY_NORMAL, %TTY_BREAK, etc. flags buffer
3768d082cd3SPeter Hurley  * @count: number of bytes to process
3778d082cd3SPeter Hurley  *
378bc17b723SJiri Slaby  * Callers other than flush_to_ldisc() need to exclude the kworker from
379bc17b723SJiri Slaby  * concurrent use of the line discipline, see paste_selection().
3808d082cd3SPeter Hurley  *
381bc17b723SJiri Slaby  * Returns: the number of bytes processed.
3828d082cd3SPeter Hurley  */
tty_ldisc_receive_buf(struct tty_ldisc * ld,const u8 * p,const u8 * f,size_t count)383892bc209SJiri Slaby (SUSE) size_t tty_ldisc_receive_buf(struct tty_ldisc *ld, const u8 *p, const u8 *f,
384a8d9cd23SJiri Slaby (SUSE) 			     size_t count)
3858d082cd3SPeter Hurley {
3868d082cd3SPeter Hurley 	if (ld->ops->receive_buf2)
3878d082cd3SPeter Hurley 		count = ld->ops->receive_buf2(ld->tty, p, f, count);
3888d082cd3SPeter Hurley 	else {
3898d9526f9SJiri Slaby (SUSE) 		count = min_t(size_t, count, ld->tty->receive_room);
3908d082cd3SPeter Hurley 		if (count && ld->ops->receive_buf)
3918d082cd3SPeter Hurley 			ld->ops->receive_buf(ld->tty, p, f, count);
3928d082cd3SPeter Hurley 	}
3938d082cd3SPeter Hurley 	return count;
3948d082cd3SPeter Hurley }
3958d082cd3SPeter Hurley EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf);
39696fd7ce5SGreg Kroah-Hartman 
lookahead_bufs(struct tty_port * port,struct tty_buffer * head)3976bb6fa69SIlpo Järvinen static void lookahead_bufs(struct tty_port *port, struct tty_buffer *head)
3986bb6fa69SIlpo Järvinen {
3996bb6fa69SIlpo Järvinen 	head->lookahead = max(head->lookahead, head->read);
4006bb6fa69SIlpo Järvinen 
4016bb6fa69SIlpo Järvinen 	while (head) {
4026bb6fa69SIlpo Järvinen 		struct tty_buffer *next;
4036bb6fa69SIlpo Järvinen 		unsigned int count;
4046bb6fa69SIlpo Järvinen 
4056bb6fa69SIlpo Järvinen 		/*
4066bb6fa69SIlpo Järvinen 		 * Paired w/ release in __tty_buffer_request_room();
4076bb6fa69SIlpo Järvinen 		 * ensures commit value read is not stale if the head
4086bb6fa69SIlpo Järvinen 		 * is advancing to the next buffer.
4096bb6fa69SIlpo Järvinen 		 */
4106bb6fa69SIlpo Järvinen 		next = smp_load_acquire(&head->next);
4116bb6fa69SIlpo Järvinen 		/*
4126bb6fa69SIlpo Järvinen 		 * Paired w/ release in __tty_buffer_request_room() or in
4136bb6fa69SIlpo Järvinen 		 * tty_buffer_flush(); ensures we see the committed buffer data.
4146bb6fa69SIlpo Järvinen 		 */
4156bb6fa69SIlpo Järvinen 		count = smp_load_acquire(&head->commit) - head->lookahead;
4166bb6fa69SIlpo Järvinen 		if (!count) {
4176bb6fa69SIlpo Järvinen 			head = next;
4186bb6fa69SIlpo Järvinen 			continue;
4196bb6fa69SIlpo Järvinen 		}
4206bb6fa69SIlpo Järvinen 
42156c14fb4SVincent Whitchurch 		if (port->client_ops->lookahead_buf) {
422a8d9cd23SJiri Slaby (SUSE) 			u8 *p, *f = NULL;
42356c14fb4SVincent Whitchurch 
4246bb6fa69SIlpo Järvinen 			p = char_buf_ptr(head, head->lookahead);
4252e2b4b89SIlpo Järvinen 			if (head->flags)
4266bb6fa69SIlpo Järvinen 				f = flag_buf_ptr(head, head->lookahead);
4276bb6fa69SIlpo Järvinen 
4286bb6fa69SIlpo Järvinen 			port->client_ops->lookahead_buf(port, p, f, count);
42956c14fb4SVincent Whitchurch 		}
43056c14fb4SVincent Whitchurch 
4316bb6fa69SIlpo Järvinen 		head->lookahead += count;
4326bb6fa69SIlpo Järvinen 	}
4336bb6fa69SIlpo Järvinen }
4346bb6fa69SIlpo Järvinen 
435201560afSJiri Slaby (SUSE) static size_t
receive_buf(struct tty_port * port,struct tty_buffer * head,size_t count)436201560afSJiri Slaby (SUSE) receive_buf(struct tty_port *port, struct tty_buffer *head, size_t count)
437da261e7fSPeter Hurley {
4380b7a2b28SJiri Slaby (SUSE) 	u8 *p = char_buf_ptr(head, head->read);
4390b7a2b28SJiri Slaby (SUSE) 	const u8 *f = NULL;
440201560afSJiri Slaby (SUSE) 	size_t n;
441acc0f67fSPeter Hurley 
4422e2b4b89SIlpo Järvinen 	if (head->flags)
443acc0f67fSPeter Hurley 		f = flag_buf_ptr(head, head->read);
444da261e7fSPeter Hurley 
445c9a8e5fcSLinus Torvalds 	n = port->client_ops->receive_buf(port, p, f, count);
446c9a8e5fcSLinus Torvalds 	if (n > 0)
447c9a8e5fcSLinus Torvalds 		memset(p, 0, n);
448c9a8e5fcSLinus Torvalds 	return n;
449da261e7fSPeter Hurley }
45096fd7ce5SGreg Kroah-Hartman 
45196fd7ce5SGreg Kroah-Hartman /**
452bc17b723SJiri Slaby  * flush_to_ldisc		-	flush data from buffer to ldisc
45396fd7ce5SGreg Kroah-Hartman  * @work: tty structure passed from work queue.
45496fd7ce5SGreg Kroah-Hartman  *
455bc17b723SJiri Slaby  * This routine is called out of the software interrupt to flush data from the
456bc17b723SJiri Slaby  * buffer chain to the line discipline.
45796fd7ce5SGreg Kroah-Hartman  *
458bc17b723SJiri Slaby  * The receive_buf() method is single threaded for each tty instance.
459e9975fdeSPeter Hurley  *
460bc17b723SJiri Slaby  * Locking: takes buffer lock to ensure single-threaded flip buffer 'consumer'.
46196fd7ce5SGreg Kroah-Hartman  */
flush_to_ldisc(struct work_struct * work)46296fd7ce5SGreg Kroah-Hartman static void flush_to_ldisc(struct work_struct *work)
46396fd7ce5SGreg Kroah-Hartman {
464ecbbfd44SJiri Slaby 	struct tty_port *port = container_of(work, struct tty_port, buf.work);
465ecbbfd44SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
46696fd7ce5SGreg Kroah-Hartman 
467a7c8d58cSPeter Hurley 	mutex_lock(&buf->lock);
46896fd7ce5SGreg Kroah-Hartman 
4697391ee16SPeter Hurley 	while (1) {
4707391ee16SPeter Hurley 		struct tty_buffer *head = buf->head;
47162a0d8d7SPeter Hurley 		struct tty_buffer *next;
472201560afSJiri Slaby (SUSE) 		size_t count, rcvd;
47396fd7ce5SGreg Kroah-Hartman 
474a7c8d58cSPeter Hurley 		/* Ldisc or user is trying to gain exclusive access */
475a7c8d58cSPeter Hurley 		if (atomic_read(&buf->priority))
476d7a68be4SPeter Hurley 			break;
477d7a68be4SPeter Hurley 
478069f38b4SPeter Hurley 		/* paired w/ release in __tty_buffer_request_room();
47962a0d8d7SPeter Hurley 		 * ensures commit value read is not stale if the head
48062a0d8d7SPeter Hurley 		 * is advancing to the next buffer
48162a0d8d7SPeter Hurley 		 */
482069f38b4SPeter Hurley 		next = smp_load_acquire(&head->next);
483facd885cSDmitry Vyukov 		/* paired w/ release in __tty_buffer_request_room() or in
484facd885cSDmitry Vyukov 		 * tty_buffer_flush(); ensures we see the committed buffer data
485facd885cSDmitry Vyukov 		 */
486facd885cSDmitry Vyukov 		count = smp_load_acquire(&head->commit) - head->read;
48796fd7ce5SGreg Kroah-Hartman 		if (!count) {
4880f40fbbcSBrian Bloniarz 			if (next == NULL)
48996fd7ce5SGreg Kroah-Hartman 				break;
49062a0d8d7SPeter Hurley 			buf->head = next;
491ecbbfd44SJiri Slaby 			tty_buffer_free(port, head);
49296fd7ce5SGreg Kroah-Hartman 			continue;
49396fd7ce5SGreg Kroah-Hartman 		}
494e9975fdeSPeter Hurley 
4956bb6fa69SIlpo Järvinen 		rcvd = receive_buf(port, head, count);
4966bb6fa69SIlpo Järvinen 		head->read += rcvd;
4976bb6fa69SIlpo Järvinen 		if (rcvd < count)
4986bb6fa69SIlpo Järvinen 			lookahead_bufs(port, head);
4996bb6fa69SIlpo Järvinen 		if (!rcvd)
50039f610e4SPeter Hurley 			break;
5013968ddcfSGuanghui Feng 
5023968ddcfSGuanghui Feng 		if (need_resched())
5033968ddcfSGuanghui Feng 			cond_resched();
50439f610e4SPeter Hurley 	}
50539f610e4SPeter Hurley 
506a7c8d58cSPeter Hurley 	mutex_unlock(&buf->lock);
50796fd7ce5SGreg Kroah-Hartman 
50896fd7ce5SGreg Kroah-Hartman }
50996fd7ce5SGreg Kroah-Hartman 
tty_flip_buffer_commit(struct tty_buffer * tail)510716b1058SJiri Slaby static inline void tty_flip_buffer_commit(struct tty_buffer *tail)
511716b1058SJiri Slaby {
512716b1058SJiri Slaby 	/*
513716b1058SJiri Slaby 	 * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
514716b1058SJiri Slaby 	 * buffer data.
515716b1058SJiri Slaby 	 */
516716b1058SJiri Slaby 	smp_store_release(&tail->commit, tail->used);
517716b1058SJiri Slaby }
518716b1058SJiri Slaby 
51996fd7ce5SGreg Kroah-Hartman /**
520bc17b723SJiri Slaby  * tty_flip_buffer_push		-	push terminal buffers
5212e124b4aSJiri Slaby  * @port: tty port to push
52296fd7ce5SGreg Kroah-Hartman  *
523bc17b723SJiri Slaby  * Queue a push of the terminal flip buffers to the line discipline. Can be
524bc17b723SJiri Slaby  * called from IRQ/atomic context.
52596fd7ce5SGreg Kroah-Hartman  *
526bc17b723SJiri Slaby  * In the event of the queue being busy for flipping the work will be held off
527bc17b723SJiri Slaby  * and retried later.
52896fd7ce5SGreg Kroah-Hartman  */
tty_flip_buffer_push(struct tty_port * port)5292e124b4aSJiri Slaby void tty_flip_buffer_push(struct tty_port *port)
53096fd7ce5SGreg Kroah-Hartman {
5315db96ef2SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
5325db96ef2SJiri Slaby 
533716b1058SJiri Slaby 	tty_flip_buffer_commit(buf->tail);
5345db96ef2SJiri Slaby 	queue_work(system_unbound_wq, &buf->work);
53596fd7ce5SGreg Kroah-Hartman }
53696fd7ce5SGreg Kroah-Hartman EXPORT_SYMBOL(tty_flip_buffer_push);
53796fd7ce5SGreg Kroah-Hartman 
53896fd7ce5SGreg Kroah-Hartman /**
539a501ab75SJiri Slaby  * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and
540a501ab75SJiri Slaby  *	push
541a501ab75SJiri Slaby  * @port: tty port
542a501ab75SJiri Slaby  * @chars: characters
543a501ab75SJiri Slaby  * @size: size
544a501ab75SJiri Slaby  *
545a501ab75SJiri Slaby  * The function combines tty_insert_flip_string() and tty_flip_buffer_push()
546a501ab75SJiri Slaby  * with the exception of properly holding the @port->lock.
547a501ab75SJiri Slaby  *
548a501ab75SJiri Slaby  * To be used only internally (by pty currently).
549a501ab75SJiri Slaby  *
550a501ab75SJiri Slaby  * Returns: the number added.
551a501ab75SJiri Slaby  */
tty_insert_flip_string_and_push_buffer(struct tty_port * port,const u8 * chars,size_t size)552a501ab75SJiri Slaby int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
553a8d9cd23SJiri Slaby (SUSE) 					   const u8 *chars, size_t size)
554a501ab75SJiri Slaby {
555a501ab75SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
556a501ab75SJiri Slaby 	unsigned long flags;
557a501ab75SJiri Slaby 
558a501ab75SJiri Slaby 	spin_lock_irqsave(&port->lock, flags);
559a501ab75SJiri Slaby 	size = tty_insert_flip_string(port, chars, size);
560a501ab75SJiri Slaby 	if (size)
561a501ab75SJiri Slaby 		tty_flip_buffer_commit(buf->tail);
562a501ab75SJiri Slaby 	spin_unlock_irqrestore(&port->lock, flags);
563a501ab75SJiri Slaby 
564a501ab75SJiri Slaby 	queue_work(system_unbound_wq, &buf->work);
565a501ab75SJiri Slaby 
566a501ab75SJiri Slaby 	return size;
567a501ab75SJiri Slaby }
568a501ab75SJiri Slaby 
569a501ab75SJiri Slaby /**
57096fd7ce5SGreg Kroah-Hartman  * tty_buffer_init		-	prepare a tty buffer structure
571fa441954SJiri Slaby  * @port: tty port to initialise
57296fd7ce5SGreg Kroah-Hartman  *
573bc17b723SJiri Slaby  * Set up the initial state of the buffer management for a tty device. Must be
574bc17b723SJiri Slaby  * called before the other tty buffer functions are used.
57596fd7ce5SGreg Kroah-Hartman  */
tty_buffer_init(struct tty_port * port)576ecbbfd44SJiri Slaby void tty_buffer_init(struct tty_port *port)
57796fd7ce5SGreg Kroah-Hartman {
578ecbbfd44SJiri Slaby 	struct tty_bufhead *buf = &port->buf;
5795cff39c6SJiri Slaby 
580a7c8d58cSPeter Hurley 	mutex_init(&buf->lock);
5817391ee16SPeter Hurley 	tty_buffer_reset(&buf->sentinel, 0);
5827391ee16SPeter Hurley 	buf->head = &buf->sentinel;
5837391ee16SPeter Hurley 	buf->tail = &buf->sentinel;
584809850b7SPeter Hurley 	init_llist_head(&buf->free);
5855dda4ca5SPeter Hurley 	atomic_set(&buf->mem_used, 0);
586a7c8d58cSPeter Hurley 	atomic_set(&buf->priority, 0);
5875cff39c6SJiri Slaby 	INIT_WORK(&buf->work, flush_to_ldisc);
5884d18e6efSPeter Hurley 	buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT;
58996fd7ce5SGreg Kroah-Hartman }
5904d18e6efSPeter Hurley 
5914d18e6efSPeter Hurley /**
5924d18e6efSPeter Hurley  * tty_buffer_set_limit		-	change the tty buffer memory limit
5934d18e6efSPeter Hurley  * @port: tty port to change
594a776f10dSLee Jones  * @limit: memory limit to set
5954d18e6efSPeter Hurley  *
5964d18e6efSPeter Hurley  * Change the tty buffer memory limit.
597bc17b723SJiri Slaby  *
5984d18e6efSPeter Hurley  * Must be called before the other tty buffer functions are used.
5994d18e6efSPeter Hurley  */
tty_buffer_set_limit(struct tty_port * port,int limit)6004d18e6efSPeter Hurley int tty_buffer_set_limit(struct tty_port *port, int limit)
6014d18e6efSPeter Hurley {
6024d18e6efSPeter Hurley 	if (limit < MIN_TTYB_SIZE)
6034d18e6efSPeter Hurley 		return -EINVAL;
6044d18e6efSPeter Hurley 	port->buf.mem_limit = limit;
6054d18e6efSPeter Hurley 	return 0;
6064d18e6efSPeter Hurley }
6074d18e6efSPeter Hurley EXPORT_SYMBOL_GPL(tty_buffer_set_limit);
6081d1d14daSPeter Hurley 
6091d1d14daSPeter Hurley /* slave ptys can claim nested buffer lock when handling BRK and INTR */
tty_buffer_set_lock_subclass(struct tty_port * port)6101d1d14daSPeter Hurley void tty_buffer_set_lock_subclass(struct tty_port *port)
6111d1d14daSPeter Hurley {
6121d1d14daSPeter Hurley 	lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
6131d1d14daSPeter Hurley }
614e176058fSPeter Hurley 
tty_buffer_restart_work(struct tty_port * port)615e176058fSPeter Hurley bool tty_buffer_restart_work(struct tty_port *port)
616e176058fSPeter Hurley {
617e176058fSPeter Hurley 	return queue_work(system_unbound_wq, &port->buf.work);
618e176058fSPeter Hurley }
619e176058fSPeter Hurley 
tty_buffer_cancel_work(struct tty_port * port)620e176058fSPeter Hurley bool tty_buffer_cancel_work(struct tty_port *port)
621e176058fSPeter Hurley {
622e176058fSPeter Hurley 	return cancel_work_sync(&port->buf.work);
623e176058fSPeter Hurley }
6240f40fbbcSBrian Bloniarz 
tty_buffer_flush_work(struct tty_port * port)6250f40fbbcSBrian Bloniarz void tty_buffer_flush_work(struct tty_port *port)
6260f40fbbcSBrian Bloniarz {
6270f40fbbcSBrian Bloniarz 	flush_work(&port->buf.work);
6280f40fbbcSBrian Bloniarz }
629