// SPDX-License-Identifier: GPL-2.0+
/*
* IBM eServer Hypervisor Virtual Console Server Device Driver
* Copyright (C) 2003, 2004 IBM Corp.
* Ryan S. Arnold (rsa@us.ibm.com)
*
* Author(s) : Ryan S. Arnold <rsa@us.ibm.com>
*
* This is the device driver for the IBM Hypervisor Virtual Console Server,
* "hvcs". The IBM hvcs provides a tty driver interface to allow Linux
* user space applications access to the system consoles of logically
* partitioned operating systems, e.g. Linux, running on the same partitioned
* Power5 ppc64 system. Physical hardware consoles per partition are not
* practical on this hardware so system consoles are accessed by this driver
* using inter-partition firmware interfaces to virtual terminal devices.
*
* A vty is known to the HMC as a "virtual serial server adapter". It is a
* virtual terminal device that is created by firmware upon partition creation
* to act as a partitioned OS's console device.
*
* Firmware dynamically (via hotplug) exposes vty-servers to a running ppc64
* Linux system upon their creation by the HMC or their exposure during boot.
* The non-user interactive backend of this driver is implemented as a vio
* device driver so that it can receive notification of vty-server lifetimes
* after it registers with the vio bus to handle vty-server probe and remove
* callbacks.
*
* Many vty-servers can be configured to connect to one vty, but a vty can
* only be actively connected to by a single vty-server, in any manner, at one
* time. If the HMC is currently hosting the console for a target Linux
* partition; attempts to open the tty device to the partition's console using
* the hvcs on any partition will return -EBUSY with every open attempt until
* the HMC frees the connection between its vty-server and the desired
* partition's vty device. Conversely, a vty-server may only be connected to
* a single vty at one time even though it may have several configured vty
* partner possibilities.
*
* Firmware does not provide notification of vty partner changes to this
* driver. This means that an HMC Super Admin may add or remove partner vtys
* from a vty-server's partner list but the changes will not be signaled to
* the vty-server. Firmware only notifies the driver when a vty-server is
* added or removed from the system. To compensate for this deficiency, this
* driver implements a sysfs update attribute which provides a method for
* rescanning partner information upon a user's request.
*
* Each vty-server, prior to being exposed to this driver is reference counted
* using the 2.6 Linux kernel kref construct.
*
* For direction on installation and usage of this driver please reference
* Documentation/powerpc/hvcs.rst.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/major.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <asm/hvconsole.h>
#include <asm/hvcserver.h>
#include <linux/uaccess.h>
#include <asm/vio.h>
/*
* 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00).
* Removed braces around single statements following conditionals. Removed '=
* 0' after static int declarations since these default to zero. Removed
* list_for_each_safe() and replaced with list_for_each_entry() in
* hvcs_get_by_index(). The 'safe' version is un-needed now that the driver is
* using spinlocks. Changed spin_lock_irqsave() to spin_lock() when locking
* hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int
* handler. Initialized hvcs_structs_lock and hvcs_pi_lock to
* SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init().
* Added spin_lock around list_del() in destroy_hvcs_struct() to protect the
* list traversals from a deletion. Removed '= NULL' from pointer declaration
* statements since they are initialized NULL by default. Removed wmb()
* instances from hvcs_try_write(). They probably aren't needed with locking in
* place. Added check and cleanup for hvcs_pi_buff = kmalloc() in
* hvcs_module_init(). Exposed hvcs_struct.index via a sysfs attribute so that
* the coupling between /dev/hvcs* and a vty-server can be automatically
* determined. Moved kobject_put() in hvcs_open outside of the
* spin_unlock_irqrestore().
*
* 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it
* align with how the tty layer always assigns the lowest index available. This
* change resulted in a list of ints that denotes which indexes are available.
* Device additions and removals use the new hvcs_get_index() and
* hvcs_return_index() helper functions. The list is created with
* hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list().
* Without these fixes hotplug vty-server adapter support goes crazy with this
* driver if the user removes a vty-server adapter. Moved free_irq() outside of
* the hvcs_final_close() function in order to get it out of the spinlock.
* Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping
* on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from
* arch/powerepc/include/asm/hvcserver.h
*
* 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to
* prevent possible lockup with realtime scheduling as similarly pointed out by
* akpm in hvc_console. Changed resulted in the removal of hvcs_final_close()
* to reorder cleanup operations and prevent discarding of pending data during
* an hvcs_close(). Removed spinlock protection of hvcs_struct data members in
* hvcs_write_room() and hvcs_cha
|