162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
462306a36Sopenharmony_ci * Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
562306a36Sopenharmony_ci * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/cdev.h>
862306a36Sopenharmony_ci#include <linux/debugfs.h>
962306a36Sopenharmony_ci#include <linux/completion.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/freezer.h>
1362306a36Sopenharmony_ci#include <linux/fs.h>
1462306a36Sopenharmony_ci#include <linux/splice.h>
1562306a36Sopenharmony_ci#include <linux/pagemap.h>
1662306a36Sopenharmony_ci#include <linux/idr.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/list.h>
1962306a36Sopenharmony_ci#include <linux/poll.h>
2062306a36Sopenharmony_ci#include <linux/sched.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <linux/spinlock.h>
2362306a36Sopenharmony_ci#include <linux/virtio.h>
2462306a36Sopenharmony_ci#include <linux/virtio_console.h>
2562306a36Sopenharmony_ci#include <linux/wait.h>
2662306a36Sopenharmony_ci#include <linux/workqueue.h>
2762306a36Sopenharmony_ci#include <linux/module.h>
2862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2962306a36Sopenharmony_ci#include "../tty/hvc/hvc_console.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC)
3262306a36Sopenharmony_ci#define VIRTCONS_MAX_PORTS 0x8000
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * This is a global struct for storing common data for all the devices
3662306a36Sopenharmony_ci * this driver handles.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Mainly, it has a linked list for all the consoles in one place so
3962306a36Sopenharmony_ci * that callbacks from hvc for get_chars(), put_chars() work properly
4062306a36Sopenharmony_ci * across multiple devices and multiple ports per device.
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_cistruct ports_driver_data {
4362306a36Sopenharmony_ci	/* Used for exporting per-port information to debugfs */
4462306a36Sopenharmony_ci	struct dentry *debugfs_dir;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/* List of all the devices we're handling */
4762306a36Sopenharmony_ci	struct list_head portdevs;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* All the console devices handled by this driver */
5062306a36Sopenharmony_ci	struct list_head consoles;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic struct ports_driver_data pdrvdata;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic const struct class port_class = {
5662306a36Sopenharmony_ci	.name = "virtio-ports",
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(pdrvdata_lock);
6062306a36Sopenharmony_cistatic DECLARE_COMPLETION(early_console_added);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* This struct holds information that's relevant only for console ports */
6362306a36Sopenharmony_cistruct console {
6462306a36Sopenharmony_ci	/* We'll place all consoles in a list in the pdrvdata struct */
6562306a36Sopenharmony_ci	struct list_head list;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* The hvc device associated with this console port */
6862306a36Sopenharmony_ci	struct hvc_struct *hvc;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* The size of the console */
7162306a36Sopenharmony_ci	struct winsize ws;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/*
7462306a36Sopenharmony_ci	 * This number identifies the number that we used to register
7562306a36Sopenharmony_ci	 * with hvc in hvc_instantiate() and hvc_alloc(); this is the
7662306a36Sopenharmony_ci	 * number passed on by the hvc callbacks to us to
7762306a36Sopenharmony_ci	 * differentiate between the other console ports handled by
7862306a36Sopenharmony_ci	 * this driver
7962306a36Sopenharmony_ci	 */
8062306a36Sopenharmony_ci	u32 vtermno;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic DEFINE_IDA(vtermno_ida);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistruct port_buffer {
8662306a36Sopenharmony_ci	char *buf;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* size of the buffer in *buf above */
8962306a36Sopenharmony_ci	size_t size;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* used length of the buffer */
9262306a36Sopenharmony_ci	size_t len;
9362306a36Sopenharmony_ci	/* offset in the buf from which to consume data */
9462306a36Sopenharmony_ci	size_t offset;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* DMA address of buffer */
9762306a36Sopenharmony_ci	dma_addr_t dma;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Device we got DMA memory from */
10062306a36Sopenharmony_ci	struct device *dev;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* List of pending dma buffers to free */
10362306a36Sopenharmony_ci	struct list_head list;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* If sgpages == 0 then buf is used */
10662306a36Sopenharmony_ci	unsigned int sgpages;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* sg is used if spages > 0. sg must be the last in is struct */
10962306a36Sopenharmony_ci	struct scatterlist sg[];
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/*
11362306a36Sopenharmony_ci * This is a per-device struct that stores data common to all the
11462306a36Sopenharmony_ci * ports for that device (vdev->priv).
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_cistruct ports_device {
11762306a36Sopenharmony_ci	/* Next portdev in the list, head is in the pdrvdata struct */
11862306a36Sopenharmony_ci	struct list_head list;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/*
12162306a36Sopenharmony_ci	 * Workqueue handlers where we process deferred work after
12262306a36Sopenharmony_ci	 * notification
12362306a36Sopenharmony_ci	 */
12462306a36Sopenharmony_ci	struct work_struct control_work;
12562306a36Sopenharmony_ci	struct work_struct config_work;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	struct list_head ports;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* To protect the list of ports */
13062306a36Sopenharmony_ci	spinlock_t ports_lock;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* To protect the vq operations for the control channel */
13362306a36Sopenharmony_ci	spinlock_t c_ivq_lock;
13462306a36Sopenharmony_ci	spinlock_t c_ovq_lock;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* max. number of ports this device can hold */
13762306a36Sopenharmony_ci	u32 max_nr_ports;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* The virtio device we're associated with */
14062306a36Sopenharmony_ci	struct virtio_device *vdev;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/*
14362306a36Sopenharmony_ci	 * A couple of virtqueues for the control channel: one for
14462306a36Sopenharmony_ci	 * guest->host transfers, one for host->guest transfers
14562306a36Sopenharmony_ci	 */
14662306a36Sopenharmony_ci	struct virtqueue *c_ivq, *c_ovq;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/*
14962306a36Sopenharmony_ci	 * A control packet buffer for guest->host requests, protected
15062306a36Sopenharmony_ci	 * by c_ovq_lock.
15162306a36Sopenharmony_ci	 */
15262306a36Sopenharmony_ci	struct virtio_console_control cpkt;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* Array of per-port IO virtqueues */
15562306a36Sopenharmony_ci	struct virtqueue **in_vqs, **out_vqs;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* Major number for this device.  Ports will be created as minors. */
15862306a36Sopenharmony_ci	int chr_major;
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistruct port_stats {
16262306a36Sopenharmony_ci	unsigned long bytes_sent, bytes_received, bytes_discarded;
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* This struct holds the per-port data */
16662306a36Sopenharmony_cistruct port {
16762306a36Sopenharmony_ci	/* Next port in the list, head is in the ports_device */
16862306a36Sopenharmony_ci	struct list_head list;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Pointer to the parent virtio_console device */
17162306a36Sopenharmony_ci	struct ports_device *portdev;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* The current buffer from which data has to be fed to readers */
17462306a36Sopenharmony_ci	struct port_buffer *inbuf;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/*
17762306a36Sopenharmony_ci	 * To protect the operations on the in_vq associated with this
17862306a36Sopenharmony_ci	 * port.  Has to be a spinlock because it can be called from
17962306a36Sopenharmony_ci	 * interrupt context (get_char()).
18062306a36Sopenharmony_ci	 */
18162306a36Sopenharmony_ci	spinlock_t inbuf_lock;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Protect the operations on the out_vq. */
18462306a36Sopenharmony_ci	spinlock_t outvq_lock;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* The IO vqs for this port */
18762306a36Sopenharmony_ci	struct virtqueue *in_vq, *out_vq;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* File in the debugfs directory that exposes this port's information */
19062306a36Sopenharmony_ci	struct dentry *debugfs_file;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/*
19362306a36Sopenharmony_ci	 * Keep count of the bytes sent, received and discarded for
19462306a36Sopenharmony_ci	 * this port for accounting and debugging purposes.  These
19562306a36Sopenharmony_ci	 * counts are not reset across port open / close events.
19662306a36Sopenharmony_ci	 */
19762306a36Sopenharmony_ci	struct port_stats stats;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/*
20062306a36Sopenharmony_ci	 * The entries in this struct will be valid if this port is
20162306a36Sopenharmony_ci	 * hooked up to an hvc console
20262306a36Sopenharmony_ci	 */
20362306a36Sopenharmony_ci	struct console cons;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* Each port associates with a separate char device */
20662306a36Sopenharmony_ci	struct cdev *cdev;
20762306a36Sopenharmony_ci	struct device *dev;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* Reference-counting to handle port hot-unplugs and file operations */
21062306a36Sopenharmony_ci	struct kref kref;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* A waitqueue for poll() or blocking read operations */
21362306a36Sopenharmony_ci	wait_queue_head_t waitqueue;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* The 'name' of the port that we expose via sysfs properties */
21662306a36Sopenharmony_ci	char *name;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	/* We can notify apps of host connect / disconnect events via SIGIO */
21962306a36Sopenharmony_ci	struct fasync_struct *async_queue;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* The 'id' to identify the port with the Host */
22262306a36Sopenharmony_ci	u32 id;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	bool outvq_full;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* Is the host device open */
22762306a36Sopenharmony_ci	bool host_connected;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* We should allow only one process to open a port */
23062306a36Sopenharmony_ci	bool guest_connected;
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* This is the very early arch-specified put chars function. */
23462306a36Sopenharmony_cistatic int (*early_put_chars)(u32, const char *, int);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic struct port *find_port_by_vtermno(u32 vtermno)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct port *port;
23962306a36Sopenharmony_ci	struct console *cons;
24062306a36Sopenharmony_ci	unsigned long flags;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	spin_lock_irqsave(&pdrvdata_lock, flags);
24362306a36Sopenharmony_ci	list_for_each_entry(cons, &pdrvdata.consoles, list) {
24462306a36Sopenharmony_ci		if (cons->vtermno == vtermno) {
24562306a36Sopenharmony_ci			port = container_of(cons, struct port, cons);
24662306a36Sopenharmony_ci			goto out;
24762306a36Sopenharmony_ci		}
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	port = NULL;
25062306a36Sopenharmony_ciout:
25162306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdrvdata_lock, flags);
25262306a36Sopenharmony_ci	return port;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
25662306a36Sopenharmony_ci						 dev_t dev)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct port *port;
25962306a36Sopenharmony_ci	unsigned long flags;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	spin_lock_irqsave(&portdev->ports_lock, flags);
26262306a36Sopenharmony_ci	list_for_each_entry(port, &portdev->ports, list) {
26362306a36Sopenharmony_ci		if (port->cdev->dev == dev) {
26462306a36Sopenharmony_ci			kref_get(&port->kref);
26562306a36Sopenharmony_ci			goto out;
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	port = NULL;
26962306a36Sopenharmony_ciout:
27062306a36Sopenharmony_ci	spin_unlock_irqrestore(&portdev->ports_lock, flags);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return port;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic struct port *find_port_by_devt(dev_t dev)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct ports_device *portdev;
27862306a36Sopenharmony_ci	struct port *port;
27962306a36Sopenharmony_ci	unsigned long flags;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	spin_lock_irqsave(&pdrvdata_lock, flags);
28262306a36Sopenharmony_ci	list_for_each_entry(portdev, &pdrvdata.portdevs, list) {
28362306a36Sopenharmony_ci		port = find_port_by_devt_in_portdev(portdev, dev);
28462306a36Sopenharmony_ci		if (port)
28562306a36Sopenharmony_ci			goto out;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci	port = NULL;
28862306a36Sopenharmony_ciout:
28962306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdrvdata_lock, flags);
29062306a36Sopenharmony_ci	return port;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic struct port *find_port_by_id(struct ports_device *portdev, u32 id)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct port *port;
29662306a36Sopenharmony_ci	unsigned long flags;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	spin_lock_irqsave(&portdev->ports_lock, flags);
29962306a36Sopenharmony_ci	list_for_each_entry(port, &portdev->ports, list)
30062306a36Sopenharmony_ci		if (port->id == id)
30162306a36Sopenharmony_ci			goto out;
30262306a36Sopenharmony_ci	port = NULL;
30362306a36Sopenharmony_ciout:
30462306a36Sopenharmony_ci	spin_unlock_irqrestore(&portdev->ports_lock, flags);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return port;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic struct port *find_port_by_vq(struct ports_device *portdev,
31062306a36Sopenharmony_ci				    struct virtqueue *vq)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct port *port;
31362306a36Sopenharmony_ci	unsigned long flags;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	spin_lock_irqsave(&portdev->ports_lock, flags);
31662306a36Sopenharmony_ci	list_for_each_entry(port, &portdev->ports, list)
31762306a36Sopenharmony_ci		if (port->in_vq == vq || port->out_vq == vq)
31862306a36Sopenharmony_ci			goto out;
31962306a36Sopenharmony_ci	port = NULL;
32062306a36Sopenharmony_ciout:
32162306a36Sopenharmony_ci	spin_unlock_irqrestore(&portdev->ports_lock, flags);
32262306a36Sopenharmony_ci	return port;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic bool is_console_port(struct port *port)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	if (port->cons.hvc)
32862306a36Sopenharmony_ci		return true;
32962306a36Sopenharmony_ci	return false;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic bool is_rproc_serial(const struct virtio_device *vdev)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic inline bool use_multiport(struct ports_device *portdev)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * This condition can be true when put_chars is called from
34162306a36Sopenharmony_ci	 * early_init
34262306a36Sopenharmony_ci	 */
34362306a36Sopenharmony_ci	if (!portdev->vdev)
34462306a36Sopenharmony_ci		return false;
34562306a36Sopenharmony_ci	return __virtio_test_bit(portdev->vdev, VIRTIO_CONSOLE_F_MULTIPORT);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(dma_bufs_lock);
34962306a36Sopenharmony_cistatic LIST_HEAD(pending_free_dma_bufs);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void free_buf(struct port_buffer *buf, bool can_sleep)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	unsigned int i;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	for (i = 0; i < buf->sgpages; i++) {
35662306a36Sopenharmony_ci		struct page *page = sg_page(&buf->sg[i]);
35762306a36Sopenharmony_ci		if (!page)
35862306a36Sopenharmony_ci			break;
35962306a36Sopenharmony_ci		put_page(page);
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (!buf->dev) {
36362306a36Sopenharmony_ci		kfree(buf->buf);
36462306a36Sopenharmony_ci	} else if (is_rproc_enabled) {
36562306a36Sopenharmony_ci		unsigned long flags;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		/* dma_free_coherent requires interrupts to be enabled. */
36862306a36Sopenharmony_ci		if (!can_sleep) {
36962306a36Sopenharmony_ci			/* queue up dma-buffers to be freed later */
37062306a36Sopenharmony_ci			spin_lock_irqsave(&dma_bufs_lock, flags);
37162306a36Sopenharmony_ci			list_add_tail(&buf->list, &pending_free_dma_bufs);
37262306a36Sopenharmony_ci			spin_unlock_irqrestore(&dma_bufs_lock, flags);
37362306a36Sopenharmony_ci			return;
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci		dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		/* Release device refcnt and allow it to be freed */
37862306a36Sopenharmony_ci		put_device(buf->dev);
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	kfree(buf);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void reclaim_dma_bufs(void)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	unsigned long flags;
38762306a36Sopenharmony_ci	struct port_buffer *buf, *tmp;
38862306a36Sopenharmony_ci	LIST_HEAD(tmp_list);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (list_empty(&pending_free_dma_bufs))
39162306a36Sopenharmony_ci		return;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* Create a copy of the pending_free_dma_bufs while holding the lock */
39462306a36Sopenharmony_ci	spin_lock_irqsave(&dma_bufs_lock, flags);
39562306a36Sopenharmony_ci	list_cut_position(&tmp_list, &pending_free_dma_bufs,
39662306a36Sopenharmony_ci			  pending_free_dma_bufs.prev);
39762306a36Sopenharmony_ci	spin_unlock_irqrestore(&dma_bufs_lock, flags);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Release the dma buffers, without irqs enabled */
40062306a36Sopenharmony_ci	list_for_each_entry_safe(buf, tmp, &tmp_list, list) {
40162306a36Sopenharmony_ci		list_del(&buf->list);
40262306a36Sopenharmony_ci		free_buf(buf, true);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size,
40762306a36Sopenharmony_ci				     int pages)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	struct port_buffer *buf;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	reclaim_dma_bufs();
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/*
41462306a36Sopenharmony_ci	 * Allocate buffer and the sg list. The sg list array is allocated
41562306a36Sopenharmony_ci	 * directly after the port_buffer struct.
41662306a36Sopenharmony_ci	 */
41762306a36Sopenharmony_ci	buf = kmalloc(struct_size(buf, sg, pages), GFP_KERNEL);
41862306a36Sopenharmony_ci	if (!buf)
41962306a36Sopenharmony_ci		goto fail;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	buf->sgpages = pages;
42262306a36Sopenharmony_ci	if (pages > 0) {
42362306a36Sopenharmony_ci		buf->dev = NULL;
42462306a36Sopenharmony_ci		buf->buf = NULL;
42562306a36Sopenharmony_ci		return buf;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (is_rproc_serial(vdev)) {
42962306a36Sopenharmony_ci		/*
43062306a36Sopenharmony_ci		 * Allocate DMA memory from ancestor. When a virtio
43162306a36Sopenharmony_ci		 * device is created by remoteproc, the DMA memory is
43262306a36Sopenharmony_ci		 * associated with the parent device:
43362306a36Sopenharmony_ci		 * virtioY => remoteprocX#vdevYbuffer.
43462306a36Sopenharmony_ci		 */
43562306a36Sopenharmony_ci		buf->dev = vdev->dev.parent;
43662306a36Sopenharmony_ci		if (!buf->dev)
43762306a36Sopenharmony_ci			goto free_buf;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		/* Increase device refcnt to avoid freeing it */
44062306a36Sopenharmony_ci		get_device(buf->dev);
44162306a36Sopenharmony_ci		buf->buf = dma_alloc_coherent(buf->dev, buf_size, &buf->dma,
44262306a36Sopenharmony_ci					      GFP_KERNEL);
44362306a36Sopenharmony_ci	} else {
44462306a36Sopenharmony_ci		buf->dev = NULL;
44562306a36Sopenharmony_ci		buf->buf = kmalloc(buf_size, GFP_KERNEL);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (!buf->buf)
44962306a36Sopenharmony_ci		goto free_buf;
45062306a36Sopenharmony_ci	buf->len = 0;
45162306a36Sopenharmony_ci	buf->offset = 0;
45262306a36Sopenharmony_ci	buf->size = buf_size;
45362306a36Sopenharmony_ci	return buf;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cifree_buf:
45662306a36Sopenharmony_ci	kfree(buf);
45762306a36Sopenharmony_cifail:
45862306a36Sopenharmony_ci	return NULL;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci/* Callers should take appropriate locks */
46262306a36Sopenharmony_cistatic struct port_buffer *get_inbuf(struct port *port)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct port_buffer *buf;
46562306a36Sopenharmony_ci	unsigned int len;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (port->inbuf)
46862306a36Sopenharmony_ci		return port->inbuf;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	buf = virtqueue_get_buf(port->in_vq, &len);
47162306a36Sopenharmony_ci	if (buf) {
47262306a36Sopenharmony_ci		buf->len = min_t(size_t, len, buf->size);
47362306a36Sopenharmony_ci		buf->offset = 0;
47462306a36Sopenharmony_ci		port->stats.bytes_received += len;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci	return buf;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci/*
48062306a36Sopenharmony_ci * Create a scatter-gather list representing our input buffer and put
48162306a36Sopenharmony_ci * it in the queue.
48262306a36Sopenharmony_ci *
48362306a36Sopenharmony_ci * Callers should take appropriate locks.
48462306a36Sopenharmony_ci */
48562306a36Sopenharmony_cistatic int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct scatterlist sg[1];
48862306a36Sopenharmony_ci	int ret;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	sg_init_one(sg, buf->buf, buf->size);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	ret = virtqueue_add_inbuf(vq, sg, 1, buf, GFP_ATOMIC);
49362306a36Sopenharmony_ci	virtqueue_kick(vq);
49462306a36Sopenharmony_ci	if (!ret)
49562306a36Sopenharmony_ci		ret = vq->num_free;
49662306a36Sopenharmony_ci	return ret;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/* Discard any unread data this port has. Callers lockers. */
50062306a36Sopenharmony_cistatic void discard_port_data(struct port *port)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct port_buffer *buf;
50362306a36Sopenharmony_ci	unsigned int err;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (!port->portdev) {
50662306a36Sopenharmony_ci		/* Device has been unplugged.  vqs are already gone. */
50762306a36Sopenharmony_ci		return;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	buf = get_inbuf(port);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	err = 0;
51262306a36Sopenharmony_ci	while (buf) {
51362306a36Sopenharmony_ci		port->stats.bytes_discarded += buf->len - buf->offset;
51462306a36Sopenharmony_ci		if (add_inbuf(port->in_vq, buf) < 0) {
51562306a36Sopenharmony_ci			err++;
51662306a36Sopenharmony_ci			free_buf(buf, false);
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci		port->inbuf = NULL;
51962306a36Sopenharmony_ci		buf = get_inbuf(port);
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci	if (err)
52262306a36Sopenharmony_ci		dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
52362306a36Sopenharmony_ci			 err);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic bool port_has_data(struct port *port)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	unsigned long flags;
52962306a36Sopenharmony_ci	bool ret;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	ret = false;
53262306a36Sopenharmony_ci	spin_lock_irqsave(&port->inbuf_lock, flags);
53362306a36Sopenharmony_ci	port->inbuf = get_inbuf(port);
53462306a36Sopenharmony_ci	if (port->inbuf)
53562306a36Sopenharmony_ci		ret = true;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	spin_unlock_irqrestore(&port->inbuf_lock, flags);
53862306a36Sopenharmony_ci	return ret;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
54262306a36Sopenharmony_ci				  unsigned int event, unsigned int value)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct scatterlist sg[1];
54562306a36Sopenharmony_ci	struct virtqueue *vq;
54662306a36Sopenharmony_ci	unsigned int len;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	if (!use_multiport(portdev))
54962306a36Sopenharmony_ci		return 0;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	vq = portdev->c_ovq;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	spin_lock(&portdev->c_ovq_lock);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	portdev->cpkt.id = cpu_to_virtio32(portdev->vdev, port_id);
55662306a36Sopenharmony_ci	portdev->cpkt.event = cpu_to_virtio16(portdev->vdev, event);
55762306a36Sopenharmony_ci	portdev->cpkt.value = cpu_to_virtio16(portdev->vdev, value);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	sg_init_one(sg, &portdev->cpkt, sizeof(struct virtio_console_control));
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (virtqueue_add_outbuf(vq, sg, 1, &portdev->cpkt, GFP_ATOMIC) == 0) {
56262306a36Sopenharmony_ci		virtqueue_kick(vq);
56362306a36Sopenharmony_ci		while (!virtqueue_get_buf(vq, &len)
56462306a36Sopenharmony_ci			&& !virtqueue_is_broken(vq))
56562306a36Sopenharmony_ci			cpu_relax();
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	spin_unlock(&portdev->c_ovq_lock);
56962306a36Sopenharmony_ci	return 0;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic ssize_t send_control_msg(struct port *port, unsigned int event,
57362306a36Sopenharmony_ci				unsigned int value)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	/* Did the port get unplugged before userspace closed it? */
57662306a36Sopenharmony_ci	if (port->portdev)
57762306a36Sopenharmony_ci		return __send_control_msg(port->portdev, port->id, event, value);
57862306a36Sopenharmony_ci	return 0;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci/* Callers must take the port->outvq_lock */
58362306a36Sopenharmony_cistatic void reclaim_consumed_buffers(struct port *port)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct port_buffer *buf;
58662306a36Sopenharmony_ci	unsigned int len;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (!port->portdev) {
58962306a36Sopenharmony_ci		/* Device has been unplugged.  vqs are already gone. */
59062306a36Sopenharmony_ci		return;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci	while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
59362306a36Sopenharmony_ci		free_buf(buf, false);
59462306a36Sopenharmony_ci		port->outvq_full = false;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
59962306a36Sopenharmony_ci			      int nents, size_t in_count,
60062306a36Sopenharmony_ci			      void *data, bool nonblock)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	struct virtqueue *out_vq;
60362306a36Sopenharmony_ci	int err;
60462306a36Sopenharmony_ci	unsigned long flags;
60562306a36Sopenharmony_ci	unsigned int len;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	out_vq = port->out_vq;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	spin_lock_irqsave(&port->outvq_lock, flags);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	reclaim_consumed_buffers(port);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	err = virtqueue_add_outbuf(out_vq, sg, nents, data, GFP_ATOMIC);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* Tell Host to go! */
61662306a36Sopenharmony_ci	virtqueue_kick(out_vq);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (err) {
61962306a36Sopenharmony_ci		in_count = 0;
62062306a36Sopenharmony_ci		goto done;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (out_vq->num_free == 0)
62462306a36Sopenharmony_ci		port->outvq_full = true;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (nonblock)
62762306a36Sopenharmony_ci		goto done;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	/*
63062306a36Sopenharmony_ci	 * Wait till the host acknowledges it pushed out the data we
63162306a36Sopenharmony_ci	 * sent.  This is done for data from the hvc_console; the tty
63262306a36Sopenharmony_ci	 * operations are performed with spinlocks held so we can't
63362306a36Sopenharmony_ci	 * sleep here.  An alternative would be to copy the data to a
63462306a36Sopenharmony_ci	 * buffer and relax the spinning requirement.  The downside is
63562306a36Sopenharmony_ci	 * we need to kmalloc a GFP_ATOMIC buffer each time the
63662306a36Sopenharmony_ci	 * console driver writes something out.
63762306a36Sopenharmony_ci	 */
63862306a36Sopenharmony_ci	while (!virtqueue_get_buf(out_vq, &len)
63962306a36Sopenharmony_ci		&& !virtqueue_is_broken(out_vq))
64062306a36Sopenharmony_ci		cpu_relax();
64162306a36Sopenharmony_cidone:
64262306a36Sopenharmony_ci	spin_unlock_irqrestore(&port->outvq_lock, flags);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	port->stats.bytes_sent += in_count;
64562306a36Sopenharmony_ci	/*
64662306a36Sopenharmony_ci	 * We're expected to return the amount of data we wrote -- all
64762306a36Sopenharmony_ci	 * of it
64862306a36Sopenharmony_ci	 */
64962306a36Sopenharmony_ci	return in_count;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci/*
65362306a36Sopenharmony_ci * Give out the data that's requested from the buffer that we have
65462306a36Sopenharmony_ci * queued up.
65562306a36Sopenharmony_ci */
65662306a36Sopenharmony_cistatic ssize_t fill_readbuf(struct port *port, char __user *out_buf,
65762306a36Sopenharmony_ci			    size_t out_count, bool to_user)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct port_buffer *buf;
66062306a36Sopenharmony_ci	unsigned long flags;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (!out_count || !port_has_data(port))
66362306a36Sopenharmony_ci		return 0;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	buf = port->inbuf;
66662306a36Sopenharmony_ci	out_count = min(out_count, buf->len - buf->offset);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	if (to_user) {
66962306a36Sopenharmony_ci		ssize_t ret;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count);
67262306a36Sopenharmony_ci		if (ret)
67362306a36Sopenharmony_ci			return -EFAULT;
67462306a36Sopenharmony_ci	} else {
67562306a36Sopenharmony_ci		memcpy((__force char *)out_buf, buf->buf + buf->offset,
67662306a36Sopenharmony_ci		       out_count);
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	buf->offset += out_count;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (buf->offset == buf->len) {
68262306a36Sopenharmony_ci		/*
68362306a36Sopenharmony_ci		 * We're done using all the data in this buffer.
68462306a36Sopenharmony_ci		 * Re-queue so that the Host can send us more data.
68562306a36Sopenharmony_ci		 */
68662306a36Sopenharmony_ci		spin_lock_irqsave(&port->inbuf_lock, flags);
68762306a36Sopenharmony_ci		port->inbuf = NULL;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		if (add_inbuf(port->in_vq, buf) < 0)
69062306a36Sopenharmony_ci			dev_warn(port->dev, "failed add_buf\n");
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		spin_unlock_irqrestore(&port->inbuf_lock, flags);
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	/* Return the number of bytes actually copied */
69562306a36Sopenharmony_ci	return out_count;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci/* The condition that must be true for polling to end */
69962306a36Sopenharmony_cistatic bool will_read_block(struct port *port)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	if (!port->guest_connected) {
70262306a36Sopenharmony_ci		/* Port got hot-unplugged. Let's exit. */
70362306a36Sopenharmony_ci		return false;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci	return !port_has_data(port) && port->host_connected;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic bool will_write_block(struct port *port)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	bool ret;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (!port->guest_connected) {
71362306a36Sopenharmony_ci		/* Port got hot-unplugged. Let's exit. */
71462306a36Sopenharmony_ci		return false;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci	if (!port->host_connected)
71762306a36Sopenharmony_ci		return true;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	spin_lock_irq(&port->outvq_lock);
72062306a36Sopenharmony_ci	/*
72162306a36Sopenharmony_ci	 * Check if the Host has consumed any buffers since we last
72262306a36Sopenharmony_ci	 * sent data (this is only applicable for nonblocking ports).
72362306a36Sopenharmony_ci	 */
72462306a36Sopenharmony_ci	reclaim_consumed_buffers(port);
72562306a36Sopenharmony_ci	ret = port->outvq_full;
72662306a36Sopenharmony_ci	spin_unlock_irq(&port->outvq_lock);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	return ret;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic ssize_t port_fops_read(struct file *filp, char __user *ubuf,
73262306a36Sopenharmony_ci			      size_t count, loff_t *offp)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct port *port;
73562306a36Sopenharmony_ci	ssize_t ret;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	port = filp->private_data;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* Port is hot-unplugged. */
74062306a36Sopenharmony_ci	if (!port->guest_connected)
74162306a36Sopenharmony_ci		return -ENODEV;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (!port_has_data(port)) {
74462306a36Sopenharmony_ci		/*
74562306a36Sopenharmony_ci		 * If nothing's connected on the host just return 0 in
74662306a36Sopenharmony_ci		 * case of list_empty; this tells the userspace app
74762306a36Sopenharmony_ci		 * that there's no connection
74862306a36Sopenharmony_ci		 */
74962306a36Sopenharmony_ci		if (!port->host_connected)
75062306a36Sopenharmony_ci			return 0;
75162306a36Sopenharmony_ci		if (filp->f_flags & O_NONBLOCK)
75262306a36Sopenharmony_ci			return -EAGAIN;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		ret = wait_event_freezable(port->waitqueue,
75562306a36Sopenharmony_ci					   !will_read_block(port));
75662306a36Sopenharmony_ci		if (ret < 0)
75762306a36Sopenharmony_ci			return ret;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci	/* Port got hot-unplugged while we were waiting above. */
76062306a36Sopenharmony_ci	if (!port->guest_connected)
76162306a36Sopenharmony_ci		return -ENODEV;
76262306a36Sopenharmony_ci	/*
76362306a36Sopenharmony_ci	 * We could've received a disconnection message while we were
76462306a36Sopenharmony_ci	 * waiting for more data.
76562306a36Sopenharmony_ci	 *
76662306a36Sopenharmony_ci	 * This check is not clubbed in the if() statement above as we
76762306a36Sopenharmony_ci	 * might receive some data as well as the host could get
76862306a36Sopenharmony_ci	 * disconnected after we got woken up from our wait.  So we
76962306a36Sopenharmony_ci	 * really want to give off whatever data we have and only then
77062306a36Sopenharmony_ci	 * check for host_connected.
77162306a36Sopenharmony_ci	 */
77262306a36Sopenharmony_ci	if (!port_has_data(port) && !port->host_connected)
77362306a36Sopenharmony_ci		return 0;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return fill_readbuf(port, ubuf, count, true);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic int wait_port_writable(struct port *port, bool nonblock)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	int ret;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (will_write_block(port)) {
78362306a36Sopenharmony_ci		if (nonblock)
78462306a36Sopenharmony_ci			return -EAGAIN;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		ret = wait_event_freezable(port->waitqueue,
78762306a36Sopenharmony_ci					   !will_write_block(port));
78862306a36Sopenharmony_ci		if (ret < 0)
78962306a36Sopenharmony_ci			return ret;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci	/* Port got hot-unplugged. */
79262306a36Sopenharmony_ci	if (!port->guest_connected)
79362306a36Sopenharmony_ci		return -ENODEV;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	return 0;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
79962306a36Sopenharmony_ci			       size_t count, loff_t *offp)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	struct port *port;
80262306a36Sopenharmony_ci	struct port_buffer *buf;
80362306a36Sopenharmony_ci	ssize_t ret;
80462306a36Sopenharmony_ci	bool nonblock;
80562306a36Sopenharmony_ci	struct scatterlist sg[1];
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* Userspace could be out to fool us */
80862306a36Sopenharmony_ci	if (!count)
80962306a36Sopenharmony_ci		return 0;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	port = filp->private_data;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	nonblock = filp->f_flags & O_NONBLOCK;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	ret = wait_port_writable(port, nonblock);
81662306a36Sopenharmony_ci	if (ret < 0)
81762306a36Sopenharmony_ci		return ret;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	count = min((size_t)(32 * 1024), count);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	buf = alloc_buf(port->portdev->vdev, count, 0);
82262306a36Sopenharmony_ci	if (!buf)
82362306a36Sopenharmony_ci		return -ENOMEM;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	ret = copy_from_user(buf->buf, ubuf, count);
82662306a36Sopenharmony_ci	if (ret) {
82762306a36Sopenharmony_ci		ret = -EFAULT;
82862306a36Sopenharmony_ci		goto free_buf;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/*
83262306a36Sopenharmony_ci	 * We now ask send_buf() to not spin for generic ports -- we
83362306a36Sopenharmony_ci	 * can re-use the same code path that non-blocking file
83462306a36Sopenharmony_ci	 * descriptors take for blocking file descriptors since the
83562306a36Sopenharmony_ci	 * wait is already done and we're certain the write will go
83662306a36Sopenharmony_ci	 * through to the host.
83762306a36Sopenharmony_ci	 */
83862306a36Sopenharmony_ci	nonblock = true;
83962306a36Sopenharmony_ci	sg_init_one(sg, buf->buf, count);
84062306a36Sopenharmony_ci	ret = __send_to_port(port, sg, 1, count, buf, nonblock);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (nonblock && ret > 0)
84362306a36Sopenharmony_ci		goto out;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cifree_buf:
84662306a36Sopenharmony_ci	free_buf(buf, true);
84762306a36Sopenharmony_ciout:
84862306a36Sopenharmony_ci	return ret;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistruct sg_list {
85262306a36Sopenharmony_ci	unsigned int n;
85362306a36Sopenharmony_ci	unsigned int size;
85462306a36Sopenharmony_ci	size_t len;
85562306a36Sopenharmony_ci	struct scatterlist *sg;
85662306a36Sopenharmony_ci};
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
85962306a36Sopenharmony_ci			struct splice_desc *sd)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	struct sg_list *sgl = sd->u.data;
86262306a36Sopenharmony_ci	unsigned int offset, len;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (sgl->n == sgl->size)
86562306a36Sopenharmony_ci		return 0;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	/* Try lock this page */
86862306a36Sopenharmony_ci	if (pipe_buf_try_steal(pipe, buf)) {
86962306a36Sopenharmony_ci		/* Get reference and unlock page for moving */
87062306a36Sopenharmony_ci		get_page(buf->page);
87162306a36Sopenharmony_ci		unlock_page(buf->page);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci		len = min(buf->len, sd->len);
87462306a36Sopenharmony_ci		sg_set_page(&(sgl->sg[sgl->n]), buf->page, len, buf->offset);
87562306a36Sopenharmony_ci	} else {
87662306a36Sopenharmony_ci		/* Failback to copying a page */
87762306a36Sopenharmony_ci		struct page *page = alloc_page(GFP_KERNEL);
87862306a36Sopenharmony_ci		char *src;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci		if (!page)
88162306a36Sopenharmony_ci			return -ENOMEM;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci		offset = sd->pos & ~PAGE_MASK;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci		len = sd->len;
88662306a36Sopenharmony_ci		if (len + offset > PAGE_SIZE)
88762306a36Sopenharmony_ci			len = PAGE_SIZE - offset;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		src = kmap_atomic(buf->page);
89062306a36Sopenharmony_ci		memcpy(page_address(page) + offset, src + buf->offset, len);
89162306a36Sopenharmony_ci		kunmap_atomic(src);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci		sg_set_page(&(sgl->sg[sgl->n]), page, len, offset);
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci	sgl->n++;
89662306a36Sopenharmony_ci	sgl->len += len;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	return len;
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci/* Faster zero-copy write by splicing */
90262306a36Sopenharmony_cistatic ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
90362306a36Sopenharmony_ci				      struct file *filp, loff_t *ppos,
90462306a36Sopenharmony_ci				      size_t len, unsigned int flags)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	struct port *port = filp->private_data;
90762306a36Sopenharmony_ci	struct sg_list sgl;
90862306a36Sopenharmony_ci	ssize_t ret;
90962306a36Sopenharmony_ci	struct port_buffer *buf;
91062306a36Sopenharmony_ci	struct splice_desc sd = {
91162306a36Sopenharmony_ci		.total_len = len,
91262306a36Sopenharmony_ci		.flags = flags,
91362306a36Sopenharmony_ci		.pos = *ppos,
91462306a36Sopenharmony_ci		.u.data = &sgl,
91562306a36Sopenharmony_ci	};
91662306a36Sopenharmony_ci	unsigned int occupancy;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	/*
91962306a36Sopenharmony_ci	 * Rproc_serial does not yet support splice. To support splice
92062306a36Sopenharmony_ci	 * pipe_to_sg() must allocate dma-buffers and copy content from
92162306a36Sopenharmony_ci	 * regular pages to dma pages. And alloc_buf and free_buf must
92262306a36Sopenharmony_ci	 * support allocating and freeing such a list of dma-buffers.
92362306a36Sopenharmony_ci	 */
92462306a36Sopenharmony_ci	if (is_rproc_serial(port->out_vq->vdev))
92562306a36Sopenharmony_ci		return -EINVAL;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	pipe_lock(pipe);
92862306a36Sopenharmony_ci	ret = 0;
92962306a36Sopenharmony_ci	if (pipe_empty(pipe->head, pipe->tail))
93062306a36Sopenharmony_ci		goto error_out;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
93362306a36Sopenharmony_ci	if (ret < 0)
93462306a36Sopenharmony_ci		goto error_out;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	occupancy = pipe_occupancy(pipe->head, pipe->tail);
93762306a36Sopenharmony_ci	buf = alloc_buf(port->portdev->vdev, 0, occupancy);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	if (!buf) {
94062306a36Sopenharmony_ci		ret = -ENOMEM;
94162306a36Sopenharmony_ci		goto error_out;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	sgl.n = 0;
94562306a36Sopenharmony_ci	sgl.len = 0;
94662306a36Sopenharmony_ci	sgl.size = occupancy;
94762306a36Sopenharmony_ci	sgl.sg = buf->sg;
94862306a36Sopenharmony_ci	sg_init_table(sgl.sg, sgl.size);
94962306a36Sopenharmony_ci	ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
95062306a36Sopenharmony_ci	pipe_unlock(pipe);
95162306a36Sopenharmony_ci	if (likely(ret > 0))
95262306a36Sopenharmony_ci		ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	if (unlikely(ret <= 0))
95562306a36Sopenharmony_ci		free_buf(buf, true);
95662306a36Sopenharmony_ci	return ret;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_cierror_out:
95962306a36Sopenharmony_ci	pipe_unlock(pipe);
96062306a36Sopenharmony_ci	return ret;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic __poll_t port_fops_poll(struct file *filp, poll_table *wait)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct port *port;
96662306a36Sopenharmony_ci	__poll_t ret;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	port = filp->private_data;
96962306a36Sopenharmony_ci	poll_wait(filp, &port->waitqueue, wait);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (!port->guest_connected) {
97262306a36Sopenharmony_ci		/* Port got unplugged */
97362306a36Sopenharmony_ci		return EPOLLHUP;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci	ret = 0;
97662306a36Sopenharmony_ci	if (!will_read_block(port))
97762306a36Sopenharmony_ci		ret |= EPOLLIN | EPOLLRDNORM;
97862306a36Sopenharmony_ci	if (!will_write_block(port))
97962306a36Sopenharmony_ci		ret |= EPOLLOUT;
98062306a36Sopenharmony_ci	if (!port->host_connected)
98162306a36Sopenharmony_ci		ret |= EPOLLHUP;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	return ret;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_cistatic void remove_port(struct kref *kref);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistatic int port_fops_release(struct inode *inode, struct file *filp)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct port *port;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	port = filp->private_data;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	/* Notify host of port being closed */
99562306a36Sopenharmony_ci	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	spin_lock_irq(&port->inbuf_lock);
99862306a36Sopenharmony_ci	port->guest_connected = false;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	discard_port_data(port);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	spin_unlock_irq(&port->inbuf_lock);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	spin_lock_irq(&port->outvq_lock);
100562306a36Sopenharmony_ci	reclaim_consumed_buffers(port);
100662306a36Sopenharmony_ci	spin_unlock_irq(&port->outvq_lock);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	reclaim_dma_bufs();
100962306a36Sopenharmony_ci	/*
101062306a36Sopenharmony_ci	 * Locks aren't necessary here as a port can't be opened after
101162306a36Sopenharmony_ci	 * unplug, and if a port isn't unplugged, a kref would already
101262306a36Sopenharmony_ci	 * exist for the port.  Plus, taking ports_lock here would
101362306a36Sopenharmony_ci	 * create a dependency on other locks taken by functions
101462306a36Sopenharmony_ci	 * inside remove_port if we're the last holder of the port,
101562306a36Sopenharmony_ci	 * creating many problems.
101662306a36Sopenharmony_ci	 */
101762306a36Sopenharmony_ci	kref_put(&port->kref, remove_port);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	return 0;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic int port_fops_open(struct inode *inode, struct file *filp)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	struct cdev *cdev = inode->i_cdev;
102562306a36Sopenharmony_ci	struct port *port;
102662306a36Sopenharmony_ci	int ret;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/* We get the port with a kref here */
102962306a36Sopenharmony_ci	port = find_port_by_devt(cdev->dev);
103062306a36Sopenharmony_ci	if (!port) {
103162306a36Sopenharmony_ci		/* Port was unplugged before we could proceed */
103262306a36Sopenharmony_ci		return -ENXIO;
103362306a36Sopenharmony_ci	}
103462306a36Sopenharmony_ci	filp->private_data = port;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	/*
103762306a36Sopenharmony_ci	 * Don't allow opening of console port devices -- that's done
103862306a36Sopenharmony_ci	 * via /dev/hvc
103962306a36Sopenharmony_ci	 */
104062306a36Sopenharmony_ci	if (is_console_port(port)) {
104162306a36Sopenharmony_ci		ret = -ENXIO;
104262306a36Sopenharmony_ci		goto out;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	/* Allow only one process to open a particular port at a time */
104662306a36Sopenharmony_ci	spin_lock_irq(&port->inbuf_lock);
104762306a36Sopenharmony_ci	if (port->guest_connected) {
104862306a36Sopenharmony_ci		spin_unlock_irq(&port->inbuf_lock);
104962306a36Sopenharmony_ci		ret = -EBUSY;
105062306a36Sopenharmony_ci		goto out;
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	port->guest_connected = true;
105462306a36Sopenharmony_ci	spin_unlock_irq(&port->inbuf_lock);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	spin_lock_irq(&port->outvq_lock);
105762306a36Sopenharmony_ci	/*
105862306a36Sopenharmony_ci	 * There might be a chance that we missed reclaiming a few
105962306a36Sopenharmony_ci	 * buffers in the window of the port getting previously closed
106062306a36Sopenharmony_ci	 * and opening now.
106162306a36Sopenharmony_ci	 */
106262306a36Sopenharmony_ci	reclaim_consumed_buffers(port);
106362306a36Sopenharmony_ci	spin_unlock_irq(&port->outvq_lock);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	nonseekable_open(inode, filp);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/* Notify host of port being opened */
106862306a36Sopenharmony_ci	send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	return 0;
107162306a36Sopenharmony_ciout:
107262306a36Sopenharmony_ci	kref_put(&port->kref, remove_port);
107362306a36Sopenharmony_ci	return ret;
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistatic int port_fops_fasync(int fd, struct file *filp, int mode)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	struct port *port;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	port = filp->private_data;
108162306a36Sopenharmony_ci	return fasync_helper(fd, filp, mode, &port->async_queue);
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci/*
108562306a36Sopenharmony_ci * The file operations that we support: programs in the guest can open
108662306a36Sopenharmony_ci * a console device, read from it, write to it, poll for data and
108762306a36Sopenharmony_ci * close it.  The devices are at
108862306a36Sopenharmony_ci *   /dev/vport<device number>p<port number>
108962306a36Sopenharmony_ci */
109062306a36Sopenharmony_cistatic const struct file_operations port_fops = {
109162306a36Sopenharmony_ci	.owner = THIS_MODULE,
109262306a36Sopenharmony_ci	.open  = port_fops_open,
109362306a36Sopenharmony_ci	.read  = port_fops_read,
109462306a36Sopenharmony_ci	.write = port_fops_write,
109562306a36Sopenharmony_ci	.splice_write = port_fops_splice_write,
109662306a36Sopenharmony_ci	.poll  = port_fops_poll,
109762306a36Sopenharmony_ci	.release = port_fops_release,
109862306a36Sopenharmony_ci	.fasync = port_fops_fasync,
109962306a36Sopenharmony_ci	.llseek = no_llseek,
110062306a36Sopenharmony_ci};
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci/*
110362306a36Sopenharmony_ci * The put_chars() callback is pretty straightforward.
110462306a36Sopenharmony_ci *
110562306a36Sopenharmony_ci * We turn the characters into a scatter-gather list, add it to the
110662306a36Sopenharmony_ci * output queue and then kick the Host.  Then we sit here waiting for
110762306a36Sopenharmony_ci * it to finish: inefficient in theory, but in practice
110862306a36Sopenharmony_ci * implementations will do it immediately.
110962306a36Sopenharmony_ci */
111062306a36Sopenharmony_cistatic int put_chars(u32 vtermno, const char *buf, int count)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	struct port *port;
111362306a36Sopenharmony_ci	struct scatterlist sg[1];
111462306a36Sopenharmony_ci	void *data;
111562306a36Sopenharmony_ci	int ret;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (unlikely(early_put_chars))
111862306a36Sopenharmony_ci		return early_put_chars(vtermno, buf, count);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	port = find_port_by_vtermno(vtermno);
112162306a36Sopenharmony_ci	if (!port)
112262306a36Sopenharmony_ci		return -EPIPE;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	data = kmemdup(buf, count, GFP_ATOMIC);
112562306a36Sopenharmony_ci	if (!data)
112662306a36Sopenharmony_ci		return -ENOMEM;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	sg_init_one(sg, data, count);
112962306a36Sopenharmony_ci	ret = __send_to_port(port, sg, 1, count, data, false);
113062306a36Sopenharmony_ci	kfree(data);
113162306a36Sopenharmony_ci	return ret;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci/*
113562306a36Sopenharmony_ci * get_chars() is the callback from the hvc_console infrastructure
113662306a36Sopenharmony_ci * when an interrupt is received.
113762306a36Sopenharmony_ci *
113862306a36Sopenharmony_ci * We call out to fill_readbuf that gets us the required data from the
113962306a36Sopenharmony_ci * buffers that are queued up.
114062306a36Sopenharmony_ci */
114162306a36Sopenharmony_cistatic int get_chars(u32 vtermno, char *buf, int count)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct port *port;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	/* If we've not set up the port yet, we have no input to give. */
114662306a36Sopenharmony_ci	if (unlikely(early_put_chars))
114762306a36Sopenharmony_ci		return 0;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	port = find_port_by_vtermno(vtermno);
115062306a36Sopenharmony_ci	if (!port)
115162306a36Sopenharmony_ci		return -EPIPE;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/* If we don't have an input queue yet, we can't get input. */
115462306a36Sopenharmony_ci	BUG_ON(!port->in_vq);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	return fill_readbuf(port, (__force char __user *)buf, count, false);
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_cistatic void resize_console(struct port *port)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	struct virtio_device *vdev;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	/* The port could have been hot-unplugged */
116462306a36Sopenharmony_ci	if (!port || !is_console_port(port))
116562306a36Sopenharmony_ci		return;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	vdev = port->portdev->vdev;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	/* Don't test F_SIZE at all if we're rproc: not a valid feature! */
117062306a36Sopenharmony_ci	if (!is_rproc_serial(vdev) &&
117162306a36Sopenharmony_ci	    virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
117262306a36Sopenharmony_ci		hvc_resize(port->cons.hvc, port->cons.ws);
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci/* We set the configuration at this point, since we now have a tty */
117662306a36Sopenharmony_cistatic int notifier_add_vio(struct hvc_struct *hp, int data)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	struct port *port;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	port = find_port_by_vtermno(hp->vtermno);
118162306a36Sopenharmony_ci	if (!port)
118262306a36Sopenharmony_ci		return -EINVAL;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	hp->irq_requested = 1;
118562306a36Sopenharmony_ci	resize_console(port);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	return 0;
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic void notifier_del_vio(struct hvc_struct *hp, int data)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	hp->irq_requested = 0;
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci/* The operations for console ports. */
119662306a36Sopenharmony_cistatic const struct hv_ops hv_ops = {
119762306a36Sopenharmony_ci	.get_chars = get_chars,
119862306a36Sopenharmony_ci	.put_chars = put_chars,
119962306a36Sopenharmony_ci	.notifier_add = notifier_add_vio,
120062306a36Sopenharmony_ci	.notifier_del = notifier_del_vio,
120162306a36Sopenharmony_ci	.notifier_hangup = notifier_del_vio,
120262306a36Sopenharmony_ci};
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci/*
120562306a36Sopenharmony_ci * Console drivers are initialized very early so boot messages can go
120662306a36Sopenharmony_ci * out, so we do things slightly differently from the generic virtio
120762306a36Sopenharmony_ci * initialization of the net and block drivers.
120862306a36Sopenharmony_ci *
120962306a36Sopenharmony_ci * At this stage, the console is output-only.  It's too early to set
121062306a36Sopenharmony_ci * up a virtqueue, so we let the drivers do some boutique early-output
121162306a36Sopenharmony_ci * thing.
121262306a36Sopenharmony_ci */
121362306a36Sopenharmony_ciint __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	early_put_chars = put_chars;
121662306a36Sopenharmony_ci	return hvc_instantiate(0, 0, &hv_ops);
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic int init_port_console(struct port *port)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	int ret;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	/*
122462306a36Sopenharmony_ci	 * The Host's telling us this port is a console port.  Hook it
122562306a36Sopenharmony_ci	 * up with an hvc console.
122662306a36Sopenharmony_ci	 *
122762306a36Sopenharmony_ci	 * To set up and manage our virtual console, we call
122862306a36Sopenharmony_ci	 * hvc_alloc().
122962306a36Sopenharmony_ci	 *
123062306a36Sopenharmony_ci	 * The first argument of hvc_alloc() is the virtual console
123162306a36Sopenharmony_ci	 * number.  The second argument is the parameter for the
123262306a36Sopenharmony_ci	 * notification mechanism (like irq number).  We currently
123362306a36Sopenharmony_ci	 * leave this as zero, virtqueues have implicit notifications.
123462306a36Sopenharmony_ci	 *
123562306a36Sopenharmony_ci	 * The third argument is a "struct hv_ops" containing the
123662306a36Sopenharmony_ci	 * put_chars() get_chars(), notifier_add() and notifier_del()
123762306a36Sopenharmony_ci	 * pointers.  The final argument is the output buffer size: we
123862306a36Sopenharmony_ci	 * can do any size, so we put PAGE_SIZE here.
123962306a36Sopenharmony_ci	 */
124062306a36Sopenharmony_ci	ret = ida_alloc_min(&vtermno_ida, 1, GFP_KERNEL);
124162306a36Sopenharmony_ci	if (ret < 0)
124262306a36Sopenharmony_ci		return ret;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	port->cons.vtermno = ret;
124562306a36Sopenharmony_ci	port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
124662306a36Sopenharmony_ci	if (IS_ERR(port->cons.hvc)) {
124762306a36Sopenharmony_ci		ret = PTR_ERR(port->cons.hvc);
124862306a36Sopenharmony_ci		dev_err(port->dev,
124962306a36Sopenharmony_ci			"error %d allocating hvc for port\n", ret);
125062306a36Sopenharmony_ci		port->cons.hvc = NULL;
125162306a36Sopenharmony_ci		ida_free(&vtermno_ida, port->cons.vtermno);
125262306a36Sopenharmony_ci		return ret;
125362306a36Sopenharmony_ci	}
125462306a36Sopenharmony_ci	spin_lock_irq(&pdrvdata_lock);
125562306a36Sopenharmony_ci	list_add_tail(&port->cons.list, &pdrvdata.consoles);
125662306a36Sopenharmony_ci	spin_unlock_irq(&pdrvdata_lock);
125762306a36Sopenharmony_ci	port->guest_connected = true;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/*
126062306a36Sopenharmony_ci	 * Start using the new console output if this is the first
126162306a36Sopenharmony_ci	 * console to come up.
126262306a36Sopenharmony_ci	 */
126362306a36Sopenharmony_ci	if (early_put_chars)
126462306a36Sopenharmony_ci		early_put_chars = NULL;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	/* Notify host of port being opened */
126762306a36Sopenharmony_ci	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	return 0;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic ssize_t show_port_name(struct device *dev,
127362306a36Sopenharmony_ci			      struct device_attribute *attr, char *buffer)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	struct port *port;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	port = dev_get_drvdata(dev);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	return sprintf(buffer, "%s\n", port->name);
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic struct attribute *port_sysfs_entries[] = {
128562306a36Sopenharmony_ci	&dev_attr_name.attr,
128662306a36Sopenharmony_ci	NULL
128762306a36Sopenharmony_ci};
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_cistatic const struct attribute_group port_attribute_group = {
129062306a36Sopenharmony_ci	.name = NULL,		/* put in device directory */
129162306a36Sopenharmony_ci	.attrs = port_sysfs_entries,
129262306a36Sopenharmony_ci};
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cistatic int port_debugfs_show(struct seq_file *s, void *data)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	struct port *port = s->private;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	seq_printf(s, "name: %s\n", port->name ? port->name : "");
129962306a36Sopenharmony_ci	seq_printf(s, "guest_connected: %d\n", port->guest_connected);
130062306a36Sopenharmony_ci	seq_printf(s, "host_connected: %d\n", port->host_connected);
130162306a36Sopenharmony_ci	seq_printf(s, "outvq_full: %d\n", port->outvq_full);
130262306a36Sopenharmony_ci	seq_printf(s, "bytes_sent: %lu\n", port->stats.bytes_sent);
130362306a36Sopenharmony_ci	seq_printf(s, "bytes_received: %lu\n", port->stats.bytes_received);
130462306a36Sopenharmony_ci	seq_printf(s, "bytes_discarded: %lu\n", port->stats.bytes_discarded);
130562306a36Sopenharmony_ci	seq_printf(s, "is_console: %s\n",
130662306a36Sopenharmony_ci		   is_console_port(port) ? "yes" : "no");
130762306a36Sopenharmony_ci	seq_printf(s, "console_vtermno: %u\n", port->cons.vtermno);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	return 0;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(port_debugfs);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic void set_console_size(struct port *port, u16 rows, u16 cols)
131562306a36Sopenharmony_ci{
131662306a36Sopenharmony_ci	if (!port || !is_console_port(port))
131762306a36Sopenharmony_ci		return;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	port->cons.ws.ws_row = rows;
132062306a36Sopenharmony_ci	port->cons.ws.ws_col = cols;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cistatic int fill_queue(struct virtqueue *vq, spinlock_t *lock)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	struct port_buffer *buf;
132662306a36Sopenharmony_ci	int nr_added_bufs;
132762306a36Sopenharmony_ci	int ret;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	nr_added_bufs = 0;
133062306a36Sopenharmony_ci	do {
133162306a36Sopenharmony_ci		buf = alloc_buf(vq->vdev, PAGE_SIZE, 0);
133262306a36Sopenharmony_ci		if (!buf)
133362306a36Sopenharmony_ci			return -ENOMEM;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci		spin_lock_irq(lock);
133662306a36Sopenharmony_ci		ret = add_inbuf(vq, buf);
133762306a36Sopenharmony_ci		if (ret < 0) {
133862306a36Sopenharmony_ci			spin_unlock_irq(lock);
133962306a36Sopenharmony_ci			free_buf(buf, true);
134062306a36Sopenharmony_ci			return ret;
134162306a36Sopenharmony_ci		}
134262306a36Sopenharmony_ci		nr_added_bufs++;
134362306a36Sopenharmony_ci		spin_unlock_irq(lock);
134462306a36Sopenharmony_ci	} while (ret > 0);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	return nr_added_bufs;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_cistatic void send_sigio_to_port(struct port *port)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	if (port->async_queue && port->guest_connected)
135262306a36Sopenharmony_ci		kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
135362306a36Sopenharmony_ci}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic int add_port(struct ports_device *portdev, u32 id)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	char debugfs_name[16];
135862306a36Sopenharmony_ci	struct port *port;
135962306a36Sopenharmony_ci	dev_t devt;
136062306a36Sopenharmony_ci	int err;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	port = kmalloc(sizeof(*port), GFP_KERNEL);
136362306a36Sopenharmony_ci	if (!port) {
136462306a36Sopenharmony_ci		err = -ENOMEM;
136562306a36Sopenharmony_ci		goto fail;
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci	kref_init(&port->kref);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	port->portdev = portdev;
137062306a36Sopenharmony_ci	port->id = id;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	port->name = NULL;
137362306a36Sopenharmony_ci	port->inbuf = NULL;
137462306a36Sopenharmony_ci	port->cons.hvc = NULL;
137562306a36Sopenharmony_ci	port->async_queue = NULL;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
137862306a36Sopenharmony_ci	port->cons.vtermno = 0;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	port->host_connected = port->guest_connected = false;
138162306a36Sopenharmony_ci	port->stats = (struct port_stats) { 0 };
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	port->outvq_full = false;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	port->in_vq = portdev->in_vqs[port->id];
138662306a36Sopenharmony_ci	port->out_vq = portdev->out_vqs[port->id];
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	port->cdev = cdev_alloc();
138962306a36Sopenharmony_ci	if (!port->cdev) {
139062306a36Sopenharmony_ci		dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n");
139162306a36Sopenharmony_ci		err = -ENOMEM;
139262306a36Sopenharmony_ci		goto free_port;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci	port->cdev->ops = &port_fops;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	devt = MKDEV(portdev->chr_major, id);
139762306a36Sopenharmony_ci	err = cdev_add(port->cdev, devt, 1);
139862306a36Sopenharmony_ci	if (err < 0) {
139962306a36Sopenharmony_ci		dev_err(&port->portdev->vdev->dev,
140062306a36Sopenharmony_ci			"Error %d adding cdev for port %u\n", err, id);
140162306a36Sopenharmony_ci		goto free_cdev;
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci	port->dev = device_create(&port_class, &port->portdev->vdev->dev,
140462306a36Sopenharmony_ci				  devt, port, "vport%up%u",
140562306a36Sopenharmony_ci				  port->portdev->vdev->index, id);
140662306a36Sopenharmony_ci	if (IS_ERR(port->dev)) {
140762306a36Sopenharmony_ci		err = PTR_ERR(port->dev);
140862306a36Sopenharmony_ci		dev_err(&port->portdev->vdev->dev,
140962306a36Sopenharmony_ci			"Error %d creating device for port %u\n",
141062306a36Sopenharmony_ci			err, id);
141162306a36Sopenharmony_ci		goto free_cdev;
141262306a36Sopenharmony_ci	}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	spin_lock_init(&port->inbuf_lock);
141562306a36Sopenharmony_ci	spin_lock_init(&port->outvq_lock);
141662306a36Sopenharmony_ci	init_waitqueue_head(&port->waitqueue);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	/* We can safely ignore ENOSPC because it means
141962306a36Sopenharmony_ci	 * the queue already has buffers. Buffers are removed
142062306a36Sopenharmony_ci	 * only by virtcons_remove(), not by unplug_port()
142162306a36Sopenharmony_ci	 */
142262306a36Sopenharmony_ci	err = fill_queue(port->in_vq, &port->inbuf_lock);
142362306a36Sopenharmony_ci	if (err < 0 && err != -ENOSPC) {
142462306a36Sopenharmony_ci		dev_err(port->dev, "Error allocating inbufs\n");
142562306a36Sopenharmony_ci		goto free_device;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	if (is_rproc_serial(port->portdev->vdev))
142962306a36Sopenharmony_ci		/*
143062306a36Sopenharmony_ci		 * For rproc_serial assume remote processor is connected.
143162306a36Sopenharmony_ci		 * rproc_serial does not want the console port, only
143262306a36Sopenharmony_ci		 * the generic port implementation.
143362306a36Sopenharmony_ci		 */
143462306a36Sopenharmony_ci		port->host_connected = true;
143562306a36Sopenharmony_ci	else if (!use_multiport(port->portdev)) {
143662306a36Sopenharmony_ci		/*
143762306a36Sopenharmony_ci		 * If we're not using multiport support,
143862306a36Sopenharmony_ci		 * this has to be a console port.
143962306a36Sopenharmony_ci		 */
144062306a36Sopenharmony_ci		err = init_port_console(port);
144162306a36Sopenharmony_ci		if (err)
144262306a36Sopenharmony_ci			goto free_inbufs;
144362306a36Sopenharmony_ci	}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	spin_lock_irq(&portdev->ports_lock);
144662306a36Sopenharmony_ci	list_add_tail(&port->list, &port->portdev->ports);
144762306a36Sopenharmony_ci	spin_unlock_irq(&portdev->ports_lock);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/*
145062306a36Sopenharmony_ci	 * Tell the Host we're set so that it can send us various
145162306a36Sopenharmony_ci	 * configuration parameters for this port (eg, port name,
145262306a36Sopenharmony_ci	 * caching, whether this is a console port, etc.)
145362306a36Sopenharmony_ci	 */
145462306a36Sopenharmony_ci	send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/*
145762306a36Sopenharmony_ci	 * Finally, create the debugfs file that we can use to
145862306a36Sopenharmony_ci	 * inspect a port's state at any time
145962306a36Sopenharmony_ci	 */
146062306a36Sopenharmony_ci	snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u",
146162306a36Sopenharmony_ci		 port->portdev->vdev->index, id);
146262306a36Sopenharmony_ci	port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
146362306a36Sopenharmony_ci						 pdrvdata.debugfs_dir,
146462306a36Sopenharmony_ci						 port, &port_debugfs_fops);
146562306a36Sopenharmony_ci	return 0;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_cifree_inbufs:
146862306a36Sopenharmony_cifree_device:
146962306a36Sopenharmony_ci	device_destroy(&port_class, port->dev->devt);
147062306a36Sopenharmony_cifree_cdev:
147162306a36Sopenharmony_ci	cdev_del(port->cdev);
147262306a36Sopenharmony_cifree_port:
147362306a36Sopenharmony_ci	kfree(port);
147462306a36Sopenharmony_cifail:
147562306a36Sopenharmony_ci	/* The host might want to notify management sw about port add failure */
147662306a36Sopenharmony_ci	__send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0);
147762306a36Sopenharmony_ci	return err;
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci/* No users remain, remove all port-specific data. */
148162306a36Sopenharmony_cistatic void remove_port(struct kref *kref)
148262306a36Sopenharmony_ci{
148362306a36Sopenharmony_ci	struct port *port;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	port = container_of(kref, struct port, kref);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	kfree(port);
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic void remove_port_data(struct port *port)
149162306a36Sopenharmony_ci{
149262306a36Sopenharmony_ci	spin_lock_irq(&port->inbuf_lock);
149362306a36Sopenharmony_ci	/* Remove unused data this port might have received. */
149462306a36Sopenharmony_ci	discard_port_data(port);
149562306a36Sopenharmony_ci	spin_unlock_irq(&port->inbuf_lock);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	spin_lock_irq(&port->outvq_lock);
149862306a36Sopenharmony_ci	reclaim_consumed_buffers(port);
149962306a36Sopenharmony_ci	spin_unlock_irq(&port->outvq_lock);
150062306a36Sopenharmony_ci}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci/*
150362306a36Sopenharmony_ci * Port got unplugged.  Remove port from portdev's list and drop the
150462306a36Sopenharmony_ci * kref reference.  If no userspace has this port opened, it will
150562306a36Sopenharmony_ci * result in immediate removal the port.
150662306a36Sopenharmony_ci */
150762306a36Sopenharmony_cistatic void unplug_port(struct port *port)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	spin_lock_irq(&port->portdev->ports_lock);
151062306a36Sopenharmony_ci	list_del(&port->list);
151162306a36Sopenharmony_ci	spin_unlock_irq(&port->portdev->ports_lock);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	spin_lock_irq(&port->inbuf_lock);
151462306a36Sopenharmony_ci	if (port->guest_connected) {
151562306a36Sopenharmony_ci		/* Let the app know the port is going down. */
151662306a36Sopenharmony_ci		send_sigio_to_port(port);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci		/* Do this after sigio is actually sent */
151962306a36Sopenharmony_ci		port->guest_connected = false;
152062306a36Sopenharmony_ci		port->host_connected = false;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci		wake_up_interruptible(&port->waitqueue);
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci	spin_unlock_irq(&port->inbuf_lock);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	if (is_console_port(port)) {
152762306a36Sopenharmony_ci		spin_lock_irq(&pdrvdata_lock);
152862306a36Sopenharmony_ci		list_del(&port->cons.list);
152962306a36Sopenharmony_ci		spin_unlock_irq(&pdrvdata_lock);
153062306a36Sopenharmony_ci		hvc_remove(port->cons.hvc);
153162306a36Sopenharmony_ci		ida_free(&vtermno_ida, port->cons.vtermno);
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	remove_port_data(port);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	/*
153762306a36Sopenharmony_ci	 * We should just assume the device itself has gone off --
153862306a36Sopenharmony_ci	 * else a close on an open port later will try to send out a
153962306a36Sopenharmony_ci	 * control message.
154062306a36Sopenharmony_ci	 */
154162306a36Sopenharmony_ci	port->portdev = NULL;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
154462306a36Sopenharmony_ci	device_destroy(&port_class, port->dev->devt);
154562306a36Sopenharmony_ci	cdev_del(port->cdev);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	debugfs_remove(port->debugfs_file);
154862306a36Sopenharmony_ci	kfree(port->name);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	/*
155162306a36Sopenharmony_ci	 * Locks around here are not necessary - a port can't be
155262306a36Sopenharmony_ci	 * opened after we removed the port struct from ports_list
155362306a36Sopenharmony_ci	 * above.
155462306a36Sopenharmony_ci	 */
155562306a36Sopenharmony_ci	kref_put(&port->kref, remove_port);
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci/* Any private messages that the Host and Guest want to share */
155962306a36Sopenharmony_cistatic void handle_control_message(struct virtio_device *vdev,
156062306a36Sopenharmony_ci				   struct ports_device *portdev,
156162306a36Sopenharmony_ci				   struct port_buffer *buf)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct virtio_console_control *cpkt;
156462306a36Sopenharmony_ci	struct port *port;
156562306a36Sopenharmony_ci	size_t name_size;
156662306a36Sopenharmony_ci	int err;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	port = find_port_by_id(portdev, virtio32_to_cpu(vdev, cpkt->id));
157162306a36Sopenharmony_ci	if (!port &&
157262306a36Sopenharmony_ci	    cpkt->event != cpu_to_virtio16(vdev, VIRTIO_CONSOLE_PORT_ADD)) {
157362306a36Sopenharmony_ci		/* No valid header at start of buffer.  Drop it. */
157462306a36Sopenharmony_ci		dev_dbg(&portdev->vdev->dev,
157562306a36Sopenharmony_ci			"Invalid index %u in control packet\n", cpkt->id);
157662306a36Sopenharmony_ci		return;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	switch (virtio16_to_cpu(vdev, cpkt->event)) {
158062306a36Sopenharmony_ci	case VIRTIO_CONSOLE_PORT_ADD:
158162306a36Sopenharmony_ci		if (port) {
158262306a36Sopenharmony_ci			dev_dbg(&portdev->vdev->dev,
158362306a36Sopenharmony_ci				"Port %u already added\n", port->id);
158462306a36Sopenharmony_ci			send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
158562306a36Sopenharmony_ci			break;
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci		if (virtio32_to_cpu(vdev, cpkt->id) >=
158862306a36Sopenharmony_ci		    portdev->max_nr_ports) {
158962306a36Sopenharmony_ci			dev_warn(&portdev->vdev->dev,
159062306a36Sopenharmony_ci				"Request for adding port with "
159162306a36Sopenharmony_ci				"out-of-bound id %u, max. supported id: %u\n",
159262306a36Sopenharmony_ci				cpkt->id, portdev->max_nr_ports - 1);
159362306a36Sopenharmony_ci			break;
159462306a36Sopenharmony_ci		}
159562306a36Sopenharmony_ci		add_port(portdev, virtio32_to_cpu(vdev, cpkt->id));
159662306a36Sopenharmony_ci		break;
159762306a36Sopenharmony_ci	case VIRTIO_CONSOLE_PORT_REMOVE:
159862306a36Sopenharmony_ci		unplug_port(port);
159962306a36Sopenharmony_ci		break;
160062306a36Sopenharmony_ci	case VIRTIO_CONSOLE_CONSOLE_PORT:
160162306a36Sopenharmony_ci		if (!cpkt->value)
160262306a36Sopenharmony_ci			break;
160362306a36Sopenharmony_ci		if (is_console_port(port))
160462306a36Sopenharmony_ci			break;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci		init_port_console(port);
160762306a36Sopenharmony_ci		complete(&early_console_added);
160862306a36Sopenharmony_ci		/*
160962306a36Sopenharmony_ci		 * Could remove the port here in case init fails - but
161062306a36Sopenharmony_ci		 * have to notify the host first.
161162306a36Sopenharmony_ci		 */
161262306a36Sopenharmony_ci		break;
161362306a36Sopenharmony_ci	case VIRTIO_CONSOLE_RESIZE: {
161462306a36Sopenharmony_ci		struct {
161562306a36Sopenharmony_ci			__u16 rows;
161662306a36Sopenharmony_ci			__u16 cols;
161762306a36Sopenharmony_ci		} size;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		if (!is_console_port(port))
162062306a36Sopenharmony_ci			break;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci		memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt),
162362306a36Sopenharmony_ci		       sizeof(size));
162462306a36Sopenharmony_ci		set_console_size(port, size.rows, size.cols);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci		port->cons.hvc->irq_requested = 1;
162762306a36Sopenharmony_ci		resize_console(port);
162862306a36Sopenharmony_ci		break;
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci	case VIRTIO_CONSOLE_PORT_OPEN:
163162306a36Sopenharmony_ci		port->host_connected = virtio16_to_cpu(vdev, cpkt->value);
163262306a36Sopenharmony_ci		wake_up_interruptible(&port->waitqueue);
163362306a36Sopenharmony_ci		/*
163462306a36Sopenharmony_ci		 * If the host port got closed and the host had any
163562306a36Sopenharmony_ci		 * unconsumed buffers, we'll be able to reclaim them
163662306a36Sopenharmony_ci		 * now.
163762306a36Sopenharmony_ci		 */
163862306a36Sopenharmony_ci		spin_lock_irq(&port->outvq_lock);
163962306a36Sopenharmony_ci		reclaim_consumed_buffers(port);
164062306a36Sopenharmony_ci		spin_unlock_irq(&port->outvq_lock);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci		/*
164362306a36Sopenharmony_ci		 * If the guest is connected, it'll be interested in
164462306a36Sopenharmony_ci		 * knowing the host connection state changed.
164562306a36Sopenharmony_ci		 */
164662306a36Sopenharmony_ci		spin_lock_irq(&port->inbuf_lock);
164762306a36Sopenharmony_ci		send_sigio_to_port(port);
164862306a36Sopenharmony_ci		spin_unlock_irq(&port->inbuf_lock);
164962306a36Sopenharmony_ci		break;
165062306a36Sopenharmony_ci	case VIRTIO_CONSOLE_PORT_NAME:
165162306a36Sopenharmony_ci		/*
165262306a36Sopenharmony_ci		 * If we woke up after hibernation, we can get this
165362306a36Sopenharmony_ci		 * again.  Skip it in that case.
165462306a36Sopenharmony_ci		 */
165562306a36Sopenharmony_ci		if (port->name)
165662306a36Sopenharmony_ci			break;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci		/*
165962306a36Sopenharmony_ci		 * Skip the size of the header and the cpkt to get the size
166062306a36Sopenharmony_ci		 * of the name that was sent
166162306a36Sopenharmony_ci		 */
166262306a36Sopenharmony_ci		name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci		port->name = kmalloc(name_size, GFP_KERNEL);
166562306a36Sopenharmony_ci		if (!port->name) {
166662306a36Sopenharmony_ci			dev_err(port->dev,
166762306a36Sopenharmony_ci				"Not enough space to store port name\n");
166862306a36Sopenharmony_ci			break;
166962306a36Sopenharmony_ci		}
167062306a36Sopenharmony_ci		strscpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
167162306a36Sopenharmony_ci			name_size);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci		/*
167462306a36Sopenharmony_ci		 * Since we only have one sysfs attribute, 'name',
167562306a36Sopenharmony_ci		 * create it only if we have a name for the port.
167662306a36Sopenharmony_ci		 */
167762306a36Sopenharmony_ci		err = sysfs_create_group(&port->dev->kobj,
167862306a36Sopenharmony_ci					 &port_attribute_group);
167962306a36Sopenharmony_ci		if (err) {
168062306a36Sopenharmony_ci			dev_err(port->dev,
168162306a36Sopenharmony_ci				"Error %d creating sysfs device attributes\n",
168262306a36Sopenharmony_ci				err);
168362306a36Sopenharmony_ci		} else {
168462306a36Sopenharmony_ci			/*
168562306a36Sopenharmony_ci			 * Generate a udev event so that appropriate
168662306a36Sopenharmony_ci			 * symlinks can be created based on udev
168762306a36Sopenharmony_ci			 * rules.
168862306a36Sopenharmony_ci			 */
168962306a36Sopenharmony_ci			kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
169062306a36Sopenharmony_ci		}
169162306a36Sopenharmony_ci		break;
169262306a36Sopenharmony_ci	}
169362306a36Sopenharmony_ci}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_cistatic void control_work_handler(struct work_struct *work)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	struct ports_device *portdev;
169862306a36Sopenharmony_ci	struct virtqueue *vq;
169962306a36Sopenharmony_ci	struct port_buffer *buf;
170062306a36Sopenharmony_ci	unsigned int len;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	portdev = container_of(work, struct ports_device, control_work);
170362306a36Sopenharmony_ci	vq = portdev->c_ivq;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	spin_lock(&portdev->c_ivq_lock);
170662306a36Sopenharmony_ci	while ((buf = virtqueue_get_buf(vq, &len))) {
170762306a36Sopenharmony_ci		spin_unlock(&portdev->c_ivq_lock);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci		buf->len = min_t(size_t, len, buf->size);
171062306a36Sopenharmony_ci		buf->offset = 0;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci		handle_control_message(vq->vdev, portdev, buf);
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci		spin_lock(&portdev->c_ivq_lock);
171562306a36Sopenharmony_ci		if (add_inbuf(portdev->c_ivq, buf) < 0) {
171662306a36Sopenharmony_ci			dev_warn(&portdev->vdev->dev,
171762306a36Sopenharmony_ci				 "Error adding buffer to queue\n");
171862306a36Sopenharmony_ci			free_buf(buf, false);
171962306a36Sopenharmony_ci		}
172062306a36Sopenharmony_ci	}
172162306a36Sopenharmony_ci	spin_unlock(&portdev->c_ivq_lock);
172262306a36Sopenharmony_ci}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_cistatic void flush_bufs(struct virtqueue *vq, bool can_sleep)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	struct port_buffer *buf;
172762306a36Sopenharmony_ci	unsigned int len;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	while ((buf = virtqueue_get_buf(vq, &len)))
173062306a36Sopenharmony_ci		free_buf(buf, can_sleep);
173162306a36Sopenharmony_ci}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_cistatic void out_intr(struct virtqueue *vq)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	struct port *port;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	port = find_port_by_vq(vq->vdev->priv, vq);
173862306a36Sopenharmony_ci	if (!port) {
173962306a36Sopenharmony_ci		flush_bufs(vq, false);
174062306a36Sopenharmony_ci		return;
174162306a36Sopenharmony_ci	}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	wake_up_interruptible(&port->waitqueue);
174462306a36Sopenharmony_ci}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_cistatic void in_intr(struct virtqueue *vq)
174762306a36Sopenharmony_ci{
174862306a36Sopenharmony_ci	struct port *port;
174962306a36Sopenharmony_ci	unsigned long flags;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	port = find_port_by_vq(vq->vdev->priv, vq);
175262306a36Sopenharmony_ci	if (!port) {
175362306a36Sopenharmony_ci		flush_bufs(vq, false);
175462306a36Sopenharmony_ci		return;
175562306a36Sopenharmony_ci	}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	spin_lock_irqsave(&port->inbuf_lock, flags);
175862306a36Sopenharmony_ci	port->inbuf = get_inbuf(port);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	/*
176162306a36Sopenharmony_ci	 * Normally the port should not accept data when the port is
176262306a36Sopenharmony_ci	 * closed. For generic serial ports, the host won't (shouldn't)
176362306a36Sopenharmony_ci	 * send data till the guest is connected. But this condition
176462306a36Sopenharmony_ci	 * can be reached when a console port is not yet connected (no
176562306a36Sopenharmony_ci	 * tty is spawned) and the other side sends out data over the
176662306a36Sopenharmony_ci	 * vring, or when a remote devices start sending data before
176762306a36Sopenharmony_ci	 * the ports are opened.
176862306a36Sopenharmony_ci	 *
176962306a36Sopenharmony_ci	 * A generic serial port will discard data if not connected,
177062306a36Sopenharmony_ci	 * while console ports and rproc-serial ports accepts data at
177162306a36Sopenharmony_ci	 * any time. rproc-serial is initiated with guest_connected to
177262306a36Sopenharmony_ci	 * false because port_fops_open expects this. Console ports are
177362306a36Sopenharmony_ci	 * hooked up with an HVC console and is initialized with
177462306a36Sopenharmony_ci	 * guest_connected to true.
177562306a36Sopenharmony_ci	 */
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev))
177862306a36Sopenharmony_ci		discard_port_data(port);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	/* Send a SIGIO indicating new data in case the process asked for it */
178162306a36Sopenharmony_ci	send_sigio_to_port(port);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	spin_unlock_irqrestore(&port->inbuf_lock, flags);
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	wake_up_interruptible(&port->waitqueue);
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	if (is_console_port(port) && hvc_poll(port->cons.hvc))
178862306a36Sopenharmony_ci		hvc_kick();
178962306a36Sopenharmony_ci}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cistatic void control_intr(struct virtqueue *vq)
179262306a36Sopenharmony_ci{
179362306a36Sopenharmony_ci	struct ports_device *portdev;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	portdev = vq->vdev->priv;
179662306a36Sopenharmony_ci	schedule_work(&portdev->control_work);
179762306a36Sopenharmony_ci}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_cistatic void config_intr(struct virtio_device *vdev)
180062306a36Sopenharmony_ci{
180162306a36Sopenharmony_ci	struct ports_device *portdev;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	portdev = vdev->priv;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	if (!use_multiport(portdev))
180662306a36Sopenharmony_ci		schedule_work(&portdev->config_work);
180762306a36Sopenharmony_ci}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_cistatic void config_work_handler(struct work_struct *work)
181062306a36Sopenharmony_ci{
181162306a36Sopenharmony_ci	struct ports_device *portdev;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	portdev = container_of(work, struct ports_device, config_work);
181462306a36Sopenharmony_ci	if (!use_multiport(portdev)) {
181562306a36Sopenharmony_ci		struct virtio_device *vdev;
181662306a36Sopenharmony_ci		struct port *port;
181762306a36Sopenharmony_ci		u16 rows, cols;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci		vdev = portdev->vdev;
182062306a36Sopenharmony_ci		virtio_cread(vdev, struct virtio_console_config, cols, &cols);
182162306a36Sopenharmony_ci		virtio_cread(vdev, struct virtio_console_config, rows, &rows);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		port = find_port_by_id(portdev, 0);
182462306a36Sopenharmony_ci		set_console_size(port, rows, cols);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci		/*
182762306a36Sopenharmony_ci		 * We'll use this way of resizing only for legacy
182862306a36Sopenharmony_ci		 * support.  For newer userspace
182962306a36Sopenharmony_ci		 * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages
183062306a36Sopenharmony_ci		 * to indicate console size changes so that it can be
183162306a36Sopenharmony_ci		 * done per-port.
183262306a36Sopenharmony_ci		 */
183362306a36Sopenharmony_ci		resize_console(port);
183462306a36Sopenharmony_ci	}
183562306a36Sopenharmony_ci}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_cistatic int init_vqs(struct ports_device *portdev)
183862306a36Sopenharmony_ci{
183962306a36Sopenharmony_ci	vq_callback_t **io_callbacks;
184062306a36Sopenharmony_ci	char **io_names;
184162306a36Sopenharmony_ci	struct virtqueue **vqs;
184262306a36Sopenharmony_ci	u32 i, j, nr_ports, nr_queues;
184362306a36Sopenharmony_ci	int err;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	nr_ports = portdev->max_nr_ports;
184662306a36Sopenharmony_ci	nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	vqs = kmalloc_array(nr_queues, sizeof(struct virtqueue *), GFP_KERNEL);
184962306a36Sopenharmony_ci	io_callbacks = kmalloc_array(nr_queues, sizeof(vq_callback_t *),
185062306a36Sopenharmony_ci				     GFP_KERNEL);
185162306a36Sopenharmony_ci	io_names = kmalloc_array(nr_queues, sizeof(char *), GFP_KERNEL);
185262306a36Sopenharmony_ci	portdev->in_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *),
185362306a36Sopenharmony_ci					GFP_KERNEL);
185462306a36Sopenharmony_ci	portdev->out_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *),
185562306a36Sopenharmony_ci					 GFP_KERNEL);
185662306a36Sopenharmony_ci	if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
185762306a36Sopenharmony_ci	    !portdev->out_vqs) {
185862306a36Sopenharmony_ci		err = -ENOMEM;
185962306a36Sopenharmony_ci		goto free;
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	/*
186362306a36Sopenharmony_ci	 * For backward compat (newer host but older guest), the host
186462306a36Sopenharmony_ci	 * spawns a console port first and also inits the vqs for port
186562306a36Sopenharmony_ci	 * 0 before others.
186662306a36Sopenharmony_ci	 */
186762306a36Sopenharmony_ci	j = 0;
186862306a36Sopenharmony_ci	io_callbacks[j] = in_intr;
186962306a36Sopenharmony_ci	io_callbacks[j + 1] = out_intr;
187062306a36Sopenharmony_ci	io_names[j] = "input";
187162306a36Sopenharmony_ci	io_names[j + 1] = "output";
187262306a36Sopenharmony_ci	j += 2;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	if (use_multiport(portdev)) {
187562306a36Sopenharmony_ci		io_callbacks[j] = control_intr;
187662306a36Sopenharmony_ci		io_callbacks[j + 1] = NULL;
187762306a36Sopenharmony_ci		io_names[j] = "control-i";
187862306a36Sopenharmony_ci		io_names[j + 1] = "control-o";
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci		for (i = 1; i < nr_ports; i++) {
188162306a36Sopenharmony_ci			j += 2;
188262306a36Sopenharmony_ci			io_callbacks[j] = in_intr;
188362306a36Sopenharmony_ci			io_callbacks[j + 1] = out_intr;
188462306a36Sopenharmony_ci			io_names[j] = "input";
188562306a36Sopenharmony_ci			io_names[j + 1] = "output";
188662306a36Sopenharmony_ci		}
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci	/* Find the queues. */
188962306a36Sopenharmony_ci	err = virtio_find_vqs(portdev->vdev, nr_queues, vqs,
189062306a36Sopenharmony_ci			      io_callbacks,
189162306a36Sopenharmony_ci			      (const char **)io_names, NULL);
189262306a36Sopenharmony_ci	if (err)
189362306a36Sopenharmony_ci		goto free;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	j = 0;
189662306a36Sopenharmony_ci	portdev->in_vqs[0] = vqs[0];
189762306a36Sopenharmony_ci	portdev->out_vqs[0] = vqs[1];
189862306a36Sopenharmony_ci	j += 2;
189962306a36Sopenharmony_ci	if (use_multiport(portdev)) {
190062306a36Sopenharmony_ci		portdev->c_ivq = vqs[j];
190162306a36Sopenharmony_ci		portdev->c_ovq = vqs[j + 1];
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci		for (i = 1; i < nr_ports; i++) {
190462306a36Sopenharmony_ci			j += 2;
190562306a36Sopenharmony_ci			portdev->in_vqs[i] = vqs[j];
190662306a36Sopenharmony_ci			portdev->out_vqs[i] = vqs[j + 1];
190762306a36Sopenharmony_ci		}
190862306a36Sopenharmony_ci	}
190962306a36Sopenharmony_ci	kfree(io_names);
191062306a36Sopenharmony_ci	kfree(io_callbacks);
191162306a36Sopenharmony_ci	kfree(vqs);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	return 0;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_cifree:
191662306a36Sopenharmony_ci	kfree(portdev->out_vqs);
191762306a36Sopenharmony_ci	kfree(portdev->in_vqs);
191862306a36Sopenharmony_ci	kfree(io_names);
191962306a36Sopenharmony_ci	kfree(io_callbacks);
192062306a36Sopenharmony_ci	kfree(vqs);
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	return err;
192362306a36Sopenharmony_ci}
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_cistatic const struct file_operations portdev_fops = {
192662306a36Sopenharmony_ci	.owner = THIS_MODULE,
192762306a36Sopenharmony_ci};
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_cistatic void remove_vqs(struct ports_device *portdev)
193062306a36Sopenharmony_ci{
193162306a36Sopenharmony_ci	struct virtqueue *vq;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	virtio_device_for_each_vq(portdev->vdev, vq) {
193462306a36Sopenharmony_ci		struct port_buffer *buf;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		flush_bufs(vq, true);
193762306a36Sopenharmony_ci		while ((buf = virtqueue_detach_unused_buf(vq)))
193862306a36Sopenharmony_ci			free_buf(buf, true);
193962306a36Sopenharmony_ci		cond_resched();
194062306a36Sopenharmony_ci	}
194162306a36Sopenharmony_ci	portdev->vdev->config->del_vqs(portdev->vdev);
194262306a36Sopenharmony_ci	kfree(portdev->in_vqs);
194362306a36Sopenharmony_ci	kfree(portdev->out_vqs);
194462306a36Sopenharmony_ci}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_cistatic void virtcons_remove(struct virtio_device *vdev)
194762306a36Sopenharmony_ci{
194862306a36Sopenharmony_ci	struct ports_device *portdev;
194962306a36Sopenharmony_ci	struct port *port, *port2;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	portdev = vdev->priv;
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci	spin_lock_irq(&pdrvdata_lock);
195462306a36Sopenharmony_ci	list_del(&portdev->list);
195562306a36Sopenharmony_ci	spin_unlock_irq(&pdrvdata_lock);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	/* Device is going away, exit any polling for buffers */
195862306a36Sopenharmony_ci	virtio_break_device(vdev);
195962306a36Sopenharmony_ci	if (use_multiport(portdev))
196062306a36Sopenharmony_ci		flush_work(&portdev->control_work);
196162306a36Sopenharmony_ci	else
196262306a36Sopenharmony_ci		flush_work(&portdev->config_work);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	/* Disable interrupts for vqs */
196562306a36Sopenharmony_ci	virtio_reset_device(vdev);
196662306a36Sopenharmony_ci	/* Finish up work that's lined up */
196762306a36Sopenharmony_ci	if (use_multiport(portdev))
196862306a36Sopenharmony_ci		cancel_work_sync(&portdev->control_work);
196962306a36Sopenharmony_ci	else
197062306a36Sopenharmony_ci		cancel_work_sync(&portdev->config_work);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	list_for_each_entry_safe(port, port2, &portdev->ports, list)
197362306a36Sopenharmony_ci		unplug_port(port);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	/*
197862306a36Sopenharmony_ci	 * When yanking out a device, we immediately lose the
197962306a36Sopenharmony_ci	 * (device-side) queues.  So there's no point in keeping the
198062306a36Sopenharmony_ci	 * guest side around till we drop our final reference.  This
198162306a36Sopenharmony_ci	 * also means that any ports which are in an open state will
198262306a36Sopenharmony_ci	 * have to just stop using the port, as the vqs are going
198362306a36Sopenharmony_ci	 * away.
198462306a36Sopenharmony_ci	 */
198562306a36Sopenharmony_ci	remove_vqs(portdev);
198662306a36Sopenharmony_ci	kfree(portdev);
198762306a36Sopenharmony_ci}
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci/*
199062306a36Sopenharmony_ci * Once we're further in boot, we get probed like any other virtio
199162306a36Sopenharmony_ci * device.
199262306a36Sopenharmony_ci *
199362306a36Sopenharmony_ci * If the host also supports multiple console ports, we check the
199462306a36Sopenharmony_ci * config space to see how many ports the host has spawned.  We
199562306a36Sopenharmony_ci * initialize each port found.
199662306a36Sopenharmony_ci */
199762306a36Sopenharmony_cistatic int virtcons_probe(struct virtio_device *vdev)
199862306a36Sopenharmony_ci{
199962306a36Sopenharmony_ci	struct ports_device *portdev;
200062306a36Sopenharmony_ci	int err;
200162306a36Sopenharmony_ci	bool multiport;
200262306a36Sopenharmony_ci	bool early = early_put_chars != NULL;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	/* We only need a config space if features are offered */
200562306a36Sopenharmony_ci	if (!vdev->config->get &&
200662306a36Sopenharmony_ci	    (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)
200762306a36Sopenharmony_ci	     || virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT))) {
200862306a36Sopenharmony_ci		dev_err(&vdev->dev, "%s failure: config access disabled\n",
200962306a36Sopenharmony_ci			__func__);
201062306a36Sopenharmony_ci		return -EINVAL;
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	/* Ensure to read early_put_chars now */
201462306a36Sopenharmony_ci	barrier();
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
201762306a36Sopenharmony_ci	if (!portdev) {
201862306a36Sopenharmony_ci		err = -ENOMEM;
201962306a36Sopenharmony_ci		goto fail;
202062306a36Sopenharmony_ci	}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	/* Attach this portdev to this virtio_device, and vice-versa. */
202362306a36Sopenharmony_ci	portdev->vdev = vdev;
202462306a36Sopenharmony_ci	vdev->priv = portdev;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	portdev->chr_major = register_chrdev(0, "virtio-portsdev",
202762306a36Sopenharmony_ci					     &portdev_fops);
202862306a36Sopenharmony_ci	if (portdev->chr_major < 0) {
202962306a36Sopenharmony_ci		dev_err(&vdev->dev,
203062306a36Sopenharmony_ci			"Error %d registering chrdev for device %u\n",
203162306a36Sopenharmony_ci			portdev->chr_major, vdev->index);
203262306a36Sopenharmony_ci		err = portdev->chr_major;
203362306a36Sopenharmony_ci		goto free;
203462306a36Sopenharmony_ci	}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	multiport = false;
203762306a36Sopenharmony_ci	portdev->max_nr_ports = 1;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	/* Don't test MULTIPORT at all if we're rproc: not a valid feature! */
204062306a36Sopenharmony_ci	if (!is_rproc_serial(vdev) &&
204162306a36Sopenharmony_ci	    virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
204262306a36Sopenharmony_ci				 struct virtio_console_config, max_nr_ports,
204362306a36Sopenharmony_ci				 &portdev->max_nr_ports) == 0) {
204462306a36Sopenharmony_ci		if (portdev->max_nr_ports == 0 ||
204562306a36Sopenharmony_ci		    portdev->max_nr_ports > VIRTCONS_MAX_PORTS) {
204662306a36Sopenharmony_ci			dev_err(&vdev->dev,
204762306a36Sopenharmony_ci				"Invalidate max_nr_ports %d",
204862306a36Sopenharmony_ci				portdev->max_nr_ports);
204962306a36Sopenharmony_ci			err = -EINVAL;
205062306a36Sopenharmony_ci			goto free;
205162306a36Sopenharmony_ci		}
205262306a36Sopenharmony_ci		multiport = true;
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	err = init_vqs(portdev);
205662306a36Sopenharmony_ci	if (err < 0) {
205762306a36Sopenharmony_ci		dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
205862306a36Sopenharmony_ci		goto free_chrdev;
205962306a36Sopenharmony_ci	}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	spin_lock_init(&portdev->ports_lock);
206262306a36Sopenharmony_ci	INIT_LIST_HEAD(&portdev->ports);
206362306a36Sopenharmony_ci	INIT_LIST_HEAD(&portdev->list);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	virtio_device_ready(portdev->vdev);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	INIT_WORK(&portdev->config_work, &config_work_handler);
206862306a36Sopenharmony_ci	INIT_WORK(&portdev->control_work, &control_work_handler);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	if (multiport) {
207162306a36Sopenharmony_ci		spin_lock_init(&portdev->c_ivq_lock);
207262306a36Sopenharmony_ci		spin_lock_init(&portdev->c_ovq_lock);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci		err = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
207562306a36Sopenharmony_ci		if (err < 0) {
207662306a36Sopenharmony_ci			dev_err(&vdev->dev,
207762306a36Sopenharmony_ci				"Error allocating buffers for control queue\n");
207862306a36Sopenharmony_ci			/*
207962306a36Sopenharmony_ci			 * The host might want to notify mgmt sw about device
208062306a36Sopenharmony_ci			 * add failure.
208162306a36Sopenharmony_ci			 */
208262306a36Sopenharmony_ci			__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
208362306a36Sopenharmony_ci					   VIRTIO_CONSOLE_DEVICE_READY, 0);
208462306a36Sopenharmony_ci			/* Device was functional: we need full cleanup. */
208562306a36Sopenharmony_ci			virtcons_remove(vdev);
208662306a36Sopenharmony_ci			return err;
208762306a36Sopenharmony_ci		}
208862306a36Sopenharmony_ci	} else {
208962306a36Sopenharmony_ci		/*
209062306a36Sopenharmony_ci		 * For backward compatibility: Create a console port
209162306a36Sopenharmony_ci		 * if we're running on older host.
209262306a36Sopenharmony_ci		 */
209362306a36Sopenharmony_ci		add_port(portdev, 0);
209462306a36Sopenharmony_ci	}
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	spin_lock_irq(&pdrvdata_lock);
209762306a36Sopenharmony_ci	list_add_tail(&portdev->list, &pdrvdata.portdevs);
209862306a36Sopenharmony_ci	spin_unlock_irq(&pdrvdata_lock);
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
210162306a36Sopenharmony_ci			   VIRTIO_CONSOLE_DEVICE_READY, 1);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	/*
210462306a36Sopenharmony_ci	 * If there was an early virtio console, assume that there are no
210562306a36Sopenharmony_ci	 * other consoles. We need to wait until the hvc_alloc matches the
210662306a36Sopenharmony_ci	 * hvc_instantiate, otherwise tty_open will complain, resulting in
210762306a36Sopenharmony_ci	 * a "Warning: unable to open an initial console" boot failure.
210862306a36Sopenharmony_ci	 * Without multiport this is done in add_port above. With multiport
210962306a36Sopenharmony_ci	 * this might take some host<->guest communication - thus we have to
211062306a36Sopenharmony_ci	 * wait.
211162306a36Sopenharmony_ci	 */
211262306a36Sopenharmony_ci	if (multiport && early)
211362306a36Sopenharmony_ci		wait_for_completion(&early_console_added);
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	return 0;
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_cifree_chrdev:
211862306a36Sopenharmony_ci	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
211962306a36Sopenharmony_cifree:
212062306a36Sopenharmony_ci	kfree(portdev);
212162306a36Sopenharmony_cifail:
212262306a36Sopenharmony_ci	return err;
212362306a36Sopenharmony_ci}
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_cistatic const struct virtio_device_id id_table[] = {
212662306a36Sopenharmony_ci	{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
212762306a36Sopenharmony_ci	{ 0 },
212862306a36Sopenharmony_ci};
212962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(virtio, id_table);
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cistatic const unsigned int features[] = {
213262306a36Sopenharmony_ci	VIRTIO_CONSOLE_F_SIZE,
213362306a36Sopenharmony_ci	VIRTIO_CONSOLE_F_MULTIPORT,
213462306a36Sopenharmony_ci};
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_cistatic const struct virtio_device_id rproc_serial_id_table[] = {
213762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_REMOTEPROC)
213862306a36Sopenharmony_ci	{ VIRTIO_ID_RPROC_SERIAL, VIRTIO_DEV_ANY_ID },
213962306a36Sopenharmony_ci#endif
214062306a36Sopenharmony_ci	{ 0 },
214162306a36Sopenharmony_ci};
214262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(virtio, rproc_serial_id_table);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_cistatic const unsigned int rproc_serial_features[] = {
214562306a36Sopenharmony_ci};
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
214862306a36Sopenharmony_cistatic int virtcons_freeze(struct virtio_device *vdev)
214962306a36Sopenharmony_ci{
215062306a36Sopenharmony_ci	struct ports_device *portdev;
215162306a36Sopenharmony_ci	struct port *port;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	portdev = vdev->priv;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	virtio_reset_device(vdev);
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	if (use_multiport(portdev))
215862306a36Sopenharmony_ci		virtqueue_disable_cb(portdev->c_ivq);
215962306a36Sopenharmony_ci	cancel_work_sync(&portdev->control_work);
216062306a36Sopenharmony_ci	cancel_work_sync(&portdev->config_work);
216162306a36Sopenharmony_ci	/*
216262306a36Sopenharmony_ci	 * Once more: if control_work_handler() was running, it would
216362306a36Sopenharmony_ci	 * enable the cb as the last step.
216462306a36Sopenharmony_ci	 */
216562306a36Sopenharmony_ci	if (use_multiport(portdev))
216662306a36Sopenharmony_ci		virtqueue_disable_cb(portdev->c_ivq);
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	list_for_each_entry(port, &portdev->ports, list) {
216962306a36Sopenharmony_ci		virtqueue_disable_cb(port->in_vq);
217062306a36Sopenharmony_ci		virtqueue_disable_cb(port->out_vq);
217162306a36Sopenharmony_ci		/*
217262306a36Sopenharmony_ci		 * We'll ask the host later if the new invocation has
217362306a36Sopenharmony_ci		 * the port opened or closed.
217462306a36Sopenharmony_ci		 */
217562306a36Sopenharmony_ci		port->host_connected = false;
217662306a36Sopenharmony_ci		remove_port_data(port);
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci	remove_vqs(portdev);
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	return 0;
218162306a36Sopenharmony_ci}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_cistatic int virtcons_restore(struct virtio_device *vdev)
218462306a36Sopenharmony_ci{
218562306a36Sopenharmony_ci	struct ports_device *portdev;
218662306a36Sopenharmony_ci	struct port *port;
218762306a36Sopenharmony_ci	int ret;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	portdev = vdev->priv;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	ret = init_vqs(portdev);
219262306a36Sopenharmony_ci	if (ret)
219362306a36Sopenharmony_ci		return ret;
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci	virtio_device_ready(portdev->vdev);
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	if (use_multiport(portdev))
219862306a36Sopenharmony_ci		fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	list_for_each_entry(port, &portdev->ports, list) {
220162306a36Sopenharmony_ci		port->in_vq = portdev->in_vqs[port->id];
220262306a36Sopenharmony_ci		port->out_vq = portdev->out_vqs[port->id];
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci		fill_queue(port->in_vq, &port->inbuf_lock);
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci		/* Get port open/close status on the host */
220762306a36Sopenharmony_ci		send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci		/*
221062306a36Sopenharmony_ci		 * If a port was open at the time of suspending, we
221162306a36Sopenharmony_ci		 * have to let the host know that it's still open.
221262306a36Sopenharmony_ci		 */
221362306a36Sopenharmony_ci		if (port->guest_connected)
221462306a36Sopenharmony_ci			send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
221562306a36Sopenharmony_ci	}
221662306a36Sopenharmony_ci	return 0;
221762306a36Sopenharmony_ci}
221862306a36Sopenharmony_ci#endif
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_cistatic struct virtio_driver virtio_console = {
222162306a36Sopenharmony_ci	.feature_table = features,
222262306a36Sopenharmony_ci	.feature_table_size = ARRAY_SIZE(features),
222362306a36Sopenharmony_ci	.driver.name =	KBUILD_MODNAME,
222462306a36Sopenharmony_ci	.driver.owner =	THIS_MODULE,
222562306a36Sopenharmony_ci	.id_table =	id_table,
222662306a36Sopenharmony_ci	.probe =	virtcons_probe,
222762306a36Sopenharmony_ci	.remove =	virtcons_remove,
222862306a36Sopenharmony_ci	.config_changed = config_intr,
222962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
223062306a36Sopenharmony_ci	.freeze =	virtcons_freeze,
223162306a36Sopenharmony_ci	.restore =	virtcons_restore,
223262306a36Sopenharmony_ci#endif
223362306a36Sopenharmony_ci};
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_cistatic struct virtio_driver virtio_rproc_serial = {
223662306a36Sopenharmony_ci	.feature_table = rproc_serial_features,
223762306a36Sopenharmony_ci	.feature_table_size = ARRAY_SIZE(rproc_serial_features),
223862306a36Sopenharmony_ci	.driver.name =	"virtio_rproc_serial",
223962306a36Sopenharmony_ci	.driver.owner =	THIS_MODULE,
224062306a36Sopenharmony_ci	.id_table =	rproc_serial_id_table,
224162306a36Sopenharmony_ci	.probe =	virtcons_probe,
224262306a36Sopenharmony_ci	.remove =	virtcons_remove,
224362306a36Sopenharmony_ci};
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_cistatic int __init virtio_console_init(void)
224662306a36Sopenharmony_ci{
224762306a36Sopenharmony_ci	int err;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	err = class_register(&port_class);
225062306a36Sopenharmony_ci	if (err)
225162306a36Sopenharmony_ci		return err;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
225462306a36Sopenharmony_ci	INIT_LIST_HEAD(&pdrvdata.consoles);
225562306a36Sopenharmony_ci	INIT_LIST_HEAD(&pdrvdata.portdevs);
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	err = register_virtio_driver(&virtio_console);
225862306a36Sopenharmony_ci	if (err < 0) {
225962306a36Sopenharmony_ci		pr_err("Error %d registering virtio driver\n", err);
226062306a36Sopenharmony_ci		goto free;
226162306a36Sopenharmony_ci	}
226262306a36Sopenharmony_ci	err = register_virtio_driver(&virtio_rproc_serial);
226362306a36Sopenharmony_ci	if (err < 0) {
226462306a36Sopenharmony_ci		pr_err("Error %d registering virtio rproc serial driver\n",
226562306a36Sopenharmony_ci		       err);
226662306a36Sopenharmony_ci		goto unregister;
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci	return 0;
226962306a36Sopenharmony_ciunregister:
227062306a36Sopenharmony_ci	unregister_virtio_driver(&virtio_console);
227162306a36Sopenharmony_cifree:
227262306a36Sopenharmony_ci	debugfs_remove_recursive(pdrvdata.debugfs_dir);
227362306a36Sopenharmony_ci	class_unregister(&port_class);
227462306a36Sopenharmony_ci	return err;
227562306a36Sopenharmony_ci}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_cistatic void __exit virtio_console_fini(void)
227862306a36Sopenharmony_ci{
227962306a36Sopenharmony_ci	reclaim_dma_bufs();
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	unregister_virtio_driver(&virtio_console);
228262306a36Sopenharmony_ci	unregister_virtio_driver(&virtio_rproc_serial);
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	class_unregister(&port_class);
228562306a36Sopenharmony_ci	debugfs_remove_recursive(pdrvdata.debugfs_dir);
228662306a36Sopenharmony_ci}
228762306a36Sopenharmony_cimodule_init(virtio_console_init);
228862306a36Sopenharmony_cimodule_exit(virtio_console_fini);
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ciMODULE_DESCRIPTION("Virtio console driver");
229162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2292