diff options
Diffstat (limited to 'drivers/char/virtio_console.c')
| -rw-r--r-- | drivers/char/virtio_console.c | 328 |
1 files changed, 129 insertions, 199 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index fbeb71953526..088182e54deb 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation * Copyright (C) 2009, 2010, 2011 Red Hat, Inc. * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/cdev.h> #include <linux/debugfs.h> @@ -26,6 +13,7 @@ #include <linux/fs.h> #include <linux/splice.h> #include <linux/pagemap.h> +#include <linux/idr.h> #include <linux/init.h> #include <linux/list.h> #include <linux/poll.h> @@ -38,9 +26,11 @@ #include <linux/workqueue.h> #include <linux/module.h> #include <linux/dma-mapping.h> +#include <linux/string_choices.h> #include "../tty/hvc/hvc_console.h" #define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) +#define VIRTCONS_MAX_PORTS 0x8000 /* * This is a global struct for storing common data for all the devices @@ -51,32 +41,22 @@ * across multiple devices and multiple ports per device. */ struct ports_driver_data { - /* Used for registering chardevs */ - struct class *class; - /* Used for exporting per-port information to debugfs */ struct dentry *debugfs_dir; /* List of all the devices we're handling */ struct list_head portdevs; - /* - * This is used to keep track of the number of hvc consoles - * spawned by this driver. This number is given as the first - * argument to hvc_alloc(). To correctly map an initial - * console spawned via hvc_instantiate to the console being - * hooked up via hvc_alloc, we need to pass the same vtermno. - * - * We also just assume the first console being initialised was - * the first one that got used as the initial console. - */ - unsigned int next_vtermno; - /* All the console devices handled by this driver */ struct list_head consoles; }; + static struct ports_driver_data pdrvdata; +static const struct class port_class = { + .name = "virtio-ports", +}; + static DEFINE_SPINLOCK(pdrvdata_lock); static DECLARE_COMPLETION(early_console_added); @@ -101,6 +81,8 @@ struct console { u32 vtermno; }; +static DEFINE_IDA(vtermno_ida); + struct port_buffer { char *buf; @@ -125,7 +107,7 @@ struct port_buffer { unsigned int sgpages; /* sg is used if spages > 0. sg must be the last in is struct */ - struct scatterlist sg[0]; + struct scatterlist sg[] __counted_by(sgpages); }; /* @@ -249,9 +231,6 @@ struct port { bool guest_connected; }; -/* This is the very early arch-specified put chars function. */ -static int (*early_put_chars)(u32, const char *, int); - static struct port *find_port_by_vtermno(u32 vtermno) { struct port *port; @@ -448,12 +427,12 @@ static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size /* * Allocate DMA memory from ancestor. When a virtio * device is created by remoteproc, the DMA memory is - * associated with the grandparent device: - * vdev => rproc => platform-dev. + * associated with the parent device: + * virtioY => remoteprocX#vdevYbuffer. */ - if (!vdev->dev.parent || !vdev->dev.parent->parent) + buf->dev = vdev->dev.parent; + if (!buf->dev) goto free_buf; - buf->dev = vdev->dev.parent->parent; /* Increase device refcnt to avoid freeing it */ get_device(buf->dev); @@ -488,7 +467,7 @@ static struct port_buffer *get_inbuf(struct port *port) buf = virtqueue_get_buf(port->in_vq, &len); if (buf) { - buf->len = len; + buf->len = min_t(size_t, len, buf->size); buf->offset = 0; port->stats.bytes_received += len; } @@ -672,7 +651,7 @@ done: * Give out the data that's requested from the buffer that we have * queued up. */ -static ssize_t fill_readbuf(struct port *port, char __user *out_buf, +static ssize_t fill_readbuf(struct port *port, u8 __user *out_buf, size_t out_count, bool to_user) { struct port_buffer *buf; @@ -691,7 +670,7 @@ static ssize_t fill_readbuf(struct port *port, char __user *out_buf, if (ret) return -EFAULT; } else { - memcpy((__force char *)out_buf, buf->buf + buf->offset, + memcpy((__force u8 *)out_buf, buf->buf + buf->offset, out_count); } @@ -884,7 +863,7 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, return 0; /* Try lock this page */ - if (pipe_buf_steal(pipe, buf) == 0) { + if (pipe_buf_try_steal(pipe, buf)) { /* Get reference and unlock page for moving */ get_page(buf->page); unlock_page(buf->page); @@ -905,9 +884,9 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, if (len + offset > PAGE_SIZE) len = PAGE_SIZE - offset; - src = kmap_atomic(buf->page); + src = kmap_local_page(buf->page); memcpy(page_address(page) + offset, src + buf->offset, len); - kunmap_atomic(src); + kunmap_local(src); sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); } @@ -932,6 +911,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, .pos = *ppos, .u.data = &sgl, }; + unsigned int occupancy; /* * Rproc_serial does not yet support splice. To support splice @@ -942,21 +922,18 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, if (is_rproc_serial(port->out_vq->vdev)) return -EINVAL; - /* - * pipe->nrbufs == 0 means there are no data to transfer, - * so this returns just 0 for no data. - */ pipe_lock(pipe); - if (!pipe->nrbufs) { - ret = 0; + ret = 0; + if (pipe_is_empty(pipe)) goto error_out; - } ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); if (ret < 0) goto error_out; - buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs); + occupancy = pipe_buf_usage(pipe); + buf = alloc_buf(port->portdev->vdev, 0, occupancy); + if (!buf) { ret = -ENOMEM; goto error_out; @@ -964,7 +941,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, sgl.n = 0; sgl.len = 0; - sgl.size = pipe->nrbufs; + sgl.size = occupancy; sgl.sg = buf->sg; sg_init_table(sgl.sg, sgl.size); ret = __splice_from_pipe(pipe, &sd, pipe_to_sg); @@ -1117,7 +1094,6 @@ static const struct file_operations port_fops = { .poll = port_fops_poll, .release = port_fops_release, .fasync = port_fops_fasync, - .llseek = no_llseek, }; /* @@ -1128,16 +1104,13 @@ static const struct file_operations port_fops = { * it to finish: inefficient in theory, but in practice * implementations will do it immediately. */ -static int put_chars(u32 vtermno, const char *buf, int count) +static ssize_t put_chars(u32 vtermno, const u8 *buf, size_t count) { struct port *port; struct scatterlist sg[1]; void *data; int ret; - if (unlikely(early_put_chars)) - return early_put_chars(vtermno, buf, count); - port = find_port_by_vtermno(vtermno); if (!port) return -EPIPE; @@ -1159,14 +1132,10 @@ static int put_chars(u32 vtermno, const char *buf, int count) * We call out to fill_readbuf that gets us the required data from the * buffers that are queued up. */ -static int get_chars(u32 vtermno, char *buf, int count) +static ssize_t get_chars(u32 vtermno, u8 *buf, size_t count) { struct port *port; - /* If we've not set up the port yet, we have no input to give. */ - if (unlikely(early_put_chars)) - return 0; - port = find_port_by_vtermno(vtermno); if (!port) return -EPIPE; @@ -1174,7 +1143,7 @@ static int get_chars(u32 vtermno, char *buf, int count) /* If we don't have an input queue yet, we can't get input. */ BUG_ON(!port->in_vq); - return fill_readbuf(port, (__force char __user *)buf, count, false); + return fill_readbuf(port, (__force u8 __user *)buf, count, false); } static void resize_console(struct port *port) @@ -1222,21 +1191,6 @@ static const struct hv_ops hv_ops = { .notifier_hangup = notifier_del_vio, }; -/* - * Console drivers are initialized very early so boot messages can go - * out, so we do things slightly differently from the generic virtio - * initialization of the net and block drivers. - * - * At this stage, the console is output-only. It's too early to set - * up a virtqueue, so we let the drivers do some boutique early-output - * thing. - */ -int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) -{ - early_put_chars = put_chars; - return hvc_instantiate(0, 0, &hv_ops); -} - static int init_port_console(struct port *port) { int ret; @@ -1258,29 +1212,25 @@ static int init_port_console(struct port *port) * pointers. The final argument is the output buffer size: we * can do any size, so we put PAGE_SIZE here. */ - port->cons.vtermno = pdrvdata.next_vtermno; + ret = ida_alloc_min(&vtermno_ida, 1, GFP_KERNEL); + if (ret < 0) + return ret; + port->cons.vtermno = ret; port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE); if (IS_ERR(port->cons.hvc)) { ret = PTR_ERR(port->cons.hvc); dev_err(port->dev, "error %d allocating hvc for port\n", ret); port->cons.hvc = NULL; + ida_free(&vtermno_ida, port->cons.vtermno); return ret; } spin_lock_irq(&pdrvdata_lock); - pdrvdata.next_vtermno++; list_add_tail(&port->cons.list, &pdrvdata.consoles); spin_unlock_irq(&pdrvdata_lock); port->guest_connected = true; - /* - * Start using the new console output if this is the first - * console to come up. - */ - if (early_put_chars) - early_put_chars = NULL; - /* Notify host of port being opened */ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); @@ -1320,8 +1270,7 @@ static int port_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "bytes_sent: %lu\n", port->stats.bytes_sent); seq_printf(s, "bytes_received: %lu\n", port->stats.bytes_received); seq_printf(s, "bytes_discarded: %lu\n", port->stats.bytes_discarded); - seq_printf(s, "is_console: %s\n", - is_console_port(port) ? "yes" : "no"); + seq_printf(s, "is_console: %s\n", str_yes_no(is_console_port(port))); seq_printf(s, "console_vtermno: %u\n", port->cons.vtermno); return 0; @@ -1338,24 +1287,24 @@ static void set_console_size(struct port *port, u16 rows, u16 cols) port->cons.ws.ws_col = cols; } -static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) +static int fill_queue(struct virtqueue *vq, spinlock_t *lock) { struct port_buffer *buf; - unsigned int nr_added_bufs; + int nr_added_bufs; int ret; nr_added_bufs = 0; do { buf = alloc_buf(vq->vdev, PAGE_SIZE, 0); if (!buf) - break; + return -ENOMEM; spin_lock_irq(lock); ret = add_inbuf(vq, buf); if (ret < 0) { spin_unlock_irq(lock); free_buf(buf, true); - break; + return ret; } nr_added_bufs++; spin_unlock_irq(lock); @@ -1372,10 +1321,8 @@ static void send_sigio_to_port(struct port *port) static int add_port(struct ports_device *portdev, u32 id) { - char debugfs_name[16]; struct port *port; dev_t devt; - unsigned int nr_added_bufs; int err; port = kmalloc(sizeof(*port), GFP_KERNEL); @@ -1394,6 +1341,7 @@ static int add_port(struct ports_device *portdev, u32 id) port->async_queue = NULL; port->cons.ws.ws_row = port->cons.ws.ws_col = 0; + port->cons.vtermno = 0; port->host_connected = port->guest_connected = false; port->stats = (struct port_stats) { 0 }; @@ -1418,7 +1366,7 @@ static int add_port(struct ports_device *portdev, u32 id) "Error %d adding cdev for port %u\n", err, id); goto free_cdev; } - port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, + port->dev = device_create(&port_class, &port->portdev->vdev->dev, devt, port, "vport%up%u", port->portdev->vdev->index, id); if (IS_ERR(port->dev)) { @@ -1433,11 +1381,13 @@ static int add_port(struct ports_device *portdev, u32 id) spin_lock_init(&port->outvq_lock); init_waitqueue_head(&port->waitqueue); - /* Fill the in_vq with buffers so the host can send us data. */ - nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); - if (!nr_added_bufs) { + /* We can safely ignore ENOSPC because it means + * the queue already has buffers. Buffers are removed + * only by virtcons_remove(), not by unplug_port() + */ + err = fill_queue(port->in_vq, &port->inbuf_lock); + if (err < 0 && err != -ENOSPC) { dev_err(port->dev, "Error allocating inbufs\n"); - err = -ENOMEM; goto free_device; } @@ -1469,23 +1419,18 @@ static int add_port(struct ports_device *portdev, u32 id) */ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); - if (pdrvdata.debugfs_dir) { - /* - * Finally, create the debugfs file that we can use to - * inspect a port's state at any time - */ - snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", - port->portdev->vdev->index, id); - port->debugfs_file = debugfs_create_file(debugfs_name, 0444, - pdrvdata.debugfs_dir, - port, - &port_debugfs_fops); - } + /* + * Finally, create the debugfs file that we can use to + * inspect a port's state at any time + */ + port->debugfs_file = debugfs_create_file(dev_name(port->dev), 0444, + pdrvdata.debugfs_dir, + port, &port_debugfs_fops); return 0; free_inbufs: free_device: - device_destroy(pdrvdata.class, port->dev->devt); + device_destroy(&port_class, port->dev->devt); free_cdev: cdev_del(port->cdev); free_port: @@ -1547,6 +1492,7 @@ static void unplug_port(struct port *port) list_del(&port->cons.list); spin_unlock_irq(&pdrvdata_lock); hvc_remove(port->cons.hvc); + ida_free(&vtermno_ida, port->cons.vtermno); } remove_port_data(port); @@ -1559,7 +1505,7 @@ static void unplug_port(struct port *port) port->portdev = NULL; sysfs_remove_group(&port->dev->kobj, &port_attribute_group); - device_destroy(pdrvdata.class, port->dev->devt); + device_destroy(&port_class, port->dev->devt); cdev_del(port->cdev); debugfs_remove(port->debugfs_file); @@ -1630,8 +1576,8 @@ static void handle_control_message(struct virtio_device *vdev, break; case VIRTIO_CONSOLE_RESIZE: { struct { - __u16 rows; - __u16 cols; + __virtio16 cols; + __virtio16 rows; } size; if (!is_console_port(port)) @@ -1639,7 +1585,8 @@ static void handle_control_message(struct virtio_device *vdev, memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), sizeof(size)); - set_console_size(port, size.rows, size.cols); + set_console_size(port, virtio16_to_cpu(vdev, size.rows), + virtio16_to_cpu(vdev, size.cols)); port->cons.hvc->irq_requested = 1; resize_console(port); @@ -1685,9 +1632,8 @@ static void handle_control_message(struct virtio_device *vdev, "Not enough space to store port name\n"); break; } - strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt), - name_size - 1); - port->name[name_size - 1] = 0; + strscpy(port->name, buf->buf + buf->offset + sizeof(*cpkt), + name_size); /* * Since we only have one sysfs attribute, 'name', @@ -1725,7 +1671,7 @@ static void control_work_handler(struct work_struct *work) while ((buf = virtqueue_get_buf(vq, &len))) { spin_unlock(&portdev->c_ivq_lock); - buf->len = len; + buf->len = min_t(size_t, len, buf->size); buf->offset = 0; handle_control_message(vq->vdev, portdev, buf); @@ -1855,8 +1801,7 @@ static void config_work_handler(struct work_struct *work) static int init_vqs(struct ports_device *portdev) { - vq_callback_t **io_callbacks; - char **io_names; + struct virtqueue_info *vqs_info; struct virtqueue **vqs; u32 i, j, nr_ports, nr_queues; int err; @@ -1865,15 +1810,12 @@ static int init_vqs(struct ports_device *portdev) nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; vqs = kmalloc_array(nr_queues, sizeof(struct virtqueue *), GFP_KERNEL); - io_callbacks = kmalloc_array(nr_queues, sizeof(vq_callback_t *), - GFP_KERNEL); - io_names = kmalloc_array(nr_queues, sizeof(char *), GFP_KERNEL); + vqs_info = kcalloc(nr_queues, sizeof(*vqs_info), GFP_KERNEL); portdev->in_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *), GFP_KERNEL); portdev->out_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *), GFP_KERNEL); - if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || - !portdev->out_vqs) { + if (!vqs || !vqs_info || !portdev->in_vqs || !portdev->out_vqs) { err = -ENOMEM; goto free; } @@ -1884,30 +1826,27 @@ static int init_vqs(struct ports_device *portdev) * 0 before others. */ j = 0; - io_callbacks[j] = in_intr; - io_callbacks[j + 1] = out_intr; - io_names[j] = "input"; - io_names[j + 1] = "output"; + vqs_info[j].callback = in_intr; + vqs_info[j + 1].callback = out_intr; + vqs_info[j].name = "input"; + vqs_info[j + 1].name = "output"; j += 2; if (use_multiport(portdev)) { - io_callbacks[j] = control_intr; - io_callbacks[j + 1] = NULL; - io_names[j] = "control-i"; - io_names[j + 1] = "control-o"; + vqs_info[j].callback = control_intr; + vqs_info[j].name = "control-i"; + vqs_info[j + 1].name = "control-o"; for (i = 1; i < nr_ports; i++) { j += 2; - io_callbacks[j] = in_intr; - io_callbacks[j + 1] = out_intr; - io_names[j] = "input"; - io_names[j + 1] = "output"; + vqs_info[j].callback = in_intr; + vqs_info[j + 1].callback = out_intr; + vqs_info[j].name = "input"; + vqs_info[j + 1].name = "output"; } } /* Find the queues. */ - err = virtio_find_vqs(portdev->vdev, nr_queues, vqs, - io_callbacks, - (const char **)io_names, NULL); + err = virtio_find_vqs(portdev->vdev, nr_queues, vqs, vqs_info, NULL); if (err) goto free; @@ -1925,8 +1864,7 @@ static int init_vqs(struct ports_device *portdev) portdev->out_vqs[i] = vqs[j + 1]; } } - kfree(io_names); - kfree(io_callbacks); + kfree(vqs_info); kfree(vqs); return 0; @@ -1934,8 +1872,7 @@ static int init_vqs(struct ports_device *portdev) free: kfree(portdev->out_vqs); kfree(portdev->in_vqs); - kfree(io_names); - kfree(io_callbacks); + kfree(vqs_info); kfree(vqs); return err; @@ -1955,6 +1892,7 @@ static void remove_vqs(struct ports_device *portdev) flush_bufs(vq, true); while ((buf = virtqueue_detach_unused_buf(vq))) free_buf(buf, true); + cond_resched(); } portdev->vdev->config->del_vqs(portdev->vdev); kfree(portdev->in_vqs); @@ -1972,8 +1910,15 @@ static void virtcons_remove(struct virtio_device *vdev) list_del(&portdev->list); spin_unlock_irq(&pdrvdata_lock); + /* Device is going away, exit any polling for buffers */ + virtio_break_device(vdev); + if (use_multiport(portdev)) + flush_work(&portdev->control_work); + else + flush_work(&portdev->config_work); + /* Disable interrupts for vqs */ - vdev->config->reset(vdev); + virtio_reset_device(vdev); /* Finish up work that's lined up */ if (use_multiport(portdev)) cancel_work_sync(&portdev->control_work); @@ -2010,7 +1955,6 @@ static int virtcons_probe(struct virtio_device *vdev) struct ports_device *portdev; int err; bool multiport; - bool early = early_put_chars != NULL; /* We only need a config space if features are offered */ if (!vdev->config->get && @@ -2021,9 +1965,6 @@ static int virtcons_probe(struct virtio_device *vdev) return -EINVAL; } - /* Ensure to read early_put_chars now */ - barrier(); - portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); if (!portdev) { err = -ENOMEM; @@ -2052,33 +1993,40 @@ static int virtcons_probe(struct virtio_device *vdev) virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, struct virtio_console_config, max_nr_ports, &portdev->max_nr_ports) == 0) { + if (portdev->max_nr_ports == 0 || + portdev->max_nr_ports > VIRTCONS_MAX_PORTS) { + dev_err(&vdev->dev, + "Invalidate max_nr_ports %d", + portdev->max_nr_ports); + err = -EINVAL; + goto free; + } multiport = true; } - err = init_vqs(portdev); - if (err < 0) { - dev_err(&vdev->dev, "Error %d initializing vqs\n", err); - goto free_chrdev; - } - spin_lock_init(&portdev->ports_lock); INIT_LIST_HEAD(&portdev->ports); INIT_LIST_HEAD(&portdev->list); - virtio_device_ready(portdev->vdev); - INIT_WORK(&portdev->config_work, &config_work_handler); INIT_WORK(&portdev->control_work, &control_work_handler); if (multiport) { - unsigned int nr_added_bufs; - spin_lock_init(&portdev->c_ivq_lock); spin_lock_init(&portdev->c_ovq_lock); + } + + err = init_vqs(portdev); + if (err < 0) { + dev_err(&vdev->dev, "Error %d initializing vqs\n", err); + goto free_chrdev; + } + + virtio_device_ready(portdev->vdev); - nr_added_bufs = fill_queue(portdev->c_ivq, - &portdev->c_ivq_lock); - if (!nr_added_bufs) { + if (multiport) { + err = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); + if (err < 0) { dev_err(&vdev->dev, "Error allocating buffers for control queue\n"); /* @@ -2089,7 +2037,7 @@ static int virtcons_probe(struct virtio_device *vdev) VIRTIO_CONSOLE_DEVICE_READY, 0); /* Device was functional: we need full cleanup. */ virtcons_remove(vdev); - return -ENOMEM; + return err; } } else { /* @@ -2106,18 +2054,6 @@ static int virtcons_probe(struct virtio_device *vdev) __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 1); - /* - * If there was an early virtio console, assume that there are no - * other consoles. We need to wait until the hvc_alloc matches the - * hvc_instantiate, otherwise tty_open will complain, resulting in - * a "Warning: unable to open an initial console" boot failure. - * Without multiport this is done in add_port above. With multiport - * this might take some host<->guest communication - thus we have to - * wait. - */ - if (multiport && early) - wait_for_completion(&early_console_added); - return 0; free_chrdev: @@ -2128,24 +2064,26 @@ fail: return err; } -static struct virtio_device_id id_table[] = { +static const struct virtio_device_id id_table[] = { { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, { 0 }, }; +MODULE_DEVICE_TABLE(virtio, id_table); -static unsigned int features[] = { +static const unsigned int features[] = { VIRTIO_CONSOLE_F_SIZE, VIRTIO_CONSOLE_F_MULTIPORT, }; -static struct virtio_device_id rproc_serial_id_table[] = { +static const struct virtio_device_id rproc_serial_id_table[] = { #if IS_ENABLED(CONFIG_REMOTEPROC) { VIRTIO_ID_RPROC_SERIAL, VIRTIO_DEV_ANY_ID }, #endif { 0 }, }; +MODULE_DEVICE_TABLE(virtio, rproc_serial_id_table); -static unsigned int rproc_serial_features[] = { +static const unsigned int rproc_serial_features[] = { }; #ifdef CONFIG_PM_SLEEP @@ -2156,7 +2094,7 @@ static int virtcons_freeze(struct virtio_device *vdev) portdev = vdev->priv; - vdev->config->reset(vdev); + virtio_reset_device(vdev); if (use_multiport(portdev)) virtqueue_disable_cb(portdev->c_ivq); @@ -2225,7 +2163,6 @@ static struct virtio_driver virtio_console = { .feature_table = features, .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, - .driver.owner = THIS_MODULE, .id_table = id_table, .probe = virtcons_probe, .remove = virtcons_remove, @@ -2240,26 +2177,20 @@ static struct virtio_driver virtio_rproc_serial = { .feature_table = rproc_serial_features, .feature_table_size = ARRAY_SIZE(rproc_serial_features), .driver.name = "virtio_rproc_serial", - .driver.owner = THIS_MODULE, .id_table = rproc_serial_id_table, .probe = virtcons_probe, .remove = virtcons_remove, }; -static int __init init(void) +static int __init virtio_console_init(void) { int err; - pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); - if (IS_ERR(pdrvdata.class)) { - err = PTR_ERR(pdrvdata.class); - pr_err("Error %d creating virtio-ports class\n", err); + err = class_register(&port_class); + if (err) return err; - } pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); - if (!pdrvdata.debugfs_dir) - pr_warn("Error creating debugfs dir for virtio-ports\n"); INIT_LIST_HEAD(&pdrvdata.consoles); INIT_LIST_HEAD(&pdrvdata.portdevs); @@ -2279,23 +2210,22 @@ unregister: unregister_virtio_driver(&virtio_console); free: debugfs_remove_recursive(pdrvdata.debugfs_dir); - class_destroy(pdrvdata.class); + class_unregister(&port_class); return err; } -static void __exit fini(void) +static void __exit virtio_console_fini(void) { reclaim_dma_bufs(); unregister_virtio_driver(&virtio_console); unregister_virtio_driver(&virtio_rproc_serial); - class_destroy(pdrvdata.class); + class_unregister(&port_class); debugfs_remove_recursive(pdrvdata.debugfs_dir); } -module_init(init); -module_exit(fini); +module_init(virtio_console_init); +module_exit(virtio_console_fini); -MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Virtio console driver"); MODULE_LICENSE("GPL"); |
