spinlock_t lock; char *domain; struct tty_struct *tty; /* only populated while dev is open */ unsignedlong index; /* index into the vcc_table */
u64 refcnt; bool excl_locked;
bool removed;
/* This buffer is required to support the tty write_room interface * and guarantee that any characters that the driver accepts will * be eventually sent, either immediately or later.
*/
size_t chars_in_buffer; struct vio_vcc buffer;
#define vccdbg(f, a...) \ do { \ if (vcc_dbg & VCC_DBG_DRV) \
pr_info(f, ## a); \
} while (0) \
#define vccdbgl(l) \ do { \ if (vcc_dbg & VCC_DBG_LDC) \
ldc_print(l); \
} while (0) \
#define vccdbgp(pkt) \ do { \ if (vcc_dbg & VCC_DBG_PKT) { \ int i; \ for (i = 0; i < pkt.tag.stype; i++) \
pr_info("[%c]", pkt.data[i]); \
} \
} while (0) \
/* Note: Be careful when adding flags to this line discipline. Don't * add anything that will cause echoing or we'll go into recursive * loop echoing chars back and forth with the console drivers.
*/ staticconststruct ktermios vcc_tty_termios = {
.c_iflag = IGNBRK | IGNPAR,
.c_oflag = OPOST,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
.c_cc = INIT_C_CC,
.c_ispeed = 38400,
.c_ospeed = 38400
};
/** * vcc_table_add() - Add VCC port to the VCC table * @port: pointer to the VCC port * * Return: index of the port in the VCC table on success, * -1 on failure
*/ staticint vcc_table_add(struct vcc_port *port)
{ unsignedlong flags; int i;
spin_lock_irqsave(&vcc_table_lock, flags); for (i = VCC_MINOR_START; i < VCC_MAX_PORTS; i++) { if (!vcc_table[i]) {
vcc_table[i] = port; break;
}
}
spin_unlock_irqrestore(&vcc_table_lock, flags);
if (i < VCC_MAX_PORTS) return i; else return -1;
}
/** * vcc_table_remove() - Removes a VCC port from the VCC table * @index: Index into the VCC table
*/ staticvoid vcc_table_remove(unsignedlong index)
{ unsignedlong flags;
/** * vcc_get() - Gets a reference to VCC port * @index: Index into the VCC table * @excl: Indicates if an exclusive access is requested * * Return: reference to the VCC port, if found * NULL, if port not found
*/ staticstruct vcc_port *vcc_get(unsignedlong index, bool excl)
{ struct vcc_port *port; unsignedlong flags;
port = vcc_table[index]; if (!port) {
spin_unlock_irqrestore(&vcc_table_lock, flags); return NULL;
}
if (!excl) { if (port->excl_locked) {
spin_unlock_irqrestore(&vcc_table_lock, flags);
udelay(VCC_REF_DELAY); goto try_again;
}
port->refcnt++;
spin_unlock_irqrestore(&vcc_table_lock, flags); return port;
}
if (port->refcnt) {
spin_unlock_irqrestore(&vcc_table_lock, flags); /* Threads wanting exclusive access will wait half the time, * probably giving them higher priority in the case of * multiple waiters.
*/
udelay(VCC_REF_DELAY/2); goto try_again;
}
/** * vcc_put() - Returns a reference to VCC port * @port: pointer to VCC port * @excl: Indicates if the returned reference is an exclusive reference * * Note: It's the caller's responsibility to ensure the correct value * for the excl flag
*/ staticvoid vcc_put(struct vcc_port *port, bool excl)
{ unsignedlong flags;
if (!port) return;
spin_lock_irqsave(&vcc_table_lock, flags);
/* check if caller attempted to put with the wrong flags */ if (WARN_ON((excl && !port->excl_locked) ||
(!excl && port->excl_locked))) goto done;
/** * vcc_get_ne() - Get a non-exclusive reference to VCC port * @index: Index into the VCC table * * Gets a non-exclusive reference to VCC port, if it's not removed * * Return: pointer to the VCC port, if found * NULL, if port not found
*/ staticstruct vcc_port *vcc_get_ne(unsignedlong index)
{ struct vcc_port *port;
port = vcc_get(index, false);
if (port && port->removed) {
vcc_put(port, false); return NULL;
}
staticint vcc_rx_check(struct tty_struct *tty, int size)
{ if (WARN_ON(!tty || !tty->port)) return 1;
/* tty_buffer_request_room won't sleep because it uses * GFP_ATOMIC flag to allocate buffer
*/ if (test_bit(TTY_THROTTLED, &tty->flags) ||
(tty_buffer_request_room(tty->port, VCC_BUFF_LEN) < VCC_BUFF_LEN)) return 0;
return 1;
}
staticint vcc_rx(struct tty_struct *tty, char *buf, int size)
{ int len = 0;
if (WARN_ON(!tty || !tty->port)) return len;
len = tty_insert_flip_string(tty->port, buf, size); if (len)
tty_flip_buffer_push(tty->port);
/** * vcc_probe() - Initialize VCC port * @vdev: Pointer to VIO device of the new VCC port * @id: VIO device ID * * Initializes a VCC port to receive serial console data from * the guest domain. Sets up a TTY end point on the control * domain. Sets up VIO/LDC link between the guest & control * domain endpoints. * * Return: status of the probe
*/ staticint vcc_probe(struct vio_dev *vdev, conststruct vio_device_id *id)
{ struct mdesc_handle *hp; struct vcc_port *port; struct device *dev; constchar *domain; char *name;
u64 node; int rv;
vccdbg("VCC: name=%s\n", dev_name(&vdev->dev));
if (!vcc_tty_driver) {
pr_err("VCC: TTY driver not registered\n"); return -ENODEV;
}
port = kzalloc(sizeof(struct vcc_port), GFP_KERNEL); if (!port) return -ENOMEM;
name = kstrdup(dev_name(&vdev->dev), GFP_KERNEL); if (!name) {
rv = -ENOMEM; goto free_port;
}
rv = vio_ldc_alloc(&port->vio, &vcc_ldc_cfg, port); if (rv) goto free_name;
spin_lock_init(&port->lock);
port->index = vcc_table_add(port); if (port->index == -1) {
pr_err("VCC: no more TTY indices left for allocation\n");
rv = -ENOMEM; goto free_ldc;
}
/* Register the device using VCC table index as TTY index */
dev = tty_register_device(vcc_tty_driver, port->index, &vdev->dev); if (IS_ERR(dev)) {
rv = PTR_ERR(dev); goto free_table;
}
/* It's possible to receive IRQs in the middle of vio_port_up. Disable * IRQs until the port is up.
*/
disable_irq_nosync(vdev->rx_irq);
vio_port_up(&port->vio);
enable_irq(vdev->rx_irq);
/** * vcc_remove() - Terminate a VCC port * @vdev: Pointer to VIO device of the VCC port * * Terminates a VCC port. Sets up the teardown of TTY and * VIO/LDC link between guest and primary domains. * * Return: status of removal
*/ staticvoid vcc_remove(struct vio_dev *vdev)
{ struct vcc_port *port = dev_get_drvdata(&vdev->dev);
/* If there's a process with the device open, do a synchronous * hangup of the TTY. This *may* cause the process to call close * asynchronously, but it's not guaranteed.
*/ if (port->tty)
tty_vhangup(port->tty);
/* Get exclusive reference to VCC, ensures that there are no other * clients to this port. This cannot fail.
*/
vcc_get(port->index, true);
/* Since we know we have enough room in VCC buffer for tosend * we record that it was sent regardless of whether the * hypervisor actually took it because we have it buffered.
*/
rv = ldc_write(port->vio.lp, pkt, (VIO_TAG_SIZE + tosend));
vccdbg("VCC: write: ldc_write(%zu)=%d\n",
(VIO_TAG_SIZE + tosend), rv);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.19Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.