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