^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) /* vcc.c: sun4v virtual channel concentrator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2017 Oracle. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/tty_flip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/vio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/ldc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define DRV_MODULE_NAME "vcc"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define DRV_MODULE_VERSION "1.1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define DRV_MODULE_RELDATE "July 1, 2017"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static char version[] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) MODULE_DESCRIPTION("Sun LDOM virtual console concentrator driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODULE_VERSION(DRV_MODULE_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct vcc_port {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct vio_driver_state vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) char *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct tty_struct *tty; /* only populated while dev is open */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned long index; /* index into the vcc_table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u64 refcnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) bool excl_locked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) bool removed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /* This buffer is required to support the tty write_room interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * and guarantee that any characters that the driver accepts will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * be eventually sent, either immediately or later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int chars_in_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct vio_vcc buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct timer_list rx_timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct timer_list tx_timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* Microseconds that thread will delay waiting for a vcc port ref */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define VCC_REF_DELAY 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define VCC_MAX_PORTS 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define VCC_MINOR_START 0 /* must be zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define VCC_BUFF_LEN VIO_VCC_MTU_SIZE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define VCC_CTL_BREAK -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define VCC_CTL_HUP -2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static const char vcc_driver_name[] = "vcc";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static const char vcc_device_node[] = "vcc";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static struct tty_driver *vcc_tty_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static struct vcc_port *vcc_table[VCC_MAX_PORTS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static DEFINE_SPINLOCK(vcc_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int vcc_dbg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int vcc_dbg_ldc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int vcc_dbg_vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) module_param(vcc_dbg, uint, 0664);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) module_param(vcc_dbg_ldc, uint, 0664);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) module_param(vcc_dbg_vio, uint, 0664);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define VCC_DBG_DRV 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define VCC_DBG_LDC 0x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define VCC_DBG_PKT 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define vccdbg(f, a...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (vcc_dbg & VCC_DBG_DRV) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) pr_info(f, ## a); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) } while (0) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define vccdbgl(l) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (vcc_dbg & VCC_DBG_LDC) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ldc_print(l); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) } while (0) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define vccdbgp(pkt) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (vcc_dbg & VCC_DBG_PKT) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int i; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) for (i = 0; i < pkt.tag.stype; i++) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) pr_info("[%c]", pkt.data[i]); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) } while (0) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* Note: Be careful when adding flags to this line discipline. Don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * add anything that will cause echoing or we'll go into recursive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * loop echoing chars back and forth with the console drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static const struct ktermios vcc_tty_termios = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .c_iflag = IGNBRK | IGNPAR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .c_oflag = OPOST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .c_cflag = B38400 | CS8 | CREAD | HUPCL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .c_cc = INIT_C_CC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .c_ispeed = 38400,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .c_ospeed = 38400
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * vcc_table_add() - Add VCC port to the VCC table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * @port: pointer to the VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * Return: index of the port in the VCC table on success,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * -1 on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int vcc_table_add(struct vcc_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) spin_lock_irqsave(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) for (i = VCC_MINOR_START; i < VCC_MAX_PORTS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (!vcc_table[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) vcc_table[i] = port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) spin_unlock_irqrestore(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (i < VCC_MAX_PORTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * vcc_table_remove() - Removes a VCC port from the VCC table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * @index: Index into the VCC table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static void vcc_table_remove(unsigned long index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (WARN_ON(index >= VCC_MAX_PORTS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) spin_lock_irqsave(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) vcc_table[index] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) spin_unlock_irqrestore(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * vcc_get() - Gets a reference to VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * @index: Index into the VCC table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * @excl: Indicates if an exclusive access is requested
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * Return: reference to the VCC port, if found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * NULL, if port not found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static struct vcc_port *vcc_get(unsigned long index, bool excl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) try_again:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) spin_lock_irqsave(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) port = vcc_table[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (!port) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) spin_unlock_irqrestore(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (!excl) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (port->excl_locked) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) spin_unlock_irqrestore(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) udelay(VCC_REF_DELAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) goto try_again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) port->refcnt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) spin_unlock_irqrestore(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (port->refcnt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) spin_unlock_irqrestore(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* Threads wanting exclusive access will wait half the time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * probably giving them higher priority in the case of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * multiple waiters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) udelay(VCC_REF_DELAY/2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) goto try_again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) port->refcnt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) port->excl_locked = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) spin_unlock_irqrestore(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * vcc_put() - Returns a reference to VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * @port: pointer to VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * @excl: Indicates if the returned reference is an exclusive reference
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * Note: It's the caller's responsibility to ensure the correct value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * for the excl flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static void vcc_put(struct vcc_port *port, bool excl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (!port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) spin_lock_irqsave(&vcc_table_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* check if caller attempted to put with the wrong flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (WARN_ON((excl && !port->excl_locked) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) (!excl && port->excl_locked)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) port->refcnt--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (excl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) port->excl_locked = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) spin_unlock_irqrestore(&vcc_table_lock, flags);
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * vcc_get_ne() - Get a non-exclusive reference to VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * @index: Index into the VCC table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * Gets a non-exclusive reference to VCC port, if it's not removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * Return: pointer to the VCC port, if found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * NULL, if port not found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static struct vcc_port *vcc_get_ne(unsigned long index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) port = vcc_get(index, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (port && port->removed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return NULL;
^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) return port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static void vcc_kick_rx(struct vcc_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct vio_driver_state *vio = &port->vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) assert_spin_locked(&port->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (!timer_pending(&port->rx_timer) && !port->removed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) disable_irq_nosync(vio->vdev->rx_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) port->rx_timer.expires = (jiffies + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) add_timer(&port->rx_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static void vcc_kick_tx(struct vcc_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) assert_spin_locked(&port->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (!timer_pending(&port->tx_timer) && !port->removed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) port->tx_timer.expires = (jiffies + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) add_timer(&port->tx_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static int vcc_rx_check(struct tty_struct *tty, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (WARN_ON(!tty || !tty->port))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) /* tty_buffer_request_room won't sleep because it uses
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * GFP_ATOMIC flag to allocate buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (test_bit(TTY_THROTTLED, &tty->flags) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) (tty_buffer_request_room(tty->port, VCC_BUFF_LEN) < VCC_BUFF_LEN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static int vcc_rx(struct tty_struct *tty, char *buf, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) int len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (WARN_ON(!tty || !tty->port))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) len = tty_insert_flip_string(tty->port, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) tty_flip_buffer_push(tty->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static int vcc_ldc_read(struct vcc_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct vio_driver_state *vio = &port->vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct vio_vcc pkt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) tty = port->tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (!tty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) rv = ldc_rx_reset(vio->lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) vccdbg("VCC: reset rx q: rv=%d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /* Read as long as LDC has incoming data. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (!vcc_rx_check(tty, VIO_VCC_MTU_SIZE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) vcc_kick_rx(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) vccdbgl(vio->lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) rv = ldc_read(vio->lp, &pkt, sizeof(pkt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (rv <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) vccdbg("VCC: ldc_read()=%d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) vccdbg("TAG [%02x:%02x:%04x:%08x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) pkt.tag.type, pkt.tag.stype,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) pkt.tag.stype_env, pkt.tag.sid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (pkt.tag.type == VIO_TYPE_DATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) vccdbgp(pkt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /* vcc_rx_check ensures memory availability */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) vcc_rx(tty, pkt.data, pkt.tag.stype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) pr_err("VCC: unknown msg [%02x:%02x:%04x:%08x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) pkt.tag.type, pkt.tag.stype,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) pkt.tag.stype_env, pkt.tag.sid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) rv = -ECONNRESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) WARN_ON(rv != LDC_PACKET_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static void vcc_rx_timer(struct timer_list *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) struct vcc_port *port = from_timer(port, t, rx_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct vio_driver_state *vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) spin_lock_irqsave(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) port->rx_timer.expires = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) vio = &port->vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) enable_irq(vio->vdev->rx_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (!port->tty || port->removed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) rv = vcc_ldc_read(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (rv == -ECONNRESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) vio_conn_reset(vio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) spin_unlock_irqrestore(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static void vcc_tx_timer(struct timer_list *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) struct vcc_port *port = from_timer(port, t, tx_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) struct vio_vcc *pkt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) int tosend = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) spin_lock_irqsave(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) port->tx_timer.expires = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (!port->tty || port->removed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) tosend = min(VCC_BUFF_LEN, port->chars_in_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (!tosend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) pkt = &port->buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) pkt->tag.type = VIO_TYPE_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) pkt->tag.stype = tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) vccdbgl(port->vio.lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) rv = ldc_write(port->vio.lp, pkt, (VIO_TAG_SIZE + tosend));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) WARN_ON(!rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (rv < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) vccdbg("VCC: ldc_write()=%d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) vcc_kick_tx(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) struct tty_struct *tty = port->tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) port->chars_in_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) tty_wakeup(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) spin_unlock_irqrestore(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) * vcc_event() - LDC event processing engine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * @arg: VCC private data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * @event: LDC event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * Handles LDC events for VCC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static void vcc_event(void *arg, int event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) struct vio_driver_state *vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) port = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) vio = &port->vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) spin_lock_irqsave(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) case LDC_EVENT_RESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) case LDC_EVENT_UP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) vio_link_state_change(vio, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) case LDC_EVENT_DATA_READY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) rv = vcc_ldc_read(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (rv == -ECONNRESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) vio_conn_reset(vio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) pr_err("VCC: unexpected LDC event(%d)\n", event);
^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) spin_unlock_irqrestore(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) static struct ldc_channel_config vcc_ldc_cfg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) .event = vcc_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) .mtu = VIO_VCC_MTU_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) .mode = LDC_MODE_RAW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) .debug = 0,
^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) /* Ordered from largest major to lowest */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static struct vio_version vcc_versions[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) { .major = 1, .minor = 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static struct tty_port_operations vcc_port_ops = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static ssize_t vcc_sysfs_domain_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) port = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (!port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) rv = scnprintf(buf, PAGE_SIZE, "%s\n", port->domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static int vcc_send_ctl(struct vcc_port *port, int ctl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) struct vio_vcc pkt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) pkt.tag.type = VIO_TYPE_CTRL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) pkt.tag.sid = ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) pkt.tag.stype = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) rv = ldc_write(port->vio.lp, &pkt, sizeof(pkt.tag));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) WARN_ON(!rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) vccdbg("VCC: ldc_write(%ld)=%d\n", sizeof(pkt.tag), rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) static ssize_t vcc_sysfs_break_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) int rv = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) int brk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) port = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (!port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) spin_lock_irqsave(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (sscanf(buf, "%ud", &brk) != 1 || brk != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) rv = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) else if (vcc_send_ctl(port, VCC_CTL_BREAK) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) vcc_kick_tx(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) spin_unlock_irqrestore(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) static DEVICE_ATTR(domain, 0400, vcc_sysfs_domain_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) static DEVICE_ATTR(break, 0200, NULL, vcc_sysfs_break_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static struct attribute *vcc_sysfs_entries[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) &dev_attr_domain.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) &dev_attr_break.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) static struct attribute_group vcc_attribute_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) .name = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) .attrs = vcc_sysfs_entries,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * vcc_probe() - Initialize VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * @vdev: Pointer to VIO device of the new VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * @id: VIO device ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * Initializes a VCC port to receive serial console data from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * the guest domain. Sets up a TTY end point on the control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * domain. Sets up VIO/LDC link between the guest & control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * domain endpoints.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * Return: status of the probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) static int vcc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) struct mdesc_handle *hp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) const char *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) u64 node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) vccdbg("VCC: name=%s\n", dev_name(&vdev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (!vcc_tty_driver) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) pr_err("VCC: TTY driver not registered\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) port = kzalloc(sizeof(struct vcc_port), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (!port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) name = kstrdup(dev_name(&vdev->dev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) rv = vio_driver_init(&port->vio, vdev, VDEV_CONSOLE_CON, vcc_versions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) ARRAY_SIZE(vcc_versions), NULL, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) goto free_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) port->vio.debug = vcc_dbg_vio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) vcc_ldc_cfg.debug = vcc_dbg_ldc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) rv = vio_ldc_alloc(&port->vio, &vcc_ldc_cfg, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) goto free_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) spin_lock_init(&port->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) port->index = vcc_table_add(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (port->index == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) pr_err("VCC: no more TTY indices left for allocation\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) rv = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) goto free_ldc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /* Register the device using VCC table index as TTY index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) dev = tty_register_device(vcc_tty_driver, port->index, &vdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (IS_ERR(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) rv = PTR_ERR(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) goto free_table;
^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) hp = mdesc_grab();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) node = vio_vdev_node(hp, vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (node == MDESC_NODE_NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) rv = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) mdesc_release(hp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) goto unreg_tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) domain = mdesc_get_property(hp, node, "vcc-domain-name", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (!domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) rv = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) mdesc_release(hp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) goto unreg_tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) port->domain = kstrdup(domain, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) mdesc_release(hp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) rv = sysfs_create_group(&vdev->dev.kobj, &vcc_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) goto free_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) timer_setup(&port->rx_timer, vcc_rx_timer, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) timer_setup(&port->tx_timer, vcc_tx_timer, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) dev_set_drvdata(&vdev->dev, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) /* It's possible to receive IRQs in the middle of vio_port_up. Disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * IRQs until the port is up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) disable_irq_nosync(vdev->rx_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) vio_port_up(&port->vio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) enable_irq(vdev->rx_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) free_domain:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) kfree(port->domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) unreg_tty:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) tty_unregister_device(vcc_tty_driver, port->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) free_table:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) vcc_table_remove(port->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) free_ldc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) vio_ldc_free(&port->vio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) free_port:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) kfree(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) kfree(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * vcc_remove() - Terminate a VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) * @vdev: Pointer to VIO device of the VCC port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) * Terminates a VCC port. Sets up the teardown of TTY and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) * VIO/LDC link between guest and primary domains.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * Return: status of removal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) static int vcc_remove(struct vio_dev *vdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) struct vcc_port *port = dev_get_drvdata(&vdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (!port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) del_timer_sync(&port->rx_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) del_timer_sync(&port->tx_timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) /* If there's a process with the device open, do a synchronous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * hangup of the TTY. This *may* cause the process to call close
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * asynchronously, but it's not guaranteed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) if (port->tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) tty_vhangup(port->tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) /* Get exclusive reference to VCC, ensures that there are no other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) * clients to this port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) port = vcc_get(port->index, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (WARN_ON(!port))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) tty_unregister_device(vcc_tty_driver, port->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) del_timer_sync(&port->vio.timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) vio_ldc_free(&port->vio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) sysfs_remove_group(&vdev->dev.kobj, &vcc_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) dev_set_drvdata(&vdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (port->tty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) port->removed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) vcc_put(port, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) vcc_table_remove(port->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) kfree(port->vio.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) kfree(port->domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) kfree(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return 0;
^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 const struct vio_device_id vcc_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) .type = "vcc-port",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) MODULE_DEVICE_TABLE(vio, vcc_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) static struct vio_driver vcc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) .id_table = vcc_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) .probe = vcc_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) .remove = vcc_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) .name = "vcc",
^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) static int vcc_open(struct tty_struct *tty, struct file *vcc_file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) pr_err("VCC: open: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (tty->count > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) port = vcc_get_ne(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if (unlikely(!port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) pr_err("VCC: open: Failed to find VCC port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) if (unlikely(!port->vio.lp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) pr_err("VCC: open: LDC channel not configured\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) return -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) vccdbgl(port->vio.lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (unlikely(!tty->port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) pr_err("VCC: open: TTY port not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (unlikely(!tty->port->ops)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) pr_err("VCC: open: TTY ops not defined\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) return tty_port_open(tty->port, tty, vcc_file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) static void vcc_close(struct tty_struct *tty, struct file *vcc_file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) pr_err("VCC: close: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if (unlikely(tty->count > 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (unlikely(!tty->port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) pr_err("VCC: close: TTY port not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) tty_port_close(tty->port, tty, vcc_file);
^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) static void vcc_ldc_hup(struct vcc_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) spin_lock_irqsave(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (vcc_send_ctl(port, VCC_CTL_HUP) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) vcc_kick_tx(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) spin_unlock_irqrestore(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) static void vcc_hangup(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) pr_err("VCC: hangup: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) port = vcc_get_ne(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) if (unlikely(!port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) pr_err("VCC: hangup: Failed to find VCC port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if (unlikely(!tty->port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) pr_err("VCC: hangup: TTY port not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) vcc_ldc_hup(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) tty_port_hangup(tty->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) static int vcc_write(struct tty_struct *tty, const unsigned char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) struct vio_vcc *pkt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) int total_sent = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) int tosend = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) int rv = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) pr_err("VCC: write: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) port = vcc_get_ne(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (unlikely(!port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) pr_err("VCC: write: Failed to find VCC port");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) spin_lock_irqsave(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) pkt = &port->buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) pkt->tag.type = VIO_TYPE_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) /* Minimum of data to write and space available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) tosend = min(count, (VCC_BUFF_LEN - port->chars_in_buffer));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) if (!tosend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) memcpy(&pkt->data[port->chars_in_buffer], &buf[total_sent],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) tosend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) port->chars_in_buffer += tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) pkt->tag.stype = tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) vccdbg("TAG [%02x:%02x:%04x:%08x]\n", pkt->tag.type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) pkt->tag.stype, pkt->tag.stype_env, pkt->tag.sid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) vccdbg("DATA [%s]\n", pkt->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) vccdbgl(port->vio.lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) /* Since we know we have enough room in VCC buffer for tosend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * we record that it was sent regardless of whether the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) * hypervisor actually took it because we have it buffered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) rv = ldc_write(port->vio.lp, pkt, (VIO_TAG_SIZE + tosend));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) vccdbg("VCC: write: ldc_write(%d)=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) (VIO_TAG_SIZE + tosend), rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) total_sent += tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) count -= tosend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) if (rv < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) vcc_kick_tx(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) port->chars_in_buffer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) spin_unlock_irqrestore(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) vccdbg("VCC: write: total=%d rv=%d", total_sent, rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return total_sent ? total_sent : rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) static int vcc_write_room(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) u64 num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) pr_err("VCC: write_room: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) port = vcc_get_ne(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) if (unlikely(!port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) pr_err("VCC: write_room: Failed to find VCC port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) num = VCC_BUFF_LEN - port->chars_in_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) return num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) static int vcc_chars_in_buffer(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) u64 num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) pr_err("VCC: chars_in_buffer: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) port = vcc_get_ne(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (unlikely(!port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) pr_err("VCC: chars_in_buffer: Failed to find VCC port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) num = port->chars_in_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) return num;
^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) static int vcc_break_ctl(struct tty_struct *tty, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) pr_err("VCC: break_ctl: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) port = vcc_get_ne(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) if (unlikely(!port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) pr_err("VCC: break_ctl: Failed to find VCC port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) /* Turn off break */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) if (state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) spin_lock_irqsave(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) if (vcc_send_ctl(port, VCC_CTL_BREAK) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) vcc_kick_tx(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) spin_unlock_irqrestore(&port->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) vcc_put(port, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) static int vcc_install(struct tty_driver *driver, struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) struct vcc_port *port_vcc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) struct tty_port *port_tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) pr_err("VCC: install: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return -ENXIO;
^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) if (tty->index >= VCC_MAX_PORTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) ret = tty_standard_install(driver, tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) port_tty = kzalloc(sizeof(struct tty_port), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (!port_tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) port_vcc = vcc_get(tty->index, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) if (!port_vcc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) pr_err("VCC: install: Failed to find VCC port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) tty->port = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) kfree(port_tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) tty_port_init(port_tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) port_tty->ops = &vcc_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) tty->port = port_tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) port_vcc->tty = tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) vcc_put(port_vcc, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) static void vcc_cleanup(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) struct vcc_port *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) if (unlikely(!tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) pr_err("VCC: cleanup: Invalid TTY handle\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) port = vcc_get(tty->index, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) if (port) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) port->tty = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) if (port->removed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) vcc_table_remove(tty->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) kfree(port->vio.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) kfree(port->domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) kfree(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) vcc_put(port, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) tty_port_destroy(tty->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) kfree(tty->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) tty->port = NULL;
^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) static const struct tty_operations vcc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) .open = vcc_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) .close = vcc_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) .hangup = vcc_hangup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) .write = vcc_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) .write_room = vcc_write_room,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) .chars_in_buffer = vcc_chars_in_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) .break_ctl = vcc_break_ctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) .install = vcc_install,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) .cleanup = vcc_cleanup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) #define VCC_TTY_FLAGS (TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_REAL_RAW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) static int vcc_tty_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) pr_info("VCC: %s\n", version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) vcc_tty_driver = tty_alloc_driver(VCC_MAX_PORTS, VCC_TTY_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) if (IS_ERR(vcc_tty_driver)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) pr_err("VCC: TTY driver alloc failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) return PTR_ERR(vcc_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) vcc_tty_driver->driver_name = vcc_driver_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) vcc_tty_driver->name = vcc_device_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) vcc_tty_driver->minor_start = VCC_MINOR_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) vcc_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) vcc_tty_driver->init_termios = vcc_tty_termios;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) tty_set_operations(vcc_tty_driver, &vcc_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) rv = tty_register_driver(vcc_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) if (rv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) pr_err("VCC: TTY driver registration failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) put_tty_driver(vcc_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) vcc_tty_driver = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) vccdbg("VCC: TTY driver registered\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) static void vcc_tty_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) tty_unregister_driver(vcc_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) put_tty_driver(vcc_tty_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) vccdbg("VCC: TTY driver unregistered\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) vcc_tty_driver = NULL;
^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) static int __init vcc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) rv = vcc_tty_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) if (rv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) pr_err("VCC: TTY init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) rv = vio_register_driver(&vcc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) if (rv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) pr_err("VCC: VIO driver registration failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) vcc_tty_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) vccdbg("VCC: VIO driver registered successfully\n");
^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) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) static void __exit vcc_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) vio_unregister_driver(&vcc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) vccdbg("VCC: VIO driver unregistered\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) vcc_tty_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) vccdbg("VCC: TTY driver unregistered\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) module_init(vcc_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) module_exit(vcc_exit);