// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2001 Anton Blanchard <[email protected]>, IBM * Copyright (C) 2001 Paul Mackerras <[email protected]>, IBM * Copyright (C) 2004 Benjamin Herrenschmidt <[email protected]>, IBM Corp. * Copyright (C) 2004 IBM Corporation * * Additional Author(s): * Ryan S. Arnold <[email protected]> */ #include <linux/console.h> #include <linux/cpumask.h> #include <linux/init.h> #include <linux/kbd_kern.h> #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/major.h> #include <linux/atomic.h> #include <linux/sysrq.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/delay.h> #include <linux/freezer.h> #include <linux/slab.h> #include <linux/serial_core.h> #include <linux/uaccess.h> #include "hvc_console.h" #define HVC_MAJOR … #define HVC_MINOR … /* * Wait this long per iteration while trying to push buffered data to the * hypervisor before allowing the tty to complete a close operation. */ #define HVC_CLOSE_WAIT … /* * These sizes are most efficient for vio, because they are the * native transfer size. We could make them selectable in the * future to better deal with backends that want other buffer sizes. */ #define N_OUTBUF … #define N_INBUF … #define __ALIGNED__ … static struct tty_driver *hvc_driver; static struct task_struct *hvc_task; /* Picks up late kicks after list walk but before schedule() */ static int hvc_kicked; /* hvc_init is triggered from hvc_alloc, i.e. only when actually used */ static atomic_t hvc_needs_init __read_mostly = …; static int hvc_init(void); #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; #endif /* dynamic list of hvc_struct instances */ static LIST_HEAD(hvc_structs); /* * Protect the list of hvc_struct instances from inserts and removals during * list traversal. */ static DEFINE_MUTEX(hvc_structs_mutex); /* * This value is used to assign a tty->index value to a hvc_struct based * upon order of exposure via hvc_probe(), when we can not match it to * a console candidate registered with hvc_instantiate(). */ static int last_hvc = …; /* * Do not call this function with either the hvc_structs_mutex or the hvc_struct * lock held. If successful, this function increments the kref reference * count against the target hvc_struct so it should be released when finished. */ static struct hvc_struct *hvc_get_by_index(int index) { … } static int __hvc_flush(const struct hv_ops *ops, uint32_t vtermno, bool wait) { … } static int hvc_console_flush(const struct hv_ops *ops, uint32_t vtermno) { … } /* * Wait for the console to flush before writing more to it. This sleeps. */ static int hvc_flush(struct hvc_struct *hp) { … } /* * Initial console vtermnos for console API usage prior to full console * initialization. Any vty adapter outside this range will not have usable * console interfaces but can still be used as a tty device. This has to be * static because kmalloc will not work during early console init. */ static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = …; /* * Console APIs, NOT TTY. These APIs are available immediately when * hvc_console_setup() finds adapters. */ static void hvc_console_print(struct console *co, const char *b, unsigned count) { … } static struct tty_driver *hvc_console_device(struct console *c, int *index) { … } static int hvc_console_setup(struct console *co, char *options) { … } static struct console hvc_console = …; /* * Early console initialization. Precedes driver initialization. * * (1) we are first, and the user specified another driver * -- index will remain -1 * (2) we are first and the user specified no driver * -- index will be set to 0, then we will fail setup. * (3) we are first and the user specified our driver * -- index will be set to user specified driver, and we will fail * (4) we are after driver, and this initcall will register us * -- if the user didn't specify a driver then the console will match * * Note that for cases 2 and 3, we will match later when the io driver * calls hvc_instantiate() and call register again. */ static int __init hvc_console_init(void) { … } console_initcall(hvc_console_init); /* callback when the kboject ref count reaches zero. */ static void hvc_port_destruct(struct tty_port *port) { … } static void hvc_check_console(int index) { … } /* * hvc_instantiate() is an early console discovery method which locates * consoles * prior to the vio subsystem discovering them. Hotplugged * vty adapters do NOT get an hvc_instantiate() callback since they * appear after early console init. */ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) { … } EXPORT_SYMBOL_GPL(…); /* Wake the sleeping khvcd */ void hvc_kick(void) { … } EXPORT_SYMBOL_GPL(…); static void hvc_unthrottle(struct tty_struct *tty) { … } static int hvc_install(struct tty_driver *driver, struct tty_struct *tty) { … } /* * The TTY interface won't be used until after the vio layer has exposed the vty * adapter to the kernel. */ static int hvc_open(struct tty_struct *tty, struct file * filp) { … } static void hvc_close(struct tty_struct *tty, struct file * filp) { … } static void hvc_cleanup(struct tty_struct *tty) { … } static void hvc_hangup(struct tty_struct *tty) { … } /* * Push buffered characters whether they were just recently buffered or waiting * on a blocked hypervisor. Call this function with hp->lock held. */ static int hvc_push(struct hvc_struct *hp) { … } static ssize_t hvc_write(struct tty_struct *tty, const u8 *buf, size_t count) { … } /** * hvc_set_winsz() - Resize the hvc tty terminal window. * @work: work structure. * * The routine shall not be called within an atomic context because it * might sleep. * * Locking: hp->lock */ static void hvc_set_winsz(struct work_struct *work) { … } /* * This is actually a contract between the driver and the tty layer outlining * how much write room the driver can guarantee will be sent OR BUFFERED. This * driver MUST honor the return value. */ static unsigned int hvc_write_room(struct tty_struct *tty) { … } static unsigned int hvc_chars_in_buffer(struct tty_struct *tty) { … } /* * timeout will vary between the MIN and MAX values defined here. By default * and during console activity we will use a default MIN_TIMEOUT of 10. When * the console is idle, we increase the timeout value on each pass through * msleep until we reach the max. This may be noticeable as a brief (average * one second) delay on the console before the console responds to input when * there has been no input for some time. */ #define MIN_TIMEOUT … #define MAX_TIMEOUT … static u32 timeout = …; /* * Maximum number of bytes to get from the console driver if hvc_poll is * called from driver (and can't sleep). Any more than this and we break * and start polling with khvcd. This value was derived from an OpenBMC * console with the OPAL driver that results in about 0.25ms interrupts off * latency. */ #define HVC_ATOMIC_READ_MAX … #define HVC_POLL_READ … #define HVC_POLL_WRITE … static int __hvc_poll(struct hvc_struct *hp, bool may_sleep) { … } int hvc_poll(struct hvc_struct *hp) { … } EXPORT_SYMBOL_GPL(…); /** * __hvc_resize() - Update terminal window size information. * @hp: HVC console pointer * @ws: Terminal window size structure * * Stores the specified window size information in the hvc structure of @hp. * The function schedule the tty resize update. * * Locking: Locking free; the function MUST be called holding hp->lock */ void __hvc_resize(struct hvc_struct *hp, struct winsize ws) { … } EXPORT_SYMBOL_GPL(…); /* * This kthread is either polling or interrupt driven. This is determined by * calling hvc_poll() who determines whether a console adapter support * interrupts. */ static int khvcd(void *unused) { … } static int hvc_tiocmget(struct tty_struct *tty) { … } static int hvc_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { … } #ifdef CONFIG_CONSOLE_POLL static int hvc_poll_init(struct tty_driver *driver, int line, char *options) { … } static int hvc_poll_get_char(struct tty_driver *driver, int line) { … } static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) { … } #endif static const struct tty_operations hvc_ops = …; static const struct tty_port_operations hvc_port_ops = …; struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, const struct hv_ops *ops, int outbuf_size) { … } EXPORT_SYMBOL_GPL(…); void hvc_remove(struct hvc_struct *hp) { … } EXPORT_SYMBOL_GPL(…); /* Driver initialization: called as soon as someone uses hvc_alloc(). */ static int hvc_init(void) { … }