151df0accSAmit Shah /* 251df0accSAmit Shah * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation 3ce86d35dSLinus Torvalds * Copyright (C) 2009, 2010, 2011 Red Hat, Inc. 4ce86d35dSLinus Torvalds * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com> 551df0accSAmit Shah * 651df0accSAmit Shah * This program is free software; you can redistribute it and/or modify 751df0accSAmit Shah * it under the terms of the GNU General Public License as published by 851df0accSAmit Shah * the Free Software Foundation; either version 2 of the License, or 951df0accSAmit Shah * (at your option) any later version. 1051df0accSAmit Shah * 1151df0accSAmit Shah * This program is distributed in the hope that it will be useful, 1251df0accSAmit Shah * but WITHOUT ANY WARRANTY; without even the implied warranty of 1351df0accSAmit Shah * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1451df0accSAmit Shah * GNU General Public License for more details. 1551df0accSAmit Shah * 1651df0accSAmit Shah * You should have received a copy of the GNU General Public License 1751df0accSAmit Shah * along with this program; if not, write to the Free Software 1851df0accSAmit Shah * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1951df0accSAmit Shah */ 2051df0accSAmit Shah #include <linux/cdev.h> 2151df0accSAmit Shah #include <linux/debugfs.h> 225e38483bSChristian Borntraeger #include <linux/completion.h> 2351df0accSAmit Shah #include <linux/device.h> 2451df0accSAmit Shah #include <linux/err.h> 25a08fa92dSAmit Shah #include <linux/freezer.h> 2651df0accSAmit Shah #include <linux/fs.h> 27eb5e89fcSMasami Hiramatsu #include <linux/splice.h> 28eb5e89fcSMasami Hiramatsu #include <linux/pagemap.h> 2951df0accSAmit Shah #include <linux/init.h> 3051df0accSAmit Shah #include <linux/list.h> 3151df0accSAmit Shah #include <linux/poll.h> 3251df0accSAmit Shah #include <linux/sched.h> 3351df0accSAmit Shah #include <linux/slab.h> 3451df0accSAmit Shah #include <linux/spinlock.h> 3551df0accSAmit Shah #include <linux/virtio.h> 3651df0accSAmit Shah #include <linux/virtio_console.h> 3751df0accSAmit Shah #include <linux/wait.h> 3851df0accSAmit Shah #include <linux/workqueue.h> 39c22405c9SPaul Gortmaker #include <linux/module.h> 401b637046SSjur Brændeland #include <linux/dma-mapping.h> 4151df0accSAmit Shah #include "../tty/hvc/hvc_console.h" 4251df0accSAmit Shah 431b637046SSjur Brændeland #define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) 441b637046SSjur Brændeland 4551df0accSAmit Shah /* 4651df0accSAmit Shah * This is a global struct for storing common data for all the devices 4751df0accSAmit Shah * this driver handles. 4851df0accSAmit Shah * 4951df0accSAmit Shah * Mainly, it has a linked list for all the consoles in one place so 5051df0accSAmit Shah * that callbacks from hvc for get_chars(), put_chars() work properly 5151df0accSAmit Shah * across multiple devices and multiple ports per device. 5251df0accSAmit Shah */ 5351df0accSAmit Shah struct ports_driver_data { 5451df0accSAmit Shah /* Used for registering chardevs */ 5551df0accSAmit Shah struct class *class; 5651df0accSAmit Shah 5751df0accSAmit Shah /* Used for exporting per-port information to debugfs */ 5851df0accSAmit Shah struct dentry *debugfs_dir; 5951df0accSAmit Shah 6051df0accSAmit Shah /* List of all the devices we're handling */ 6151df0accSAmit Shah struct list_head portdevs; 6251df0accSAmit Shah 6351df0accSAmit Shah /* 6451df0accSAmit Shah * This is used to keep track of the number of hvc consoles 6551df0accSAmit Shah * spawned by this driver. This number is given as the first 6651df0accSAmit Shah * argument to hvc_alloc(). To correctly map an initial 6751df0accSAmit Shah * console spawned via hvc_instantiate to the console being 6851df0accSAmit Shah * hooked up via hvc_alloc, we need to pass the same vtermno. 6951df0accSAmit Shah * 7051df0accSAmit Shah * We also just assume the first console being initialised was 7151df0accSAmit Shah * the first one that got used as the initial console. 7251df0accSAmit Shah */ 7351df0accSAmit Shah unsigned int next_vtermno; 7451df0accSAmit Shah 7551df0accSAmit Shah /* All the console devices handled by this driver */ 7651df0accSAmit Shah struct list_head consoles; 7751df0accSAmit Shah }; 7851df0accSAmit Shah static struct ports_driver_data pdrvdata; 7951df0accSAmit Shah 803826835aSWei Yongjun static DEFINE_SPINLOCK(pdrvdata_lock); 813826835aSWei Yongjun static DECLARE_COMPLETION(early_console_added); 8251df0accSAmit Shah 8351df0accSAmit Shah /* This struct holds information that's relevant only for console ports */ 8451df0accSAmit Shah struct console { 8551df0accSAmit Shah /* We'll place all consoles in a list in the pdrvdata struct */ 8651df0accSAmit Shah struct list_head list; 8751df0accSAmit Shah 8851df0accSAmit Shah /* The hvc device associated with this console port */ 8951df0accSAmit Shah struct hvc_struct *hvc; 9051df0accSAmit Shah 9151df0accSAmit Shah /* The size of the console */ 9251df0accSAmit Shah struct winsize ws; 9351df0accSAmit Shah 9451df0accSAmit Shah /* 9551df0accSAmit Shah * This number identifies the number that we used to register 9651df0accSAmit Shah * with hvc in hvc_instantiate() and hvc_alloc(); this is the 9751df0accSAmit Shah * number passed on by the hvc callbacks to us to 9851df0accSAmit Shah * differentiate between the other console ports handled by 9951df0accSAmit Shah * this driver 10051df0accSAmit Shah */ 10151df0accSAmit Shah u32 vtermno; 10251df0accSAmit Shah }; 10351df0accSAmit Shah 10451df0accSAmit Shah struct port_buffer { 10551df0accSAmit Shah char *buf; 10651df0accSAmit Shah 10751df0accSAmit Shah /* size of the buffer in *buf above */ 10851df0accSAmit Shah size_t size; 10951df0accSAmit Shah 11051df0accSAmit Shah /* used length of the buffer */ 11151df0accSAmit Shah size_t len; 11251df0accSAmit Shah /* offset in the buf from which to consume data */ 11351df0accSAmit Shah size_t offset; 114276a3e95SSjur Brændeland 1151b637046SSjur Brændeland /* DMA address of buffer */ 1161b637046SSjur Brændeland dma_addr_t dma; 1171b637046SSjur Brændeland 1181b637046SSjur Brændeland /* Device we got DMA memory from */ 1191b637046SSjur Brændeland struct device *dev; 1201b637046SSjur Brændeland 1211b637046SSjur Brændeland /* List of pending dma buffers to free */ 1221b637046SSjur Brændeland struct list_head list; 1231b637046SSjur Brændeland 124276a3e95SSjur Brændeland /* If sgpages == 0 then buf is used */ 125276a3e95SSjur Brændeland unsigned int sgpages; 126276a3e95SSjur Brændeland 127276a3e95SSjur Brændeland /* sg is used if spages > 0. sg must be the last in is struct */ 128276a3e95SSjur Brændeland struct scatterlist sg[0]; 12951df0accSAmit Shah }; 13051df0accSAmit Shah 13151df0accSAmit Shah /* 13251df0accSAmit Shah * This is a per-device struct that stores data common to all the 13351df0accSAmit Shah * ports for that device (vdev->priv). 13451df0accSAmit Shah */ 13551df0accSAmit Shah struct ports_device { 13651df0accSAmit Shah /* Next portdev in the list, head is in the pdrvdata struct */ 13751df0accSAmit Shah struct list_head list; 13851df0accSAmit Shah 13951df0accSAmit Shah /* 14051df0accSAmit Shah * Workqueue handlers where we process deferred work after 14151df0accSAmit Shah * notification 14251df0accSAmit Shah */ 14351df0accSAmit Shah struct work_struct control_work; 144eeb8a7e8SMichael S. Tsirkin struct work_struct config_work; 14551df0accSAmit Shah 14651df0accSAmit Shah struct list_head ports; 14751df0accSAmit Shah 14851df0accSAmit Shah /* To protect the list of ports */ 14951df0accSAmit Shah spinlock_t ports_lock; 15051df0accSAmit Shah 15151df0accSAmit Shah /* To protect the vq operations for the control channel */ 152165b1b8bSAmit Shah spinlock_t c_ivq_lock; 1539ba5c80bSAmit Shah spinlock_t c_ovq_lock; 15451df0accSAmit Shah 1557328fa64SMichael S. Tsirkin /* max. number of ports this device can hold */ 1567328fa64SMichael S. Tsirkin u32 max_nr_ports; 15751df0accSAmit Shah 15851df0accSAmit Shah /* The virtio device we're associated with */ 15951df0accSAmit Shah struct virtio_device *vdev; 16051df0accSAmit Shah 16151df0accSAmit Shah /* 16251df0accSAmit Shah * A couple of virtqueues for the control channel: one for 16351df0accSAmit Shah * guest->host transfers, one for host->guest transfers 16451df0accSAmit Shah */ 16551df0accSAmit Shah struct virtqueue *c_ivq, *c_ovq; 16651df0accSAmit Shah 1675e59d9a1SAndy Lutomirski /* 1685e59d9a1SAndy Lutomirski * A control packet buffer for guest->host requests, protected 1695e59d9a1SAndy Lutomirski * by c_ovq_lock. 1705e59d9a1SAndy Lutomirski */ 1715e59d9a1SAndy Lutomirski struct virtio_console_control cpkt; 1725e59d9a1SAndy Lutomirski 17351df0accSAmit Shah /* Array of per-port IO virtqueues */ 17451df0accSAmit Shah struct virtqueue **in_vqs, **out_vqs; 17551df0accSAmit Shah 17651df0accSAmit Shah /* Major number for this device. Ports will be created as minors. */ 17751df0accSAmit Shah int chr_major; 17851df0accSAmit Shah }; 17951df0accSAmit Shah 18017e5b4f2SAmit Shah struct port_stats { 18117e5b4f2SAmit Shah unsigned long bytes_sent, bytes_received, bytes_discarded; 18217e5b4f2SAmit Shah }; 18317e5b4f2SAmit Shah 18451df0accSAmit Shah /* This struct holds the per-port data */ 18551df0accSAmit Shah struct port { 18651df0accSAmit Shah /* Next port in the list, head is in the ports_device */ 18751df0accSAmit Shah struct list_head list; 18851df0accSAmit Shah 18951df0accSAmit Shah /* Pointer to the parent virtio_console device */ 19051df0accSAmit Shah struct ports_device *portdev; 19151df0accSAmit Shah 19251df0accSAmit Shah /* The current buffer from which data has to be fed to readers */ 19351df0accSAmit Shah struct port_buffer *inbuf; 19451df0accSAmit Shah 19551df0accSAmit Shah /* 19651df0accSAmit Shah * To protect the operations on the in_vq associated with this 19751df0accSAmit Shah * port. Has to be a spinlock because it can be called from 19851df0accSAmit Shah * interrupt context (get_char()). 19951df0accSAmit Shah */ 20051df0accSAmit Shah spinlock_t inbuf_lock; 20151df0accSAmit Shah 20251df0accSAmit Shah /* Protect the operations on the out_vq. */ 20351df0accSAmit Shah spinlock_t outvq_lock; 20451df0accSAmit Shah 20551df0accSAmit Shah /* The IO vqs for this port */ 20651df0accSAmit Shah struct virtqueue *in_vq, *out_vq; 20751df0accSAmit Shah 20851df0accSAmit Shah /* File in the debugfs directory that exposes this port's information */ 20951df0accSAmit Shah struct dentry *debugfs_file; 21051df0accSAmit Shah 21151df0accSAmit Shah /* 21217e5b4f2SAmit Shah * Keep count of the bytes sent, received and discarded for 21317e5b4f2SAmit Shah * this port for accounting and debugging purposes. These 21417e5b4f2SAmit Shah * counts are not reset across port open / close events. 21517e5b4f2SAmit Shah */ 21617e5b4f2SAmit Shah struct port_stats stats; 21717e5b4f2SAmit Shah 21817e5b4f2SAmit Shah /* 21951df0accSAmit Shah * The entries in this struct will be valid if this port is 22051df0accSAmit Shah * hooked up to an hvc console 22151df0accSAmit Shah */ 22251df0accSAmit Shah struct console cons; 22351df0accSAmit Shah 22451df0accSAmit Shah /* Each port associates with a separate char device */ 22551df0accSAmit Shah struct cdev *cdev; 22651df0accSAmit Shah struct device *dev; 22751df0accSAmit Shah 22851df0accSAmit Shah /* Reference-counting to handle port hot-unplugs and file operations */ 22951df0accSAmit Shah struct kref kref; 23051df0accSAmit Shah 23151df0accSAmit Shah /* A waitqueue for poll() or blocking read operations */ 23251df0accSAmit Shah wait_queue_head_t waitqueue; 23351df0accSAmit Shah 23451df0accSAmit Shah /* The 'name' of the port that we expose via sysfs properties */ 23551df0accSAmit Shah char *name; 23651df0accSAmit Shah 23751df0accSAmit Shah /* We can notify apps of host connect / disconnect events via SIGIO */ 23851df0accSAmit Shah struct fasync_struct *async_queue; 23951df0accSAmit Shah 24051df0accSAmit Shah /* The 'id' to identify the port with the Host */ 24151df0accSAmit Shah u32 id; 24251df0accSAmit Shah 24351df0accSAmit Shah bool outvq_full; 24451df0accSAmit Shah 24551df0accSAmit Shah /* Is the host device open */ 24651df0accSAmit Shah bool host_connected; 24751df0accSAmit Shah 24851df0accSAmit Shah /* We should allow only one process to open a port */ 24951df0accSAmit Shah bool guest_connected; 25051df0accSAmit Shah }; 25151df0accSAmit Shah 25251df0accSAmit Shah /* This is the very early arch-specified put chars function. */ 25351df0accSAmit Shah static int (*early_put_chars)(u32, const char *, int); 25451df0accSAmit Shah 25551df0accSAmit Shah static struct port *find_port_by_vtermno(u32 vtermno) 25651df0accSAmit Shah { 25751df0accSAmit Shah struct port *port; 25851df0accSAmit Shah struct console *cons; 25951df0accSAmit Shah unsigned long flags; 26051df0accSAmit Shah 26151df0accSAmit Shah spin_lock_irqsave(&pdrvdata_lock, flags); 26251df0accSAmit Shah list_for_each_entry(cons, &pdrvdata.consoles, list) { 26351df0accSAmit Shah if (cons->vtermno == vtermno) { 26451df0accSAmit Shah port = container_of(cons, struct port, cons); 26551df0accSAmit Shah goto out; 26651df0accSAmit Shah } 26751df0accSAmit Shah } 26851df0accSAmit Shah port = NULL; 26951df0accSAmit Shah out: 27051df0accSAmit Shah spin_unlock_irqrestore(&pdrvdata_lock, flags); 27151df0accSAmit Shah return port; 27251df0accSAmit Shah } 27351df0accSAmit Shah 27451df0accSAmit Shah static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, 27551df0accSAmit Shah dev_t dev) 27651df0accSAmit Shah { 27751df0accSAmit Shah struct port *port; 27851df0accSAmit Shah unsigned long flags; 27951df0accSAmit Shah 28051df0accSAmit Shah spin_lock_irqsave(&portdev->ports_lock, flags); 281057b82beSAmit Shah list_for_each_entry(port, &portdev->ports, list) { 282057b82beSAmit Shah if (port->cdev->dev == dev) { 283057b82beSAmit Shah kref_get(&port->kref); 28451df0accSAmit Shah goto out; 285057b82beSAmit Shah } 286057b82beSAmit Shah } 28751df0accSAmit Shah port = NULL; 28851df0accSAmit Shah out: 28951df0accSAmit Shah spin_unlock_irqrestore(&portdev->ports_lock, flags); 29051df0accSAmit Shah 29151df0accSAmit Shah return port; 29251df0accSAmit Shah } 29351df0accSAmit Shah 29451df0accSAmit Shah static struct port *find_port_by_devt(dev_t dev) 29551df0accSAmit Shah { 29651df0accSAmit Shah struct ports_device *portdev; 29751df0accSAmit Shah struct port *port; 29851df0accSAmit Shah unsigned long flags; 29951df0accSAmit Shah 30051df0accSAmit Shah spin_lock_irqsave(&pdrvdata_lock, flags); 30151df0accSAmit Shah list_for_each_entry(portdev, &pdrvdata.portdevs, list) { 30251df0accSAmit Shah port = find_port_by_devt_in_portdev(portdev, dev); 30351df0accSAmit Shah if (port) 30451df0accSAmit Shah goto out; 30551df0accSAmit Shah } 30651df0accSAmit Shah port = NULL; 30751df0accSAmit Shah out: 30851df0accSAmit Shah spin_unlock_irqrestore(&pdrvdata_lock, flags); 30951df0accSAmit Shah return port; 31051df0accSAmit Shah } 31151df0accSAmit Shah 31251df0accSAmit Shah static struct port *find_port_by_id(struct ports_device *portdev, u32 id) 31351df0accSAmit Shah { 31451df0accSAmit Shah struct port *port; 31551df0accSAmit Shah unsigned long flags; 31651df0accSAmit Shah 31751df0accSAmit Shah spin_lock_irqsave(&portdev->ports_lock, flags); 31851df0accSAmit Shah list_for_each_entry(port, &portdev->ports, list) 31951df0accSAmit Shah if (port->id == id) 32051df0accSAmit Shah goto out; 32151df0accSAmit Shah port = NULL; 32251df0accSAmit Shah out: 32351df0accSAmit Shah spin_unlock_irqrestore(&portdev->ports_lock, flags); 32451df0accSAmit Shah 32551df0accSAmit Shah return port; 32651df0accSAmit Shah } 32751df0accSAmit Shah 32851df0accSAmit Shah static struct port *find_port_by_vq(struct ports_device *portdev, 32951df0accSAmit Shah struct virtqueue *vq) 33051df0accSAmit Shah { 33151df0accSAmit Shah struct port *port; 33251df0accSAmit Shah unsigned long flags; 33351df0accSAmit Shah 33451df0accSAmit Shah spin_lock_irqsave(&portdev->ports_lock, flags); 33551df0accSAmit Shah list_for_each_entry(port, &portdev->ports, list) 33651df0accSAmit Shah if (port->in_vq == vq || port->out_vq == vq) 33751df0accSAmit Shah goto out; 33851df0accSAmit Shah port = NULL; 33951df0accSAmit Shah out: 34051df0accSAmit Shah spin_unlock_irqrestore(&portdev->ports_lock, flags); 34151df0accSAmit Shah return port; 34251df0accSAmit Shah } 34351df0accSAmit Shah 34451df0accSAmit Shah static bool is_console_port(struct port *port) 34551df0accSAmit Shah { 34651df0accSAmit Shah if (port->cons.hvc) 34751df0accSAmit Shah return true; 34851df0accSAmit Shah return false; 34951df0accSAmit Shah } 35051df0accSAmit Shah 3511b637046SSjur Brændeland static bool is_rproc_serial(const struct virtio_device *vdev) 3521b637046SSjur Brændeland { 3531b637046SSjur Brændeland return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL; 3541b637046SSjur Brændeland } 3551b637046SSjur Brændeland 35651df0accSAmit Shah static inline bool use_multiport(struct ports_device *portdev) 35751df0accSAmit Shah { 35851df0accSAmit Shah /* 35951df0accSAmit Shah * This condition can be true when put_chars is called from 36051df0accSAmit Shah * early_init 36151df0accSAmit Shah */ 36251df0accSAmit Shah if (!portdev->vdev) 363f580d730SJoe Perches return false; 364e16e12beSMichael S. Tsirkin return __virtio_test_bit(portdev->vdev, VIRTIO_CONSOLE_F_MULTIPORT); 36551df0accSAmit Shah } 36651df0accSAmit Shah 3671b637046SSjur Brændeland static DEFINE_SPINLOCK(dma_bufs_lock); 3681b637046SSjur Brændeland static LIST_HEAD(pending_free_dma_bufs); 3691b637046SSjur Brændeland 3701b637046SSjur Brændeland static void free_buf(struct port_buffer *buf, bool can_sleep) 37151df0accSAmit Shah { 372276a3e95SSjur Brændeland unsigned int i; 373276a3e95SSjur Brændeland 374276a3e95SSjur Brændeland for (i = 0; i < buf->sgpages; i++) { 375276a3e95SSjur Brændeland struct page *page = sg_page(&buf->sg[i]); 376276a3e95SSjur Brændeland if (!page) 377276a3e95SSjur Brændeland break; 378276a3e95SSjur Brændeland put_page(page); 379276a3e95SSjur Brændeland } 380276a3e95SSjur Brændeland 3811b637046SSjur Brændeland if (!buf->dev) { 38251df0accSAmit Shah kfree(buf->buf); 3831b637046SSjur Brændeland } else if (is_rproc_enabled) { 3841b637046SSjur Brændeland unsigned long flags; 3851b637046SSjur Brændeland 3861b637046SSjur Brændeland /* dma_free_coherent requires interrupts to be enabled. */ 3871b637046SSjur Brændeland if (!can_sleep) { 3881b637046SSjur Brændeland /* queue up dma-buffers to be freed later */ 3891b637046SSjur Brændeland spin_lock_irqsave(&dma_bufs_lock, flags); 3901b637046SSjur Brændeland list_add_tail(&buf->list, &pending_free_dma_bufs); 3911b637046SSjur Brændeland spin_unlock_irqrestore(&dma_bufs_lock, flags); 3921b637046SSjur Brændeland return; 3931b637046SSjur Brændeland } 3941b637046SSjur Brændeland dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma); 3951b637046SSjur Brændeland 3961b637046SSjur Brændeland /* Release device refcnt and allow it to be freed */ 3971b637046SSjur Brændeland put_device(buf->dev); 3981b637046SSjur Brændeland } 3991b637046SSjur Brændeland 40051df0accSAmit Shah kfree(buf); 40151df0accSAmit Shah } 40251df0accSAmit Shah 4031b637046SSjur Brændeland static void reclaim_dma_bufs(void) 4041b637046SSjur Brændeland { 4051b637046SSjur Brændeland unsigned long flags; 4061b637046SSjur Brændeland struct port_buffer *buf, *tmp; 4071b637046SSjur Brændeland LIST_HEAD(tmp_list); 4081b637046SSjur Brændeland 4091b637046SSjur Brændeland if (list_empty(&pending_free_dma_bufs)) 4101b637046SSjur Brændeland return; 4111b637046SSjur Brændeland 4121b637046SSjur Brændeland /* Create a copy of the pending_free_dma_bufs while holding the lock */ 4131b637046SSjur Brændeland spin_lock_irqsave(&dma_bufs_lock, flags); 4141b637046SSjur Brændeland list_cut_position(&tmp_list, &pending_free_dma_bufs, 4151b637046SSjur Brændeland pending_free_dma_bufs.prev); 4161b637046SSjur Brændeland spin_unlock_irqrestore(&dma_bufs_lock, flags); 4171b637046SSjur Brændeland 4181b637046SSjur Brændeland /* Release the dma buffers, without irqs enabled */ 4191b637046SSjur Brændeland list_for_each_entry_safe(buf, tmp, &tmp_list, list) { 4201b637046SSjur Brændeland list_del(&buf->list); 4211b637046SSjur Brændeland free_buf(buf, true); 4221b637046SSjur Brændeland } 4231b637046SSjur Brændeland } 4241b637046SSjur Brændeland 425276a3e95SSjur Brændeland static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, 426276a3e95SSjur Brændeland int pages) 42751df0accSAmit Shah { 42851df0accSAmit Shah struct port_buffer *buf; 42951df0accSAmit Shah 4301b637046SSjur Brændeland reclaim_dma_bufs(); 4311b637046SSjur Brændeland 432276a3e95SSjur Brændeland /* 433276a3e95SSjur Brændeland * Allocate buffer and the sg list. The sg list array is allocated 434276a3e95SSjur Brændeland * directly after the port_buffer struct. 435276a3e95SSjur Brændeland */ 436276a3e95SSjur Brændeland buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages, 437276a3e95SSjur Brændeland GFP_KERNEL); 43851df0accSAmit Shah if (!buf) 43951df0accSAmit Shah goto fail; 440276a3e95SSjur Brændeland 441276a3e95SSjur Brændeland buf->sgpages = pages; 442276a3e95SSjur Brændeland if (pages > 0) { 4431b637046SSjur Brændeland buf->dev = NULL; 444276a3e95SSjur Brændeland buf->buf = NULL; 445276a3e95SSjur Brændeland return buf; 446276a3e95SSjur Brændeland } 447276a3e95SSjur Brændeland 4481b637046SSjur Brændeland if (is_rproc_serial(vq->vdev)) { 4491b637046SSjur Brændeland /* 4501b637046SSjur Brændeland * Allocate DMA memory from ancestor. When a virtio 4511b637046SSjur Brændeland * device is created by remoteproc, the DMA memory is 4521b637046SSjur Brændeland * associated with the grandparent device: 4531b637046SSjur Brændeland * vdev => rproc => platform-dev. 4541b637046SSjur Brændeland * The code here would have been less quirky if 4551b637046SSjur Brændeland * DMA_MEMORY_INCLUDES_CHILDREN had been supported 4561b637046SSjur Brændeland * in dma-coherent.c 4571b637046SSjur Brændeland */ 4581b637046SSjur Brændeland if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent) 4591b637046SSjur Brændeland goto free_buf; 4601b637046SSjur Brændeland buf->dev = vq->vdev->dev.parent->parent; 4611b637046SSjur Brændeland 4621b637046SSjur Brændeland /* Increase device refcnt to avoid freeing it */ 4631b637046SSjur Brændeland get_device(buf->dev); 4641b637046SSjur Brændeland buf->buf = dma_alloc_coherent(buf->dev, buf_size, &buf->dma, 4651b637046SSjur Brændeland GFP_KERNEL); 4661b637046SSjur Brændeland } else { 4671b637046SSjur Brændeland buf->dev = NULL; 4680127f685SSjur Brændeland buf->buf = kmalloc(buf_size, GFP_KERNEL); 4691b637046SSjur Brændeland } 4701b637046SSjur Brændeland 47151df0accSAmit Shah if (!buf->buf) 47251df0accSAmit Shah goto free_buf; 47351df0accSAmit Shah buf->len = 0; 47451df0accSAmit Shah buf->offset = 0; 47551df0accSAmit Shah buf->size = buf_size; 47651df0accSAmit Shah return buf; 47751df0accSAmit Shah 47851df0accSAmit Shah free_buf: 47951df0accSAmit Shah kfree(buf); 48051df0accSAmit Shah fail: 48151df0accSAmit Shah return NULL; 48251df0accSAmit Shah } 48351df0accSAmit Shah 48451df0accSAmit Shah /* Callers should take appropriate locks */ 485defde669SAmit Shah static struct port_buffer *get_inbuf(struct port *port) 48651df0accSAmit Shah { 48751df0accSAmit Shah struct port_buffer *buf; 48851df0accSAmit Shah unsigned int len; 48951df0accSAmit Shah 490d25a9ddaSAmit Shah if (port->inbuf) 491d25a9ddaSAmit Shah return port->inbuf; 492d25a9ddaSAmit Shah 493d25a9ddaSAmit Shah buf = virtqueue_get_buf(port->in_vq, &len); 49451df0accSAmit Shah if (buf) { 49551df0accSAmit Shah buf->len = len; 49651df0accSAmit Shah buf->offset = 0; 49717e5b4f2SAmit Shah port->stats.bytes_received += len; 49851df0accSAmit Shah } 49951df0accSAmit Shah return buf; 50051df0accSAmit Shah } 50151df0accSAmit Shah 50251df0accSAmit Shah /* 50351df0accSAmit Shah * Create a scatter-gather list representing our input buffer and put 50451df0accSAmit Shah * it in the queue. 50551df0accSAmit Shah * 50651df0accSAmit Shah * Callers should take appropriate locks. 50751df0accSAmit Shah */ 50851df0accSAmit Shah static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) 50951df0accSAmit Shah { 51051df0accSAmit Shah struct scatterlist sg[1]; 51151df0accSAmit Shah int ret; 51251df0accSAmit Shah 51351df0accSAmit Shah sg_init_one(sg, buf->buf, buf->size); 51451df0accSAmit Shah 5156797999dSRusty Russell ret = virtqueue_add_inbuf(vq, sg, 1, buf, GFP_ATOMIC); 51651df0accSAmit Shah virtqueue_kick(vq); 51749e86f16SAmit Shah if (!ret) 51849e86f16SAmit Shah ret = vq->num_free; 51951df0accSAmit Shah return ret; 52051df0accSAmit Shah } 52151df0accSAmit Shah 52251df0accSAmit Shah /* Discard any unread data this port has. Callers lockers. */ 52351df0accSAmit Shah static void discard_port_data(struct port *port) 52451df0accSAmit Shah { 52551df0accSAmit Shah struct port_buffer *buf; 5262d24cdaaSAmit Shah unsigned int err; 52751df0accSAmit Shah 528d7a62cd0SAmit Shah if (!port->portdev) { 529d7a62cd0SAmit Shah /* Device has been unplugged. vqs are already gone. */ 530d7a62cd0SAmit Shah return; 531d7a62cd0SAmit Shah } 5322d24cdaaSAmit Shah buf = get_inbuf(port); 53351df0accSAmit Shah 534ce072a0cSAmit Shah err = 0; 53551df0accSAmit Shah while (buf) { 53617e5b4f2SAmit Shah port->stats.bytes_discarded += buf->len - buf->offset; 5372d24cdaaSAmit Shah if (add_inbuf(port->in_vq, buf) < 0) { 538ce072a0cSAmit Shah err++; 5391b637046SSjur Brændeland free_buf(buf, false); 54051df0accSAmit Shah } 54151df0accSAmit Shah port->inbuf = NULL; 5422d24cdaaSAmit Shah buf = get_inbuf(port); 5432d24cdaaSAmit Shah } 544ce072a0cSAmit Shah if (err) 54551df0accSAmit Shah dev_warn(port->dev, "Errors adding %d buffers back to vq\n", 546ce072a0cSAmit Shah err); 54751df0accSAmit Shah } 54851df0accSAmit Shah 54951df0accSAmit Shah static bool port_has_data(struct port *port) 55051df0accSAmit Shah { 55151df0accSAmit Shah unsigned long flags; 55251df0accSAmit Shah bool ret; 55351df0accSAmit Shah 55451df0accSAmit Shah ret = false; 555d25a9ddaSAmit Shah spin_lock_irqsave(&port->inbuf_lock, flags); 556d25a9ddaSAmit Shah port->inbuf = get_inbuf(port); 557d25a9ddaSAmit Shah if (port->inbuf) 558d25a9ddaSAmit Shah ret = true; 559d25a9ddaSAmit Shah 56051df0accSAmit Shah spin_unlock_irqrestore(&port->inbuf_lock, flags); 56151df0accSAmit Shah return ret; 56251df0accSAmit Shah } 56351df0accSAmit Shah 56451df0accSAmit Shah static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, 56551df0accSAmit Shah unsigned int event, unsigned int value) 56651df0accSAmit Shah { 56751df0accSAmit Shah struct scatterlist sg[1]; 56851df0accSAmit Shah struct virtqueue *vq; 56951df0accSAmit Shah unsigned int len; 57051df0accSAmit Shah 57151df0accSAmit Shah if (!use_multiport(portdev)) 57251df0accSAmit Shah return 0; 57351df0accSAmit Shah 57451df0accSAmit Shah vq = portdev->c_ovq; 57551df0accSAmit Shah 5769ba5c80bSAmit Shah spin_lock(&portdev->c_ovq_lock); 5775e59d9a1SAndy Lutomirski 5785e59d9a1SAndy Lutomirski portdev->cpkt.id = cpu_to_virtio32(portdev->vdev, port_id); 5795e59d9a1SAndy Lutomirski portdev->cpkt.event = cpu_to_virtio16(portdev->vdev, event); 5805e59d9a1SAndy Lutomirski portdev->cpkt.value = cpu_to_virtio16(portdev->vdev, value); 5815e59d9a1SAndy Lutomirski 5825e59d9a1SAndy Lutomirski sg_init_one(sg, &portdev->cpkt, sizeof(struct virtio_console_control)); 5835e59d9a1SAndy Lutomirski 5845e59d9a1SAndy Lutomirski if (virtqueue_add_outbuf(vq, sg, 1, &portdev->cpkt, GFP_ATOMIC) == 0) { 58551df0accSAmit Shah virtqueue_kick(vq); 58640e4dc53SHeinz Graalfs while (!virtqueue_get_buf(vq, &len) 58740e4dc53SHeinz Graalfs && !virtqueue_is_broken(vq)) 58851df0accSAmit Shah cpu_relax(); 58951df0accSAmit Shah } 5905e59d9a1SAndy Lutomirski 5919ba5c80bSAmit Shah spin_unlock(&portdev->c_ovq_lock); 59251df0accSAmit Shah return 0; 59351df0accSAmit Shah } 59451df0accSAmit Shah 59551df0accSAmit Shah static ssize_t send_control_msg(struct port *port, unsigned int event, 59651df0accSAmit Shah unsigned int value) 59751df0accSAmit Shah { 59851df0accSAmit Shah /* Did the port get unplugged before userspace closed it? */ 59951df0accSAmit Shah if (port->portdev) 60051df0accSAmit Shah return __send_control_msg(port->portdev, port->id, event, value); 60151df0accSAmit Shah return 0; 60251df0accSAmit Shah } 60351df0accSAmit Shah 604eb5e89fcSMasami Hiramatsu 60551df0accSAmit Shah /* Callers must take the port->outvq_lock */ 60651df0accSAmit Shah static void reclaim_consumed_buffers(struct port *port) 60751df0accSAmit Shah { 608276a3e95SSjur Brændeland struct port_buffer *buf; 60951df0accSAmit Shah unsigned int len; 61051df0accSAmit Shah 611d7a62cd0SAmit Shah if (!port->portdev) { 612d7a62cd0SAmit Shah /* Device has been unplugged. vqs are already gone. */ 613d7a62cd0SAmit Shah return; 614d7a62cd0SAmit Shah } 615276a3e95SSjur Brændeland while ((buf = virtqueue_get_buf(port->out_vq, &len))) { 6161b637046SSjur Brændeland free_buf(buf, false); 61751df0accSAmit Shah port->outvq_full = false; 61851df0accSAmit Shah } 61951df0accSAmit Shah } 62051df0accSAmit Shah 621eb5e89fcSMasami Hiramatsu static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, 622eb5e89fcSMasami Hiramatsu int nents, size_t in_count, 623276a3e95SSjur Brændeland void *data, bool nonblock) 62451df0accSAmit Shah { 62551df0accSAmit Shah struct virtqueue *out_vq; 626589575a2SRusty Russell int err; 62751df0accSAmit Shah unsigned long flags; 62851df0accSAmit Shah unsigned int len; 62951df0accSAmit Shah 63051df0accSAmit Shah out_vq = port->out_vq; 63151df0accSAmit Shah 63251df0accSAmit Shah spin_lock_irqsave(&port->outvq_lock, flags); 63351df0accSAmit Shah 63451df0accSAmit Shah reclaim_consumed_buffers(port); 63551df0accSAmit Shah 6366797999dSRusty Russell err = virtqueue_add_outbuf(out_vq, sg, nents, data, GFP_ATOMIC); 63751df0accSAmit Shah 63851df0accSAmit Shah /* Tell Host to go! */ 63951df0accSAmit Shah virtqueue_kick(out_vq); 64051df0accSAmit Shah 641589575a2SRusty Russell if (err) { 64251df0accSAmit Shah in_count = 0; 64351df0accSAmit Shah goto done; 64451df0accSAmit Shah } 64551df0accSAmit Shah 646589575a2SRusty Russell if (out_vq->num_free == 0) 64751df0accSAmit Shah port->outvq_full = true; 64851df0accSAmit Shah 64951df0accSAmit Shah if (nonblock) 65051df0accSAmit Shah goto done; 65151df0accSAmit Shah 65251df0accSAmit Shah /* 65351df0accSAmit Shah * Wait till the host acknowledges it pushed out the data we 65451df0accSAmit Shah * sent. This is done for data from the hvc_console; the tty 65551df0accSAmit Shah * operations are performed with spinlocks held so we can't 65651df0accSAmit Shah * sleep here. An alternative would be to copy the data to a 65751df0accSAmit Shah * buffer and relax the spinning requirement. The downside is 65851df0accSAmit Shah * we need to kmalloc a GFP_ATOMIC buffer each time the 65951df0accSAmit Shah * console driver writes something out. 66051df0accSAmit Shah */ 66140e4dc53SHeinz Graalfs while (!virtqueue_get_buf(out_vq, &len) 66240e4dc53SHeinz Graalfs && !virtqueue_is_broken(out_vq)) 66351df0accSAmit Shah cpu_relax(); 66451df0accSAmit Shah done: 66551df0accSAmit Shah spin_unlock_irqrestore(&port->outvq_lock, flags); 66617e5b4f2SAmit Shah 66717e5b4f2SAmit Shah port->stats.bytes_sent += in_count; 66851df0accSAmit Shah /* 66951df0accSAmit Shah * We're expected to return the amount of data we wrote -- all 67051df0accSAmit Shah * of it 67151df0accSAmit Shah */ 67251df0accSAmit Shah return in_count; 67351df0accSAmit Shah } 67451df0accSAmit Shah 67551df0accSAmit Shah /* 67651df0accSAmit Shah * Give out the data that's requested from the buffer that we have 67751df0accSAmit Shah * queued up. 67851df0accSAmit Shah */ 67948b36066SMichael S. Tsirkin static ssize_t fill_readbuf(struct port *port, char __user *out_buf, 68048b36066SMichael S. Tsirkin size_t out_count, bool to_user) 68151df0accSAmit Shah { 68251df0accSAmit Shah struct port_buffer *buf; 68351df0accSAmit Shah unsigned long flags; 68451df0accSAmit Shah 68551df0accSAmit Shah if (!out_count || !port_has_data(port)) 68651df0accSAmit Shah return 0; 68751df0accSAmit Shah 68851df0accSAmit Shah buf = port->inbuf; 68951df0accSAmit Shah out_count = min(out_count, buf->len - buf->offset); 69051df0accSAmit Shah 69151df0accSAmit Shah if (to_user) { 69251df0accSAmit Shah ssize_t ret; 69351df0accSAmit Shah 69451df0accSAmit Shah ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count); 69551df0accSAmit Shah if (ret) 69651df0accSAmit Shah return -EFAULT; 69751df0accSAmit Shah } else { 69848b36066SMichael S. Tsirkin memcpy((__force char *)out_buf, buf->buf + buf->offset, 69948b36066SMichael S. Tsirkin out_count); 70051df0accSAmit Shah } 70151df0accSAmit Shah 70251df0accSAmit Shah buf->offset += out_count; 70351df0accSAmit Shah 70451df0accSAmit Shah if (buf->offset == buf->len) { 70551df0accSAmit Shah /* 70651df0accSAmit Shah * We're done using all the data in this buffer. 70751df0accSAmit Shah * Re-queue so that the Host can send us more data. 70851df0accSAmit Shah */ 70951df0accSAmit Shah spin_lock_irqsave(&port->inbuf_lock, flags); 71051df0accSAmit Shah port->inbuf = NULL; 71151df0accSAmit Shah 71251df0accSAmit Shah if (add_inbuf(port->in_vq, buf) < 0) 71351df0accSAmit Shah dev_warn(port->dev, "failed add_buf\n"); 71451df0accSAmit Shah 71551df0accSAmit Shah spin_unlock_irqrestore(&port->inbuf_lock, flags); 71651df0accSAmit Shah } 71751df0accSAmit Shah /* Return the number of bytes actually copied */ 71851df0accSAmit Shah return out_count; 71951df0accSAmit Shah } 72051df0accSAmit Shah 72151df0accSAmit Shah /* The condition that must be true for polling to end */ 72251df0accSAmit Shah static bool will_read_block(struct port *port) 72351df0accSAmit Shah { 72451df0accSAmit Shah if (!port->guest_connected) { 72551df0accSAmit Shah /* Port got hot-unplugged. Let's exit. */ 72651df0accSAmit Shah return false; 72751df0accSAmit Shah } 72851df0accSAmit Shah return !port_has_data(port) && port->host_connected; 72951df0accSAmit Shah } 73051df0accSAmit Shah 73151df0accSAmit Shah static bool will_write_block(struct port *port) 73251df0accSAmit Shah { 73351df0accSAmit Shah bool ret; 73451df0accSAmit Shah 73551df0accSAmit Shah if (!port->guest_connected) { 73651df0accSAmit Shah /* Port got hot-unplugged. Let's exit. */ 73751df0accSAmit Shah return false; 73851df0accSAmit Shah } 73951df0accSAmit Shah if (!port->host_connected) 74051df0accSAmit Shah return true; 74151df0accSAmit Shah 74251df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 74351df0accSAmit Shah /* 74451df0accSAmit Shah * Check if the Host has consumed any buffers since we last 74551df0accSAmit Shah * sent data (this is only applicable for nonblocking ports). 74651df0accSAmit Shah */ 74751df0accSAmit Shah reclaim_consumed_buffers(port); 74851df0accSAmit Shah ret = port->outvq_full; 74951df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 75051df0accSAmit Shah 75151df0accSAmit Shah return ret; 75251df0accSAmit Shah } 75351df0accSAmit Shah 75451df0accSAmit Shah static ssize_t port_fops_read(struct file *filp, char __user *ubuf, 75551df0accSAmit Shah size_t count, loff_t *offp) 75651df0accSAmit Shah { 75751df0accSAmit Shah struct port *port; 75851df0accSAmit Shah ssize_t ret; 75951df0accSAmit Shah 76051df0accSAmit Shah port = filp->private_data; 76151df0accSAmit Shah 76296f97a83SAmit Shah /* Port is hot-unplugged. */ 76396f97a83SAmit Shah if (!port->guest_connected) 76496f97a83SAmit Shah return -ENODEV; 76596f97a83SAmit Shah 76651df0accSAmit Shah if (!port_has_data(port)) { 76751df0accSAmit Shah /* 76851df0accSAmit Shah * If nothing's connected on the host just return 0 in 76951df0accSAmit Shah * case of list_empty; this tells the userspace app 77051df0accSAmit Shah * that there's no connection 77151df0accSAmit Shah */ 77251df0accSAmit Shah if (!port->host_connected) 77351df0accSAmit Shah return 0; 77451df0accSAmit Shah if (filp->f_flags & O_NONBLOCK) 77551df0accSAmit Shah return -EAGAIN; 77651df0accSAmit Shah 777a08fa92dSAmit Shah ret = wait_event_freezable(port->waitqueue, 77851df0accSAmit Shah !will_read_block(port)); 77951df0accSAmit Shah if (ret < 0) 78051df0accSAmit Shah return ret; 78151df0accSAmit Shah } 78296f97a83SAmit Shah /* Port got hot-unplugged while we were waiting above. */ 78351df0accSAmit Shah if (!port->guest_connected) 78451df0accSAmit Shah return -ENODEV; 78551df0accSAmit Shah /* 78651df0accSAmit Shah * We could've received a disconnection message while we were 78751df0accSAmit Shah * waiting for more data. 78851df0accSAmit Shah * 78951df0accSAmit Shah * This check is not clubbed in the if() statement above as we 79051df0accSAmit Shah * might receive some data as well as the host could get 79151df0accSAmit Shah * disconnected after we got woken up from our wait. So we 79251df0accSAmit Shah * really want to give off whatever data we have and only then 79351df0accSAmit Shah * check for host_connected. 79451df0accSAmit Shah */ 79551df0accSAmit Shah if (!port_has_data(port) && !port->host_connected) 79651df0accSAmit Shah return 0; 79751df0accSAmit Shah 79851df0accSAmit Shah return fill_readbuf(port, ubuf, count, true); 79951df0accSAmit Shah } 80051df0accSAmit Shah 801efe75d24SMasami Hiramatsu static int wait_port_writable(struct port *port, bool nonblock) 802efe75d24SMasami Hiramatsu { 803efe75d24SMasami Hiramatsu int ret; 804efe75d24SMasami Hiramatsu 805efe75d24SMasami Hiramatsu if (will_write_block(port)) { 806efe75d24SMasami Hiramatsu if (nonblock) 807efe75d24SMasami Hiramatsu return -EAGAIN; 808efe75d24SMasami Hiramatsu 809efe75d24SMasami Hiramatsu ret = wait_event_freezable(port->waitqueue, 810efe75d24SMasami Hiramatsu !will_write_block(port)); 811efe75d24SMasami Hiramatsu if (ret < 0) 812efe75d24SMasami Hiramatsu return ret; 813efe75d24SMasami Hiramatsu } 814efe75d24SMasami Hiramatsu /* Port got hot-unplugged. */ 815efe75d24SMasami Hiramatsu if (!port->guest_connected) 816efe75d24SMasami Hiramatsu return -ENODEV; 817efe75d24SMasami Hiramatsu 818efe75d24SMasami Hiramatsu return 0; 819efe75d24SMasami Hiramatsu } 820efe75d24SMasami Hiramatsu 82151df0accSAmit Shah static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, 82251df0accSAmit Shah size_t count, loff_t *offp) 82351df0accSAmit Shah { 82451df0accSAmit Shah struct port *port; 825276a3e95SSjur Brændeland struct port_buffer *buf; 82651df0accSAmit Shah ssize_t ret; 82751df0accSAmit Shah bool nonblock; 828276a3e95SSjur Brændeland struct scatterlist sg[1]; 82951df0accSAmit Shah 83051df0accSAmit Shah /* Userspace could be out to fool us */ 83151df0accSAmit Shah if (!count) 83251df0accSAmit Shah return 0; 83351df0accSAmit Shah 83451df0accSAmit Shah port = filp->private_data; 83551df0accSAmit Shah 83651df0accSAmit Shah nonblock = filp->f_flags & O_NONBLOCK; 83751df0accSAmit Shah 838efe75d24SMasami Hiramatsu ret = wait_port_writable(port, nonblock); 83951df0accSAmit Shah if (ret < 0) 84051df0accSAmit Shah return ret; 84151df0accSAmit Shah 84251df0accSAmit Shah count = min((size_t)(32 * 1024), count); 84351df0accSAmit Shah 844276a3e95SSjur Brændeland buf = alloc_buf(port->out_vq, count, 0); 84551df0accSAmit Shah if (!buf) 84651df0accSAmit Shah return -ENOMEM; 84751df0accSAmit Shah 848276a3e95SSjur Brændeland ret = copy_from_user(buf->buf, ubuf, count); 84951df0accSAmit Shah if (ret) { 85051df0accSAmit Shah ret = -EFAULT; 85151df0accSAmit Shah goto free_buf; 85251df0accSAmit Shah } 85351df0accSAmit Shah 85451df0accSAmit Shah /* 85551df0accSAmit Shah * We now ask send_buf() to not spin for generic ports -- we 85651df0accSAmit Shah * can re-use the same code path that non-blocking file 85751df0accSAmit Shah * descriptors take for blocking file descriptors since the 85851df0accSAmit Shah * wait is already done and we're certain the write will go 85951df0accSAmit Shah * through to the host. 86051df0accSAmit Shah */ 86151df0accSAmit Shah nonblock = true; 862276a3e95SSjur Brændeland sg_init_one(sg, buf->buf, count); 863276a3e95SSjur Brændeland ret = __send_to_port(port, sg, 1, count, buf, nonblock); 86451df0accSAmit Shah 86551df0accSAmit Shah if (nonblock && ret > 0) 86651df0accSAmit Shah goto out; 86751df0accSAmit Shah 86851df0accSAmit Shah free_buf: 8691b637046SSjur Brændeland free_buf(buf, true); 87051df0accSAmit Shah out: 87151df0accSAmit Shah return ret; 87251df0accSAmit Shah } 87351df0accSAmit Shah 874eb5e89fcSMasami Hiramatsu struct sg_list { 875eb5e89fcSMasami Hiramatsu unsigned int n; 8768ca84a50SMasami Hiramatsu unsigned int size; 877eb5e89fcSMasami Hiramatsu size_t len; 878eb5e89fcSMasami Hiramatsu struct scatterlist *sg; 879eb5e89fcSMasami Hiramatsu }; 880eb5e89fcSMasami Hiramatsu 881eb5e89fcSMasami Hiramatsu static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, 882eb5e89fcSMasami Hiramatsu struct splice_desc *sd) 883eb5e89fcSMasami Hiramatsu { 884eb5e89fcSMasami Hiramatsu struct sg_list *sgl = sd->u.data; 885ec8fc870SMasami Hiramatsu unsigned int offset, len; 886eb5e89fcSMasami Hiramatsu 8878ca84a50SMasami Hiramatsu if (sgl->n == sgl->size) 888eb5e89fcSMasami Hiramatsu return 0; 889eb5e89fcSMasami Hiramatsu 890eb5e89fcSMasami Hiramatsu /* Try lock this page */ 891ca76f5b6SMiklos Szeredi if (pipe_buf_steal(pipe, buf) == 0) { 892eb5e89fcSMasami Hiramatsu /* Get reference and unlock page for moving */ 893eb5e89fcSMasami Hiramatsu get_page(buf->page); 894eb5e89fcSMasami Hiramatsu unlock_page(buf->page); 895eb5e89fcSMasami Hiramatsu 896eb5e89fcSMasami Hiramatsu len = min(buf->len, sd->len); 897eb5e89fcSMasami Hiramatsu sg_set_page(&(sgl->sg[sgl->n]), buf->page, len, buf->offset); 898ec8fc870SMasami Hiramatsu } else { 899ec8fc870SMasami Hiramatsu /* Failback to copying a page */ 900ec8fc870SMasami Hiramatsu struct page *page = alloc_page(GFP_KERNEL); 901c9efe511SAl Viro char *src; 902ec8fc870SMasami Hiramatsu 903ec8fc870SMasami Hiramatsu if (!page) 904ec8fc870SMasami Hiramatsu return -ENOMEM; 905ec8fc870SMasami Hiramatsu 906ec8fc870SMasami Hiramatsu offset = sd->pos & ~PAGE_MASK; 907ec8fc870SMasami Hiramatsu 908ec8fc870SMasami Hiramatsu len = sd->len; 909ec8fc870SMasami Hiramatsu if (len + offset > PAGE_SIZE) 910ec8fc870SMasami Hiramatsu len = PAGE_SIZE - offset; 911ec8fc870SMasami Hiramatsu 912fbb32750SAl Viro src = kmap_atomic(buf->page); 913c9efe511SAl Viro memcpy(page_address(page) + offset, src + buf->offset, len); 914fbb32750SAl Viro kunmap_atomic(src); 915ec8fc870SMasami Hiramatsu 916ec8fc870SMasami Hiramatsu sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); 917ec8fc870SMasami Hiramatsu } 918eb5e89fcSMasami Hiramatsu sgl->n++; 919eb5e89fcSMasami Hiramatsu sgl->len += len; 920eb5e89fcSMasami Hiramatsu 921eb5e89fcSMasami Hiramatsu return len; 922eb5e89fcSMasami Hiramatsu } 923eb5e89fcSMasami Hiramatsu 924eb5e89fcSMasami Hiramatsu /* Faster zero-copy write by splicing */ 925eb5e89fcSMasami Hiramatsu static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, 926eb5e89fcSMasami Hiramatsu struct file *filp, loff_t *ppos, 927eb5e89fcSMasami Hiramatsu size_t len, unsigned int flags) 928eb5e89fcSMasami Hiramatsu { 929eb5e89fcSMasami Hiramatsu struct port *port = filp->private_data; 930eb5e89fcSMasami Hiramatsu struct sg_list sgl; 931eb5e89fcSMasami Hiramatsu ssize_t ret; 932276a3e95SSjur Brændeland struct port_buffer *buf; 933eb5e89fcSMasami Hiramatsu struct splice_desc sd = { 934eb5e89fcSMasami Hiramatsu .total_len = len, 935eb5e89fcSMasami Hiramatsu .flags = flags, 936eb5e89fcSMasami Hiramatsu .pos = *ppos, 937eb5e89fcSMasami Hiramatsu .u.data = &sgl, 938eb5e89fcSMasami Hiramatsu }; 939eb5e89fcSMasami Hiramatsu 9401b637046SSjur Brændeland /* 9411b637046SSjur Brændeland * Rproc_serial does not yet support splice. To support splice 9421b637046SSjur Brændeland * pipe_to_sg() must allocate dma-buffers and copy content from 9431b637046SSjur Brændeland * regular pages to dma pages. And alloc_buf and free_buf must 9441b637046SSjur Brændeland * support allocating and freeing such a list of dma-buffers. 9451b637046SSjur Brændeland */ 9461b637046SSjur Brændeland if (is_rproc_serial(port->out_vq->vdev)) 9471b637046SSjur Brændeland return -EINVAL; 9481b637046SSjur Brændeland 94968c034feSYoshihiro YUNOMAE /* 95068c034feSYoshihiro YUNOMAE * pipe->nrbufs == 0 means there are no data to transfer, 95168c034feSYoshihiro YUNOMAE * so this returns just 0 for no data. 95268c034feSYoshihiro YUNOMAE */ 9532b4fbf02SYoshihiro YUNOMAE pipe_lock(pipe); 9542b4fbf02SYoshihiro YUNOMAE if (!pipe->nrbufs) { 9552b4fbf02SYoshihiro YUNOMAE ret = 0; 9562b4fbf02SYoshihiro YUNOMAE goto error_out; 9572b4fbf02SYoshihiro YUNOMAE } 95868c034feSYoshihiro YUNOMAE 959efe75d24SMasami Hiramatsu ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); 960efe75d24SMasami Hiramatsu if (ret < 0) 9612b4fbf02SYoshihiro YUNOMAE goto error_out; 962efe75d24SMasami Hiramatsu 963276a3e95SSjur Brændeland buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); 9642b4fbf02SYoshihiro YUNOMAE if (!buf) { 9652b4fbf02SYoshihiro YUNOMAE ret = -ENOMEM; 9662b4fbf02SYoshihiro YUNOMAE goto error_out; 9672b4fbf02SYoshihiro YUNOMAE } 968276a3e95SSjur Brændeland 969eb5e89fcSMasami Hiramatsu sgl.n = 0; 970eb5e89fcSMasami Hiramatsu sgl.len = 0; 9718ca84a50SMasami Hiramatsu sgl.size = pipe->nrbufs; 972276a3e95SSjur Brændeland sgl.sg = buf->sg; 9738ca84a50SMasami Hiramatsu sg_init_table(sgl.sg, sgl.size); 974eb5e89fcSMasami Hiramatsu ret = __splice_from_pipe(pipe, &sd, pipe_to_sg); 9752b4fbf02SYoshihiro YUNOMAE pipe_unlock(pipe); 976eb5e89fcSMasami Hiramatsu if (likely(ret > 0)) 977276a3e95SSjur Brændeland ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true); 978eb5e89fcSMasami Hiramatsu 979fe529537SSjur Brændeland if (unlikely(ret <= 0)) 9801b637046SSjur Brændeland free_buf(buf, true); 981eb5e89fcSMasami Hiramatsu return ret; 9822b4fbf02SYoshihiro YUNOMAE 9832b4fbf02SYoshihiro YUNOMAE error_out: 9842b4fbf02SYoshihiro YUNOMAE pipe_unlock(pipe); 9852b4fbf02SYoshihiro YUNOMAE return ret; 986eb5e89fcSMasami Hiramatsu } 987eb5e89fcSMasami Hiramatsu 98851df0accSAmit Shah static unsigned int port_fops_poll(struct file *filp, poll_table *wait) 98951df0accSAmit Shah { 99051df0accSAmit Shah struct port *port; 99151df0accSAmit Shah unsigned int ret; 99251df0accSAmit Shah 99351df0accSAmit Shah port = filp->private_data; 99451df0accSAmit Shah poll_wait(filp, &port->waitqueue, wait); 99551df0accSAmit Shah 99651df0accSAmit Shah if (!port->guest_connected) { 99751df0accSAmit Shah /* Port got unplugged */ 99851df0accSAmit Shah return POLLHUP; 99951df0accSAmit Shah } 100051df0accSAmit Shah ret = 0; 100151df0accSAmit Shah if (!will_read_block(port)) 100251df0accSAmit Shah ret |= POLLIN | POLLRDNORM; 100351df0accSAmit Shah if (!will_write_block(port)) 100451df0accSAmit Shah ret |= POLLOUT; 100551df0accSAmit Shah if (!port->host_connected) 100651df0accSAmit Shah ret |= POLLHUP; 100751df0accSAmit Shah 100851df0accSAmit Shah return ret; 100951df0accSAmit Shah } 101051df0accSAmit Shah 101151df0accSAmit Shah static void remove_port(struct kref *kref); 101251df0accSAmit Shah 101351df0accSAmit Shah static int port_fops_release(struct inode *inode, struct file *filp) 101451df0accSAmit Shah { 101551df0accSAmit Shah struct port *port; 101651df0accSAmit Shah 101751df0accSAmit Shah port = filp->private_data; 101851df0accSAmit Shah 101951df0accSAmit Shah /* Notify host of port being closed */ 102051df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); 102151df0accSAmit Shah 102251df0accSAmit Shah spin_lock_irq(&port->inbuf_lock); 102351df0accSAmit Shah port->guest_connected = false; 102451df0accSAmit Shah 102551df0accSAmit Shah discard_port_data(port); 102651df0accSAmit Shah 102751df0accSAmit Shah spin_unlock_irq(&port->inbuf_lock); 102851df0accSAmit Shah 102951df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 103051df0accSAmit Shah reclaim_consumed_buffers(port); 103151df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 103251df0accSAmit Shah 10331b637046SSjur Brændeland reclaim_dma_bufs(); 103451df0accSAmit Shah /* 103551df0accSAmit Shah * Locks aren't necessary here as a port can't be opened after 103651df0accSAmit Shah * unplug, and if a port isn't unplugged, a kref would already 103751df0accSAmit Shah * exist for the port. Plus, taking ports_lock here would 103851df0accSAmit Shah * create a dependency on other locks taken by functions 103951df0accSAmit Shah * inside remove_port if we're the last holder of the port, 104051df0accSAmit Shah * creating many problems. 104151df0accSAmit Shah */ 104251df0accSAmit Shah kref_put(&port->kref, remove_port); 104351df0accSAmit Shah 104451df0accSAmit Shah return 0; 104551df0accSAmit Shah } 104651df0accSAmit Shah 104751df0accSAmit Shah static int port_fops_open(struct inode *inode, struct file *filp) 104851df0accSAmit Shah { 104951df0accSAmit Shah struct cdev *cdev = inode->i_cdev; 105051df0accSAmit Shah struct port *port; 105151df0accSAmit Shah int ret; 105251df0accSAmit Shah 1053057b82beSAmit Shah /* We get the port with a kref here */ 105451df0accSAmit Shah port = find_port_by_devt(cdev->dev); 1055671bdea2SAmit Shah if (!port) { 1056671bdea2SAmit Shah /* Port was unplugged before we could proceed */ 1057671bdea2SAmit Shah return -ENXIO; 1058671bdea2SAmit Shah } 105951df0accSAmit Shah filp->private_data = port; 106051df0accSAmit Shah 106151df0accSAmit Shah /* 106251df0accSAmit Shah * Don't allow opening of console port devices -- that's done 106351df0accSAmit Shah * via /dev/hvc 106451df0accSAmit Shah */ 106551df0accSAmit Shah if (is_console_port(port)) { 106651df0accSAmit Shah ret = -ENXIO; 106751df0accSAmit Shah goto out; 106851df0accSAmit Shah } 106951df0accSAmit Shah 107051df0accSAmit Shah /* Allow only one process to open a particular port at a time */ 107151df0accSAmit Shah spin_lock_irq(&port->inbuf_lock); 107251df0accSAmit Shah if (port->guest_connected) { 107351df0accSAmit Shah spin_unlock_irq(&port->inbuf_lock); 107474ff582cSAmit Shah ret = -EBUSY; 107551df0accSAmit Shah goto out; 107651df0accSAmit Shah } 107751df0accSAmit Shah 107851df0accSAmit Shah port->guest_connected = true; 107951df0accSAmit Shah spin_unlock_irq(&port->inbuf_lock); 108051df0accSAmit Shah 108151df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 108251df0accSAmit Shah /* 108351df0accSAmit Shah * There might be a chance that we missed reclaiming a few 108451df0accSAmit Shah * buffers in the window of the port getting previously closed 108551df0accSAmit Shah * and opening now. 108651df0accSAmit Shah */ 108751df0accSAmit Shah reclaim_consumed_buffers(port); 108851df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 108951df0accSAmit Shah 109051df0accSAmit Shah nonseekable_open(inode, filp); 109151df0accSAmit Shah 109251df0accSAmit Shah /* Notify host of port being opened */ 109351df0accSAmit Shah send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); 109451df0accSAmit Shah 109551df0accSAmit Shah return 0; 109651df0accSAmit Shah out: 109751df0accSAmit Shah kref_put(&port->kref, remove_port); 109851df0accSAmit Shah return ret; 109951df0accSAmit Shah } 110051df0accSAmit Shah 110151df0accSAmit Shah static int port_fops_fasync(int fd, struct file *filp, int mode) 110251df0accSAmit Shah { 110351df0accSAmit Shah struct port *port; 110451df0accSAmit Shah 110551df0accSAmit Shah port = filp->private_data; 110651df0accSAmit Shah return fasync_helper(fd, filp, mode, &port->async_queue); 110751df0accSAmit Shah } 110851df0accSAmit Shah 110951df0accSAmit Shah /* 111051df0accSAmit Shah * The file operations that we support: programs in the guest can open 111151df0accSAmit Shah * a console device, read from it, write to it, poll for data and 111251df0accSAmit Shah * close it. The devices are at 111351df0accSAmit Shah * /dev/vport<device number>p<port number> 111451df0accSAmit Shah */ 111551df0accSAmit Shah static const struct file_operations port_fops = { 111651df0accSAmit Shah .owner = THIS_MODULE, 111751df0accSAmit Shah .open = port_fops_open, 111851df0accSAmit Shah .read = port_fops_read, 111951df0accSAmit Shah .write = port_fops_write, 1120eb5e89fcSMasami Hiramatsu .splice_write = port_fops_splice_write, 112151df0accSAmit Shah .poll = port_fops_poll, 112251df0accSAmit Shah .release = port_fops_release, 112351df0accSAmit Shah .fasync = port_fops_fasync, 112451df0accSAmit Shah .llseek = no_llseek, 112551df0accSAmit Shah }; 112651df0accSAmit Shah 112751df0accSAmit Shah /* 112851df0accSAmit Shah * The put_chars() callback is pretty straightforward. 112951df0accSAmit Shah * 113051df0accSAmit Shah * We turn the characters into a scatter-gather list, add it to the 113151df0accSAmit Shah * output queue and then kick the Host. Then we sit here waiting for 113251df0accSAmit Shah * it to finish: inefficient in theory, but in practice 113351df0accSAmit Shah * implementations will do it immediately (lguest's Launcher does). 113451df0accSAmit Shah */ 113551df0accSAmit Shah static int put_chars(u32 vtermno, const char *buf, int count) 113651df0accSAmit Shah { 113751df0accSAmit Shah struct port *port; 1138276a3e95SSjur Brændeland struct scatterlist sg[1]; 1139c4baad50SOmar Sandoval void *data; 1140c4baad50SOmar Sandoval int ret; 114151df0accSAmit Shah 114251df0accSAmit Shah if (unlikely(early_put_chars)) 114351df0accSAmit Shah return early_put_chars(vtermno, buf, count); 114451df0accSAmit Shah 114551df0accSAmit Shah port = find_port_by_vtermno(vtermno); 114651df0accSAmit Shah if (!port) 114751df0accSAmit Shah return -EPIPE; 114851df0accSAmit Shah 1149c4baad50SOmar Sandoval data = kmemdup(buf, count, GFP_ATOMIC); 1150c4baad50SOmar Sandoval if (!data) 1151c4baad50SOmar Sandoval return -ENOMEM; 1152c4baad50SOmar Sandoval 1153c4baad50SOmar Sandoval sg_init_one(sg, data, count); 1154c4baad50SOmar Sandoval ret = __send_to_port(port, sg, 1, count, data, false); 1155c4baad50SOmar Sandoval kfree(data); 1156c4baad50SOmar Sandoval return ret; 115751df0accSAmit Shah } 115851df0accSAmit Shah 115951df0accSAmit Shah /* 116051df0accSAmit Shah * get_chars() is the callback from the hvc_console infrastructure 116151df0accSAmit Shah * when an interrupt is received. 116251df0accSAmit Shah * 116351df0accSAmit Shah * We call out to fill_readbuf that gets us the required data from the 116451df0accSAmit Shah * buffers that are queued up. 116551df0accSAmit Shah */ 116651df0accSAmit Shah static int get_chars(u32 vtermno, char *buf, int count) 116751df0accSAmit Shah { 116851df0accSAmit Shah struct port *port; 116951df0accSAmit Shah 117051df0accSAmit Shah /* If we've not set up the port yet, we have no input to give. */ 117151df0accSAmit Shah if (unlikely(early_put_chars)) 117251df0accSAmit Shah return 0; 117351df0accSAmit Shah 117451df0accSAmit Shah port = find_port_by_vtermno(vtermno); 117551df0accSAmit Shah if (!port) 117651df0accSAmit Shah return -EPIPE; 117751df0accSAmit Shah 117851df0accSAmit Shah /* If we don't have an input queue yet, we can't get input. */ 117951df0accSAmit Shah BUG_ON(!port->in_vq); 118051df0accSAmit Shah 118148b36066SMichael S. Tsirkin return fill_readbuf(port, (__force char __user *)buf, count, false); 118251df0accSAmit Shah } 118351df0accSAmit Shah 118451df0accSAmit Shah static void resize_console(struct port *port) 118551df0accSAmit Shah { 118651df0accSAmit Shah struct virtio_device *vdev; 118751df0accSAmit Shah 118851df0accSAmit Shah /* The port could have been hot-unplugged */ 118951df0accSAmit Shah if (!port || !is_console_port(port)) 119051df0accSAmit Shah return; 119151df0accSAmit Shah 119251df0accSAmit Shah vdev = port->portdev->vdev; 11931b637046SSjur Brændeland 11941b637046SSjur Brændeland /* Don't test F_SIZE at all if we're rproc: not a valid feature! */ 11951b637046SSjur Brændeland if (!is_rproc_serial(vdev) && 11961b637046SSjur Brændeland virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) 119751df0accSAmit Shah hvc_resize(port->cons.hvc, port->cons.ws); 119851df0accSAmit Shah } 119951df0accSAmit Shah 120051df0accSAmit Shah /* We set the configuration at this point, since we now have a tty */ 120151df0accSAmit Shah static int notifier_add_vio(struct hvc_struct *hp, int data) 120251df0accSAmit Shah { 120351df0accSAmit Shah struct port *port; 120451df0accSAmit Shah 120551df0accSAmit Shah port = find_port_by_vtermno(hp->vtermno); 120651df0accSAmit Shah if (!port) 120751df0accSAmit Shah return -EINVAL; 120851df0accSAmit Shah 120951df0accSAmit Shah hp->irq_requested = 1; 121051df0accSAmit Shah resize_console(port); 121151df0accSAmit Shah 121251df0accSAmit Shah return 0; 121351df0accSAmit Shah } 121451df0accSAmit Shah 121551df0accSAmit Shah static void notifier_del_vio(struct hvc_struct *hp, int data) 121651df0accSAmit Shah { 121751df0accSAmit Shah hp->irq_requested = 0; 121851df0accSAmit Shah } 121951df0accSAmit Shah 122051df0accSAmit Shah /* The operations for console ports. */ 122151df0accSAmit Shah static const struct hv_ops hv_ops = { 122251df0accSAmit Shah .get_chars = get_chars, 122351df0accSAmit Shah .put_chars = put_chars, 122451df0accSAmit Shah .notifier_add = notifier_add_vio, 122551df0accSAmit Shah .notifier_del = notifier_del_vio, 122651df0accSAmit Shah .notifier_hangup = notifier_del_vio, 122751df0accSAmit Shah }; 122851df0accSAmit Shah 122951df0accSAmit Shah /* 123051df0accSAmit Shah * Console drivers are initialized very early so boot messages can go 123151df0accSAmit Shah * out, so we do things slightly differently from the generic virtio 123251df0accSAmit Shah * initialization of the net and block drivers. 123351df0accSAmit Shah * 123451df0accSAmit Shah * At this stage, the console is output-only. It's too early to set 123551df0accSAmit Shah * up a virtqueue, so we let the drivers do some boutique early-output 123651df0accSAmit Shah * thing. 123751df0accSAmit Shah */ 123851df0accSAmit Shah int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) 123951df0accSAmit Shah { 124051df0accSAmit Shah early_put_chars = put_chars; 124151df0accSAmit Shah return hvc_instantiate(0, 0, &hv_ops); 124251df0accSAmit Shah } 124351df0accSAmit Shah 12443826835aSWei Yongjun static int init_port_console(struct port *port) 124551df0accSAmit Shah { 124651df0accSAmit Shah int ret; 124751df0accSAmit Shah 124851df0accSAmit Shah /* 124951df0accSAmit Shah * The Host's telling us this port is a console port. Hook it 125051df0accSAmit Shah * up with an hvc console. 125151df0accSAmit Shah * 125251df0accSAmit Shah * To set up and manage our virtual console, we call 125351df0accSAmit Shah * hvc_alloc(). 125451df0accSAmit Shah * 125551df0accSAmit Shah * The first argument of hvc_alloc() is the virtual console 125651df0accSAmit Shah * number. The second argument is the parameter for the 125751df0accSAmit Shah * notification mechanism (like irq number). We currently 125851df0accSAmit Shah * leave this as zero, virtqueues have implicit notifications. 125951df0accSAmit Shah * 126051df0accSAmit Shah * The third argument is a "struct hv_ops" containing the 126151df0accSAmit Shah * put_chars() get_chars(), notifier_add() and notifier_del() 126251df0accSAmit Shah * pointers. The final argument is the output buffer size: we 126351df0accSAmit Shah * can do any size, so we put PAGE_SIZE here. 126451df0accSAmit Shah */ 126551df0accSAmit Shah port->cons.vtermno = pdrvdata.next_vtermno; 126651df0accSAmit Shah 126751df0accSAmit Shah port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE); 126851df0accSAmit Shah if (IS_ERR(port->cons.hvc)) { 126951df0accSAmit Shah ret = PTR_ERR(port->cons.hvc); 127051df0accSAmit Shah dev_err(port->dev, 127151df0accSAmit Shah "error %d allocating hvc for port\n", ret); 127251df0accSAmit Shah port->cons.hvc = NULL; 127351df0accSAmit Shah return ret; 127451df0accSAmit Shah } 127551df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 127651df0accSAmit Shah pdrvdata.next_vtermno++; 127751df0accSAmit Shah list_add_tail(&port->cons.list, &pdrvdata.consoles); 127851df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 127951df0accSAmit Shah port->guest_connected = true; 128051df0accSAmit Shah 128151df0accSAmit Shah /* 128251df0accSAmit Shah * Start using the new console output if this is the first 128351df0accSAmit Shah * console to come up. 128451df0accSAmit Shah */ 128551df0accSAmit Shah if (early_put_chars) 128651df0accSAmit Shah early_put_chars = NULL; 128751df0accSAmit Shah 128851df0accSAmit Shah /* Notify host of port being opened */ 128951df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); 129051df0accSAmit Shah 129151df0accSAmit Shah return 0; 129251df0accSAmit Shah } 129351df0accSAmit Shah 129451df0accSAmit Shah static ssize_t show_port_name(struct device *dev, 129551df0accSAmit Shah struct device_attribute *attr, char *buffer) 129651df0accSAmit Shah { 129751df0accSAmit Shah struct port *port; 129851df0accSAmit Shah 129951df0accSAmit Shah port = dev_get_drvdata(dev); 130051df0accSAmit Shah 130151df0accSAmit Shah return sprintf(buffer, "%s\n", port->name); 130251df0accSAmit Shah } 130351df0accSAmit Shah 130451df0accSAmit Shah static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL); 130551df0accSAmit Shah 130651df0accSAmit Shah static struct attribute *port_sysfs_entries[] = { 130751df0accSAmit Shah &dev_attr_name.attr, 130851df0accSAmit Shah NULL 130951df0accSAmit Shah }; 131051df0accSAmit Shah 131151df0accSAmit Shah static struct attribute_group port_attribute_group = { 131251df0accSAmit Shah .name = NULL, /* put in device directory */ 131351df0accSAmit Shah .attrs = port_sysfs_entries, 131451df0accSAmit Shah }; 131551df0accSAmit Shah 131651df0accSAmit Shah static ssize_t debugfs_read(struct file *filp, char __user *ubuf, 131751df0accSAmit Shah size_t count, loff_t *offp) 131851df0accSAmit Shah { 131951df0accSAmit Shah struct port *port; 132051df0accSAmit Shah char *buf; 132151df0accSAmit Shah ssize_t ret, out_offset, out_count; 132251df0accSAmit Shah 132351df0accSAmit Shah out_count = 1024; 132451df0accSAmit Shah buf = kmalloc(out_count, GFP_KERNEL); 132551df0accSAmit Shah if (!buf) 132651df0accSAmit Shah return -ENOMEM; 132751df0accSAmit Shah 132851df0accSAmit Shah port = filp->private_data; 132951df0accSAmit Shah out_offset = 0; 133051df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count, 133151df0accSAmit Shah "name: %s\n", port->name ? port->name : ""); 133251df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 133351df0accSAmit Shah "guest_connected: %d\n", port->guest_connected); 133451df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 133551df0accSAmit Shah "host_connected: %d\n", port->host_connected); 133651df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 133751df0accSAmit Shah "outvq_full: %d\n", port->outvq_full); 133851df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 133917e5b4f2SAmit Shah "bytes_sent: %lu\n", port->stats.bytes_sent); 134017e5b4f2SAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 134117e5b4f2SAmit Shah "bytes_received: %lu\n", 134217e5b4f2SAmit Shah port->stats.bytes_received); 134317e5b4f2SAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 134417e5b4f2SAmit Shah "bytes_discarded: %lu\n", 134517e5b4f2SAmit Shah port->stats.bytes_discarded); 134617e5b4f2SAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 134751df0accSAmit Shah "is_console: %s\n", 134851df0accSAmit Shah is_console_port(port) ? "yes" : "no"); 134951df0accSAmit Shah out_offset += snprintf(buf + out_offset, out_count - out_offset, 135051df0accSAmit Shah "console_vtermno: %u\n", port->cons.vtermno); 135151df0accSAmit Shah 135251df0accSAmit Shah ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); 135351df0accSAmit Shah kfree(buf); 135451df0accSAmit Shah return ret; 135551df0accSAmit Shah } 135651df0accSAmit Shah 135751df0accSAmit Shah static const struct file_operations port_debugfs_ops = { 135851df0accSAmit Shah .owner = THIS_MODULE, 1359234e3405SStephen Boyd .open = simple_open, 136051df0accSAmit Shah .read = debugfs_read, 136151df0accSAmit Shah }; 136251df0accSAmit Shah 136351df0accSAmit Shah static void set_console_size(struct port *port, u16 rows, u16 cols) 136451df0accSAmit Shah { 136551df0accSAmit Shah if (!port || !is_console_port(port)) 136651df0accSAmit Shah return; 136751df0accSAmit Shah 136851df0accSAmit Shah port->cons.ws.ws_row = rows; 136951df0accSAmit Shah port->cons.ws.ws_col = cols; 137051df0accSAmit Shah } 137151df0accSAmit Shah 137251df0accSAmit Shah static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) 137351df0accSAmit Shah { 137451df0accSAmit Shah struct port_buffer *buf; 137551df0accSAmit Shah unsigned int nr_added_bufs; 137651df0accSAmit Shah int ret; 137751df0accSAmit Shah 137851df0accSAmit Shah nr_added_bufs = 0; 137951df0accSAmit Shah do { 1380276a3e95SSjur Brændeland buf = alloc_buf(vq, PAGE_SIZE, 0); 138151df0accSAmit Shah if (!buf) 138251df0accSAmit Shah break; 138351df0accSAmit Shah 138451df0accSAmit Shah spin_lock_irq(lock); 138551df0accSAmit Shah ret = add_inbuf(vq, buf); 138651df0accSAmit Shah if (ret < 0) { 138751df0accSAmit Shah spin_unlock_irq(lock); 13881b637046SSjur Brændeland free_buf(buf, true); 138951df0accSAmit Shah break; 139051df0accSAmit Shah } 139151df0accSAmit Shah nr_added_bufs++; 139251df0accSAmit Shah spin_unlock_irq(lock); 139351df0accSAmit Shah } while (ret > 0); 139451df0accSAmit Shah 139551df0accSAmit Shah return nr_added_bufs; 139651df0accSAmit Shah } 139751df0accSAmit Shah 139851df0accSAmit Shah static void send_sigio_to_port(struct port *port) 139951df0accSAmit Shah { 140051df0accSAmit Shah if (port->async_queue && port->guest_connected) 140151df0accSAmit Shah kill_fasync(&port->async_queue, SIGIO, POLL_OUT); 140251df0accSAmit Shah } 140351df0accSAmit Shah 140451df0accSAmit Shah static int add_port(struct ports_device *portdev, u32 id) 140551df0accSAmit Shah { 140651df0accSAmit Shah char debugfs_name[16]; 140751df0accSAmit Shah struct port *port; 140851df0accSAmit Shah struct port_buffer *buf; 140951df0accSAmit Shah dev_t devt; 141051df0accSAmit Shah unsigned int nr_added_bufs; 141151df0accSAmit Shah int err; 141251df0accSAmit Shah 141351df0accSAmit Shah port = kmalloc(sizeof(*port), GFP_KERNEL); 141451df0accSAmit Shah if (!port) { 141551df0accSAmit Shah err = -ENOMEM; 141651df0accSAmit Shah goto fail; 141751df0accSAmit Shah } 141851df0accSAmit Shah kref_init(&port->kref); 141951df0accSAmit Shah 142051df0accSAmit Shah port->portdev = portdev; 142151df0accSAmit Shah port->id = id; 142251df0accSAmit Shah 142351df0accSAmit Shah port->name = NULL; 142451df0accSAmit Shah port->inbuf = NULL; 142551df0accSAmit Shah port->cons.hvc = NULL; 142651df0accSAmit Shah port->async_queue = NULL; 142751df0accSAmit Shah 142851df0accSAmit Shah port->cons.ws.ws_row = port->cons.ws.ws_col = 0; 142951df0accSAmit Shah 143051df0accSAmit Shah port->host_connected = port->guest_connected = false; 143117e5b4f2SAmit Shah port->stats = (struct port_stats) { 0 }; 143251df0accSAmit Shah 143351df0accSAmit Shah port->outvq_full = false; 143451df0accSAmit Shah 143551df0accSAmit Shah port->in_vq = portdev->in_vqs[port->id]; 143651df0accSAmit Shah port->out_vq = portdev->out_vqs[port->id]; 143751df0accSAmit Shah 143851df0accSAmit Shah port->cdev = cdev_alloc(); 143951df0accSAmit Shah if (!port->cdev) { 144051df0accSAmit Shah dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n"); 144151df0accSAmit Shah err = -ENOMEM; 144251df0accSAmit Shah goto free_port; 144351df0accSAmit Shah } 144451df0accSAmit Shah port->cdev->ops = &port_fops; 144551df0accSAmit Shah 144651df0accSAmit Shah devt = MKDEV(portdev->chr_major, id); 144751df0accSAmit Shah err = cdev_add(port->cdev, devt, 1); 144851df0accSAmit Shah if (err < 0) { 144951df0accSAmit Shah dev_err(&port->portdev->vdev->dev, 145051df0accSAmit Shah "Error %d adding cdev for port %u\n", err, id); 145151df0accSAmit Shah goto free_cdev; 145251df0accSAmit Shah } 145351df0accSAmit Shah port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, 145451df0accSAmit Shah devt, port, "vport%up%u", 1455dc18f080SSjur Brændeland port->portdev->vdev->index, id); 145651df0accSAmit Shah if (IS_ERR(port->dev)) { 145751df0accSAmit Shah err = PTR_ERR(port->dev); 145851df0accSAmit Shah dev_err(&port->portdev->vdev->dev, 145951df0accSAmit Shah "Error %d creating device for port %u\n", 146051df0accSAmit Shah err, id); 146151df0accSAmit Shah goto free_cdev; 146251df0accSAmit Shah } 146351df0accSAmit Shah 146451df0accSAmit Shah spin_lock_init(&port->inbuf_lock); 146551df0accSAmit Shah spin_lock_init(&port->outvq_lock); 146651df0accSAmit Shah init_waitqueue_head(&port->waitqueue); 146751df0accSAmit Shah 146851df0accSAmit Shah /* Fill the in_vq with buffers so the host can send us data. */ 146951df0accSAmit Shah nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); 147051df0accSAmit Shah if (!nr_added_bufs) { 147151df0accSAmit Shah dev_err(port->dev, "Error allocating inbufs\n"); 147251df0accSAmit Shah err = -ENOMEM; 147351df0accSAmit Shah goto free_device; 147451df0accSAmit Shah } 147551df0accSAmit Shah 14761b637046SSjur Brændeland if (is_rproc_serial(port->portdev->vdev)) 147751df0accSAmit Shah /* 14781b637046SSjur Brændeland * For rproc_serial assume remote processor is connected. 14791b637046SSjur Brændeland * rproc_serial does not want the console port, only 14801b637046SSjur Brændeland * the generic port implementation. 148151df0accSAmit Shah */ 1482aabd6a8fSSjur Brændeland port->host_connected = true; 14831b637046SSjur Brændeland else if (!use_multiport(port->portdev)) { 14841b637046SSjur Brændeland /* 14851b637046SSjur Brændeland * If we're not using multiport support, 14861b637046SSjur Brændeland * this has to be a console port. 14871b637046SSjur Brændeland */ 148851df0accSAmit Shah err = init_port_console(port); 148951df0accSAmit Shah if (err) 149051df0accSAmit Shah goto free_inbufs; 149151df0accSAmit Shah } 149251df0accSAmit Shah 149351df0accSAmit Shah spin_lock_irq(&portdev->ports_lock); 149451df0accSAmit Shah list_add_tail(&port->list, &port->portdev->ports); 149551df0accSAmit Shah spin_unlock_irq(&portdev->ports_lock); 149651df0accSAmit Shah 149751df0accSAmit Shah /* 149851df0accSAmit Shah * Tell the Host we're set so that it can send us various 149951df0accSAmit Shah * configuration parameters for this port (eg, port name, 150051df0accSAmit Shah * caching, whether this is a console port, etc.) 150151df0accSAmit Shah */ 150251df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); 150351df0accSAmit Shah 150451df0accSAmit Shah if (pdrvdata.debugfs_dir) { 150551df0accSAmit Shah /* 150651df0accSAmit Shah * Finally, create the debugfs file that we can use to 150751df0accSAmit Shah * inspect a port's state at any time 150851df0accSAmit Shah */ 1509db170068SDan Carpenter snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", 1510dc18f080SSjur Brændeland port->portdev->vdev->index, id); 151151df0accSAmit Shah port->debugfs_file = debugfs_create_file(debugfs_name, 0444, 151251df0accSAmit Shah pdrvdata.debugfs_dir, 151351df0accSAmit Shah port, 151451df0accSAmit Shah &port_debugfs_ops); 151551df0accSAmit Shah } 151651df0accSAmit Shah return 0; 151751df0accSAmit Shah 151851df0accSAmit Shah free_inbufs: 151951df0accSAmit Shah while ((buf = virtqueue_detach_unused_buf(port->in_vq))) 15201b637046SSjur Brændeland free_buf(buf, true); 152151df0accSAmit Shah free_device: 152251df0accSAmit Shah device_destroy(pdrvdata.class, port->dev->devt); 152351df0accSAmit Shah free_cdev: 152451df0accSAmit Shah cdev_del(port->cdev); 152551df0accSAmit Shah free_port: 152651df0accSAmit Shah kfree(port); 152751df0accSAmit Shah fail: 152851df0accSAmit Shah /* The host might want to notify management sw about port add failure */ 152951df0accSAmit Shah __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0); 153051df0accSAmit Shah return err; 153151df0accSAmit Shah } 153251df0accSAmit Shah 153351df0accSAmit Shah /* No users remain, remove all port-specific data. */ 153451df0accSAmit Shah static void remove_port(struct kref *kref) 153551df0accSAmit Shah { 153651df0accSAmit Shah struct port *port; 153751df0accSAmit Shah 153851df0accSAmit Shah port = container_of(kref, struct port, kref); 153951df0accSAmit Shah 154051df0accSAmit Shah kfree(port); 154151df0accSAmit Shah } 154251df0accSAmit Shah 1543a0e2dbfcSAmit Shah static void remove_port_data(struct port *port) 1544a0e2dbfcSAmit Shah { 1545a0e2dbfcSAmit Shah struct port_buffer *buf; 1546a0e2dbfcSAmit Shah 1547c6017e79SAmit Shah spin_lock_irq(&port->inbuf_lock); 1548a0e2dbfcSAmit Shah /* Remove unused data this port might have received. */ 1549a0e2dbfcSAmit Shah discard_port_data(port); 155034563769SMatt Redfearn spin_unlock_irq(&port->inbuf_lock); 1551a0e2dbfcSAmit Shah 1552a0e2dbfcSAmit Shah /* Remove buffers we queued up for the Host to send us data in. */ 155334563769SMatt Redfearn do { 155434563769SMatt Redfearn spin_lock_irq(&port->inbuf_lock); 155534563769SMatt Redfearn buf = virtqueue_detach_unused_buf(port->in_vq); 1556c6017e79SAmit Shah spin_unlock_irq(&port->inbuf_lock); 155734563769SMatt Redfearn if (buf) 155834563769SMatt Redfearn free_buf(buf, true); 155934563769SMatt Redfearn } while (buf); 1560c6017e79SAmit Shah 1561c6017e79SAmit Shah spin_lock_irq(&port->outvq_lock); 1562c6017e79SAmit Shah reclaim_consumed_buffers(port); 156334563769SMatt Redfearn spin_unlock_irq(&port->outvq_lock); 1564eb34f12bSsjur.brandeland@stericsson.com 1565eb34f12bSsjur.brandeland@stericsson.com /* Free pending buffers from the out-queue. */ 156634563769SMatt Redfearn do { 156734563769SMatt Redfearn spin_lock_irq(&port->outvq_lock); 156834563769SMatt Redfearn buf = virtqueue_detach_unused_buf(port->out_vq); 1569c6017e79SAmit Shah spin_unlock_irq(&port->outvq_lock); 157034563769SMatt Redfearn if (buf) 157134563769SMatt Redfearn free_buf(buf, true); 157234563769SMatt Redfearn } while (buf); 1573a0e2dbfcSAmit Shah } 1574a0e2dbfcSAmit Shah 157551df0accSAmit Shah /* 157651df0accSAmit Shah * Port got unplugged. Remove port from portdev's list and drop the 157751df0accSAmit Shah * kref reference. If no userspace has this port opened, it will 157851df0accSAmit Shah * result in immediate removal the port. 157951df0accSAmit Shah */ 158051df0accSAmit Shah static void unplug_port(struct port *port) 158151df0accSAmit Shah { 158251df0accSAmit Shah spin_lock_irq(&port->portdev->ports_lock); 158351df0accSAmit Shah list_del(&port->list); 158451df0accSAmit Shah spin_unlock_irq(&port->portdev->ports_lock); 158551df0accSAmit Shah 15865549fb25SAmit Shah spin_lock_irq(&port->inbuf_lock); 158751df0accSAmit Shah if (port->guest_connected) { 158851df0accSAmit Shah /* Let the app know the port is going down. */ 158951df0accSAmit Shah send_sigio_to_port(port); 159092d34538SAmit Shah 159192d34538SAmit Shah /* Do this after sigio is actually sent */ 159292d34538SAmit Shah port->guest_connected = false; 159392d34538SAmit Shah port->host_connected = false; 159492d34538SAmit Shah 159592d34538SAmit Shah wake_up_interruptible(&port->waitqueue); 159651df0accSAmit Shah } 15975549fb25SAmit Shah spin_unlock_irq(&port->inbuf_lock); 159851df0accSAmit Shah 159951df0accSAmit Shah if (is_console_port(port)) { 160051df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 160151df0accSAmit Shah list_del(&port->cons.list); 160251df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 160351df0accSAmit Shah hvc_remove(port->cons.hvc); 160451df0accSAmit Shah } 160551df0accSAmit Shah 1606a0e2dbfcSAmit Shah remove_port_data(port); 160751df0accSAmit Shah 160851df0accSAmit Shah /* 160951df0accSAmit Shah * We should just assume the device itself has gone off -- 161051df0accSAmit Shah * else a close on an open port later will try to send out a 161151df0accSAmit Shah * control message. 161251df0accSAmit Shah */ 161351df0accSAmit Shah port->portdev = NULL; 161451df0accSAmit Shah 1615ea3768b4SAmit Shah sysfs_remove_group(&port->dev->kobj, &port_attribute_group); 1616ea3768b4SAmit Shah device_destroy(pdrvdata.class, port->dev->devt); 1617ea3768b4SAmit Shah cdev_del(port->cdev); 1618ea3768b4SAmit Shah 1619ea3768b4SAmit Shah debugfs_remove(port->debugfs_file); 16203b868a40SAmit Shah kfree(port->name); 1621ea3768b4SAmit Shah 162251df0accSAmit Shah /* 162351df0accSAmit Shah * Locks around here are not necessary - a port can't be 162451df0accSAmit Shah * opened after we removed the port struct from ports_list 162551df0accSAmit Shah * above. 162651df0accSAmit Shah */ 162751df0accSAmit Shah kref_put(&port->kref, remove_port); 162851df0accSAmit Shah } 162951df0accSAmit Shah 163051df0accSAmit Shah /* Any private messages that the Host and Guest want to share */ 16311f0f9106SMichael S. Tsirkin static void handle_control_message(struct virtio_device *vdev, 16321f0f9106SMichael S. Tsirkin struct ports_device *portdev, 163351df0accSAmit Shah struct port_buffer *buf) 163451df0accSAmit Shah { 163551df0accSAmit Shah struct virtio_console_control *cpkt; 163651df0accSAmit Shah struct port *port; 163751df0accSAmit Shah size_t name_size; 163851df0accSAmit Shah int err; 163951df0accSAmit Shah 164051df0accSAmit Shah cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); 164151df0accSAmit Shah 16421f0f9106SMichael S. Tsirkin port = find_port_by_id(portdev, virtio32_to_cpu(vdev, cpkt->id)); 16431f0f9106SMichael S. Tsirkin if (!port && 16441f0f9106SMichael S. Tsirkin cpkt->event != cpu_to_virtio16(vdev, VIRTIO_CONSOLE_PORT_ADD)) { 164551df0accSAmit Shah /* No valid header at start of buffer. Drop it. */ 164651df0accSAmit Shah dev_dbg(&portdev->vdev->dev, 164751df0accSAmit Shah "Invalid index %u in control packet\n", cpkt->id); 164851df0accSAmit Shah return; 164951df0accSAmit Shah } 165051df0accSAmit Shah 16511f0f9106SMichael S. Tsirkin switch (virtio16_to_cpu(vdev, cpkt->event)) { 165251df0accSAmit Shah case VIRTIO_CONSOLE_PORT_ADD: 165351df0accSAmit Shah if (port) { 165451df0accSAmit Shah dev_dbg(&portdev->vdev->dev, 165551df0accSAmit Shah "Port %u already added\n", port->id); 165651df0accSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); 165751df0accSAmit Shah break; 165851df0accSAmit Shah } 16591f0f9106SMichael S. Tsirkin if (virtio32_to_cpu(vdev, cpkt->id) >= 16607328fa64SMichael S. Tsirkin portdev->max_nr_ports) { 166151df0accSAmit Shah dev_warn(&portdev->vdev->dev, 16621f0f9106SMichael S. Tsirkin "Request for adding port with " 16631f0f9106SMichael S. Tsirkin "out-of-bound id %u, max. supported id: %u\n", 16647328fa64SMichael S. Tsirkin cpkt->id, portdev->max_nr_ports - 1); 166551df0accSAmit Shah break; 166651df0accSAmit Shah } 16671f0f9106SMichael S. Tsirkin add_port(portdev, virtio32_to_cpu(vdev, cpkt->id)); 166851df0accSAmit Shah break; 166951df0accSAmit Shah case VIRTIO_CONSOLE_PORT_REMOVE: 167051df0accSAmit Shah unplug_port(port); 167151df0accSAmit Shah break; 167251df0accSAmit Shah case VIRTIO_CONSOLE_CONSOLE_PORT: 167351df0accSAmit Shah if (!cpkt->value) 167451df0accSAmit Shah break; 167551df0accSAmit Shah if (is_console_port(port)) 167651df0accSAmit Shah break; 167751df0accSAmit Shah 167851df0accSAmit Shah init_port_console(port); 16795e38483bSChristian Borntraeger complete(&early_console_added); 168051df0accSAmit Shah /* 168151df0accSAmit Shah * Could remove the port here in case init fails - but 168251df0accSAmit Shah * have to notify the host first. 168351df0accSAmit Shah */ 168451df0accSAmit Shah break; 168551df0accSAmit Shah case VIRTIO_CONSOLE_RESIZE: { 168651df0accSAmit Shah struct { 168751df0accSAmit Shah __u16 rows; 168851df0accSAmit Shah __u16 cols; 168951df0accSAmit Shah } size; 169051df0accSAmit Shah 169151df0accSAmit Shah if (!is_console_port(port)) 169251df0accSAmit Shah break; 169351df0accSAmit Shah 169451df0accSAmit Shah memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), 169551df0accSAmit Shah sizeof(size)); 169651df0accSAmit Shah set_console_size(port, size.rows, size.cols); 169751df0accSAmit Shah 169851df0accSAmit Shah port->cons.hvc->irq_requested = 1; 169951df0accSAmit Shah resize_console(port); 170051df0accSAmit Shah break; 170151df0accSAmit Shah } 170251df0accSAmit Shah case VIRTIO_CONSOLE_PORT_OPEN: 17031f0f9106SMichael S. Tsirkin port->host_connected = virtio16_to_cpu(vdev, cpkt->value); 170451df0accSAmit Shah wake_up_interruptible(&port->waitqueue); 170551df0accSAmit Shah /* 170651df0accSAmit Shah * If the host port got closed and the host had any 170751df0accSAmit Shah * unconsumed buffers, we'll be able to reclaim them 170851df0accSAmit Shah * now. 170951df0accSAmit Shah */ 171051df0accSAmit Shah spin_lock_irq(&port->outvq_lock); 171151df0accSAmit Shah reclaim_consumed_buffers(port); 171251df0accSAmit Shah spin_unlock_irq(&port->outvq_lock); 171351df0accSAmit Shah 171451df0accSAmit Shah /* 171551df0accSAmit Shah * If the guest is connected, it'll be interested in 171651df0accSAmit Shah * knowing the host connection state changed. 171751df0accSAmit Shah */ 1718314081f1SAmit Shah spin_lock_irq(&port->inbuf_lock); 171951df0accSAmit Shah send_sigio_to_port(port); 1720314081f1SAmit Shah spin_unlock_irq(&port->inbuf_lock); 172151df0accSAmit Shah break; 172251df0accSAmit Shah case VIRTIO_CONSOLE_PORT_NAME: 172351df0accSAmit Shah /* 1724291024efSAmit Shah * If we woke up after hibernation, we can get this 1725291024efSAmit Shah * again. Skip it in that case. 1726291024efSAmit Shah */ 1727291024efSAmit Shah if (port->name) 1728291024efSAmit Shah break; 1729291024efSAmit Shah 1730291024efSAmit Shah /* 173151df0accSAmit Shah * Skip the size of the header and the cpkt to get the size 173251df0accSAmit Shah * of the name that was sent 173351df0accSAmit Shah */ 173451df0accSAmit Shah name_size = buf->len - buf->offset - sizeof(*cpkt) + 1; 173551df0accSAmit Shah 173651df0accSAmit Shah port->name = kmalloc(name_size, GFP_KERNEL); 173751df0accSAmit Shah if (!port->name) { 173851df0accSAmit Shah dev_err(port->dev, 173951df0accSAmit Shah "Not enough space to store port name\n"); 174051df0accSAmit Shah break; 174151df0accSAmit Shah } 174251df0accSAmit Shah strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt), 174351df0accSAmit Shah name_size - 1); 174451df0accSAmit Shah port->name[name_size - 1] = 0; 174551df0accSAmit Shah 174651df0accSAmit Shah /* 174751df0accSAmit Shah * Since we only have one sysfs attribute, 'name', 174851df0accSAmit Shah * create it only if we have a name for the port. 174951df0accSAmit Shah */ 175051df0accSAmit Shah err = sysfs_create_group(&port->dev->kobj, 175151df0accSAmit Shah &port_attribute_group); 175251df0accSAmit Shah if (err) { 175351df0accSAmit Shah dev_err(port->dev, 175451df0accSAmit Shah "Error %d creating sysfs device attributes\n", 175551df0accSAmit Shah err); 175651df0accSAmit Shah } else { 175751df0accSAmit Shah /* 175851df0accSAmit Shah * Generate a udev event so that appropriate 175951df0accSAmit Shah * symlinks can be created based on udev 176051df0accSAmit Shah * rules. 176151df0accSAmit Shah */ 176251df0accSAmit Shah kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); 176351df0accSAmit Shah } 176451df0accSAmit Shah break; 176551df0accSAmit Shah } 176651df0accSAmit Shah } 176751df0accSAmit Shah 176851df0accSAmit Shah static void control_work_handler(struct work_struct *work) 176951df0accSAmit Shah { 177051df0accSAmit Shah struct ports_device *portdev; 177151df0accSAmit Shah struct virtqueue *vq; 177251df0accSAmit Shah struct port_buffer *buf; 177351df0accSAmit Shah unsigned int len; 177451df0accSAmit Shah 177551df0accSAmit Shah portdev = container_of(work, struct ports_device, control_work); 177651df0accSAmit Shah vq = portdev->c_ivq; 177751df0accSAmit Shah 1778165b1b8bSAmit Shah spin_lock(&portdev->c_ivq_lock); 177951df0accSAmit Shah while ((buf = virtqueue_get_buf(vq, &len))) { 1780165b1b8bSAmit Shah spin_unlock(&portdev->c_ivq_lock); 178151df0accSAmit Shah 178251df0accSAmit Shah buf->len = len; 178351df0accSAmit Shah buf->offset = 0; 178451df0accSAmit Shah 17851f0f9106SMichael S. Tsirkin handle_control_message(vq->vdev, portdev, buf); 178651df0accSAmit Shah 1787165b1b8bSAmit Shah spin_lock(&portdev->c_ivq_lock); 178851df0accSAmit Shah if (add_inbuf(portdev->c_ivq, buf) < 0) { 178951df0accSAmit Shah dev_warn(&portdev->vdev->dev, 179051df0accSAmit Shah "Error adding buffer to queue\n"); 17911b637046SSjur Brændeland free_buf(buf, false); 179251df0accSAmit Shah } 179351df0accSAmit Shah } 1794165b1b8bSAmit Shah spin_unlock(&portdev->c_ivq_lock); 179551df0accSAmit Shah } 179651df0accSAmit Shah 1797ce86d35dSLinus Torvalds static void out_intr(struct virtqueue *vq) 1798ce86d35dSLinus Torvalds { 1799ce86d35dSLinus Torvalds struct port *port; 1800ce86d35dSLinus Torvalds 1801ce86d35dSLinus Torvalds port = find_port_by_vq(vq->vdev->priv, vq); 1802ce86d35dSLinus Torvalds if (!port) 1803ce86d35dSLinus Torvalds return; 1804ce86d35dSLinus Torvalds 1805ce86d35dSLinus Torvalds wake_up_interruptible(&port->waitqueue); 1806ce86d35dSLinus Torvalds } 1807ce86d35dSLinus Torvalds 180851df0accSAmit Shah static void in_intr(struct virtqueue *vq) 180951df0accSAmit Shah { 181051df0accSAmit Shah struct port *port; 181151df0accSAmit Shah unsigned long flags; 181251df0accSAmit Shah 181351df0accSAmit Shah port = find_port_by_vq(vq->vdev->priv, vq); 181451df0accSAmit Shah if (!port) 181551df0accSAmit Shah return; 181651df0accSAmit Shah 181751df0accSAmit Shah spin_lock_irqsave(&port->inbuf_lock, flags); 181851df0accSAmit Shah port->inbuf = get_inbuf(port); 181951df0accSAmit Shah 182051df0accSAmit Shah /* 1821aabd6a8fSSjur Brændeland * Normally the port should not accept data when the port is 1822aabd6a8fSSjur Brændeland * closed. For generic serial ports, the host won't (shouldn't) 1823aabd6a8fSSjur Brændeland * send data till the guest is connected. But this condition 182451df0accSAmit Shah * can be reached when a console port is not yet connected (no 1825aabd6a8fSSjur Brændeland * tty is spawned) and the other side sends out data over the 1826aabd6a8fSSjur Brændeland * vring, or when a remote devices start sending data before 1827aabd6a8fSSjur Brændeland * the ports are opened. 1828aabd6a8fSSjur Brændeland * 1829aabd6a8fSSjur Brændeland * A generic serial port will discard data if not connected, 1830aabd6a8fSSjur Brændeland * while console ports and rproc-serial ports accepts data at 1831aabd6a8fSSjur Brændeland * any time. rproc-serial is initiated with guest_connected to 1832aabd6a8fSSjur Brændeland * false because port_fops_open expects this. Console ports are 1833aabd6a8fSSjur Brændeland * hooked up with an HVC console and is initialized with 1834aabd6a8fSSjur Brændeland * guest_connected to true. 183551df0accSAmit Shah */ 1836aabd6a8fSSjur Brændeland 1837aabd6a8fSSjur Brændeland if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) 183851df0accSAmit Shah discard_port_data(port); 183951df0accSAmit Shah 1840314081f1SAmit Shah /* Send a SIGIO indicating new data in case the process asked for it */ 1841314081f1SAmit Shah send_sigio_to_port(port); 1842314081f1SAmit Shah 184351df0accSAmit Shah spin_unlock_irqrestore(&port->inbuf_lock, flags); 184451df0accSAmit Shah 184551df0accSAmit Shah wake_up_interruptible(&port->waitqueue); 184651df0accSAmit Shah 184751df0accSAmit Shah if (is_console_port(port) && hvc_poll(port->cons.hvc)) 184851df0accSAmit Shah hvc_kick(); 184951df0accSAmit Shah } 185051df0accSAmit Shah 185151df0accSAmit Shah static void control_intr(struct virtqueue *vq) 185251df0accSAmit Shah { 185351df0accSAmit Shah struct ports_device *portdev; 185451df0accSAmit Shah 185551df0accSAmit Shah portdev = vq->vdev->priv; 185651df0accSAmit Shah schedule_work(&portdev->control_work); 185751df0accSAmit Shah } 185851df0accSAmit Shah 185951df0accSAmit Shah static void config_intr(struct virtio_device *vdev) 186051df0accSAmit Shah { 186151df0accSAmit Shah struct ports_device *portdev; 186251df0accSAmit Shah 186351df0accSAmit Shah portdev = vdev->priv; 186451df0accSAmit Shah 1865eeb8a7e8SMichael S. Tsirkin if (!use_multiport(portdev)) 1866eeb8a7e8SMichael S. Tsirkin schedule_work(&portdev->config_work); 1867eeb8a7e8SMichael S. Tsirkin } 1868eeb8a7e8SMichael S. Tsirkin 1869eeb8a7e8SMichael S. Tsirkin static void config_work_handler(struct work_struct *work) 1870eeb8a7e8SMichael S. Tsirkin { 1871eeb8a7e8SMichael S. Tsirkin struct ports_device *portdev; 1872eeb8a7e8SMichael S. Tsirkin 18738379cadfSG. Campana portdev = container_of(work, struct ports_device, config_work); 187451df0accSAmit Shah if (!use_multiport(portdev)) { 1875eeb8a7e8SMichael S. Tsirkin struct virtio_device *vdev; 187651df0accSAmit Shah struct port *port; 187751df0accSAmit Shah u16 rows, cols; 187851df0accSAmit Shah 1879eeb8a7e8SMichael S. Tsirkin vdev = portdev->vdev; 1880855e0c52SRusty Russell virtio_cread(vdev, struct virtio_console_config, cols, &cols); 1881855e0c52SRusty Russell virtio_cread(vdev, struct virtio_console_config, rows, &rows); 188251df0accSAmit Shah 188351df0accSAmit Shah port = find_port_by_id(portdev, 0); 188451df0accSAmit Shah set_console_size(port, rows, cols); 188551df0accSAmit Shah 188651df0accSAmit Shah /* 188751df0accSAmit Shah * We'll use this way of resizing only for legacy 188851df0accSAmit Shah * support. For newer userspace 188951df0accSAmit Shah * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages 189051df0accSAmit Shah * to indicate console size changes so that it can be 189151df0accSAmit Shah * done per-port. 189251df0accSAmit Shah */ 189351df0accSAmit Shah resize_console(port); 189451df0accSAmit Shah } 189551df0accSAmit Shah } 189651df0accSAmit Shah 189751df0accSAmit Shah static int init_vqs(struct ports_device *portdev) 189851df0accSAmit Shah { 189951df0accSAmit Shah vq_callback_t **io_callbacks; 190051df0accSAmit Shah char **io_names; 190151df0accSAmit Shah struct virtqueue **vqs; 190251df0accSAmit Shah u32 i, j, nr_ports, nr_queues; 190351df0accSAmit Shah int err; 190451df0accSAmit Shah 19057328fa64SMichael S. Tsirkin nr_ports = portdev->max_nr_ports; 190651df0accSAmit Shah nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; 190751df0accSAmit Shah 190851df0accSAmit Shah vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); 190951df0accSAmit Shah io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); 191051df0accSAmit Shah io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); 191151df0accSAmit Shah portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), 191251df0accSAmit Shah GFP_KERNEL); 191351df0accSAmit Shah portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), 191451df0accSAmit Shah GFP_KERNEL); 191551df0accSAmit Shah if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || 191651df0accSAmit Shah !portdev->out_vqs) { 191751df0accSAmit Shah err = -ENOMEM; 191851df0accSAmit Shah goto free; 191951df0accSAmit Shah } 192051df0accSAmit Shah 192151df0accSAmit Shah /* 192251df0accSAmit Shah * For backward compat (newer host but older guest), the host 192351df0accSAmit Shah * spawns a console port first and also inits the vqs for port 192451df0accSAmit Shah * 0 before others. 192551df0accSAmit Shah */ 192651df0accSAmit Shah j = 0; 192751df0accSAmit Shah io_callbacks[j] = in_intr; 1928ce86d35dSLinus Torvalds io_callbacks[j + 1] = out_intr; 192951df0accSAmit Shah io_names[j] = "input"; 193051df0accSAmit Shah io_names[j + 1] = "output"; 193151df0accSAmit Shah j += 2; 193251df0accSAmit Shah 193351df0accSAmit Shah if (use_multiport(portdev)) { 193451df0accSAmit Shah io_callbacks[j] = control_intr; 193551df0accSAmit Shah io_callbacks[j + 1] = NULL; 193651df0accSAmit Shah io_names[j] = "control-i"; 193751df0accSAmit Shah io_names[j + 1] = "control-o"; 193851df0accSAmit Shah 193951df0accSAmit Shah for (i = 1; i < nr_ports; i++) { 194051df0accSAmit Shah j += 2; 194151df0accSAmit Shah io_callbacks[j] = in_intr; 1942ce86d35dSLinus Torvalds io_callbacks[j + 1] = out_intr; 194351df0accSAmit Shah io_names[j] = "input"; 194451df0accSAmit Shah io_names[j + 1] = "output"; 194551df0accSAmit Shah } 194651df0accSAmit Shah } 194751df0accSAmit Shah /* Find the queues. */ 19489b2bbdb2SMichael S. Tsirkin err = virtio_find_vqs(portdev->vdev, nr_queues, vqs, 194951df0accSAmit Shah io_callbacks, 1950fb5e31d9SChristoph Hellwig (const char **)io_names, NULL); 195151df0accSAmit Shah if (err) 195251df0accSAmit Shah goto free; 195351df0accSAmit Shah 195451df0accSAmit Shah j = 0; 195551df0accSAmit Shah portdev->in_vqs[0] = vqs[0]; 195651df0accSAmit Shah portdev->out_vqs[0] = vqs[1]; 195751df0accSAmit Shah j += 2; 195851df0accSAmit Shah if (use_multiport(portdev)) { 195951df0accSAmit Shah portdev->c_ivq = vqs[j]; 196051df0accSAmit Shah portdev->c_ovq = vqs[j + 1]; 196151df0accSAmit Shah 196251df0accSAmit Shah for (i = 1; i < nr_ports; i++) { 196351df0accSAmit Shah j += 2; 196451df0accSAmit Shah portdev->in_vqs[i] = vqs[j]; 196551df0accSAmit Shah portdev->out_vqs[i] = vqs[j + 1]; 196651df0accSAmit Shah } 196751df0accSAmit Shah } 196851df0accSAmit Shah kfree(io_names); 196951df0accSAmit Shah kfree(io_callbacks); 197051df0accSAmit Shah kfree(vqs); 197151df0accSAmit Shah 197251df0accSAmit Shah return 0; 197351df0accSAmit Shah 197451df0accSAmit Shah free: 197551df0accSAmit Shah kfree(portdev->out_vqs); 197651df0accSAmit Shah kfree(portdev->in_vqs); 197751df0accSAmit Shah kfree(io_names); 197851df0accSAmit Shah kfree(io_callbacks); 197951df0accSAmit Shah kfree(vqs); 198051df0accSAmit Shah 198151df0accSAmit Shah return err; 198251df0accSAmit Shah } 198351df0accSAmit Shah 198451df0accSAmit Shah static const struct file_operations portdev_fops = { 198551df0accSAmit Shah .owner = THIS_MODULE, 198651df0accSAmit Shah }; 198751df0accSAmit Shah 1988a0e2dbfcSAmit Shah static void remove_vqs(struct ports_device *portdev) 1989a0e2dbfcSAmit Shah { 1990a0e2dbfcSAmit Shah portdev->vdev->config->del_vqs(portdev->vdev); 1991a0e2dbfcSAmit Shah kfree(portdev->in_vqs); 1992a0e2dbfcSAmit Shah kfree(portdev->out_vqs); 1993a0e2dbfcSAmit Shah } 1994a0e2dbfcSAmit Shah 1995a0e2dbfcSAmit Shah static void remove_controlq_data(struct ports_device *portdev) 1996a0e2dbfcSAmit Shah { 1997a0e2dbfcSAmit Shah struct port_buffer *buf; 1998a0e2dbfcSAmit Shah unsigned int len; 1999a0e2dbfcSAmit Shah 2000a0e2dbfcSAmit Shah if (!use_multiport(portdev)) 2001a0e2dbfcSAmit Shah return; 2002a0e2dbfcSAmit Shah 2003a0e2dbfcSAmit Shah while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) 20041b637046SSjur Brændeland free_buf(buf, true); 2005a0e2dbfcSAmit Shah 2006a0e2dbfcSAmit Shah while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) 20071b637046SSjur Brændeland free_buf(buf, true); 2008a0e2dbfcSAmit Shah } 2009a0e2dbfcSAmit Shah 201051df0accSAmit Shah /* 201151df0accSAmit Shah * Once we're further in boot, we get probed like any other virtio 201251df0accSAmit Shah * device. 201351df0accSAmit Shah * 201451df0accSAmit Shah * If the host also supports multiple console ports, we check the 201551df0accSAmit Shah * config space to see how many ports the host has spawned. We 201651df0accSAmit Shah * initialize each port found. 201751df0accSAmit Shah */ 20182223cbecSBill Pemberton static int virtcons_probe(struct virtio_device *vdev) 201951df0accSAmit Shah { 202051df0accSAmit Shah struct ports_device *portdev; 202151df0accSAmit Shah int err; 202251df0accSAmit Shah bool multiport; 20235e38483bSChristian Borntraeger bool early = early_put_chars != NULL; 20245e38483bSChristian Borntraeger 2025be8ff595SRusty Russell /* We only need a config space if features are offered */ 2026be8ff595SRusty Russell if (!vdev->config->get && 2027be8ff595SRusty Russell (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE) 2028be8ff595SRusty Russell || virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT))) { 2029011f0e7aSMichael S. Tsirkin dev_err(&vdev->dev, "%s failure: config access disabled\n", 2030011f0e7aSMichael S. Tsirkin __func__); 2031011f0e7aSMichael S. Tsirkin return -EINVAL; 2032011f0e7aSMichael S. Tsirkin } 2033011f0e7aSMichael S. Tsirkin 20345e38483bSChristian Borntraeger /* Ensure to read early_put_chars now */ 20355e38483bSChristian Borntraeger barrier(); 203651df0accSAmit Shah 203751df0accSAmit Shah portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); 203851df0accSAmit Shah if (!portdev) { 203951df0accSAmit Shah err = -ENOMEM; 204051df0accSAmit Shah goto fail; 204151df0accSAmit Shah } 204251df0accSAmit Shah 204351df0accSAmit Shah /* Attach this portdev to this virtio_device, and vice-versa. */ 204451df0accSAmit Shah portdev->vdev = vdev; 204551df0accSAmit Shah vdev->priv = portdev; 204651df0accSAmit Shah 204751df0accSAmit Shah portdev->chr_major = register_chrdev(0, "virtio-portsdev", 204851df0accSAmit Shah &portdev_fops); 204951df0accSAmit Shah if (portdev->chr_major < 0) { 205051df0accSAmit Shah dev_err(&vdev->dev, 205151df0accSAmit Shah "Error %d registering chrdev for device %u\n", 2052dc18f080SSjur Brændeland portdev->chr_major, vdev->index); 205351df0accSAmit Shah err = portdev->chr_major; 205451df0accSAmit Shah goto free; 205551df0accSAmit Shah } 205651df0accSAmit Shah 205751df0accSAmit Shah multiport = false; 20587328fa64SMichael S. Tsirkin portdev->max_nr_ports = 1; 20591b637046SSjur Brændeland 20601b637046SSjur Brændeland /* Don't test MULTIPORT at all if we're rproc: not a valid feature! */ 20611b637046SSjur Brændeland if (!is_rproc_serial(vdev) && 2062855e0c52SRusty Russell virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, 2063855e0c52SRusty Russell struct virtio_console_config, max_nr_ports, 20647328fa64SMichael S. Tsirkin &portdev->max_nr_ports) == 0) { 206551c6d61aSSasha Levin multiport = true; 20661b637046SSjur Brændeland } 206751df0accSAmit Shah 206851df0accSAmit Shah err = init_vqs(portdev); 206951df0accSAmit Shah if (err < 0) { 207051df0accSAmit Shah dev_err(&vdev->dev, "Error %d initializing vqs\n", err); 207151df0accSAmit Shah goto free_chrdev; 207251df0accSAmit Shah } 207351df0accSAmit Shah 207451df0accSAmit Shah spin_lock_init(&portdev->ports_lock); 207551df0accSAmit Shah INIT_LIST_HEAD(&portdev->ports); 207651df0accSAmit Shah 207765eca3a2SCornelia Huck virtio_device_ready(portdev->vdev); 207865eca3a2SCornelia Huck 2079eeb8a7e8SMichael S. Tsirkin INIT_WORK(&portdev->config_work, &config_work_handler); 20804f6e24edSMichael S. Tsirkin INIT_WORK(&portdev->control_work, &control_work_handler); 20814f6e24edSMichael S. Tsirkin 208251df0accSAmit Shah if (multiport) { 208351df0accSAmit Shah unsigned int nr_added_bufs; 208451df0accSAmit Shah 2085165b1b8bSAmit Shah spin_lock_init(&portdev->c_ivq_lock); 20869ba5c80bSAmit Shah spin_lock_init(&portdev->c_ovq_lock); 208751df0accSAmit Shah 2088165b1b8bSAmit Shah nr_added_bufs = fill_queue(portdev->c_ivq, 2089165b1b8bSAmit Shah &portdev->c_ivq_lock); 209051df0accSAmit Shah if (!nr_added_bufs) { 209151df0accSAmit Shah dev_err(&vdev->dev, 209251df0accSAmit Shah "Error allocating buffers for control queue\n"); 209351df0accSAmit Shah err = -ENOMEM; 209451df0accSAmit Shah goto free_vqs; 209551df0accSAmit Shah } 209651df0accSAmit Shah } else { 209751df0accSAmit Shah /* 209851df0accSAmit Shah * For backward compatibility: Create a console port 209951df0accSAmit Shah * if we're running on older host. 210051df0accSAmit Shah */ 210151df0accSAmit Shah add_port(portdev, 0); 210251df0accSAmit Shah } 210351df0accSAmit Shah 210451df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 210551df0accSAmit Shah list_add_tail(&portdev->list, &pdrvdata.portdevs); 210651df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 210751df0accSAmit Shah 210851df0accSAmit Shah __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, 210951df0accSAmit Shah VIRTIO_CONSOLE_DEVICE_READY, 1); 21105e38483bSChristian Borntraeger 21115e38483bSChristian Borntraeger /* 21125e38483bSChristian Borntraeger * If there was an early virtio console, assume that there are no 21135e38483bSChristian Borntraeger * other consoles. We need to wait until the hvc_alloc matches the 21145e38483bSChristian Borntraeger * hvc_instantiate, otherwise tty_open will complain, resulting in 21155e38483bSChristian Borntraeger * a "Warning: unable to open an initial console" boot failure. 21165e38483bSChristian Borntraeger * Without multiport this is done in add_port above. With multiport 21175e38483bSChristian Borntraeger * this might take some host<->guest communication - thus we have to 21185e38483bSChristian Borntraeger * wait. 21195e38483bSChristian Borntraeger */ 21205e38483bSChristian Borntraeger if (multiport && early) 21215e38483bSChristian Borntraeger wait_for_completion(&early_console_added); 21225e38483bSChristian Borntraeger 212351df0accSAmit Shah return 0; 212451df0accSAmit Shah 212551df0accSAmit Shah free_vqs: 212651df0accSAmit Shah /* The host might want to notify mgmt sw about device add failure */ 212751df0accSAmit Shah __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, 212851df0accSAmit Shah VIRTIO_CONSOLE_DEVICE_READY, 0); 2129a0e2dbfcSAmit Shah remove_vqs(portdev); 213051df0accSAmit Shah free_chrdev: 213151df0accSAmit Shah unregister_chrdev(portdev->chr_major, "virtio-portsdev"); 213251df0accSAmit Shah free: 213351df0accSAmit Shah kfree(portdev); 213451df0accSAmit Shah fail: 213551df0accSAmit Shah return err; 213651df0accSAmit Shah } 213751df0accSAmit Shah 213851df0accSAmit Shah static void virtcons_remove(struct virtio_device *vdev) 213951df0accSAmit Shah { 214051df0accSAmit Shah struct ports_device *portdev; 214151df0accSAmit Shah struct port *port, *port2; 214251df0accSAmit Shah 214351df0accSAmit Shah portdev = vdev->priv; 214451df0accSAmit Shah 214551df0accSAmit Shah spin_lock_irq(&pdrvdata_lock); 214651df0accSAmit Shah list_del(&portdev->list); 214751df0accSAmit Shah spin_unlock_irq(&pdrvdata_lock); 214851df0accSAmit Shah 214951df0accSAmit Shah /* Disable interrupts for vqs */ 215051df0accSAmit Shah vdev->config->reset(vdev); 215151df0accSAmit Shah /* Finish up work that's lined up */ 2152aded024aSSjur Brændeland if (use_multiport(portdev)) 215351df0accSAmit Shah cancel_work_sync(&portdev->control_work); 2154eeb8a7e8SMichael S. Tsirkin else 2155eeb8a7e8SMichael S. Tsirkin cancel_work_sync(&portdev->config_work); 215651df0accSAmit Shah 215751df0accSAmit Shah list_for_each_entry_safe(port, port2, &portdev->ports, list) 215851df0accSAmit Shah unplug_port(port); 215951df0accSAmit Shah 216051df0accSAmit Shah unregister_chrdev(portdev->chr_major, "virtio-portsdev"); 216151df0accSAmit Shah 216251df0accSAmit Shah /* 216351df0accSAmit Shah * When yanking out a device, we immediately lose the 216451df0accSAmit Shah * (device-side) queues. So there's no point in keeping the 216551df0accSAmit Shah * guest side around till we drop our final reference. This 216651df0accSAmit Shah * also means that any ports which are in an open state will 216751df0accSAmit Shah * have to just stop using the port, as the vqs are going 216851df0accSAmit Shah * away. 216951df0accSAmit Shah */ 2170a0e2dbfcSAmit Shah remove_controlq_data(portdev); 2171a0e2dbfcSAmit Shah remove_vqs(portdev); 217251df0accSAmit Shah kfree(portdev); 217351df0accSAmit Shah } 217451df0accSAmit Shah 217551df0accSAmit Shah static struct virtio_device_id id_table[] = { 217651df0accSAmit Shah { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, 217751df0accSAmit Shah { 0 }, 217851df0accSAmit Shah }; 217951df0accSAmit Shah 218051df0accSAmit Shah static unsigned int features[] = { 218151df0accSAmit Shah VIRTIO_CONSOLE_F_SIZE, 218251df0accSAmit Shah VIRTIO_CONSOLE_F_MULTIPORT, 218351df0accSAmit Shah }; 218451df0accSAmit Shah 21851b637046SSjur Brændeland static struct virtio_device_id rproc_serial_id_table[] = { 21861b637046SSjur Brændeland #if IS_ENABLED(CONFIG_REMOTEPROC) 21871b637046SSjur Brændeland { VIRTIO_ID_RPROC_SERIAL, VIRTIO_DEV_ANY_ID }, 21881b637046SSjur Brændeland #endif 21891b637046SSjur Brændeland { 0 }, 21901b637046SSjur Brændeland }; 21911b637046SSjur Brændeland 21921b637046SSjur Brændeland static unsigned int rproc_serial_features[] = { 21931b637046SSjur Brændeland }; 21941b637046SSjur Brændeland 219589107000SAaron Lu #ifdef CONFIG_PM_SLEEP 21962b8f41d8SAmit Shah static int virtcons_freeze(struct virtio_device *vdev) 21972b8f41d8SAmit Shah { 21982b8f41d8SAmit Shah struct ports_device *portdev; 21992b8f41d8SAmit Shah struct port *port; 22002b8f41d8SAmit Shah 22012b8f41d8SAmit Shah portdev = vdev->priv; 22022b8f41d8SAmit Shah 22032b8f41d8SAmit Shah vdev->config->reset(vdev); 22042b8f41d8SAmit Shah 22052055997fSMichael S. Tsirkin if (use_multiport(portdev)) 2206c743d09dSAmit Shah virtqueue_disable_cb(portdev->c_ivq); 22072b8f41d8SAmit Shah cancel_work_sync(&portdev->control_work); 2208eeb8a7e8SMichael S. Tsirkin cancel_work_sync(&portdev->config_work); 2209c743d09dSAmit Shah /* 2210c743d09dSAmit Shah * Once more: if control_work_handler() was running, it would 2211c743d09dSAmit Shah * enable the cb as the last step. 2212c743d09dSAmit Shah */ 22132055997fSMichael S. Tsirkin if (use_multiport(portdev)) 2214c743d09dSAmit Shah virtqueue_disable_cb(portdev->c_ivq); 22152b8f41d8SAmit Shah remove_controlq_data(portdev); 22162b8f41d8SAmit Shah 22172b8f41d8SAmit Shah list_for_each_entry(port, &portdev->ports, list) { 2218c743d09dSAmit Shah virtqueue_disable_cb(port->in_vq); 2219c743d09dSAmit Shah virtqueue_disable_cb(port->out_vq); 22202b8f41d8SAmit Shah /* 22212b8f41d8SAmit Shah * We'll ask the host later if the new invocation has 22222b8f41d8SAmit Shah * the port opened or closed. 22232b8f41d8SAmit Shah */ 22242b8f41d8SAmit Shah port->host_connected = false; 22252b8f41d8SAmit Shah remove_port_data(port); 22262b8f41d8SAmit Shah } 22272b8f41d8SAmit Shah remove_vqs(portdev); 22282b8f41d8SAmit Shah 22292b8f41d8SAmit Shah return 0; 22302b8f41d8SAmit Shah } 22312b8f41d8SAmit Shah 22322b8f41d8SAmit Shah static int virtcons_restore(struct virtio_device *vdev) 22332b8f41d8SAmit Shah { 22342b8f41d8SAmit Shah struct ports_device *portdev; 22352b8f41d8SAmit Shah struct port *port; 22362b8f41d8SAmit Shah int ret; 22372b8f41d8SAmit Shah 22382b8f41d8SAmit Shah portdev = vdev->priv; 22392b8f41d8SAmit Shah 22402b8f41d8SAmit Shah ret = init_vqs(portdev); 22412b8f41d8SAmit Shah if (ret) 22422b8f41d8SAmit Shah return ret; 22432b8f41d8SAmit Shah 2244401bbdc9SMichael S. Tsirkin virtio_device_ready(portdev->vdev); 2245401bbdc9SMichael S. Tsirkin 22462b8f41d8SAmit Shah if (use_multiport(portdev)) 2247165b1b8bSAmit Shah fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); 22482b8f41d8SAmit Shah 22492b8f41d8SAmit Shah list_for_each_entry(port, &portdev->ports, list) { 22502b8f41d8SAmit Shah port->in_vq = portdev->in_vqs[port->id]; 22512b8f41d8SAmit Shah port->out_vq = portdev->out_vqs[port->id]; 22522b8f41d8SAmit Shah 22532b8f41d8SAmit Shah fill_queue(port->in_vq, &port->inbuf_lock); 22542b8f41d8SAmit Shah 22552b8f41d8SAmit Shah /* Get port open/close status on the host */ 22562b8f41d8SAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); 2257fa8b66ccSAmit Shah 2258fa8b66ccSAmit Shah /* 2259fa8b66ccSAmit Shah * If a port was open at the time of suspending, we 2260fa8b66ccSAmit Shah * have to let the host know that it's still open. 2261fa8b66ccSAmit Shah */ 2262fa8b66ccSAmit Shah if (port->guest_connected) 2263fa8b66ccSAmit Shah send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); 22642b8f41d8SAmit Shah } 22652b8f41d8SAmit Shah return 0; 22662b8f41d8SAmit Shah } 22672b8f41d8SAmit Shah #endif 22682b8f41d8SAmit Shah 226951df0accSAmit Shah static struct virtio_driver virtio_console = { 227051df0accSAmit Shah .feature_table = features, 227151df0accSAmit Shah .feature_table_size = ARRAY_SIZE(features), 227251df0accSAmit Shah .driver.name = KBUILD_MODNAME, 227351df0accSAmit Shah .driver.owner = THIS_MODULE, 227451df0accSAmit Shah .id_table = id_table, 227551df0accSAmit Shah .probe = virtcons_probe, 227651df0accSAmit Shah .remove = virtcons_remove, 227751df0accSAmit Shah .config_changed = config_intr, 227889107000SAaron Lu #ifdef CONFIG_PM_SLEEP 22792b8f41d8SAmit Shah .freeze = virtcons_freeze, 22802b8f41d8SAmit Shah .restore = virtcons_restore, 22812b8f41d8SAmit Shah #endif 228251df0accSAmit Shah }; 228351df0accSAmit Shah 2284bcd2982aSGreg Kroah-Hartman static struct virtio_driver virtio_rproc_serial = { 22851b637046SSjur Brændeland .feature_table = rproc_serial_features, 22861b637046SSjur Brændeland .feature_table_size = ARRAY_SIZE(rproc_serial_features), 22871b637046SSjur Brændeland .driver.name = "virtio_rproc_serial", 22881b637046SSjur Brændeland .driver.owner = THIS_MODULE, 22891b637046SSjur Brændeland .id_table = rproc_serial_id_table, 22901b637046SSjur Brændeland .probe = virtcons_probe, 22911b637046SSjur Brændeland .remove = virtcons_remove, 22921b637046SSjur Brændeland }; 22931b637046SSjur Brændeland 229451df0accSAmit Shah static int __init init(void) 229551df0accSAmit Shah { 229651df0accSAmit Shah int err; 229751df0accSAmit Shah 229851df0accSAmit Shah pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); 229951df0accSAmit Shah if (IS_ERR(pdrvdata.class)) { 230051df0accSAmit Shah err = PTR_ERR(pdrvdata.class); 230151df0accSAmit Shah pr_err("Error %d creating virtio-ports class\n", err); 230251df0accSAmit Shah return err; 230351df0accSAmit Shah } 230451df0accSAmit Shah 230551df0accSAmit Shah pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); 23063f0d0c9bSDan Carpenter if (!pdrvdata.debugfs_dir) 23073f0d0c9bSDan Carpenter pr_warning("Error creating debugfs dir for virtio-ports\n"); 230851df0accSAmit Shah INIT_LIST_HEAD(&pdrvdata.consoles); 230951df0accSAmit Shah INIT_LIST_HEAD(&pdrvdata.portdevs); 231051df0accSAmit Shah 231133e1afc3SAlexey Khoroshilov err = register_virtio_driver(&virtio_console); 231233e1afc3SAlexey Khoroshilov if (err < 0) { 231333e1afc3SAlexey Khoroshilov pr_err("Error %d registering virtio driver\n", err); 231433e1afc3SAlexey Khoroshilov goto free; 231533e1afc3SAlexey Khoroshilov } 23161b637046SSjur Brændeland err = register_virtio_driver(&virtio_rproc_serial); 23171b637046SSjur Brændeland if (err < 0) { 23181b637046SSjur Brændeland pr_err("Error %d registering virtio rproc serial driver\n", 23191b637046SSjur Brændeland err); 23201b637046SSjur Brændeland goto unregister; 23211b637046SSjur Brændeland } 232233e1afc3SAlexey Khoroshilov return 0; 23231b637046SSjur Brændeland unregister: 23241b637046SSjur Brændeland unregister_virtio_driver(&virtio_console); 232533e1afc3SAlexey Khoroshilov free: 232633e1afc3SAlexey Khoroshilov debugfs_remove_recursive(pdrvdata.debugfs_dir); 232733e1afc3SAlexey Khoroshilov class_destroy(pdrvdata.class); 232833e1afc3SAlexey Khoroshilov return err; 232951df0accSAmit Shah } 233051df0accSAmit Shah 233151df0accSAmit Shah static void __exit fini(void) 233251df0accSAmit Shah { 23331b637046SSjur Brændeland reclaim_dma_bufs(); 23341b637046SSjur Brændeland 233551df0accSAmit Shah unregister_virtio_driver(&virtio_console); 23361b637046SSjur Brændeland unregister_virtio_driver(&virtio_rproc_serial); 233751df0accSAmit Shah 233851df0accSAmit Shah class_destroy(pdrvdata.class); 233951df0accSAmit Shah debugfs_remove_recursive(pdrvdata.debugfs_dir); 234051df0accSAmit Shah } 234151df0accSAmit Shah module_init(init); 234251df0accSAmit Shah module_exit(fini); 234351df0accSAmit Shah 234451df0accSAmit Shah MODULE_DEVICE_TABLE(virtio, id_table); 234551df0accSAmit Shah MODULE_DESCRIPTION("Virtio console driver"); 234651df0accSAmit Shah MODULE_LICENSE("GPL"); 2347