18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Tty buffer allocation management 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <linux/errno.h> 88c2ecf20Sopenharmony_ci#include <linux/tty.h> 98c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 108c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 118c2ecf20Sopenharmony_ci#include <linux/timer.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/sched.h> 158c2ecf20Sopenharmony_ci#include <linux/wait.h> 168c2ecf20Sopenharmony_ci#include <linux/bitops.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 208c2ecf20Sopenharmony_ci#include "tty.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define MIN_TTYB_SIZE 256 238c2ecf20Sopenharmony_ci#define TTYB_ALIGN_MASK 255 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * Byte threshold to limit memory consumption for flip buffers. 278c2ecf20Sopenharmony_ci * The actual memory limit is > 2x this amount. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci#define TTYB_DEFAULT_MEM_LIMIT (640 * 1024UL) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * We default to dicing tty buffer allocations to this many characters 338c2ecf20Sopenharmony_ci * in order to avoid multiple page allocations. We know the size of 348c2ecf20Sopenharmony_ci * tty_buffer itself but it must also be taken into account that the 358c2ecf20Sopenharmony_ci * the buffer is 256 byte aligned. See tty_buffer_find for the allocation 368c2ecf20Sopenharmony_ci * logic this must match 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/** 428c2ecf20Sopenharmony_ci * tty_buffer_lock_exclusive - gain exclusive access to buffer 438c2ecf20Sopenharmony_ci * tty_buffer_unlock_exclusive - release exclusive access 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * @port: tty port owning the flip buffer 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * Guarantees safe use of the line discipline's receive_buf() method by 488c2ecf20Sopenharmony_ci * excluding the buffer work and any pending flush from using the flip 498c2ecf20Sopenharmony_ci * buffer. Data can continue to be added concurrently to the flip buffer 508c2ecf20Sopenharmony_ci * from the driver side. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * On release, the buffer work is restarted if there is data in the 538c2ecf20Sopenharmony_ci * flip buffer 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_civoid tty_buffer_lock_exclusive(struct tty_port *port) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci atomic_inc(&buf->priority); 618c2ecf20Sopenharmony_ci mutex_lock(&buf->lock); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_civoid tty_buffer_unlock_exclusive(struct tty_port *port) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 688c2ecf20Sopenharmony_ci int restart; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci restart = buf->head->commit != buf->head->read; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci atomic_dec(&buf->priority); 738c2ecf20Sopenharmony_ci mutex_unlock(&buf->lock); 748c2ecf20Sopenharmony_ci if (restart) 758c2ecf20Sopenharmony_ci queue_work(system_unbound_wq, &buf->work); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * tty_buffer_space_avail - return unused buffer space 818c2ecf20Sopenharmony_ci * @port: tty port owning the flip buffer 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * Returns the # of bytes which can be written by the driver without 848c2ecf20Sopenharmony_ci * reaching the buffer limit. 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Note: this does not guarantee that memory is available to write 878c2ecf20Sopenharmony_ci * the returned # of bytes (use tty_prepare_flip_string_xxx() to 888c2ecf20Sopenharmony_ci * pre-allocate if memory guarantee is required). 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ciint tty_buffer_space_avail(struct tty_port *port) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used); 948c2ecf20Sopenharmony_ci return max(space, 0); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_space_avail); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void tty_buffer_reset(struct tty_buffer *p, size_t size) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci p->used = 0; 1018c2ecf20Sopenharmony_ci p->size = size; 1028c2ecf20Sopenharmony_ci p->next = NULL; 1038c2ecf20Sopenharmony_ci p->commit = 0; 1048c2ecf20Sopenharmony_ci p->read = 0; 1058c2ecf20Sopenharmony_ci p->flags = 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/** 1098c2ecf20Sopenharmony_ci * tty_buffer_free_all - free buffers used by a tty 1108c2ecf20Sopenharmony_ci * @port: tty port to free from 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Remove all the buffers pending on a tty whether queued with data 1138c2ecf20Sopenharmony_ci * or in the free ring. Must be called when the tty is no longer in use 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid tty_buffer_free_all(struct tty_port *port) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 1198c2ecf20Sopenharmony_ci struct tty_buffer *p, *next; 1208c2ecf20Sopenharmony_ci struct llist_node *llist; 1218c2ecf20Sopenharmony_ci unsigned int freed = 0; 1228c2ecf20Sopenharmony_ci int still_used; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci while ((p = buf->head) != NULL) { 1258c2ecf20Sopenharmony_ci buf->head = p->next; 1268c2ecf20Sopenharmony_ci freed += p->size; 1278c2ecf20Sopenharmony_ci if (p->size > 0) 1288c2ecf20Sopenharmony_ci kfree(p); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci llist = llist_del_all(&buf->free); 1318c2ecf20Sopenharmony_ci llist_for_each_entry_safe(p, next, llist, free) 1328c2ecf20Sopenharmony_ci kfree(p); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci tty_buffer_reset(&buf->sentinel, 0); 1358c2ecf20Sopenharmony_ci buf->head = &buf->sentinel; 1368c2ecf20Sopenharmony_ci buf->tail = &buf->sentinel; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci still_used = atomic_xchg(&buf->mem_used, 0); 1398c2ecf20Sopenharmony_ci WARN(still_used != freed, "we still have not freed %d bytes!", 1408c2ecf20Sopenharmony_ci still_used - freed); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/** 1448c2ecf20Sopenharmony_ci * tty_buffer_alloc - allocate a tty buffer 1458c2ecf20Sopenharmony_ci * @port: tty port 1468c2ecf20Sopenharmony_ci * @size: desired size (characters) 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * Allocate a new tty buffer to hold the desired number of characters. 1498c2ecf20Sopenharmony_ci * We round our buffers off in 256 character chunks to get better 1508c2ecf20Sopenharmony_ci * allocation behaviour. 1518c2ecf20Sopenharmony_ci * Return NULL if out of memory or the allocation would exceed the 1528c2ecf20Sopenharmony_ci * per device queue 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct llist_node *free; 1588c2ecf20Sopenharmony_ci struct tty_buffer *p; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Round the buffer size out */ 1618c2ecf20Sopenharmony_ci size = __ALIGN_MASK(size, TTYB_ALIGN_MASK); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (size <= MIN_TTYB_SIZE) { 1648c2ecf20Sopenharmony_ci free = llist_del_first(&port->buf.free); 1658c2ecf20Sopenharmony_ci if (free) { 1668c2ecf20Sopenharmony_ci p = llist_entry(free, struct tty_buffer, free); 1678c2ecf20Sopenharmony_ci goto found; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Should possibly check if this fails for the largest buffer we 1728c2ecf20Sopenharmony_ci have queued and recycle that ? */ 1738c2ecf20Sopenharmony_ci if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit) 1748c2ecf20Sopenharmony_ci return NULL; 1758c2ecf20Sopenharmony_ci p = kmalloc(sizeof(struct tty_buffer) + 2 * size, 1768c2ecf20Sopenharmony_ci GFP_ATOMIC | __GFP_NOWARN); 1778c2ecf20Sopenharmony_ci if (p == NULL) 1788c2ecf20Sopenharmony_ci return NULL; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cifound: 1818c2ecf20Sopenharmony_ci tty_buffer_reset(p, size); 1828c2ecf20Sopenharmony_ci atomic_add(size, &port->buf.mem_used); 1838c2ecf20Sopenharmony_ci return p; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/** 1878c2ecf20Sopenharmony_ci * tty_buffer_free - free a tty buffer 1888c2ecf20Sopenharmony_ci * @port: tty port owning the buffer 1898c2ecf20Sopenharmony_ci * @b: the buffer to free 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * Free a tty buffer, or add it to the free list according to our 1928c2ecf20Sopenharmony_ci * internal strategy 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Dumb strategy for now - should keep some stats */ 2008c2ecf20Sopenharmony_ci WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (b->size > MIN_TTYB_SIZE) 2038c2ecf20Sopenharmony_ci kfree(b); 2048c2ecf20Sopenharmony_ci else if (b->size > 0) 2058c2ecf20Sopenharmony_ci llist_add(&b->free, &buf->free); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/** 2098c2ecf20Sopenharmony_ci * tty_buffer_flush - flush full tty buffers 2108c2ecf20Sopenharmony_ci * @tty: tty to flush 2118c2ecf20Sopenharmony_ci * @ld: optional ldisc ptr (must be referenced) 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * flush all the buffers containing receive data. If ld != NULL, 2148c2ecf20Sopenharmony_ci * flush the ldisc input buffer. 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * Locking: takes buffer lock to ensure single-threaded flip buffer 2178c2ecf20Sopenharmony_ci * 'consumer' 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_civoid tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct tty_port *port = tty->port; 2238c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 2248c2ecf20Sopenharmony_ci struct tty_buffer *next; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci atomic_inc(&buf->priority); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci mutex_lock(&buf->lock); 2298c2ecf20Sopenharmony_ci /* paired w/ release in __tty_buffer_request_room; ensures there are 2308c2ecf20Sopenharmony_ci * no pending memory accesses to the freed buffer 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci while ((next = smp_load_acquire(&buf->head->next)) != NULL) { 2338c2ecf20Sopenharmony_ci tty_buffer_free(port, buf->head); 2348c2ecf20Sopenharmony_ci buf->head = next; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci buf->head->read = buf->head->commit; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (ld && ld->ops->flush_buffer) 2398c2ecf20Sopenharmony_ci ld->ops->flush_buffer(tty); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci atomic_dec(&buf->priority); 2428c2ecf20Sopenharmony_ci mutex_unlock(&buf->lock); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/** 2468c2ecf20Sopenharmony_ci * tty_buffer_request_room - grow tty buffer if needed 2478c2ecf20Sopenharmony_ci * @port: tty port 2488c2ecf20Sopenharmony_ci * @size: size desired 2498c2ecf20Sopenharmony_ci * @flags: buffer flags if new buffer allocated (default = 0) 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * Make at least size bytes of linear space available for the tty 2528c2ecf20Sopenharmony_ci * buffer. If we fail return the size we managed to find. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Will change over to a new buffer if the current buffer is encoded as 2558c2ecf20Sopenharmony_ci * TTY_NORMAL (so has no flags buffer) and the new buffer requires 2568c2ecf20Sopenharmony_ci * a flags buffer. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_cistatic int __tty_buffer_request_room(struct tty_port *port, size_t size, 2598c2ecf20Sopenharmony_ci int flags) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 2628c2ecf20Sopenharmony_ci struct tty_buffer *b, *n; 2638c2ecf20Sopenharmony_ci int left, change; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci b = buf->tail; 2668c2ecf20Sopenharmony_ci if (b->flags & TTYB_NORMAL) 2678c2ecf20Sopenharmony_ci left = 2 * b->size - b->used; 2688c2ecf20Sopenharmony_ci else 2698c2ecf20Sopenharmony_ci left = b->size - b->used; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); 2728c2ecf20Sopenharmony_ci if (change || left < size) { 2738c2ecf20Sopenharmony_ci /* This is the slow path - looking for new buffers to use */ 2748c2ecf20Sopenharmony_ci n = tty_buffer_alloc(port, size); 2758c2ecf20Sopenharmony_ci if (n != NULL) { 2768c2ecf20Sopenharmony_ci n->flags = flags; 2778c2ecf20Sopenharmony_ci buf->tail = n; 2788c2ecf20Sopenharmony_ci /* paired w/ acquire in flush_to_ldisc(); ensures 2798c2ecf20Sopenharmony_ci * flush_to_ldisc() sees buffer data. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci smp_store_release(&b->commit, b->used); 2828c2ecf20Sopenharmony_ci /* paired w/ acquire in flush_to_ldisc(); ensures the 2838c2ecf20Sopenharmony_ci * latest commit value can be read before the head is 2848c2ecf20Sopenharmony_ci * advanced to the next buffer 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci smp_store_release(&b->next, n); 2878c2ecf20Sopenharmony_ci } else if (change) 2888c2ecf20Sopenharmony_ci size = 0; 2898c2ecf20Sopenharmony_ci else 2908c2ecf20Sopenharmony_ci size = left; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci return size; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ciint tty_buffer_request_room(struct tty_port *port, size_t size) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci return __tty_buffer_request_room(port, size, 0); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_request_room); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/** 3028c2ecf20Sopenharmony_ci * tty_insert_flip_string_fixed_flag - Add characters to the tty buffer 3038c2ecf20Sopenharmony_ci * @port: tty port 3048c2ecf20Sopenharmony_ci * @chars: characters 3058c2ecf20Sopenharmony_ci * @flag: flag value for each character 3068c2ecf20Sopenharmony_ci * @size: size 3078c2ecf20Sopenharmony_ci * 3088c2ecf20Sopenharmony_ci * Queue a series of bytes to the tty buffering. All the characters 3098c2ecf20Sopenharmony_ci * passed are marked with the supplied flag. Returns the number added. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ciint tty_insert_flip_string_fixed_flag(struct tty_port *port, 3138c2ecf20Sopenharmony_ci const unsigned char *chars, char flag, size_t size) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci int copied = 0; 3168c2ecf20Sopenharmony_ci do { 3178c2ecf20Sopenharmony_ci int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); 3188c2ecf20Sopenharmony_ci int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; 3198c2ecf20Sopenharmony_ci int space = __tty_buffer_request_room(port, goal, flags); 3208c2ecf20Sopenharmony_ci struct tty_buffer *tb = port->buf.tail; 3218c2ecf20Sopenharmony_ci if (unlikely(space == 0)) 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci memcpy(char_buf_ptr(tb, tb->used), chars, space); 3248c2ecf20Sopenharmony_ci if (~tb->flags & TTYB_NORMAL) 3258c2ecf20Sopenharmony_ci memset(flag_buf_ptr(tb, tb->used), flag, space); 3268c2ecf20Sopenharmony_ci tb->used += space; 3278c2ecf20Sopenharmony_ci copied += space; 3288c2ecf20Sopenharmony_ci chars += space; 3298c2ecf20Sopenharmony_ci /* There is a small chance that we need to split the data over 3308c2ecf20Sopenharmony_ci several buffers. If this is the case we must loop */ 3318c2ecf20Sopenharmony_ci } while (unlikely(size > copied)); 3328c2ecf20Sopenharmony_ci return copied; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/** 3378c2ecf20Sopenharmony_ci * tty_insert_flip_string_flags - Add characters to the tty buffer 3388c2ecf20Sopenharmony_ci * @port: tty port 3398c2ecf20Sopenharmony_ci * @chars: characters 3408c2ecf20Sopenharmony_ci * @flags: flag bytes 3418c2ecf20Sopenharmony_ci * @size: size 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * Queue a series of bytes to the tty buffering. For each character 3448c2ecf20Sopenharmony_ci * the flags array indicates the status of the character. Returns the 3458c2ecf20Sopenharmony_ci * number added. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciint tty_insert_flip_string_flags(struct tty_port *port, 3498c2ecf20Sopenharmony_ci const unsigned char *chars, const char *flags, size_t size) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci int copied = 0; 3528c2ecf20Sopenharmony_ci do { 3538c2ecf20Sopenharmony_ci int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); 3548c2ecf20Sopenharmony_ci int space = tty_buffer_request_room(port, goal); 3558c2ecf20Sopenharmony_ci struct tty_buffer *tb = port->buf.tail; 3568c2ecf20Sopenharmony_ci if (unlikely(space == 0)) 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci memcpy(char_buf_ptr(tb, tb->used), chars, space); 3598c2ecf20Sopenharmony_ci memcpy(flag_buf_ptr(tb, tb->used), flags, space); 3608c2ecf20Sopenharmony_ci tb->used += space; 3618c2ecf20Sopenharmony_ci copied += space; 3628c2ecf20Sopenharmony_ci chars += space; 3638c2ecf20Sopenharmony_ci flags += space; 3648c2ecf20Sopenharmony_ci /* There is a small chance that we need to split the data over 3658c2ecf20Sopenharmony_ci several buffers. If this is the case we must loop */ 3668c2ecf20Sopenharmony_ci } while (unlikely(size > copied)); 3678c2ecf20Sopenharmony_ci return copied; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_insert_flip_string_flags); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/** 3728c2ecf20Sopenharmony_ci * __tty_insert_flip_char - Add one character to the tty buffer 3738c2ecf20Sopenharmony_ci * @port: tty port 3748c2ecf20Sopenharmony_ci * @ch: character 3758c2ecf20Sopenharmony_ci * @flag: flag byte 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * Queue a single byte to the tty buffering, with an optional flag. 3788c2ecf20Sopenharmony_ci * This is the slow path of tty_insert_flip_char. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ciint __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct tty_buffer *tb; 3838c2ecf20Sopenharmony_ci int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (!__tty_buffer_request_room(port, 1, flags)) 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci tb = port->buf.tail; 3898c2ecf20Sopenharmony_ci if (~tb->flags & TTYB_NORMAL) 3908c2ecf20Sopenharmony_ci *flag_buf_ptr(tb, tb->used) = flag; 3918c2ecf20Sopenharmony_ci *char_buf_ptr(tb, tb->used++) = ch; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 1; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__tty_insert_flip_char); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * tty_prepare_flip_string - make room for characters 3998c2ecf20Sopenharmony_ci * @port: tty port 4008c2ecf20Sopenharmony_ci * @chars: return pointer for character write area 4018c2ecf20Sopenharmony_ci * @size: desired size 4028c2ecf20Sopenharmony_ci * 4038c2ecf20Sopenharmony_ci * Prepare a block of space in the buffer for data. Returns the length 4048c2ecf20Sopenharmony_ci * available and buffer pointer to the space which is now allocated and 4058c2ecf20Sopenharmony_ci * accounted for as ready for normal characters. This is used for drivers 4068c2ecf20Sopenharmony_ci * that need their own block copy routines into the buffer. There is no 4078c2ecf20Sopenharmony_ci * guarantee the buffer is a DMA target! 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciint tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, 4118c2ecf20Sopenharmony_ci size_t size) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci int space = __tty_buffer_request_room(port, size, TTYB_NORMAL); 4148c2ecf20Sopenharmony_ci if (likely(space)) { 4158c2ecf20Sopenharmony_ci struct tty_buffer *tb = port->buf.tail; 4168c2ecf20Sopenharmony_ci *chars = char_buf_ptr(tb, tb->used); 4178c2ecf20Sopenharmony_ci if (~tb->flags & TTYB_NORMAL) 4188c2ecf20Sopenharmony_ci memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); 4198c2ecf20Sopenharmony_ci tb->used += space; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci return space; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_prepare_flip_string); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci/** 4268c2ecf20Sopenharmony_ci * tty_ldisc_receive_buf - forward data to line discipline 4278c2ecf20Sopenharmony_ci * @ld: line discipline to process input 4288c2ecf20Sopenharmony_ci * @p: char buffer 4298c2ecf20Sopenharmony_ci * @f: TTY_* flags buffer 4308c2ecf20Sopenharmony_ci * @count: number of bytes to process 4318c2ecf20Sopenharmony_ci * 4328c2ecf20Sopenharmony_ci * Callers other than flush_to_ldisc() need to exclude the kworker 4338c2ecf20Sopenharmony_ci * from concurrent use of the line discipline, see paste_selection(). 4348c2ecf20Sopenharmony_ci * 4358c2ecf20Sopenharmony_ci * Returns the number of bytes processed 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ciint tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, 4388c2ecf20Sopenharmony_ci char *f, int count) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci if (ld->ops->receive_buf2) 4418c2ecf20Sopenharmony_ci count = ld->ops->receive_buf2(ld->tty, p, f, count); 4428c2ecf20Sopenharmony_ci else { 4438c2ecf20Sopenharmony_ci count = min_t(int, count, ld->tty->receive_room); 4448c2ecf20Sopenharmony_ci if (count && ld->ops->receive_buf) 4458c2ecf20Sopenharmony_ci ld->ops->receive_buf(ld->tty, p, f, count); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci return count; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_ldisc_receive_buf); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int 4528c2ecf20Sopenharmony_cireceive_buf(struct tty_port *port, struct tty_buffer *head, int count) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci unsigned char *p = char_buf_ptr(head, head->read); 4558c2ecf20Sopenharmony_ci char *f = NULL; 4568c2ecf20Sopenharmony_ci int n; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (~head->flags & TTYB_NORMAL) 4598c2ecf20Sopenharmony_ci f = flag_buf_ptr(head, head->read); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci n = port->client_ops->receive_buf(port, p, f, count); 4628c2ecf20Sopenharmony_ci if (n > 0) 4638c2ecf20Sopenharmony_ci memset(p, 0, n); 4648c2ecf20Sopenharmony_ci return n; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci/** 4688c2ecf20Sopenharmony_ci * flush_to_ldisc 4698c2ecf20Sopenharmony_ci * @work: tty structure passed from work queue. 4708c2ecf20Sopenharmony_ci * 4718c2ecf20Sopenharmony_ci * This routine is called out of the software interrupt to flush data 4728c2ecf20Sopenharmony_ci * from the buffer chain to the line discipline. 4738c2ecf20Sopenharmony_ci * 4748c2ecf20Sopenharmony_ci * The receive_buf method is single threaded for each tty instance. 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci * Locking: takes buffer lock to ensure single-threaded flip buffer 4778c2ecf20Sopenharmony_ci * 'consumer' 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic void flush_to_ldisc(struct work_struct *work) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct tty_port *port = container_of(work, struct tty_port, buf.work); 4838c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci mutex_lock(&buf->lock); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci while (1) { 4888c2ecf20Sopenharmony_ci struct tty_buffer *head = buf->head; 4898c2ecf20Sopenharmony_ci struct tty_buffer *next; 4908c2ecf20Sopenharmony_ci int count; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Ldisc or user is trying to gain exclusive access */ 4938c2ecf20Sopenharmony_ci if (atomic_read(&buf->priority)) 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* paired w/ release in __tty_buffer_request_room(); 4978c2ecf20Sopenharmony_ci * ensures commit value read is not stale if the head 4988c2ecf20Sopenharmony_ci * is advancing to the next buffer 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci next = smp_load_acquire(&head->next); 5018c2ecf20Sopenharmony_ci /* paired w/ release in __tty_buffer_request_room() or in 5028c2ecf20Sopenharmony_ci * tty_buffer_flush(); ensures we see the committed buffer data 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci count = smp_load_acquire(&head->commit) - head->read; 5058c2ecf20Sopenharmony_ci if (!count) { 5068c2ecf20Sopenharmony_ci if (next == NULL) 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci buf->head = next; 5098c2ecf20Sopenharmony_ci tty_buffer_free(port, head); 5108c2ecf20Sopenharmony_ci continue; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci count = receive_buf(port, head, count); 5148c2ecf20Sopenharmony_ci if (!count) 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci head->read += count; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (need_resched()) 5198c2ecf20Sopenharmony_ci cond_resched(); 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci mutex_unlock(&buf->lock); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic inline void tty_flip_buffer_commit(struct tty_buffer *tail) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees 5308c2ecf20Sopenharmony_ci * buffer data. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci smp_store_release(&tail->commit, tail->used); 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/** 5368c2ecf20Sopenharmony_ci * tty_flip_buffer_push - terminal 5378c2ecf20Sopenharmony_ci * @port: tty port to push 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * Queue a push of the terminal flip buffers to the line discipline. 5408c2ecf20Sopenharmony_ci * Can be called from IRQ/atomic context. 5418c2ecf20Sopenharmony_ci * 5428c2ecf20Sopenharmony_ci * In the event of the queue being busy for flipping the work will be 5438c2ecf20Sopenharmony_ci * held off and retried later. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_civoid tty_flip_buffer_push(struct tty_port *port) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci tty_flip_buffer_commit(buf->tail); 5518c2ecf20Sopenharmony_ci queue_work(system_unbound_wq, &buf->work); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_flip_buffer_push); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/** 5568c2ecf20Sopenharmony_ci * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and 5578c2ecf20Sopenharmony_ci * push 5588c2ecf20Sopenharmony_ci * @port: tty port 5598c2ecf20Sopenharmony_ci * @chars: characters 5608c2ecf20Sopenharmony_ci * @size: size 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * The function combines tty_insert_flip_string() and tty_flip_buffer_push() 5638c2ecf20Sopenharmony_ci * with the exception of properly holding the @port->lock. 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * To be used only internally (by pty currently). 5668c2ecf20Sopenharmony_ci * 5678c2ecf20Sopenharmony_ci * Returns: the number added. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ciint tty_insert_flip_string_and_push_buffer(struct tty_port *port, 5708c2ecf20Sopenharmony_ci const unsigned char *chars, size_t size) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 5738c2ecf20Sopenharmony_ci unsigned long flags; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 5768c2ecf20Sopenharmony_ci size = tty_insert_flip_string(port, chars, size); 5778c2ecf20Sopenharmony_ci if (size) 5788c2ecf20Sopenharmony_ci tty_flip_buffer_commit(buf->tail); 5798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci queue_work(system_unbound_wq, &buf->work); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return size; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci/** 5878c2ecf20Sopenharmony_ci * tty_buffer_init - prepare a tty buffer structure 5888c2ecf20Sopenharmony_ci * @port: tty port to initialise 5898c2ecf20Sopenharmony_ci * 5908c2ecf20Sopenharmony_ci * Set up the initial state of the buffer management for a tty device. 5918c2ecf20Sopenharmony_ci * Must be called before the other tty buffer functions are used. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_civoid tty_buffer_init(struct tty_port *port) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct tty_bufhead *buf = &port->buf; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci mutex_init(&buf->lock); 5998c2ecf20Sopenharmony_ci tty_buffer_reset(&buf->sentinel, 0); 6008c2ecf20Sopenharmony_ci buf->head = &buf->sentinel; 6018c2ecf20Sopenharmony_ci buf->tail = &buf->sentinel; 6028c2ecf20Sopenharmony_ci init_llist_head(&buf->free); 6038c2ecf20Sopenharmony_ci atomic_set(&buf->mem_used, 0); 6048c2ecf20Sopenharmony_ci atomic_set(&buf->priority, 0); 6058c2ecf20Sopenharmony_ci INIT_WORK(&buf->work, flush_to_ldisc); 6068c2ecf20Sopenharmony_ci buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/** 6108c2ecf20Sopenharmony_ci * tty_buffer_set_limit - change the tty buffer memory limit 6118c2ecf20Sopenharmony_ci * @port: tty port to change 6128c2ecf20Sopenharmony_ci * 6138c2ecf20Sopenharmony_ci * Change the tty buffer memory limit. 6148c2ecf20Sopenharmony_ci * Must be called before the other tty buffer functions are used. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ciint tty_buffer_set_limit(struct tty_port *port, int limit) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci if (limit < MIN_TTYB_SIZE) 6208c2ecf20Sopenharmony_ci return -EINVAL; 6218c2ecf20Sopenharmony_ci port->buf.mem_limit = limit; 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_buffer_set_limit); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci/* slave ptys can claim nested buffer lock when handling BRK and INTR */ 6278c2ecf20Sopenharmony_civoid tty_buffer_set_lock_subclass(struct tty_port *port) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE); 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cibool tty_buffer_restart_work(struct tty_port *port) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci return queue_work(system_unbound_wq, &port->buf.work); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cibool tty_buffer_cancel_work(struct tty_port *port) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci return cancel_work_sync(&port->buf.work); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_civoid tty_buffer_flush_work(struct tty_port *port) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci flush_work(&port->buf.work); 6458c2ecf20Sopenharmony_ci} 646