^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * IBM eServer Hypervisor Virtual Console Server Device Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2003, 2004 IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Ryan S. Arnold (rsa@us.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author(s) : Ryan S. Arnold <rsa@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * This is the device driver for the IBM Hypervisor Virtual Console Server,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * "hvcs". The IBM hvcs provides a tty driver interface to allow Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * user space applications access to the system consoles of logically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * partitioned operating systems, e.g. Linux, running on the same partitioned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Power5 ppc64 system. Physical hardware consoles per partition are not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * practical on this hardware so system consoles are accessed by this driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * using inter-partition firmware interfaces to virtual terminal devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * A vty is known to the HMC as a "virtual serial server adapter". It is a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * virtual terminal device that is created by firmware upon partition creation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * to act as a partitioned OS's console device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Firmware dynamically (via hotplug) exposes vty-servers to a running ppc64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * Linux system upon their creation by the HMC or their exposure during boot.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * The non-user interactive backend of this driver is implemented as a vio
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * device driver so that it can receive notification of vty-server lifetimes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * after it registers with the vio bus to handle vty-server probe and remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * callbacks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * Many vty-servers can be configured to connect to one vty, but a vty can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * only be actively connected to by a single vty-server, in any manner, at one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * time. If the HMC is currently hosting the console for a target Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * partition; attempts to open the tty device to the partition's console using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * the hvcs on any partition will return -EBUSY with every open attempt until
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * the HMC frees the connection between its vty-server and the desired
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * partition's vty device. Conversely, a vty-server may only be connected to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * a single vty at one time even though it may have several configured vty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * partner possibilities.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * Firmware does not provide notification of vty partner changes to this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * driver. This means that an HMC Super Admin may add or remove partner vtys
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * from a vty-server's partner list but the changes will not be signaled to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * the vty-server. Firmware only notifies the driver when a vty-server is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * added or removed from the system. To compensate for this deficiency, this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * driver implements a sysfs update attribute which provides a method for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * rescanning partner information upon a user's request.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Each vty-server, prior to being exposed to this driver is reference counted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * using the 2.6 Linux kernel kref construct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * For direction on installation and usage of this driver please reference
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * Documentation/powerpc/hvcs.rst.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #include <linux/kref.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #include <linux/kthread.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #include <linux/major.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #include <linux/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #include <linux/tty_flip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #include <asm/hvconsole.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #include <asm/hvcserver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #include <asm/vio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * Removed braces around single statements following conditionals. Removed '=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * 0' after static int declarations since these default to zero. Removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * list_for_each_safe() and replaced with list_for_each_entry() in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * hvcs_get_by_index(). The 'safe' version is un-needed now that the driver is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * using spinlocks. Changed spin_lock_irqsave() to spin_lock() when locking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * handler. Initialized hvcs_structs_lock and hvcs_pi_lock to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * Added spin_lock around list_del() in destroy_hvcs_struct() to protect the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * list traversals from a deletion. Removed '= NULL' from pointer declaration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * statements since they are initialized NULL by default. Removed wmb()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * instances from hvcs_try_write(). They probably aren't needed with locking in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * place. Added check and cleanup for hvcs_pi_buff = kmalloc() in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * hvcs_module_init(). Exposed hvcs_struct.index via a sysfs attribute so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * the coupling between /dev/hvcs* and a vty-server can be automatically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * determined. Moved kobject_put() in hvcs_open outside of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * spin_unlock_irqrestore().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * align with how the tty layer always assigns the lowest index available. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * change resulted in a list of ints that denotes which indexes are available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * Device additions and removals use the new hvcs_get_index() and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * hvcs_return_index() helper functions. The list is created with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Without these fixes hotplug vty-server adapter support goes crazy with this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * driver if the user removes a vty-server adapter. Moved free_irq() outside of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * the hvcs_final_close() function in order to get it out of the spinlock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * arch/powerepc/include/asm/hvcserver.h
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * prevent possible lockup with realtime scheduling as similarly pointed out by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * akpm in hvc_console. Changed resulted in the removal of hvcs_final_close()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * to reorder cleanup operations and prevent discarding of pending data during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * an hvcs_close(). Removed spinlock protection of hvcs_struct data members in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * hvcs_write_room() and hvcs_chars_in_buffer() because they aren't needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define HVCS_DRIVER_VERSION "1.3.3"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) MODULE_AUTHOR("Ryan S. Arnold <rsa@us.ibm.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) MODULE_VERSION(HVCS_DRIVER_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * Wait this long per iteration while trying to push buffered data to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * hypervisor before allowing the tty to complete a close operation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define HVCS_CLOSE_WAIT (HZ/100) /* 1/10 of a second */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Since the Linux TTY code does not currently (2-04-2004) support dynamic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * addition of tty derived devices and we shouldn't allocate thousands of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * tty_device pointers when the number of vty-server & vty partner connections
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * will most often be much lower than this, we'll arbitrarily allocate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * HVCS_DEFAULT_SERVER_ADAPTERS tty_structs and cdev's by default when we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * register the tty_driver. This can be overridden using an insmod parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define HVCS_DEFAULT_SERVER_ADAPTERS 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * The user can't insmod with more than HVCS_MAX_SERVER_ADAPTERS hvcs device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * nodes as a sanity check. Theoretically there can be over 1 Billion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * vty-server & vty partner connections.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define HVCS_MAX_SERVER_ADAPTERS 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * We let Linux assign us a major number and we start the minors at zero. There
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * is no intuitive mapping between minor number and the target vty-server
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * adapter except that each new vty-server adapter is always assigned to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * smallest minor number available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define HVCS_MINOR_START 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * The hcall interface involves putting 8 chars into each of two registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * We load up those 2 registers (in arch/powerpc/platforms/pseries/hvconsole.c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * by casting char[16] to long[2]. It would work without __ALIGNED__, but a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * little (tiny) bit slower because an unaligned load is slower than aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * load.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define __ALIGNED__ __attribute__((__aligned__(8)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * How much data can firmware send with each hvc_put_chars()? Maybe this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * should be moved into an architecture specific area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define HVCS_BUFF_LEN 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * This is the maximum amount of data we'll let the user send us (hvcs_write) at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * once in a chunk as a sanity check.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) #define HVCS_MAX_FROM_USER 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * Be careful when adding flags to this line discipline. Don't add anything
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * that will cause echoing or we'll go into recursive loop echoing chars back
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * and forth with the console drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static const struct ktermios hvcs_tty_termios = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .c_iflag = IGNBRK | IGNPAR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .c_oflag = OPOST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .c_cflag = B38400 | CS8 | CREAD | HUPCL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) .c_cc = INIT_C_CC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .c_ispeed = 38400,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .c_ospeed = 38400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * This value is used to take the place of a command line parameter when the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * module is inserted. It starts as -1 and stays as such if the user doesn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * specify a module insmod parameter. If they DO specify one then it is set to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * the value of the integer passed in.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) static int hvcs_parm_num_devs = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) module_param(hvcs_parm_num_devs, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static const char hvcs_driver_name[] = "hvcs";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static const char hvcs_device_node[] = "hvcs";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /* Status of partner info rescan triggered via sysfs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static int hvcs_rescan_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static struct tty_driver *hvcs_tty_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * In order to be somewhat sane this driver always associates the hvcs_struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * index element with the numerically equal tty->index. This means that a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * hotplugged vty-server adapter will always map to the lowest index valued
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * device node. If vty-servers were hotplug removed from the system and then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * new ones added the new vty-server may have the largest slot number of all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * the vty-server adapters in the partition but it may have the lowest dev node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * index of all the adapters due to the hole left by the hotplug removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * adapter. There are a set of functions provided to get the lowest index for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * a new device as well as return the index to the list. This list is allocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * with a number of elements equal to the number of device nodes requested when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * the module was inserted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static int *hvcs_index_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * How large is the list? This is kept for traversal since the list is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * dynamically created.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static int hvcs_index_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * Used by the khvcsd to pick up I/O operations when the kernel_thread is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * already awake but potentially shifted to TASK_INTERRUPTIBLE state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static int hvcs_kicked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * Use by the kthread construct for task operations like waking the sleeping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * thread and stopping the kthread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static struct task_struct *hvcs_task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * We allocate this for the use of all of the hvcs_structs when they fetch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * partner info.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static unsigned long *hvcs_pi_buff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /* Only allow one hvcs_struct to use the hvcs_pi_buff at a time. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static DEFINE_SPINLOCK(hvcs_pi_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* One vty-server per hvcs_struct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct hvcs_struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct tty_port port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * This index identifies this hvcs device as the complement to a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * specific tty index.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * Used to tell the driver kernel_thread what operations need to take
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * place upon this hvcs_struct instance.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) int todo_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * This buffer is required so that when hvcs_write_room() reports that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * it can send HVCS_BUFF_LEN characters that it will buffer the full
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * HVCS_BUFF_LEN characters if need be. This is essential for opost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * writes since they do not do high level buffering and expect to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) * able to send what the driver commits to sending buffering
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * [e.g. tab to space conversions in n_tty.c opost()].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) char buffer[HVCS_BUFF_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) int chars_in_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * Any variable below is valid before a tty is connected and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * stays valid after the tty is disconnected. These shouldn't be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * whacked until the kobject refcount reaches zero though some entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * may be changed via sysfs initiatives.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) int connected; /* is the vty-server currently connected to a vty? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) uint32_t p_unit_address; /* partner unit address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) uint32_t p_partition_ID; /* partner partition ID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct list_head next; /* list management */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct vio_dev *vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static LIST_HEAD(hvcs_structs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static DEFINE_SPINLOCK(hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) static DEFINE_MUTEX(hvcs_init_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static void hvcs_unthrottle(struct tty_struct *tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static void hvcs_throttle(struct tty_struct *tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) static int hvcs_write(struct tty_struct *tty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) const unsigned char *buf, int count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static int hvcs_write_room(struct tty_struct *tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static int hvcs_chars_in_buffer(struct tty_struct *tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) static int hvcs_has_pi(struct hvcs_struct *hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) static void hvcs_set_pi(struct hvcs_partner_info *pi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct hvcs_struct *hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static int hvcs_get_pi(struct hvcs_struct *hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) static int hvcs_rescan_devices_list(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static int hvcs_partner_connect(struct hvcs_struct *hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static void hvcs_partner_free(struct hvcs_struct *hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static int hvcs_enable_device(struct hvcs_struct *hvcsd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) uint32_t unit_address, unsigned int irq, struct vio_dev *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static int hvcs_open(struct tty_struct *tty, struct file *filp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) static void hvcs_close(struct tty_struct *tty, struct file *filp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) static void hvcs_hangup(struct tty_struct * tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static int hvcs_probe(struct vio_dev *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) const struct vio_device_id *id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static int hvcs_remove(struct vio_dev *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static int __init hvcs_module_init(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static void __exit hvcs_module_exit(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static int hvcs_initialize(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) #define HVCS_SCHED_READ 0x00000001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) #define HVCS_QUICK_READ 0x00000002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) #define HVCS_TRY_WRITE 0x00000004
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) #define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return dev_get_drvdata(&viod->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /* The sysfs interface for the driver and devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct vio_dev *viod = to_vio_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) struct hvcs_struct *hvcsd = from_vio_dev(viod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) retval = sprintf(buf, "%X\n", hvcsd->p_unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) struct vio_dev *viod = to_vio_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct hvcs_struct *hvcsd = from_vio_dev(viod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * Don't need this feature at the present time because firmware doesn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * yet support multiple partners.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) struct vio_dev *viod = to_vio_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) struct hvcs_struct *hvcsd = from_vio_dev(viod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static DEVICE_ATTR(current_vty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) struct vio_dev *viod = to_vio_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct hvcs_struct *hvcsd = from_vio_dev(viod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* writing a '0' to this sysfs entry will result in the disconnect. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (simple_strtol(buf, NULL, 0) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (hvcsd->port.count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) printk(KERN_INFO "HVCS: vterm state unchanged. "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) "The hvcs device node is still in use.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (hvcsd->connected == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) printk(KERN_INFO "HVCS: vterm state unchanged. The"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) " vty-server is not connected to a vty.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) hvcs_partner_free(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) printk(KERN_INFO "HVCS: Closed vty-server@%X and"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) " partner vty@%X:%d connection.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) hvcsd->vdev->unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) hvcsd->p_unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) (uint32_t)hvcsd->p_partition_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) struct vio_dev *viod = to_vio_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) struct hvcs_struct *hvcsd = from_vio_dev(viod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) retval = sprintf(buf, "%d\n", hvcsd->connected);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) hvcs_vterm_state_show, hvcs_vterm_state_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct vio_dev *viod = to_vio_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) struct hvcs_struct *hvcsd = from_vio_dev(viod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) retval = sprintf(buf, "%d\n", hvcsd->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) static struct attribute *hvcs_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) &dev_attr_partner_vtys.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) &dev_attr_partner_clcs.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) &dev_attr_current_vty.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) &dev_attr_vterm_state.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) &dev_attr_index.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) static struct attribute_group hvcs_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) .attrs = hvcs_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) static ssize_t rescan_show(struct device_driver *ddp, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) /* A 1 means it is updating, a 0 means it is done updating */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static ssize_t rescan_store(struct device_driver *ddp, const char * buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if ((simple_strtol(buf, NULL, 0) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) && (hvcs_rescan_status != 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) hvcs_rescan_status = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) printk(KERN_INFO "HVCS: rescanning partner info for all"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) " vty-servers.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) hvcs_rescan_devices_list();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) hvcs_rescan_status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) static DRIVER_ATTR_RW(rescan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static void hvcs_kick(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) hvcs_kicked = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) wake_up_process(hvcs_task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static void hvcs_unthrottle(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) hvcsd->todo_mask |= HVCS_SCHED_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) hvcs_kick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static void hvcs_throttle(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) vio_disable_interrupts(hvcsd->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * If the device is being removed we don't have to worry about this interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * handler taking any further interrupts because they are disabled which means
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * the hvcs_struct will always be valid in this handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) struct hvcs_struct *hvcsd = dev_instance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) spin_lock(&hvcsd->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) vio_disable_interrupts(hvcsd->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) hvcsd->todo_mask |= HVCS_SCHED_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) spin_unlock(&hvcsd->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) hvcs_kick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /* This function must be called with the hvcsd->lock held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) static void hvcs_try_write(struct hvcs_struct *hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) uint32_t unit_address = hvcsd->vdev->unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) struct tty_struct *tty = hvcsd->port.tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) int sent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /* won't send partial writes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) sent = hvc_put_chars(unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) &hvcsd->buffer[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) hvcsd->chars_in_buffer );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (sent > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) hvcsd->chars_in_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) /* wmb(); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) hvcsd->todo_mask &= ~(HVCS_TRY_WRITE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) /* wmb(); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * We are still obligated to deliver the data to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * hypervisor even if the tty has been closed because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * we committed to delivering it. But don't try to wake
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * a non-existent tty.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (tty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) tty_wakeup(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) static int hvcs_io(struct hvcs_struct *hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) uint32_t unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) char buf[HVCS_BUFF_LEN] __ALIGNED__;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) int got = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) unit_address = hvcsd->vdev->unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) tty = hvcsd->port.tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) hvcs_try_write(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (!tty || tty_throttled(tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) hvcsd->todo_mask &= ~(HVCS_READ_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) goto bail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) goto bail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /* remove the read masks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) hvcsd->todo_mask &= ~(HVCS_READ_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (tty_buffer_request_room(&hvcsd->port, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) got = hvc_get_chars(unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) &buf[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) HVCS_BUFF_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) tty_insert_flip_string(&hvcsd->port, buf, got);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /* Give the TTY time to process the data we just sent. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (got)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) hvcsd->todo_mask |= HVCS_QUICK_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) /* This is synch because tty->low_latency == 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if(got)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) tty_flip_buffer_push(&hvcsd->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (!got) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) /* Do this _after_ the flip_buffer_push */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) vio_enable_interrupts(hvcsd->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) return hvcsd->todo_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) bail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return hvcsd->todo_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) static int khvcsd(void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct hvcs_struct *hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) int hvcs_todo_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) __set_current_state(TASK_RUNNING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) hvcs_todo_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) hvcs_kicked = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) spin_lock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) list_for_each_entry(hvcsd, &hvcs_structs, next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) hvcs_todo_mask |= hvcs_io(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) spin_unlock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * If any of the hvcs adapters want to try a write or quick read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * don't schedule(), yield a smidgen then execute the hvcs_io
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) * thread again for those that want the write.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) if (hvcs_todo_mask & (HVCS_TRY_WRITE | HVCS_QUICK_READ)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) yield();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (!hvcs_kicked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) __set_current_state(TASK_RUNNING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) } while (!kthread_should_stop());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static const struct vio_device_id hvcs_driver_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) {"serial-server", "hvterm2"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) { "", "" }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) MODULE_DEVICE_TABLE(vio, hvcs_driver_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) static void hvcs_return_index(int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) /* Paranoia check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (!hvcs_index_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (index < 0 || index >= hvcs_index_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (hvcs_index_list[index] == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) hvcs_index_list[index] = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) static void hvcs_destruct_port(struct tty_port *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) struct vio_dev *vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) spin_lock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) /* the list_del poisons the pointers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) list_del(&(hvcsd->next));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) if (hvcsd->connected == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) hvcs_partner_free(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) printk(KERN_INFO "HVCS: Closed vty-server@%X and"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) " partner vty@%X:%d connection.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) hvcsd->vdev->unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) hvcsd->p_unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) (uint32_t)hvcsd->p_partition_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) hvcsd->vdev->unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) vdev = hvcsd->vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) hvcsd->vdev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) hvcsd->p_unit_address = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) hvcsd->p_partition_ID = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) hvcs_return_index(hvcsd->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) spin_unlock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) kfree(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) static const struct tty_port_operations hvcs_port_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) .destruct = hvcs_destruct_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) static int hvcs_get_index(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) /* Paranoia check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (!hvcs_index_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) /* Find the numerically lowest first free index. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) for(i = 0; i < hvcs_index_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (hvcs_index_list[i] == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) hvcs_index_list[i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) static int hvcs_probe(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) struct vio_dev *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) const struct vio_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) struct hvcs_struct *hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) int index, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (!dev || !id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) /* Make sure we are properly initialized */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) rc = hvcs_initialize();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) pr_err("HVCS: Failed to initialize core driver.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) /* early to avoid cleanup on failure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) index = hvcs_get_index();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (index < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (!hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) tty_port_init(&hvcsd->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) hvcsd->port.ops = &hvcs_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) spin_lock_init(&hvcsd->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) hvcsd->vdev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) dev_set_drvdata(&dev->dev, hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) hvcsd->index = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) /* hvcsd->index = ++hvcs_struct_count; */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) hvcsd->chars_in_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) hvcsd->todo_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) hvcsd->connected = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) * This will populate the hvcs_struct's partner info fields for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) * first time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (hvcs_get_pi(hvcsd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) printk(KERN_ERR "HVCS: Failed to fetch partner"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) " info for vty-server@%X on device probe.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) hvcsd->vdev->unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) * If a user app opens a tty that corresponds to this vty-server before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) * the hvcs_struct has been added to the devices list then the user app
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) * will get -ENODEV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) spin_lock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) list_add_tail(&(hvcsd->next), &hvcs_structs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) spin_unlock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) hvcsd->vdev->unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) * DON'T enable interrupts here because there is no user to receive the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) * data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) static int hvcs_remove(struct vio_dev *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (!hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) /* By this time the vty-server won't be getting any more interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) tty = hvcsd->port.tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) * Let the last holder of this object cause it to be removed, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) * would probably be tty_hangup below.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) tty_port_put(&hvcsd->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) * The hangup is a scheduled function which will auto chain call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) * hvcs_hangup. The tty should always be valid at this time unless a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) * simultaneous tty close already cleaned up the hvcs_struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) if (tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) tty_hangup(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) printk(KERN_INFO "HVCS: vty-server@%X removed from the"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) " vio bus.\n", dev->unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) static struct vio_driver hvcs_vio_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) .id_table = hvcs_driver_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) .probe = hvcs_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) .remove = hvcs_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) .name = hvcs_driver_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) /* Only called from hvcs_get_pi please */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) hvcsd->p_unit_address = pi->unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) hvcsd->p_partition_ID = pi->partition_ID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) /* copy the null-term char too */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) strlcpy(hvcsd->p_location_code, pi->location_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) sizeof(hvcsd->p_location_code));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) * Traverse the list and add the partner info that is found to the hvcs_struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) * struct entry. NOTE: At this time I know that partner info will return a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) * single entry but in the future there may be multiple partner info entries per
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) * vty-server and you'll want to zero out that list and reset it. If for some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) * reason you have an old version of this driver but there IS more than one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * partner info then hvcsd->p_* will hold the last partner info data from the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) * firmware query. A good way to update this code would be to replace the three
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) * partner info fields in hvcs_struct with a list of hvcs_partner_info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) * instances.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) * This function must be called with the hvcsd->lock held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) static int hvcs_get_pi(struct hvcs_struct *hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) struct hvcs_partner_info *pi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) uint32_t unit_address = hvcsd->vdev->unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) struct list_head head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) spin_lock(&hvcs_pi_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) if (!hvcs_pi_buff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) spin_unlock(&hvcs_pi_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) spin_unlock(&hvcs_pi_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) printk(KERN_ERR "HVCS: Failed to fetch partner"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) " info for vty-server@%x.\n", unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) /* nixes the values if the partner vty went away */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) hvcsd->p_unit_address = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) hvcsd->p_partition_ID = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) list_for_each_entry(pi, &head, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) hvcs_set_pi(pi, hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) hvcs_free_partner_info(&head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) * This function is executed by the driver "rescan" sysfs entry. It shouldn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) * be executed elsewhere, in order to prevent deadlock issues.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) static int hvcs_rescan_devices_list(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) struct hvcs_struct *hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) spin_lock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) list_for_each_entry(hvcsd, &hvcs_structs, next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) hvcs_get_pi(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) spin_unlock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) * Farm this off into its own function because it could be more complex once
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) * multiple partners support is added. This function should be called with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) * the hvcsd->lock held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) static int hvcs_has_pi(struct hvcs_struct *hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) if ((!hvcsd->p_unit_address) || (!hvcsd->p_partition_ID))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) * NOTE: It is possible that the super admin removed a partner vty and then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) * added a different vty as the new partner.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) * This function must be called with the hvcsd->lock held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) static int hvcs_partner_connect(struct hvcs_struct *hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) unsigned int unit_address = hvcsd->vdev->unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) * If there wasn't any pi when the device was added it doesn't meant
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) * there isn't any now. This driver isn't notified when a new partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) * vty is added to a vty-server so we discover changes on our own.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) * Please see comments in hvcs_register_connection() for justification
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) * of this bizarre code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) retval = hvcs_register_connection(unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) hvcsd->p_partition_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) hvcsd->p_unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) if (!retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) hvcsd->connected = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) } else if (retval != -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) * As per the spec re-get the pi and try again if -EINVAL after the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) * first connection attempt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) if (hvcs_get_pi(hvcsd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) if (!hvcs_has_pi(hvcsd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) retval = hvcs_register_connection(unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) hvcsd->p_partition_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) hvcsd->p_unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (retval != -EINVAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) hvcsd->connected = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) * EBUSY is the most likely scenario though the vty could have been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * removed or there really could be an hcall error due to the parameter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * data but thanks to ambiguous firmware return codes we can't really
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) * tell.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) printk(KERN_INFO "HVCS: vty-server or partner"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) " vty is busy. Try again later.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) /* This function must be called with the hvcsd->lock held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) static void hvcs_partner_free(struct hvcs_struct *hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) retval = hvcs_free_connection(hvcsd->vdev->unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) } while (retval == -EBUSY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) hvcsd->connected = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) /* This helper function must be called WITHOUT the hvcsd->lock held */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) unsigned int irq, struct vio_dev *vdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) * It is possible that the vty-server was removed between the time that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) * the conn was registered and now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) rc = request_irq(irq, &hvcs_handle_interrupt, 0, "ibmhvcs", hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) * It is possible the vty-server was removed after the irq was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) * requested but before we have time to enable interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) if (vio_enable_interrupts(vdev) == H_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) printk(KERN_ERR "HVCS: int enable failed for"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) " vty-server@%X.\n", unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) free_irq(irq, hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) printk(KERN_ERR "HVCS: irq req failed for"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) " vty-server@%X.\n", unit_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) hvcs_partner_free(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) * This always increments the kref ref count if the call is successful.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) * Please remember to dec when you are done with the instance.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) * calling this function or you will get deadlock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) static struct hvcs_struct *hvcs_get_by_index(int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) struct hvcs_struct *hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) spin_lock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) list_for_each_entry(hvcsd, &hvcs_structs, next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) if (hvcsd->index == index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) tty_port_get(&hvcsd->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) spin_unlock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) return hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) spin_unlock(&hvcs_structs_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) struct hvcs_struct *hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) struct vio_dev *vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) unsigned long unit_address, flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) unsigned int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) * Is there a vty-server that shares the same index?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) * This function increments the kref index.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) hvcsd = hvcs_get_by_index(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) if (!hvcsd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) printk(KERN_WARNING "HVCS: open failed, no device associated"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) " with tty->index %d.\n", tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) if (hvcsd->connected == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) retval = hvcs_partner_connect(hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) printk(KERN_WARNING "HVCS: partner connect failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) goto err_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) hvcsd->port.count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) hvcsd->port.tty = tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) tty->driver_data = hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) * Save these in the spinlock for the enable operations that need them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) * outside of the spinlock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) irq = hvcsd->vdev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) vdev = hvcsd->vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) unit_address = hvcsd->vdev->unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) hvcsd->todo_mask |= HVCS_SCHED_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) * This must be done outside of the spinlock because it requests irqs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) * and will grab the spinlock and free the connection if it fails.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) printk(KERN_WARNING "HVCS: enable device failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) goto err_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) retval = tty_port_install(&hvcsd->port, driver, tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) goto err_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) err_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) vio_disable_interrupts(hvcsd->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) free_irq(irq, hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) err_put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) tty_port_put(&hvcsd->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) * This is invoked via the tty_open interface when a user app connects to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) * /dev node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) static int hvcs_open(struct tty_struct *tty, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) hvcsd->port.count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) hvcsd->todo_mask |= HVCS_SCHED_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) hvcs_kick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) hvcsd->vdev->unit_address );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) static void hvcs_close(struct tty_struct *tty, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) struct hvcs_struct *hvcsd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) * Is someone trying to close the file associated with this device after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) * we have hung up? If so tty->driver_data wouldn't be valid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) if (tty_hung_up_p(filp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) * No driver_data means that this close was probably issued after a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) * failed hvcs_open by the tty layer's release_dev() api and we can just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) * exit cleanly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) if (!tty->driver_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) if (--hvcsd->port.count == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) vio_disable_interrupts(hvcsd->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) * NULL this early so that the kernel_thread doesn't try to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) * execute any operations on the TTY even though it is obligated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) * to deliver any pending I/O to the hypervisor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) hvcsd->port.tty = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) irq = hvcsd->vdev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) free_irq(irq, hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) } else if (hvcsd->port.count < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) printk(KERN_ERR "HVCS: vty-server@%X open_count: %d is mismanaged.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) hvcsd->vdev->unit_address, hvcsd->port.count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) static void hvcs_cleanup(struct tty_struct * tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) * This line is important because it tells hvcs_open that this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) * device needs to be re-configured the next time hvcs_open is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) * called.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) tty->driver_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) tty_port_put(&hvcsd->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) static void hvcs_hangup(struct tty_struct * tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) int temp_open_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) /* Preserve this so that we know how many kref refs to put */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) temp_open_count = hvcsd->port.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) * Don't kref put inside the spinlock because the destruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) * callback may use the spinlock and it may get called before the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) * spinlock has been released.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) vio_disable_interrupts(hvcsd->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) hvcsd->todo_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) /* I don't think the tty needs the hvcs_struct pointer after a hangup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) tty->driver_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) hvcsd->port.tty = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) hvcsd->port.count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) /* This will drop any buffered data on the floor which is OK in a hangup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) * scenario. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) hvcsd->chars_in_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) irq = hvcsd->vdev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) free_irq(irq, hvcsd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) * We need to kref_put() for every open_count we have since the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) * tty_hangup() function doesn't invoke a close per open connection on a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) * non-console device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) while(temp_open_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) --temp_open_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) * The final put will trigger destruction of the hvcs_struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) * NOTE: If this hangup was signaled from user space then the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) * final put will never happen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) tty_port_put(&hvcsd->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) * NOTE: This is almost always from_user since user level apps interact with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) * /dev nodes. I'm trusting that if hvcs_write gets called and interrupted by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) * hvcs_remove (which removes the target device and executes tty_hangup()) that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) * tty_hangup will allow hvcs_write time to complete execution before it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) * terminates our device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) static int hvcs_write(struct tty_struct *tty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) const unsigned char *buf, int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) unsigned int unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) const unsigned char *charbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) int total_sent = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) int tosend = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) * If they don't check the return code off of their open they may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) * attempt this even if there is no connected device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) if (!hvcsd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) /* Reasonable size to prevent user level flooding */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) if (count > HVCS_MAX_FROM_USER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) printk(KERN_WARNING "HVCS write: count being truncated to"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) " HVCS_MAX_FROM_USER.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) count = HVCS_MAX_FROM_USER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) charbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) spin_lock_irqsave(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) * Somehow an open succeeded but the device was removed or the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) * connection terminated between the vty-server and partner vty during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) * the middle of a write operation? This is a crummy place to do this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) * but we want to keep it all in the spinlock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) if (hvcsd->port.count <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) unit_address = hvcsd->vdev->unit_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) tosend = min(count, (HVCS_BUFF_LEN - hvcsd->chars_in_buffer));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) * No more space, this probably means that the last call to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) * hvcs_write() didn't succeed and the buffer was filled up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) if (!tosend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) &charbuf[total_sent],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) tosend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) hvcsd->chars_in_buffer += tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) * If this is true then we don't want to try writing to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) * hypervisor because that is the kernel_threads job now. We'll
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) * just add to the buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) if (!(hvcsd->todo_mask & HVCS_TRY_WRITE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) /* won't send partial writes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) result = hvc_put_chars(unit_address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) &hvcsd->buffer[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) hvcsd->chars_in_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) * Since we know we have enough room in hvcsd->buffer for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) * tosend we record that it was sent regardless of whether the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) * hypervisor actually took it because we have it buffered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) total_sent+=tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) count-=tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) if (result == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) hvcsd->todo_mask |= HVCS_TRY_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) hvcs_kick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) hvcsd->chars_in_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) * Test after the chars_in_buffer reset otherwise this could
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) * deadlock our writes if hvc_put_chars fails.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) spin_unlock_irqrestore(&hvcsd->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) if (result == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) return total_sent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) * This is really asking how much can we guarantee that we can send or that we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) * absolutely WILL BUFFER if we can't send it. This driver MUST honor the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) * return value, hence the reason for hvcs_struct buffering.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) static int hvcs_write_room(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) if (!hvcsd || hvcsd->port.count <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) static int hvcs_chars_in_buffer(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) struct hvcs_struct *hvcsd = tty->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) return hvcsd->chars_in_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) static const struct tty_operations hvcs_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) .install = hvcs_install,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) .open = hvcs_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) .close = hvcs_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) .cleanup = hvcs_cleanup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) .hangup = hvcs_hangup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) .write = hvcs_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) .write_room = hvcs_write_room,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) .chars_in_buffer = hvcs_chars_in_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) .unthrottle = hvcs_unthrottle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) .throttle = hvcs_throttle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) static int hvcs_alloc_index_list(int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) hvcs_index_list = kmalloc_array(n, sizeof(hvcs_index_count),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) if (!hvcs_index_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) hvcs_index_count = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) for (i = 0; i < hvcs_index_count; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) hvcs_index_list[i] = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) static void hvcs_free_index_list(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) /* Paranoia check to be thorough. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) kfree(hvcs_index_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) hvcs_index_list = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) hvcs_index_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) static int hvcs_initialize(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) int rc, num_ttys_to_alloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) mutex_lock(&hvcs_init_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) if (hvcs_task) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) mutex_unlock(&hvcs_init_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) /* Has the user specified an overload with an insmod param? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) if (hvcs_parm_num_devs <= 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) num_ttys_to_alloc = hvcs_parm_num_devs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) if (!hvcs_tty_driver) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) mutex_unlock(&hvcs_init_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) if (hvcs_alloc_index_list(num_ttys_to_alloc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) goto index_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) hvcs_tty_driver->driver_name = hvcs_driver_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) hvcs_tty_driver->name = hvcs_device_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) * We'll let the system assign us a major number, indicated by leaving
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) * it blank.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) hvcs_tty_driver->minor_start = HVCS_MINOR_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) * We role our own so that we DONT ECHO. We can't echo because the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) * device we are connecting to already echoes by default and this would
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) * throw us into a horrible recursive echo-echo-echo loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) hvcs_tty_driver->init_termios = hvcs_tty_termios;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) tty_set_operations(hvcs_tty_driver, &hvcs_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) * The following call will result in sysfs entries that denote the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) * dynamically assigned major and minor numbers for our devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) if (tty_register_driver(hvcs_tty_driver)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) printk(KERN_ERR "HVCS: registration as a tty driver failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) goto register_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) if (!hvcs_pi_buff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) goto buff_alloc_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) if (IS_ERR(hvcs_task)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) printk(KERN_ERR "HVCS: khvcsd creation failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) goto kthread_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) mutex_unlock(&hvcs_init_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) kthread_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) free_page((unsigned long)hvcs_pi_buff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) buff_alloc_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) tty_unregister_driver(hvcs_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) register_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) hvcs_free_index_list();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) index_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) put_tty_driver(hvcs_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) hvcs_tty_driver = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) mutex_unlock(&hvcs_init_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) static int __init hvcs_module_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) int rc = vio_register_driver(&hvcs_vio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) printk(KERN_ERR "HVCS: can't register vio driver\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) pr_info("HVCS: Driver registered.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) /* This needs to be done AFTER the vio_register_driver() call or else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) * the kobjects won't be initialized properly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) pr_warn("HVCS: Failed to create rescan file (err %d)\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) static void __exit hvcs_module_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) * This driver receives hvcs_remove callbacks for each device upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) * module removal.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) vio_unregister_driver(&hvcs_vio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) if (!hvcs_task)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) * This synchronous operation will wake the khvcsd kthread if it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) * asleep and will return when khvcsd has terminated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) kthread_stop(hvcs_task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) spin_lock(&hvcs_pi_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) free_page((unsigned long)hvcs_pi_buff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) hvcs_pi_buff = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) spin_unlock(&hvcs_pi_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) tty_unregister_driver(hvcs_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) hvcs_free_index_list();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) put_tty_driver(hvcs_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) printk(KERN_INFO "HVCS: driver module removed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) module_init(hvcs_module_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) module_exit(hvcs_module_exit);