162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Tty buffer allocation management 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include <linux/errno.h> 862306a36Sopenharmony_ci#include <linux/minmax.h> 962306a36Sopenharmony_ci#include <linux/tty.h> 1062306a36Sopenharmony_ci#include <linux/tty_driver.h> 1162306a36Sopenharmony_ci#include <linux/tty_flip.h> 1262306a36Sopenharmony_ci#include <linux/timer.h> 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/sched.h> 1662306a36Sopenharmony_ci#include <linux/wait.h> 1762306a36Sopenharmony_ci#include <linux/bitops.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/ratelimit.h> 2162306a36Sopenharmony_ci#include "tty.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define MIN_TTYB_SIZE 256 2462306a36Sopenharmony_ci#define TTYB_ALIGN_MASK 0xff 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Byte threshold to limit memory consumption for flip buffers. 2862306a36Sopenharmony_ci * The actual memory limit is > 2x this amount. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#define TTYB_DEFAULT_MEM_LIMIT (640 * 1024UL) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * We default to dicing tty buffer allocations to this many characters 3462306a36Sopenharmony_ci * in order to avoid multiple page allocations. We know the size of 3562306a36Sopenharmony_ci * tty_buffer itself but it must also be taken into account that the 3662306a36Sopenharmony_ci * buffer is 256 byte aligned. See tty_buffer_find for the allocation 3762306a36Sopenharmony_ci * logic this must match. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~TTYB_ALIGN_MASK) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/** 4362306a36Sopenharmony_ci * tty_buffer_lock_exclusive - gain exclusive access to buffer 4462306a36Sopenharmony_ci * @port: tty port owning the flip buffer 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * Guarantees safe use of the &tty_ldisc_ops.receive_buf() method by excluding 4762306a36Sopenharmony_ci * the buffer work and any pending flush from using the flip buffer. Data can 4862306a36Sopenharmony_ci * continue to be added concurrently to the flip buffer from the driver side. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * See also tty_buffer_unlock_exclusive(). 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_civoid tty_buffer_lock_exclusive(struct tty_port *port) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci atomic_inc(&buf->priority); 5762306a36Sopenharmony_ci mutex_lock(&buf->lock); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/** 6262306a36Sopenharmony_ci * tty_buffer_unlock_exclusive - release exclusive access 6362306a36Sopenharmony_ci * @port: tty port owning the flip buffer 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * The buffer work is restarted if there is data in the flip buffer. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * See also tty_buffer_lock_exclusive(). 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_civoid tty_buffer_unlock_exclusive(struct tty_port *port) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 7262306a36Sopenharmony_ci int restart; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci restart = buf->head->commit != buf->head->read; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci atomic_dec(&buf->priority); 7762306a36Sopenharmony_ci mutex_unlock(&buf->lock); 7862306a36Sopenharmony_ci if (restart) 7962306a36Sopenharmony_ci queue_work(system_unbound_wq, &buf->work); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/** 8462306a36Sopenharmony_ci * tty_buffer_space_avail - return unused buffer space 8562306a36Sopenharmony_ci * @port: tty port owning the flip buffer 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * Returns: the # of bytes which can be written by the driver without reaching 8862306a36Sopenharmony_ci * the buffer limit. 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * Note: this does not guarantee that memory is available to write the returned 9162306a36Sopenharmony_ci * # of bytes (use tty_prepare_flip_string() to pre-allocate if memory 9262306a36Sopenharmony_ci * guarantee is required). 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ciunsigned int tty_buffer_space_avail(struct tty_port *port) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return max(space, 0); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_space_avail); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void tty_buffer_reset(struct tty_buffer *p, size_t size) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci p->used = 0; 10562306a36Sopenharmony_ci p->size = size; 10662306a36Sopenharmony_ci p->next = NULL; 10762306a36Sopenharmony_ci p->commit = 0; 10862306a36Sopenharmony_ci p->lookahead = 0; 10962306a36Sopenharmony_ci p->read = 0; 11062306a36Sopenharmony_ci p->flags = true; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/** 11462306a36Sopenharmony_ci * tty_buffer_free_all - free buffers used by a tty 11562306a36Sopenharmony_ci * @port: tty port to free from 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * Remove all the buffers pending on a tty whether queued with data or in the 11862306a36Sopenharmony_ci * free ring. Must be called when the tty is no longer in use. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_civoid tty_buffer_free_all(struct tty_port *port) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 12362306a36Sopenharmony_ci struct tty_buffer *p, *next; 12462306a36Sopenharmony_ci struct llist_node *llist; 12562306a36Sopenharmony_ci unsigned int freed = 0; 12662306a36Sopenharmony_ci int still_used; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci while ((p = buf->head) != NULL) { 12962306a36Sopenharmony_ci buf->head = p->next; 13062306a36Sopenharmony_ci freed += p->size; 13162306a36Sopenharmony_ci if (p->size > 0) 13262306a36Sopenharmony_ci kfree(p); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci llist = llist_del_all(&buf->free); 13562306a36Sopenharmony_ci llist_for_each_entry_safe(p, next, llist, free) 13662306a36Sopenharmony_ci kfree(p); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci tty_buffer_reset(&buf->sentinel, 0); 13962306a36Sopenharmony_ci buf->head = &buf->sentinel; 14062306a36Sopenharmony_ci buf->tail = &buf->sentinel; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci still_used = atomic_xchg(&buf->mem_used, 0); 14362306a36Sopenharmony_ci WARN(still_used != freed, "we still have not freed %d bytes!", 14462306a36Sopenharmony_ci still_used - freed); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/** 14862306a36Sopenharmony_ci * tty_buffer_alloc - allocate a tty buffer 14962306a36Sopenharmony_ci * @port: tty port 15062306a36Sopenharmony_ci * @size: desired size (characters) 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Allocate a new tty buffer to hold the desired number of characters. We 15362306a36Sopenharmony_ci * round our buffers off in 256 character chunks to get better allocation 15462306a36Sopenharmony_ci * behaviour. 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci * Returns: %NULL if out of memory or the allocation would exceed the per 15762306a36Sopenharmony_ci * device queue. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_cistatic struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct llist_node *free; 16262306a36Sopenharmony_ci struct tty_buffer *p; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Round the buffer size out */ 16562306a36Sopenharmony_ci size = __ALIGN_MASK(size, TTYB_ALIGN_MASK); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (size <= MIN_TTYB_SIZE) { 16862306a36Sopenharmony_ci free = llist_del_first(&port->buf.free); 16962306a36Sopenharmony_ci if (free) { 17062306a36Sopenharmony_ci p = llist_entry(free, struct tty_buffer, free); 17162306a36Sopenharmony_ci goto found; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Should possibly check if this fails for the largest buffer we 17662306a36Sopenharmony_ci * have queued and recycle that ? 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit) 17962306a36Sopenharmony_ci return NULL; 18062306a36Sopenharmony_ci p = kmalloc(struct_size(p, data, 2 * size), GFP_ATOMIC | __GFP_NOWARN); 18162306a36Sopenharmony_ci if (p == NULL) 18262306a36Sopenharmony_ci return NULL; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cifound: 18562306a36Sopenharmony_ci tty_buffer_reset(p, size); 18662306a36Sopenharmony_ci atomic_add(size, &port->buf.mem_used); 18762306a36Sopenharmony_ci return p; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/** 19162306a36Sopenharmony_ci * tty_buffer_free - free a tty buffer 19262306a36Sopenharmony_ci * @port: tty port owning the buffer 19362306a36Sopenharmony_ci * @b: the buffer to free 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * Free a tty buffer, or add it to the free list according to our internal 19662306a36Sopenharmony_ci * strategy. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_cistatic void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Dumb strategy for now - should keep some stats */ 20362306a36Sopenharmony_ci WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (b->size > MIN_TTYB_SIZE) 20662306a36Sopenharmony_ci kfree(b); 20762306a36Sopenharmony_ci else if (b->size > 0) 20862306a36Sopenharmony_ci llist_add(&b->free, &buf->free); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/** 21262306a36Sopenharmony_ci * tty_buffer_flush - flush full tty buffers 21362306a36Sopenharmony_ci * @tty: tty to flush 21462306a36Sopenharmony_ci * @ld: optional ldisc ptr (must be referenced) 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Flush all the buffers containing receive data. If @ld != %NULL, flush the 21762306a36Sopenharmony_ci * ldisc input buffer. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * Locking: takes buffer lock to ensure single-threaded flip buffer 'consumer'. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_civoid tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct tty_port *port = tty->port; 22462306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 22562306a36Sopenharmony_ci struct tty_buffer *next; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci atomic_inc(&buf->priority); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci mutex_lock(&buf->lock); 23062306a36Sopenharmony_ci /* paired w/ release in __tty_buffer_request_room; ensures there are 23162306a36Sopenharmony_ci * no pending memory accesses to the freed buffer 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci while ((next = smp_load_acquire(&buf->head->next)) != NULL) { 23462306a36Sopenharmony_ci tty_buffer_free(port, buf->head); 23562306a36Sopenharmony_ci buf->head = next; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci buf->head->read = buf->head->commit; 23862306a36Sopenharmony_ci buf->head->lookahead = buf->head->read; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (ld && ld->ops->flush_buffer) 24162306a36Sopenharmony_ci ld->ops->flush_buffer(tty); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci atomic_dec(&buf->priority); 24462306a36Sopenharmony_ci mutex_unlock(&buf->lock); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * __tty_buffer_request_room - grow tty buffer if needed 24962306a36Sopenharmony_ci * @port: tty port 25062306a36Sopenharmony_ci * @size: size desired 25162306a36Sopenharmony_ci * @flags: buffer has to store flags along character data 25262306a36Sopenharmony_ci * 25362306a36Sopenharmony_ci * Make at least @size bytes of linear space available for the tty buffer. 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * Will change over to a new buffer if the current buffer is encoded as 25662306a36Sopenharmony_ci * %TTY_NORMAL (so has no flags buffer) and the new buffer requires a flags 25762306a36Sopenharmony_ci * buffer. 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * Returns: the size we managed to find. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_cistatic int __tty_buffer_request_room(struct tty_port *port, size_t size, 26262306a36Sopenharmony_ci bool flags) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 26562306a36Sopenharmony_ci struct tty_buffer *n, *b = buf->tail; 26662306a36Sopenharmony_ci size_t left = (b->flags ? 1 : 2) * b->size - b->used; 26762306a36Sopenharmony_ci bool change = !b->flags && flags; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (!change && left >= size) 27062306a36Sopenharmony_ci return size; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* This is the slow path - looking for new buffers to use */ 27362306a36Sopenharmony_ci n = tty_buffer_alloc(port, size); 27462306a36Sopenharmony_ci if (n == NULL) 27562306a36Sopenharmony_ci return change ? 0 : left; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci n->flags = flags; 27862306a36Sopenharmony_ci buf->tail = n; 27962306a36Sopenharmony_ci /* 28062306a36Sopenharmony_ci * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs() 28162306a36Sopenharmony_ci * ensures they see all buffer data. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci smp_store_release(&b->commit, b->used); 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs() 28662306a36Sopenharmony_ci * ensures the latest commit value can be read before the head 28762306a36Sopenharmony_ci * is advanced to the next buffer. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci smp_store_release(&b->next, n); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return size; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ciint tty_buffer_request_room(struct tty_port *port, size_t size) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci return __tty_buffer_request_room(port, size, true); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_request_room); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cisize_t __tty_insert_flip_string_flags(struct tty_port *port, const u8 *chars, 30162306a36Sopenharmony_ci const u8 *flags, bool mutable_flags, 30262306a36Sopenharmony_ci size_t size) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci bool need_flags = mutable_flags || flags[0] != TTY_NORMAL; 30562306a36Sopenharmony_ci size_t copied = 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci do { 30862306a36Sopenharmony_ci size_t goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); 30962306a36Sopenharmony_ci size_t space = __tty_buffer_request_room(port, goal, need_flags); 31062306a36Sopenharmony_ci struct tty_buffer *tb = port->buf.tail; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (unlikely(space == 0)) 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci memcpy(char_buf_ptr(tb, tb->used), chars, space); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (mutable_flags) { 31862306a36Sopenharmony_ci memcpy(flag_buf_ptr(tb, tb->used), flags, space); 31962306a36Sopenharmony_ci flags += space; 32062306a36Sopenharmony_ci } else if (tb->flags) { 32162306a36Sopenharmony_ci memset(flag_buf_ptr(tb, tb->used), flags[0], space); 32262306a36Sopenharmony_ci } else { 32362306a36Sopenharmony_ci /* tb->flags should be available once requested */ 32462306a36Sopenharmony_ci WARN_ON_ONCE(need_flags); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci tb->used += space; 32862306a36Sopenharmony_ci copied += space; 32962306a36Sopenharmony_ci chars += space; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* There is a small chance that we need to split the data over 33262306a36Sopenharmony_ci * several buffers. If this is the case we must loop. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci } while (unlikely(size > copied)); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return copied; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ciEXPORT_SYMBOL(__tty_insert_flip_string_flags); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/** 34162306a36Sopenharmony_ci * tty_prepare_flip_string - make room for characters 34262306a36Sopenharmony_ci * @port: tty port 34362306a36Sopenharmony_ci * @chars: return pointer for character write area 34462306a36Sopenharmony_ci * @size: desired size 34562306a36Sopenharmony_ci * 34662306a36Sopenharmony_ci * Prepare a block of space in the buffer for data. 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * This is used for drivers that need their own block copy routines into the 34962306a36Sopenharmony_ci * buffer. There is no guarantee the buffer is a DMA target! 35062306a36Sopenharmony_ci * 35162306a36Sopenharmony_ci * Returns: the length available and buffer pointer (@chars) to the space which 35262306a36Sopenharmony_ci * is now allocated and accounted for as ready for normal characters. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_cisize_t tty_prepare_flip_string(struct tty_port *port, u8 **chars, size_t size) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci size_t space = __tty_buffer_request_room(port, size, false); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (likely(space)) { 35962306a36Sopenharmony_ci struct tty_buffer *tb = port->buf.tail; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci *chars = char_buf_ptr(tb, tb->used); 36262306a36Sopenharmony_ci if (tb->flags) 36362306a36Sopenharmony_ci memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); 36462306a36Sopenharmony_ci tb->used += space; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return space; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_prepare_flip_string); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/** 37262306a36Sopenharmony_ci * tty_ldisc_receive_buf - forward data to line discipline 37362306a36Sopenharmony_ci * @ld: line discipline to process input 37462306a36Sopenharmony_ci * @p: char buffer 37562306a36Sopenharmony_ci * @f: %TTY_NORMAL, %TTY_BREAK, etc. flags buffer 37662306a36Sopenharmony_ci * @count: number of bytes to process 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * Callers other than flush_to_ldisc() need to exclude the kworker from 37962306a36Sopenharmony_ci * concurrent use of the line discipline, see paste_selection(). 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * Returns: the number of bytes processed. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_cisize_t tty_ldisc_receive_buf(struct tty_ldisc *ld, const u8 *p, const u8 *f, 38462306a36Sopenharmony_ci size_t count) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci if (ld->ops->receive_buf2) 38762306a36Sopenharmony_ci count = ld->ops->receive_buf2(ld->tty, p, f, count); 38862306a36Sopenharmony_ci else { 38962306a36Sopenharmony_ci count = min_t(size_t, count, ld->tty->receive_room); 39062306a36Sopenharmony_ci if (count && ld->ops->receive_buf) 39162306a36Sopenharmony_ci ld->ops->receive_buf(ld->tty, p, f, count); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci return count; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_ldisc_receive_buf); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic void lookahead_bufs(struct tty_port *port, struct tty_buffer *head) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci head->lookahead = max(head->lookahead, head->read); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci while (head) { 40262306a36Sopenharmony_ci struct tty_buffer *next; 40362306a36Sopenharmony_ci unsigned int count; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* 40662306a36Sopenharmony_ci * Paired w/ release in __tty_buffer_request_room(); 40762306a36Sopenharmony_ci * ensures commit value read is not stale if the head 40862306a36Sopenharmony_ci * is advancing to the next buffer. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci next = smp_load_acquire(&head->next); 41162306a36Sopenharmony_ci /* 41262306a36Sopenharmony_ci * Paired w/ release in __tty_buffer_request_room() or in 41362306a36Sopenharmony_ci * tty_buffer_flush(); ensures we see the committed buffer data. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ci count = smp_load_acquire(&head->commit) - head->lookahead; 41662306a36Sopenharmony_ci if (!count) { 41762306a36Sopenharmony_ci head = next; 41862306a36Sopenharmony_ci continue; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (port->client_ops->lookahead_buf) { 42262306a36Sopenharmony_ci u8 *p, *f = NULL; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci p = char_buf_ptr(head, head->lookahead); 42562306a36Sopenharmony_ci if (head->flags) 42662306a36Sopenharmony_ci f = flag_buf_ptr(head, head->lookahead); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci port->client_ops->lookahead_buf(port, p, f, count); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci head->lookahead += count; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic size_t 43662306a36Sopenharmony_cireceive_buf(struct tty_port *port, struct tty_buffer *head, size_t count) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci u8 *p = char_buf_ptr(head, head->read); 43962306a36Sopenharmony_ci const u8 *f = NULL; 44062306a36Sopenharmony_ci size_t n; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (head->flags) 44362306a36Sopenharmony_ci f = flag_buf_ptr(head, head->read); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci n = port->client_ops->receive_buf(port, p, f, count); 44662306a36Sopenharmony_ci if (n > 0) 44762306a36Sopenharmony_ci memset(p, 0, n); 44862306a36Sopenharmony_ci return n; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/** 45262306a36Sopenharmony_ci * flush_to_ldisc - flush data from buffer to ldisc 45362306a36Sopenharmony_ci * @work: tty structure passed from work queue. 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * This routine is called out of the software interrupt to flush data from the 45662306a36Sopenharmony_ci * buffer chain to the line discipline. 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * The receive_buf() method is single threaded for each tty instance. 45962306a36Sopenharmony_ci * 46062306a36Sopenharmony_ci * Locking: takes buffer lock to ensure single-threaded flip buffer 'consumer'. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_cistatic void flush_to_ldisc(struct work_struct *work) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct tty_port *port = container_of(work, struct tty_port, buf.work); 46562306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mutex_lock(&buf->lock); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci while (1) { 47062306a36Sopenharmony_ci struct tty_buffer *head = buf->head; 47162306a36Sopenharmony_ci struct tty_buffer *next; 47262306a36Sopenharmony_ci size_t count, rcvd; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* Ldisc or user is trying to gain exclusive access */ 47562306a36Sopenharmony_ci if (atomic_read(&buf->priority)) 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* paired w/ release in __tty_buffer_request_room(); 47962306a36Sopenharmony_ci * ensures commit value read is not stale if the head 48062306a36Sopenharmony_ci * is advancing to the next buffer 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci next = smp_load_acquire(&head->next); 48362306a36Sopenharmony_ci /* paired w/ release in __tty_buffer_request_room() or in 48462306a36Sopenharmony_ci * tty_buffer_flush(); ensures we see the committed buffer data 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci count = smp_load_acquire(&head->commit) - head->read; 48762306a36Sopenharmony_ci if (!count) { 48862306a36Sopenharmony_ci if (next == NULL) 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci buf->head = next; 49162306a36Sopenharmony_ci tty_buffer_free(port, head); 49262306a36Sopenharmony_ci continue; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci rcvd = receive_buf(port, head, count); 49662306a36Sopenharmony_ci head->read += rcvd; 49762306a36Sopenharmony_ci if (rcvd < count) 49862306a36Sopenharmony_ci lookahead_bufs(port, head); 49962306a36Sopenharmony_ci if (!rcvd) 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (need_resched()) 50362306a36Sopenharmony_ci cond_resched(); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci mutex_unlock(&buf->lock); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic inline void tty_flip_buffer_commit(struct tty_buffer *tail) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci /* 51362306a36Sopenharmony_ci * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees 51462306a36Sopenharmony_ci * buffer data. 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci smp_store_release(&tail->commit, tail->used); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/** 52062306a36Sopenharmony_ci * tty_flip_buffer_push - push terminal buffers 52162306a36Sopenharmony_ci * @port: tty port to push 52262306a36Sopenharmony_ci * 52362306a36Sopenharmony_ci * Queue a push of the terminal flip buffers to the line discipline. Can be 52462306a36Sopenharmony_ci * called from IRQ/atomic context. 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * In the event of the queue being busy for flipping the work will be held off 52762306a36Sopenharmony_ci * and retried later. 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_civoid tty_flip_buffer_push(struct tty_port *port) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci tty_flip_buffer_commit(buf->tail); 53462306a36Sopenharmony_ci queue_work(system_unbound_wq, &buf->work); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ciEXPORT_SYMBOL(tty_flip_buffer_push); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci/** 53962306a36Sopenharmony_ci * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and 54062306a36Sopenharmony_ci * push 54162306a36Sopenharmony_ci * @port: tty port 54262306a36Sopenharmony_ci * @chars: characters 54362306a36Sopenharmony_ci * @size: size 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * The function combines tty_insert_flip_string() and tty_flip_buffer_push() 54662306a36Sopenharmony_ci * with the exception of properly holding the @port->lock. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * To be used only internally (by pty currently). 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci * Returns: the number added. 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_ciint tty_insert_flip_string_and_push_buffer(struct tty_port *port, 55362306a36Sopenharmony_ci const u8 *chars, size_t size) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 55662306a36Sopenharmony_ci unsigned long flags; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 55962306a36Sopenharmony_ci size = tty_insert_flip_string(port, chars, size); 56062306a36Sopenharmony_ci if (size) 56162306a36Sopenharmony_ci tty_flip_buffer_commit(buf->tail); 56262306a36Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci queue_work(system_unbound_wq, &buf->work); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return size; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/** 57062306a36Sopenharmony_ci * tty_buffer_init - prepare a tty buffer structure 57162306a36Sopenharmony_ci * @port: tty port to initialise 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * Set up the initial state of the buffer management for a tty device. Must be 57462306a36Sopenharmony_ci * called before the other tty buffer functions are used. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_civoid tty_buffer_init(struct tty_port *port) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci mutex_init(&buf->lock); 58162306a36Sopenharmony_ci tty_buffer_reset(&buf->sentinel, 0); 58262306a36Sopenharmony_ci buf->head = &buf->sentinel; 58362306a36Sopenharmony_ci buf->tail = &buf->sentinel; 58462306a36Sopenharmony_ci init_llist_head(&buf->free); 58562306a36Sopenharmony_ci atomic_set(&buf->mem_used, 0); 58662306a36Sopenharmony_ci atomic_set(&buf->priority, 0); 58762306a36Sopenharmony_ci INIT_WORK(&buf->work, flush_to_ldisc); 58862306a36Sopenharmony_ci buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/** 59262306a36Sopenharmony_ci * tty_buffer_set_limit - change the tty buffer memory limit 59362306a36Sopenharmony_ci * @port: tty port to change 59462306a36Sopenharmony_ci * @limit: memory limit to set 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * Change the tty buffer memory limit. 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * Must be called before the other tty buffer functions are used. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ciint tty_buffer_set_limit(struct tty_port *port, int limit) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci if (limit < MIN_TTYB_SIZE) 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci port->buf.mem_limit = limit; 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_set_limit); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* slave ptys can claim nested buffer lock when handling BRK and INTR */ 61062306a36Sopenharmony_civoid tty_buffer_set_lock_subclass(struct tty_port *port) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cibool tty_buffer_restart_work(struct tty_port *port) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci return queue_work(system_unbound_wq, &port->buf.work); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cibool tty_buffer_cancel_work(struct tty_port *port) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci return cancel_work_sync(&port->buf.work); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_civoid tty_buffer_flush_work(struct tty_port *port) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci flush_work(&port->buf.work); 62862306a36Sopenharmony_ci} 629